From ddfdb0de7acb4ea97aab14dce003cc93b0fea23d Mon Sep 17 00:00:00 2001 From: "Carl J. Bialorucki" Date: Thu, 8 Jan 2026 23:17:08 -0600 Subject: [PATCH] [KERNEL32_WINETEST] Sync kernel32 winetest to wine-10.0 - [KERNEL32_WINETEST] Sync to wine-10.0 - [KERNEL32_WINETEST] Define out tests we can't yet build, fix test failures for WS03-Win 10 1607. - [KERNEL32_WINETEST] Consolidate header hacks needed for the winesync in winehacks.h. This documents what incompatibilities we need to work around in our and Wine headers in one place. --- .../winetests/kernel32/CMakeLists.txt | 70 +- modules/rostests/winetests/kernel32/actctx.c | 2681 ++++-- modules/rostests/winetests/kernel32/atom.c | 40 +- modules/rostests/winetests/kernel32/change.c | 372 +- .../rostests/winetests/kernel32/codepage.c | 344 +- modules/rostests/winetests/kernel32/comm.c | 401 +- modules/rostests/winetests/kernel32/console.c | 3376 +++++++- .../rostests/winetests/kernel32/debugger.c | 1988 ++++- .../rostests/winetests/kernel32/directory.c | 137 +- modules/rostests/winetests/kernel32/drive.c | 63 +- modules/rostests/winetests/kernel32/dummy.c | 42 + .../rostests/winetests/kernel32/dummy.spec | 1 + modules/rostests/winetests/kernel32/environ.c | 591 +- modules/rostests/winetests/kernel32/fiber.c | 804 +- modules/rostests/winetests/kernel32/file.c | 3125 +++++-- .../rostests/winetests/kernel32/format_msg.c | 1500 ++-- .../rostests/winetests/kernel32/generated.c | 284 +- .../winetests/kernel32/get_fpu_cw.asm | 10 + modules/rostests/winetests/kernel32/heap.c | 4583 ++++++++-- modules/rostests/winetests/kernel32/loader.c | 2871 +++++-- modules/rostests/winetests/kernel32/locale.c | 7374 ++++++++++++----- .../rostests/winetests/kernel32/mailslot.c | 194 +- modules/rostests/winetests/kernel32/module.c | 1169 ++- modules/rostests/winetests/kernel32/path.c | 1305 +-- modules/rostests/winetests/kernel32/pipe.c | 2001 ++++- modules/rostests/winetests/kernel32/power.c | 83 + modules/rostests/winetests/kernel32/process.c | 3466 ++++++-- modules/rostests/winetests/kernel32/profile.c | 867 +- .../rostests/winetests/kernel32/resource.c | 417 +- .../rostests/winetests/kernel32/resource.rc | 6 + modules/rostests/winetests/kernel32/sync.c | 1109 ++- .../rostests/winetests/kernel32/testlist.c | 6 +- modules/rostests/winetests/kernel32/thread.c | 1152 ++- modules/rostests/winetests/kernel32/time.c | 433 +- modules/rostests/winetests/kernel32/timer.c | 213 +- .../rostests/winetests/kernel32/toolhelp.c | 206 +- modules/rostests/winetests/kernel32/version.c | 484 +- modules/rostests/winetests/kernel32/virtual.c | 3336 ++++---- modules/rostests/winetests/kernel32/volume.c | 1137 ++- .../winetests/kernel32/wine_test.manifest | 4 + .../rostests/winetests/kernel32/winehacks.h | 32 + 41 files changed, 36260 insertions(+), 12017 deletions(-) create mode 100644 modules/rostests/winetests/kernel32/dummy.c create mode 100644 modules/rostests/winetests/kernel32/dummy.spec create mode 100644 modules/rostests/winetests/kernel32/get_fpu_cw.asm create mode 100644 modules/rostests/winetests/kernel32/power.c create mode 100644 modules/rostests/winetests/kernel32/wine_test.manifest create mode 100644 modules/rostests/winetests/kernel32/winehacks.h diff --git a/modules/rostests/winetests/kernel32/CMakeLists.txt b/modules/rostests/winetests/kernel32/CMakeLists.txt index e095252ab02..518e005ab18 100644 --- a/modules/rostests/winetests/kernel32/CMakeLists.txt +++ b/modules/rostests/winetests/kernel32/CMakeLists.txt @@ -1,13 +1,19 @@ -add_definitions(-D__ROS_LONG64__) - include_directories(BEFORE ${REACTOS_SOURCE_DIR}/sdk/include/wine) -remove_definitions(-DWINVER=0x502 -D_WIN32_IE=0x600 -D_WIN32_WINNT=0x502) -add_definitions(-DWINVER=0x600 -D_WIN32_WINNT=0x601) +remove_definitions(-DWINVER=0x502 -D_WIN32_IE=0x600 -D_WIN32_WINNT=0x502 -D_CRT_NON_CONFORMING_SWPRINTFS) +add_definitions(-DWINVER=0x0A00 -D_WIN32_WINNT=0x0A00 -DNTDDI_VERSION=0x0A000007) -add_definitions( - -Dstrcasecmp=_stricmp -) +# Comment this block out if you want to debug the heap issue with these tests on ROS x64. ROSTESTS-415 +if(ARCH STREQUAL "amd64") + add_definitions(-DSKIPBADHEAP_K32_WINETEST=1) +endif() + +spec2def(dummy.dll dummy.spec) +add_library(kernel32_winetest_dummy MODULE dummy.c ${CMAKE_CURRENT_BINARY_DIR}/dummy.def) +set_target_properties(kernel32_winetest_dummy PROPERTIES OUTPUT_NAME "dummy") +set_module_type(kernel32_winetest_dummy win32dll) +add_importlibs(kernel32_winetest_dummy msvcrt kernel32) +add_rostests_file(TARGET kernel32_winetest_dummy) list(APPEND SOURCE actctx.c @@ -31,6 +37,7 @@ list(APPEND SOURCE module.c path.c pipe.c + power.c process.c profile.c resource.c @@ -46,28 +53,57 @@ list(APPEND SOURCE list(APPEND PCH_SKIP_SOURCE testlist.c) +if (MSVC AND ARCH STREQUAL "amd64") + list(APPEND SOURCE + get_fpu_cw.asm) +endif() + add_executable(kernel32_winetest ${SOURCE} ${PCH_SKIP_SOURCE} resource.rc) -if(MSVC) - # Disable warning C4477 (printf format warnings) - remove_target_compile_option(kernel32_winetest "/we4477") +# CMake 3.9 and higher requires to specify this dependency manually +# see https://gitlab.kitware.com/cmake/cmake/issues/19933 +set_property(SOURCE resource.rc PROPERTY OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/dummy.dll ${CMAKE_CURRENT_BINARY_DIR}/dummy.dll) - if(ARCH STREQUAL "amd64") - # error C4101: 'is_wow64': unreferenced local variable - remove_target_compile_option(kernel32_winetest "/we4101") - target_compile_options(kernel32_winetest PRIVATE /wd4101) - endif() +# resource.rc: let rc.exe find the dlls in their subdirectory, i.e. Debug. +if (MSVC_IDE) + target_include_directories(kernel32_winetest PRIVATE + $<$:$>) +endif() + +if (MSVC) + # error C4101: unreferenced local variable + target_compile_options(kernel32_winetest PRIVATE /wd4101) + + # Approximates a __FILE__ macro with forward slashes instead of back slashes + # and defines it as __FILE_FW_SLASH__. + foreach(source_file ${SOURCE}) + get_filename_component(abs_source_file "${source_file}" ABSOLUTE) + file(RELATIVE_PATH rel_path "${CMAKE_SOURCE_DIR}" "${abs_source_file}") + string(REPLACE "\\" "/" rel_path_forward "${rel_path}") + set_source_files_properties(${source_file} PROPERTIES + COMPILE_DEFINITIONS "__FILE_FW_SLASH__=\"../${rel_path_forward}\"" + ) + endforeach() endif() if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang") - target_compile_options(kernel32_winetest PRIVATE "-Wno-format") + target_compile_options(kernel32_winetest PRIVATE + -Wno-format + -Wno-int-conversion + -Wno-old-style-declaration + -Wno-unused) endif() set_module_type(kernel32_winetest win32cui) -target_link_libraries(kernel32_winetest pseh) +target_link_libraries(kernel32_winetest pseh oldnames) add_importlibs(kernel32_winetest user32 advapi32 msvcrt kernel32 ntdll) add_pch(kernel32_winetest precomp.h "${PCH_SKIP_SOURCE}") add_rostests_file(TARGET kernel32_winetest) +target_compile_definitions(kernel32_winetest PRIVATE + WINETEST_USE_DBGSTR_LONGLONG + __WINESRC__ + strncasecmp=_strnicmp + strcasecmp=_stricmp) diff --git a/modules/rostests/winetests/kernel32/actctx.c b/modules/rostests/winetests/kernel32/actctx.c index 1e7d80d93a1..150099172fc 100644 --- a/modules/rostests/winetests/kernel32/actctx.c +++ b/modules/rostests/winetests/kernel32/actctx.c @@ -29,41 +29,20 @@ #include "oaidl.h" #include "initguid.h" -static BOOL (WINAPI *pActivateActCtx)(HANDLE,ULONG_PTR*); -static HANDLE (WINAPI *pCreateActCtxA)(PCACTCTXA); -static HANDLE (WINAPI *pCreateActCtxW)(PCACTCTXW); -static BOOL (WINAPI *pDeactivateActCtx)(DWORD,ULONG_PTR); -static BOOL (WINAPI *pFindActCtxSectionStringA)(DWORD,const GUID *,ULONG,LPCSTR,PACTCTX_SECTION_KEYED_DATA); -static BOOL (WINAPI *pFindActCtxSectionStringW)(DWORD,const GUID *,ULONG,LPCWSTR,PACTCTX_SECTION_KEYED_DATA); -static BOOL (WINAPI *pGetCurrentActCtx)(HANDLE *); -static BOOL (WINAPI *pIsDebuggerPresent)(void); -static BOOL (WINAPI *pQueryActCtxW)(DWORD,HANDLE,PVOID,ULONG,PVOID,SIZE_T,SIZE_T*); -static VOID (WINAPI *pReleaseActCtx)(HANDLE); -static BOOL (WINAPI *pFindActCtxSectionGuid)(DWORD,const GUID*,ULONG,const GUID*,PACTCTX_SECTION_KEYED_DATA); -static BOOL (WINAPI *pZombifyActCtx)(HANDLE); +static BOOL (WINAPI *pQueryActCtxSettingsW)(DWORD,HANDLE,LPCWSTR,LPCWSTR,LPWSTR,SIZE_T,SIZE_T*); static NTSTATUS(NTAPI *pRtlFindActivationContextSectionString)(DWORD,const GUID *,ULONG,PUNICODE_STRING,PACTCTX_SECTION_KEYED_DATA); static BOOLEAN (NTAPI *pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING, PCSZ); static VOID (NTAPI *pRtlFreeUnicodeString)(PUNICODE_STRING); -static const char* strw(LPCWSTR x) -{ - static char buffer[1024]; - char* p = buffer; - - if (!x) return "(nil)"; - else while ((*p++ = *x++)); - return buffer; -} - #ifdef __i386__ #define ARCH "x86" +#elif defined __aarch64__ || defined__arm64ec__ +#define ARCH "arm64" #elif defined __x86_64__ #define ARCH "amd64" #elif defined __arm__ #define ARCH "arm" -#elif defined __aarch64__ -#define ARCH "arm64" #else #define ARCH "none" #endif @@ -141,6 +120,12 @@ static const char manifest3[] = " numMethods=\"10\"" " baseInterface=\"{66666666-8888-7777-6666-555555555557}\"" " />" +" " +" " +" " +"" +"" +" " "" " " +" " " "; +static const char manifest10[] = +"" +"" +"" +" " +" " +" " +" " +" " +"" +""; + +/* Empty element */ +static const char manifest11[] = +"" +"" +"" +""; + static const char testdep_manifest1[] = "" "" @@ -397,6 +406,15 @@ static const char wrong_manifest10[] = "" ""; +/* activatableClass with the wrong xmlns is invalid */ +static const char wrong_manifest11[] = +"" +"" +"" +" " +"" +""; + static const char wrong_depmanifest1[] = "" "" @@ -431,6 +449,8 @@ static const char compat_manifest_vista_7_8_10_81[] = " " /* Windows 8 */ " " /* Windows 10 */ " " /* Windows 8.1 */ +" " +" " " " " " ""; @@ -445,6 +465,103 @@ static const char compat_manifest_other_guid[] = " " ""; +static const char settings_manifest[] = +"" +" " +" " +" " +" true" +" true" +" " +" " +""; + +static const char settings_manifest2[] = +"" +" " +" " +" " +" true" +" true" +" true" +" true" +" true" +" true" +" true" +" true" +" true" +" true" +" true" +" " +" " +""; + +/* broken manifest found in some binaries: asmv3 namespace is used but not declared */ +static const char settings_manifest3[] = +"" +" " +" " +" " +" true" +" " +" " +""; + +static const char settings_manifest4[] = +"" +" " +" " +" " +" " +" true" +" " +" " +" " +" " +" " +" true" +" " +" " +""; + +static const char two_dll_manifest_dll[] = +"" +" " +" " +""; + +static const char two_dll_manifest_exe[] = +"" +" " +" " +" " +" " +" " +""; + +static const char builtin_dll_manifest[] = +"" +" " +" " +" " +" " +" " +""; + +static const char empty_assembly_manifest[] = +""; + DEFINE_GUID(VISTA_COMPAT_GUID, 0xe2011457, 0x1546, 0x43c5, 0xa5, 0xfe, 0x00, 0x8d, 0xee, 0xe3, 0xd3, 0xf0); DEFINE_GUID(WIN7_COMPAT_GUID, 0x35138b9a, 0x5d96, 0x4fbd, 0x8e, 0x2d, 0xa2, 0x44, 0x02, 0x25, 0xf9, 0x3a); DEFINE_GUID(WIN8_COMPAT_GUID, 0x4a2f28e3, 0x53b9, 0x4441, 0xba, 0x9c, 0xd6, 0x9d, 0x4a, 0x4a, 0x6e, 0x38); @@ -469,20 +586,6 @@ static const WCHAR wndClass3W[] = static WCHAR app_dir[MAX_PATH], exe_path[MAX_PATH], work_dir[MAX_PATH], work_dir_subdir[MAX_PATH]; static WCHAR app_manifest_path[MAX_PATH], manifest_path[MAX_PATH], depmanifest_path[MAX_PATH]; -static int strcmp_aw(LPCWSTR strw, const char *stra) -{ - WCHAR buf[1024]; - - if (!stra) return 1; - MultiByteToWideChar(CP_ACP, 0, stra, -1, buf, sizeof(buf)/sizeof(WCHAR)); - return lstrcmpW(strw, buf); -} - -static DWORD strlen_aw(const char *str) -{ - return MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0) - 1; -} - static BOOL create_manifest_file(const char *filename, const char *manifest, int manifest_len, const char *depfile, const char *depmanifest) { @@ -491,14 +594,14 @@ static BOOL create_manifest_file(const char *filename, const char *manifest, int WCHAR path[MAX_PATH]; MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH ); - GetFullPathNameW(path, sizeof(manifest_path)/sizeof(WCHAR), manifest_path, NULL); + GetFullPathNameW(path, ARRAY_SIZE(manifest_path), manifest_path, NULL); if (manifest_len == -1) manifest_len = strlen(manifest); file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError()); + ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %lu\n", GetLastError()); if(file == INVALID_HANDLE_VALUE) return FALSE; WriteFile(file, manifest, manifest_len, &size, NULL); @@ -507,10 +610,10 @@ static BOOL create_manifest_file(const char *filename, const char *manifest, int if (depmanifest) { MultiByteToWideChar( CP_ACP, 0, depfile, -1, path, MAX_PATH ); - GetFullPathNameW(path, sizeof(depmanifest_path)/sizeof(WCHAR), depmanifest_path, NULL); + GetFullPathNameW(path, ARRAY_SIZE(depmanifest_path), depmanifest_path, NULL); file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError()); + ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %lu\n", GetLastError()); if(file == INVALID_HANDLE_VALUE) return FALSE; WriteFile(file, depmanifest, strlen(depmanifest), &size, NULL); @@ -538,6 +641,50 @@ static BOOL create_wide_manifest(const char *filename, const char *manifest, BOO return ret; } +static HANDLE create_temp_manifest_file(const char *manifest, WCHAR *pathname) +{ + WCHAR tmp_path[MAX_PATH]; + DWORD size, tmp_path_len; + HANDLE file, file_w; + UINT unique; + + tmp_path_len = GetTempPathW(ARRAY_SIZE(tmp_path), tmp_path); + ok(tmp_path_len != 0, "GetTempPathW returned error %lu\n", GetLastError()); + ok(tmp_path_len < ARRAY_SIZE(tmp_path), "GetTempPathW return value %lu should be less than %Iu\n", + tmp_path_len, ARRAY_SIZE(tmp_path)); + + memset(pathname, 0, MAX_PATH * sizeof(WCHAR)); + unique = GetTempFileNameW(tmp_path, L"tst", 0, pathname); + ok(unique != 0, "GetTempFileNameW returned error %lu\n", GetLastError()); + + /* Open file handle that will be deleted on close or process termination */ + file = CreateFileW(pathname, + GENERIC_READ | DELETE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, + NULL); + ok(file != INVALID_HANDLE_VALUE, "CreateFile returned error %lu\n", GetLastError()); + + /* Re-open file with write access */ + file_w = CreateFileW(pathname, + GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + TRUNCATE_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + ok(file_w != INVALID_HANDLE_VALUE, "CreateFile returned error %lu\n", GetLastError()); + + WriteFile(file_w, manifest, strlen(manifest), &size, NULL); + + /* Close file handle that was open for write to avoid sharing violation */ + CloseHandle(file_w); + + return file; +} + typedef struct { ULONG format_version; ULONG assembly_cnt_min; @@ -556,7 +703,7 @@ static const detailed_info_t detailed_info0 = { static const detailed_info_t detailed_info1 = { 1, 1, 1, ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE, manifest_path, ACTIVATION_CONTEXT_PATH_TYPE_NONE, ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE, - work_dir, + app_dir, }; static const detailed_info_t detailed_info1_child = { @@ -569,7 +716,7 @@ static const detailed_info_t detailed_info1_child = { static const detailed_info_t detailed_info2 = { 1, 2, 3, ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE, manifest_path, ACTIVATION_CONTEXT_PATH_TYPE_NONE, ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE, - work_dir, + app_dir, }; static void test_detailed_info(HANDLE handle, const detailed_info_t *exinfo, int line) @@ -584,56 +731,53 @@ static void test_detailed_info(HANDLE handle, const detailed_info_t *exinfo, int if(exsize != sizeof(ACTIVATION_CONTEXT_DETAILED_INFORMATION)) { size = 0xdeadbeef; - b = pQueryActCtxW(0, handle, NULL, - ActivationContextDetailedInformation, &detailed_info_tmp, - sizeof(detailed_info_tmp), &size); + b = QueryActCtxW(0, handle, NULL, ActivationContextDetailedInformation, &detailed_info_tmp, + sizeof(detailed_info_tmp), &size); ok_(__FILE__, line)(!b, "QueryActCtx succeeded\n"); - ok_(__FILE__, line)(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetLastError() = %u\n", GetLastError()); - ok_(__FILE__, line)(size == exsize, "size=%ld, expected %ld\n", size, exsize); + ok_(__FILE__, line)(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetLastError() = %lu\n", GetLastError()); + ok_(__FILE__, line)(size == exsize, "size=%Id, expected %Id\n", size, exsize); }else { size = sizeof(ACTIVATION_CONTEXT_DETAILED_INFORMATION); } detailed_info = HeapAlloc(GetProcessHeap(), 0, size); memset(detailed_info, 0xfe, size); - b = pQueryActCtxW(0, handle, NULL, - ActivationContextDetailedInformation, detailed_info, - size, &retsize); - ok_(__FILE__, line)(b, "QueryActCtx failed: %u\n", GetLastError()); - ok_(__FILE__, line)(retsize == exsize, "size=%ld, expected %ld\n", retsize, exsize); + b = QueryActCtxW(0, handle, NULL, ActivationContextDetailedInformation, detailed_info, size, &retsize); + ok_(__FILE__, line)(b, "QueryActCtx failed: %lu\n", GetLastError()); + ok_(__FILE__, line)(retsize == exsize, "size=%Id, expected %Id\n", retsize, exsize); - ok_(__FILE__, line)(detailed_info->dwFlags == 0, "detailed_info->dwFlags=%x\n", detailed_info->dwFlags); + ok_(__FILE__, line)(detailed_info->dwFlags == 0, "detailed_info->dwFlags=%lx\n", detailed_info->dwFlags); ok_(__FILE__, line)(detailed_info->ulFormatVersion == exinfo->format_version, - "detailed_info->ulFormatVersion=%u, expected %u\n", detailed_info->ulFormatVersion, + "detailed_info->ulFormatVersion=%lu, expected %lu\n", detailed_info->ulFormatVersion, exinfo->format_version); ok_(__FILE__, line)(exinfo->assembly_cnt_min <= detailed_info->ulAssemblyCount && detailed_info->ulAssemblyCount <= exinfo->assembly_cnt_max, - "detailed_info->ulAssemblyCount=%u, expected between %u and %u\n", detailed_info->ulAssemblyCount, + "detailed_info->ulAssemblyCount=%lu, expected between %lu and %lu\n", detailed_info->ulAssemblyCount, exinfo->assembly_cnt_min, exinfo->assembly_cnt_max); ok_(__FILE__, line)(detailed_info->ulRootManifestPathType == exinfo->root_manifest_type, - "detailed_info->ulRootManifestPathType=%u, expected %u\n", + "detailed_info->ulRootManifestPathType=%lu, expected %lu\n", detailed_info->ulRootManifestPathType, exinfo->root_manifest_type); ok_(__FILE__, line)(detailed_info->ulRootManifestPathChars == (exinfo->root_manifest_path ? lstrlenW(exinfo->root_manifest_path) : 0), - "detailed_info->ulRootManifestPathChars=%u, expected %u\n", + "detailed_info->ulRootManifestPathChars=%lu, expected %u\n", detailed_info->ulRootManifestPathChars, exinfo->root_manifest_path ?lstrlenW(exinfo->root_manifest_path) : 0); ok_(__FILE__, line)(detailed_info->ulRootConfigurationPathType == exinfo->root_config_type, - "detailed_info->ulRootConfigurationPathType=%u, expected %u\n", + "detailed_info->ulRootConfigurationPathType=%lu, expected %lu\n", detailed_info->ulRootConfigurationPathType, exinfo->root_config_type); ok_(__FILE__, line)(detailed_info->ulRootConfigurationPathChars == 0, - "detailed_info->ulRootConfigurationPathChars=%d\n", detailed_info->ulRootConfigurationPathChars); + "detailed_info->ulRootConfigurationPathChars=%ld\n", detailed_info->ulRootConfigurationPathChars); ok_(__FILE__, line)(detailed_info->ulAppDirPathType == exinfo->app_dir_type, - "detailed_info->ulAppDirPathType=%u, expected %u\n", detailed_info->ulAppDirPathType, + "detailed_info->ulAppDirPathType=%lu, expected %lu\n", detailed_info->ulAppDirPathType, exinfo->app_dir_type); ok_(__FILE__, line)(detailed_info->ulAppDirPathChars == (exinfo->app_dir ? lstrlenW(exinfo->app_dir) : 0), - "detailed_info->ulAppDirPathChars=%u, expected %u\n", + "detailed_info->ulAppDirPathChars=%lu, expected %u\n", detailed_info->ulAppDirPathChars, exinfo->app_dir ? lstrlenW(exinfo->app_dir) : 0); if(exinfo->root_manifest_path) { ok_(__FILE__, line)(detailed_info->lpRootManifestPath != NULL, "detailed_info->lpRootManifestPath == NULL\n"); if(detailed_info->lpRootManifestPath) ok_(__FILE__, line)(!lstrcmpiW(detailed_info->lpRootManifestPath, exinfo->root_manifest_path), - "unexpected detailed_info->lpRootManifestPath\n"); + "unexpected detailed_info->lpRootManifestPath %s\n", wine_dbgstr_w(detailed_info->lpRootManifestPath)); }else { ok_(__FILE__, line)(detailed_info->lpRootManifestPath == NULL, "detailed_info->lpRootManifestPath != NULL\n"); } @@ -643,7 +787,8 @@ static void test_detailed_info(HANDLE handle, const detailed_info_t *exinfo, int ok_(__FILE__, line)(detailed_info->lpAppDirPath != NULL, "detailed_info->lpAppDirPath == NULL\n"); if(detailed_info->lpAppDirPath) ok_(__FILE__, line)(!lstrcmpiW(exinfo->app_dir, detailed_info->lpAppDirPath), - "unexpected detailed_info->lpAppDirPath\n%s\n",strw(detailed_info->lpAppDirPath)); + "unexpected detailed_info->lpAppDirPath %s / %s\n", + wine_dbgstr_w(detailed_info->lpAppDirPath), wine_dbgstr_w( exinfo->app_dir )); }else { ok_(__FILE__, line)(detailed_info->lpAppDirPath == NULL, "detailed_info->lpAppDirPath != NULL\n"); } @@ -655,57 +800,57 @@ typedef struct { ULONG flags; /* ULONG manifest_path_type; FIXME */ LPCWSTR manifest_path; - LPCSTR encoded_assembly_id; + LPCWSTR encoded_assembly_id; BOOL has_assembly_dir; } info_in_assembly; static const info_in_assembly manifest1_info = { 1, manifest_path, - "Wine.Test,type=\"win32\",version=\"1.0.0.0\"", + L"Wine.Test,type=\"win32\",version=\"1.0.0.0\"", FALSE }; static const info_in_assembly manifest1_child_info = { 1, app_manifest_path, - "Wine.Test,type=\"win32\",version=\"1.0.0.0\"", + L"Wine.Test,type=\"win32\",version=\"1.0.0.0\"", FALSE }; static const info_in_assembly manifest2_info = { 1, manifest_path, - "Wine.Test,type=\"win32\",version=\"1.2.3.4\"", + L"Wine.Test,type=\"win32\",version=\"1.2.3.4\"", FALSE }; static const info_in_assembly manifest3_info = { 1, manifest_path, - "Wine.Test,publicKeyToken=\"6595b6414666f1df\",type=\"win32\",version=\"1.2.3.4\"", + L"Wine.Test,publicKeyToken=\"6595b6414666f1df\",type=\"win32\",version=\"1.2.3.4\"", FALSE }; static const info_in_assembly manifest4_info = { 1, manifest_path, - "Wine.Test,type=\"win32\",version=\"1.2.3.4\"", + L"Wine.Test,type=\"win32\",version=\"1.2.3.4\"", FALSE }; static const info_in_assembly depmanifest1_info = { 0x10, depmanifest_path, - "testdep,processorArchitecture=\"" ARCH "\"," + L"testdep,processorArchitecture=\"" ARCH "\"," "type=\"win32\",version=\"6.5.4.3\"", TRUE }; static const info_in_assembly depmanifest2_info = { 0x10, depmanifest_path, - "testdep,processorArchitecture=\"" ARCH "\"," + L"testdep,processorArchitecture=\"" ARCH "\"," "type=\"win32\",version=\"6.5.4.3\"", TRUE }; static const info_in_assembly depmanifest3_info = { 0x10, depmanifest_path, - "testdep,processorArchitecture=\"" ARCH "\",type=\"win32\",version=\"6.5.4.3\"", + L"testdep,processorArchitecture=\"" ARCH "\",type=\"win32\",version=\"6.5.4.3\"", TRUE }; @@ -722,16 +867,14 @@ static void test_info_in_assembly(HANDLE handle, DWORD id, const info_in_assembl exsize = sizeof(ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION); if (exinfo->manifest_path) exsize += (lstrlenW(exinfo->manifest_path)+1) * sizeof(WCHAR); - if (exinfo->encoded_assembly_id) exsize += (strlen_aw(exinfo->encoded_assembly_id) + 1) * sizeof(WCHAR); + if (exinfo->encoded_assembly_id) exsize += (lstrlenW(exinfo->encoded_assembly_id) + 1) * sizeof(WCHAR); size = 0xdeadbeef; - b = pQueryActCtxW(0, handle, &id, - AssemblyDetailedInformationInActivationContext, &info_tmp, - sizeof(info_tmp), &size); + b = QueryActCtxW(0, handle, &id, AssemblyDetailedInformationInActivationContext, &info_tmp, sizeof(info_tmp), &size); ok_(__FILE__, line)(!b, "QueryActCtx succeeded\n"); - ok_(__FILE__, line)(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetLastError() = %u\n", GetLastError()); + ok_(__FILE__, line)(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetLastError() = %lu\n", GetLastError()); - ok_(__FILE__, line)(size >= exsize, "size=%lu, expected %lu\n", size, exsize); + ok_(__FILE__, line)(size >= exsize, "size=%Iu, expected %Iu\n", size, exsize); if (size == 0xdeadbeef) { @@ -743,54 +886,53 @@ static void test_info_in_assembly(HANDLE handle, DWORD id, const info_in_assembl memset(info, 0xfe, size); size = 0xdeadbeef; - b = pQueryActCtxW(0, handle, &id, - AssemblyDetailedInformationInActivationContext, info, size, &size); - ok_(__FILE__, line)(b, "QueryActCtx failed: %u\n", GetLastError()); + b = QueryActCtxW(0, handle, &id, AssemblyDetailedInformationInActivationContext, info, size, &size); + ok_(__FILE__, line)(b, "QueryActCtx failed: %lu\n", GetLastError()); if (!exinfo->manifest_path) exsize += info->ulManifestPathLength + sizeof(WCHAR); if (!exinfo->encoded_assembly_id) exsize += info->ulEncodedAssemblyIdentityLength + sizeof(WCHAR); if (exinfo->has_assembly_dir) exsize += info->ulAssemblyDirectoryNameLength + sizeof(WCHAR); - ok_(__FILE__, line)(size == exsize, "size=%lu, expected %lu\n", size, exsize); + ok_(__FILE__, line)(size == exsize, "size=%Iu, expected %Iu\n", size, exsize); if (0) /* FIXME: flags meaning unknown */ { - ok_(__FILE__, line)((info->ulFlags) == exinfo->flags, "info->ulFlags = %x, expected %x\n", + ok_(__FILE__, line)((info->ulFlags) == exinfo->flags, "info->ulFlags = %lx, expected %lx\n", info->ulFlags, exinfo->flags); } if(exinfo->encoded_assembly_id) { - len = strlen_aw(exinfo->encoded_assembly_id)*sizeof(WCHAR); + len = lstrlenW(exinfo->encoded_assembly_id)*sizeof(WCHAR); ok_(__FILE__, line)(info->ulEncodedAssemblyIdentityLength == len, - "info->ulEncodedAssemblyIdentityLength = %u, expected %u\n", + "info->ulEncodedAssemblyIdentityLength = %lu, expected %lu\n", info->ulEncodedAssemblyIdentityLength, len); } else { ok_(__FILE__, line)(info->ulEncodedAssemblyIdentityLength != 0, "info->ulEncodedAssemblyIdentityLength == 0\n"); } ok_(__FILE__, line)(info->ulManifestPathType == ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE, - "info->ulManifestPathType = %x\n", info->ulManifestPathType); + "info->ulManifestPathType = %lx\n", info->ulManifestPathType); if(exinfo->manifest_path) { len = lstrlenW(exinfo->manifest_path)*sizeof(WCHAR); - ok_(__FILE__, line)(info->ulManifestPathLength == len, "info->ulManifestPathLength = %u, expected %u\n", + ok_(__FILE__, line)(info->ulManifestPathLength == len, "info->ulManifestPathLength = %lu, expected %lu\n", info->ulManifestPathLength, len); } else { ok_(__FILE__, line)(info->ulManifestPathLength != 0, "info->ulManifestPathLength == 0\n"); } ok_(__FILE__, line)(info->ulPolicyPathType == ACTIVATION_CONTEXT_PATH_TYPE_NONE, - "info->ulPolicyPathType = %x\n", info->ulPolicyPathType); + "info->ulPolicyPathType = %lx\n", info->ulPolicyPathType); ok_(__FILE__, line)(info->ulPolicyPathLength == 0, - "info->ulPolicyPathLength = %u, expected 0\n", info->ulPolicyPathLength); - ok_(__FILE__, line)(info->ulMetadataSatelliteRosterIndex == 0, "info->ulMetadataSatelliteRosterIndex = %x\n", + "info->ulPolicyPathLength = %lu, expected 0\n", info->ulPolicyPathLength); + ok_(__FILE__, line)(info->ulMetadataSatelliteRosterIndex == 0, "info->ulMetadataSatelliteRosterIndex = %lx\n", info->ulMetadataSatelliteRosterIndex); - ok_(__FILE__, line)(info->ulManifestVersionMajor == 1,"info->ulManifestVersionMajor = %x\n", + ok_(__FILE__, line)(info->ulManifestVersionMajor == 1,"info->ulManifestVersionMajor = %lx\n", info->ulManifestVersionMajor); - ok_(__FILE__, line)(info->ulManifestVersionMinor == 0, "info->ulManifestVersionMinor = %x\n", + ok_(__FILE__, line)(info->ulManifestVersionMinor == 0, "info->ulManifestVersionMinor = %lx\n", info->ulManifestVersionMinor); - ok_(__FILE__, line)(info->ulPolicyVersionMajor == 0, "info->ulPolicyVersionMajor = %x\n", + ok_(__FILE__, line)(info->ulPolicyVersionMajor == 0, "info->ulPolicyVersionMajor = %lx\n", info->ulPolicyVersionMajor); - ok_(__FILE__, line)(info->ulPolicyVersionMinor == 0, "info->ulPolicyVersionMinor = %x\n", + ok_(__FILE__, line)(info->ulPolicyVersionMinor == 0, "info->ulPolicyVersionMinor = %lx\n", info->ulPolicyVersionMinor); if(exinfo->has_assembly_dir) ok_(__FILE__, line)(info->ulAssemblyDirectoryNameLength != 0, @@ -802,9 +944,9 @@ static void test_info_in_assembly(HANDLE handle, DWORD id, const info_in_assembl ok_(__FILE__, line)(info->lpAssemblyEncodedAssemblyIdentity != NULL, "info->lpAssemblyEncodedAssemblyIdentity == NULL\n"); if(info->lpAssemblyEncodedAssemblyIdentity && exinfo->encoded_assembly_id) { - ok_(__FILE__, line)(!strcmp_aw(info->lpAssemblyEncodedAssemblyIdentity, exinfo->encoded_assembly_id), + ok_(__FILE__, line)(!lstrcmpW(info->lpAssemblyEncodedAssemblyIdentity, exinfo->encoded_assembly_id), "unexpected info->lpAssemblyEncodedAssemblyIdentity %s / %s\n", - strw(info->lpAssemblyEncodedAssemblyIdentity), exinfo->encoded_assembly_id); + wine_dbgstr_w(info->lpAssemblyEncodedAssemblyIdentity), wine_dbgstr_w(exinfo->encoded_assembly_id)); } if(exinfo->manifest_path) { ok_(__FILE__, line)(info->lpAssemblyManifestPath != NULL, "info->lpAssemblyManifestPath == NULL\n"); @@ -822,7 +964,7 @@ static void test_info_in_assembly(HANDLE handle, DWORD id, const info_in_assembl ok_(__FILE__, line)(info->lpAssemblyDirectoryName != NULL, "info->lpAssemblyDirectoryName == NULL\n"); else ok_(__FILE__, line)(info->lpAssemblyDirectoryName == NULL, "info->lpAssemblyDirectoryName = %s\n", - strw(info->lpAssemblyDirectoryName)); + wine_dbgstr_w(info->lpAssemblyDirectoryName)); HeapFree(GetProcessHeap(), 0, info); } @@ -837,12 +979,11 @@ static void test_file_info(HANDLE handle, ULONG assid, ULONG fileid, LPCWSTR fil +(lstrlenW(filename)+1)*sizeof(WCHAR); size = 0xdeadbeef; - b = pQueryActCtxW(0, handle, &index, - FileInformationInAssemblyOfAssemblyInActivationContext, &info_tmp, + b = QueryActCtxW(0, handle, &index, FileInformationInAssemblyOfAssemblyInActivationContext, &info_tmp, sizeof(info_tmp), &size); ok_(__FILE__, line)(!b, "QueryActCtx succeeded\n"); - ok_(__FILE__, line)(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetLastError() = %u\n", GetLastError()); - ok_(__FILE__, line)(size == exsize, "size=%lu, expected %lu\n", size, exsize); + ok_(__FILE__, line)(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetLastError() = %lu\n", GetLastError()); + ok_(__FILE__, line)(size == exsize, "size=%Iu, expected %Iu\n", size, exsize); if(size == 0xdeadbeef) { @@ -853,16 +994,15 @@ static void test_file_info(HANDLE handle, ULONG assid, ULONG fileid, LPCWSTR fil info = HeapAlloc(GetProcessHeap(), 0, size); memset(info, 0xfe, size); - b = pQueryActCtxW(0, handle, &index, - FileInformationInAssemblyOfAssemblyInActivationContext, info, size, &size); - ok_(__FILE__, line)(b, "QueryActCtx failed: %u\n", GetLastError()); - ok_(__FILE__, line)(!size, "size=%lu, expected 0\n", size); + b = QueryActCtxW(0, handle, &index, FileInformationInAssemblyOfAssemblyInActivationContext, info, size, &size); + ok_(__FILE__, line)(b, "QueryActCtx failed: %lu\n", GetLastError()); + ok_(__FILE__, line)(!size, "size=%Iu, expected 0\n", size); - ok_(__FILE__, line)(info->ulFlags == 2, "info->ulFlags=%x, expected 2\n", info->ulFlags); + ok_(__FILE__, line)(info->ulFlags == 2, "info->ulFlags=%lx, expected 2\n", info->ulFlags); ok_(__FILE__, line)(info->ulFilenameLength == lstrlenW(filename)*sizeof(WCHAR), - "info->ulFilenameLength=%u, expected %u*sizeof(WCHAR)\n", + "info->ulFilenameLength=%lu, expected %u*sizeof(WCHAR)\n", info->ulFilenameLength, lstrlenW(filename)); - ok_(__FILE__, line)(info->ulPathLength == 0, "info->ulPathLength=%u\n", info->ulPathLength); + ok_(__FILE__, line)(info->ulPathLength == 0, "info->ulPathLength=%lu\n", info->ulPathLength); ok_(__FILE__, line)(info->lpFileName != NULL, "info->lpFileName == NULL\n"); if(info->lpFileName) ok_(__FILE__, line)(!lstrcmpiW(info->lpFileName, filename), "unexpected info->lpFileName\n"); @@ -902,8 +1042,7 @@ static void test_runlevel_info(HANDLE handle, const runlevel_info_t *exinfo, int BOOL b; size = sizeof(runlevel_info); - b = pQueryActCtxW(0, handle, NULL, - RunlevelInformationInActivationContext, &runlevel_info, + b = QueryActCtxW(0, handle, NULL, RunlevelInformationInActivationContext, &runlevel_info, sizeof(runlevel_info), &retsize); if (!b && GetLastError() == ERROR_INVALID_PARAMETER) { @@ -911,14 +1050,14 @@ static void test_runlevel_info(HANDLE handle, const runlevel_info_t *exinfo, int return; } - ok_(__FILE__, line)(b, "QueryActCtx failed: %u\n", GetLastError()); - ok_(__FILE__, line)(retsize == size, "size=%ld, expected %ld\n", retsize, size); + ok_(__FILE__, line)(b, "QueryActCtx failed: %lu\n", GetLastError()); + ok_(__FILE__, line)(retsize == size, "size=%Id, expected %Id\n", retsize, size); - ok_(__FILE__, line)(runlevel_info.ulFlags == 0, "runlevel_info.ulFlags=%x\n", runlevel_info.ulFlags); + ok_(__FILE__, line)(runlevel_info.ulFlags == 0, "runlevel_info.ulFlags=%lx\n", runlevel_info.ulFlags); ok_(__FILE__, line)(runlevel_info.RunLevel == exinfo->run_level, "runlevel_info.RunLevel=%u, expected %u\n", runlevel_info.RunLevel, exinfo->run_level); ok_(__FILE__, line)(runlevel_info.UiAccess == exinfo->ui_access, - "runlevel_info.UiAccess=%u, expected %u\n", runlevel_info.UiAccess, exinfo->ui_access); + "runlevel_info.UiAccess=%lu, expected %lu\n", runlevel_info.UiAccess, exinfo->ui_access); } static HANDLE test_create(const char *file) @@ -932,12 +1071,12 @@ static HANDLE test_create(const char *file) actctx.cbSize = sizeof(ACTCTXW); actctx.lpSource = path; - handle = pCreateActCtxW(&actctx); + handle = CreateActCtxW(&actctx); /* to be tested outside of this helper, including last error */ if (handle == INVALID_HANDLE_VALUE) return handle; - ok(actctx.cbSize == sizeof(actctx), "actctx.cbSize=%d\n", actctx.cbSize); - ok(actctx.dwFlags == 0, "actctx.dwFlags=%d\n", actctx.dwFlags); + ok(actctx.cbSize == sizeof(actctx), "actctx.cbSize=%ld\n", actctx.cbSize); + ok(actctx.dwFlags == 0, "actctx.dwFlags=%ld\n", actctx.dwFlags); ok(actctx.lpSource == path, "actctx.lpSource=%p\n", actctx.lpSource); ok(actctx.wProcessorArchitecture == 0, "actctx.wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture); @@ -964,7 +1103,7 @@ static void test_create_and_fail(const char *manifest, const char *depmanifest, actctx.lpSource = path; create_manifest_file("bad.manifest", manifest, -1, "testdep.manifest", depmanifest); - handle = pCreateActCtxW(&actctx); + handle = CreateActCtxW(&actctx); todo_wine_if(todo) { if (is_broken) @@ -974,9 +1113,9 @@ static void test_create_and_fail(const char *manifest, const char *depmanifest, ok(handle == INVALID_HANDLE_VALUE, "Unexpected context handle %p.\n", handle); if (handle == INVALID_HANDLE_VALUE) - ok(GetLastError() == ERROR_SXS_CANT_GEN_ACTCTX, "Unexpected error %d.\n", GetLastError()); + ok(GetLastError() == ERROR_SXS_CANT_GEN_ACTCTX, "Unexpected error %ld.\n", GetLastError()); } - if (handle != INVALID_HANDLE_VALUE) pReleaseActCtx( handle ); + if (handle != INVALID_HANDLE_VALUE) ReleaseActCtx( handle ); DeleteFileA("bad.manifest"); DeleteFileA("testdep.manifest"); } @@ -993,11 +1132,11 @@ static void test_create_wide_and_fail(const char *manifest, BOOL fBOM) actctx.lpSource = path; create_wide_manifest("bad.manifest", manifest, fBOM, FALSE); - handle = pCreateActCtxW(&actctx); + handle = CreateActCtxW(&actctx); ok(handle == INVALID_HANDLE_VALUE, "handle != INVALID_HANDLE_VALUE\n"); - ok(GetLastError() == ERROR_SXS_CANT_GEN_ACTCTX, "GetLastError == %u\n", GetLastError()); + ok(GetLastError() == ERROR_SXS_CANT_GEN_ACTCTX, "GetLastError == %lu\n", GetLastError()); - if (handle != INVALID_HANDLE_VALUE) pReleaseActCtx( handle ); + if (handle != INVALID_HANDLE_VALUE) ReleaseActCtx( handle ); DeleteFileA("bad.manifest"); } @@ -1012,9 +1151,9 @@ static void test_create_fail(void) actctx.cbSize = sizeof(ACTCTXW); actctx.lpSource = path; - handle = pCreateActCtxW(&actctx); + handle = CreateActCtxW(&actctx); ok(handle == INVALID_HANDLE_VALUE, "handle != INVALID_HANDLE_VALUE\n"); - ok(GetLastError() == ERROR_FILE_NOT_FOUND, "GetLastError == %u\n", GetLastError()); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "GetLastError == %lu\n", GetLastError()); trace("wrong_manifest1\n"); test_create_and_fail(wrong_manifest1, NULL, 0, FALSE); @@ -1036,6 +1175,8 @@ static void test_create_fail(void) test_create_and_fail(wrong_manifest9, NULL, 0, TRUE /* WinXP */); trace("wrong_manifest10\n"); test_create_and_fail(wrong_manifest10, NULL, 0, TRUE /* WinXP */); + trace("wrong_manifest11\n"); + test_create_and_fail(wrong_manifest11, NULL, 1, TRUE /* w1064v1909 */); trace("UTF-16 manifest1 without BOM\n"); test_create_wide_and_fail(manifest1, FALSE ); trace("manifest2\n"); @@ -1096,13 +1237,27 @@ struct wndclass_redirect_data ULONG module_offset;/* container name offset */ }; +struct dllredirect_data_path +{ + ULONG len; + ULONG offset; +}; + struct dllredirect_data { ULONG size; - ULONG unk; - DWORD res[3]; + ULONG flags; + ULONG total_len; + ULONG paths_count; + ULONG paths_offset; + struct dllredirect_data_path paths[1]; }; +#define DLL_REDIRECT_PATH_INCLUDES_BASE_NAME 1 +#define DLL_REDIRECT_PATH_OMITS_ASSEMBLY_ROOT 2 +#define DLL_REDIRECT_PATH_EXPAND 4 +#define DLL_REDIRECT_PATH_SYSTEM_DEFAULT_REDIRECTED_SYSTEM32_DLL 8 + struct tlibredirect_data { ULONG size; @@ -1132,61 +1287,60 @@ static void test_find_dll_redirection(HANDLE handle, LPCWSTR libname, ULONG exid memset(&data, 0xfe, sizeof(data)); data.cbSize = sizeof(data); - ret = pFindActCtxSectionStringW(0, NULL, - ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, - libname, &data); - ok_(__FILE__, line)(ret, "FindActCtxSectionStringW failed: %u\n", GetLastError()); + ret = FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, libname, &data); + ok_(__FILE__, line)(ret, "FindActCtxSectionStringW failed: %lu\n", GetLastError()); if (!ret) return; - ok_(__FILE__, line)(data.cbSize == sizeof(data), "data.cbSize=%u\n", data.cbSize); - ok_(__FILE__, line)(data.ulDataFormatVersion == 1, "data.ulDataFormatVersion=%u\n", data.ulDataFormatVersion); + ok_(__FILE__, line)(data.cbSize == sizeof(data), "data.cbSize=%lu\n", data.cbSize); + ok_(__FILE__, line)(data.ulDataFormatVersion == 1, "data.ulDataFormatVersion=%lu\n", data.ulDataFormatVersion); ok_(__FILE__, line)(data.lpData != NULL, "data.lpData == NULL\n"); - ok_(__FILE__, line)(data.ulLength == 20, "data.ulLength=%u\n", data.ulLength); + ok_(__FILE__, line)(data.ulLength == offsetof( struct dllredirect_data, paths[0]), "data.ulLength=%lu\n", data.ulLength); if (data.lpData) { struct dllredirect_data *dlldata = (struct dllredirect_data*)data.lpData; - ok_(__FILE__, line)(dlldata->size == data.ulLength, "got wrong size %d\n", dlldata->size); - ok_(__FILE__, line)(dlldata->unk == 2, "got wrong field value %d\n", dlldata->unk); - ok_(__FILE__, line)(dlldata->res[0] == 0, "got wrong res[0] value %d\n", dlldata->res[0]); - ok_(__FILE__, line)(dlldata->res[1] == 0, "got wrong res[1] value %d\n", dlldata->res[1]); - ok_(__FILE__, line)(dlldata->res[2] == 0, "got wrong res[2] value %d\n", dlldata->res[2]); + ok_(__FILE__, line)(dlldata->size == offsetof( struct dllredirect_data, paths[dlldata->paths_count]), + "got wrong size %ld\n", dlldata->size); + ok_(__FILE__, line)(dlldata->flags == DLL_REDIRECT_PATH_OMITS_ASSEMBLY_ROOT, + "got wrong flags value %lx\n", dlldata->flags); + ok_(__FILE__, line)(dlldata->total_len == 0, "got wrong total len value %ld\n", dlldata->total_len); + ok_(__FILE__, line)(dlldata->paths_count == 0, "got wrong paths count value %ld\n", dlldata->paths_count); + ok_(__FILE__, line)(dlldata->paths_offset == 0, "got wrong paths offset value %ld\n", dlldata->paths_offset); } ok_(__FILE__, line)(data.lpSectionGlobalData == NULL, "data.lpSectionGlobalData != NULL\n"); - ok_(__FILE__, line)(data.ulSectionGlobalDataLength == 0, "data.ulSectionGlobalDataLength=%u\n", + ok_(__FILE__, line)(data.ulSectionGlobalDataLength == 0, "data.ulSectionGlobalDataLength=%lu\n", data.ulSectionGlobalDataLength); ok_(__FILE__, line)(data.lpSectionBase != NULL, "data.lpSectionBase == NULL\n"); - ok_(__FILE__, line)(data.ulSectionTotalLength > 0, "data.ulSectionTotalLength=%u\n", + ok_(__FILE__, line)(data.ulSectionTotalLength > 0, "data.ulSectionTotalLength=%lu\n", data.ulSectionTotalLength); ok_(__FILE__, line)(data.hActCtx == NULL, "data.hActCtx=%p\n", data.hActCtx); - ok_(__FILE__, line)(data.ulAssemblyRosterIndex == exid, "data.ulAssemblyRosterIndex=%u, expected %u\n", + ok_(__FILE__, line)(data.ulAssemblyRosterIndex == exid, "data.ulAssemblyRosterIndex=%lu, expected %lu\n", data.ulAssemblyRosterIndex, exid); memset(&data, 0xfe, sizeof(data)); data.cbSize = sizeof(data); - ret = pFindActCtxSectionStringW(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL, - ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, - libname, &data); - ok_(__FILE__, line)(ret, "FindActCtxSectionStringW failed: %u\n", GetLastError()); + ret = FindActCtxSectionStringW(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL, + ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, libname, &data); + ok_(__FILE__, line)(ret, "FindActCtxSectionStringW failed: %lu\n", GetLastError()); if (!ret) return; - ok_(__FILE__, line)(data.cbSize == sizeof(data), "data.cbSize=%u\n", data.cbSize); - ok_(__FILE__, line)(data.ulDataFormatVersion == 1, "data.ulDataFormatVersion=%u\n", data.ulDataFormatVersion); + ok_(__FILE__, line)(data.cbSize == sizeof(data), "data.cbSize=%lu\n", data.cbSize); + ok_(__FILE__, line)(data.ulDataFormatVersion == 1, "data.ulDataFormatVersion=%lu\n", data.ulDataFormatVersion); ok_(__FILE__, line)(data.lpData != NULL, "data.lpData == NULL\n"); - ok_(__FILE__, line)(data.ulLength == 20, "data.ulLength=%u\n", data.ulLength); + ok_(__FILE__, line)(data.ulLength == 20, "data.ulLength=%lu\n", data.ulLength); ok_(__FILE__, line)(data.lpSectionGlobalData == NULL, "data.lpSectionGlobalData != NULL\n"); - ok_(__FILE__, line)(data.ulSectionGlobalDataLength == 0, "data.ulSectionGlobalDataLength=%u\n", + ok_(__FILE__, line)(data.ulSectionGlobalDataLength == 0, "data.ulSectionGlobalDataLength=%lu\n", data.ulSectionGlobalDataLength); ok_(__FILE__, line)(data.lpSectionBase != NULL, "data.lpSectionBase == NULL\n"); - ok_(__FILE__, line)(data.ulSectionTotalLength > 0, "data.ulSectionTotalLength=%u\n", + ok_(__FILE__, line)(data.ulSectionTotalLength > 0, "data.ulSectionTotalLength=%lu\n", data.ulSectionTotalLength); ok_(__FILE__, line)(data.hActCtx == handle, "data.hActCtx=%p\n", data.hActCtx); - ok_(__FILE__, line)(data.ulAssemblyRosterIndex == exid, "data.ulAssemblyRosterIndex=%u, expected %u\n", + ok_(__FILE__, line)(data.ulAssemblyRosterIndex == exid, "data.ulAssemblyRosterIndex=%lu, expected %lu\n", data.ulAssemblyRosterIndex, exid); - pReleaseActCtx(handle); + ReleaseActCtx(handle); } static void test_find_window_class(HANDLE handle, LPCWSTR clsname, ULONG exid, int line) @@ -1199,22 +1353,20 @@ static void test_find_window_class(HANDLE handle, LPCWSTR clsname, ULONG exid, i memset(&data, 0xfe, sizeof(data)); data.cbSize = sizeof(data); - ret = pFindActCtxSectionStringW(0, NULL, - ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, - clsname, &data); - ok_(__FILE__, line)(ret, "FindActCtxSectionStringW failed: %u, class %s\n", GetLastError(), + ret = FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, clsname, &data); + ok_(__FILE__, line)(ret, "FindActCtxSectionStringW failed: %lu, class %s\n", GetLastError(), wine_dbgstr_w(clsname)); if (!ret) return; header = (struct strsection_header*)data.lpSectionBase; wnddata = (struct wndclass_redirect_data*)data.lpData; - ok_(__FILE__, line)(header->magic == 0x64487353, "got wrong magic 0x%08x\n", header->magic); - ok_(__FILE__, line)(header->count > 0, "got count %d\n", header->count); - ok_(__FILE__, line)(data.cbSize == sizeof(data), "data.cbSize=%u\n", data.cbSize); - ok_(__FILE__, line)(data.ulDataFormatVersion == 1, "data.ulDataFormatVersion=%u\n", data.ulDataFormatVersion); + ok_(__FILE__, line)(header->magic == 0x64487353, "got wrong magic 0x%08lx\n", header->magic); + ok_(__FILE__, line)(header->count > 0, "got count %ld\n", header->count); + ok_(__FILE__, line)(data.cbSize == sizeof(data), "data.cbSize=%lu\n", data.cbSize); + ok_(__FILE__, line)(data.ulDataFormatVersion == 1, "data.ulDataFormatVersion=%lu\n", data.ulDataFormatVersion); ok_(__FILE__, line)(data.lpData != NULL, "data.lpData == NULL\n"); - ok_(__FILE__, line)(wnddata->size == sizeof(*wnddata), "got %d for header size\n", wnddata->size); + ok_(__FILE__, line)(wnddata->size == sizeof(*wnddata), "got %ld for header size\n", wnddata->size); if (data.lpData && wnddata->size == sizeof(*wnddata)) { static const WCHAR verW[] = {'6','.','5','.','4','.','3','!',0}; @@ -1222,10 +1374,10 @@ static void test_find_window_class(HANDLE handle, LPCWSTR clsname, ULONG exid, i WCHAR *ptr; ULONG len; - ok_(__FILE__, line)(wnddata->res == 0, "got reserved as %d\n", wnddata->res); + ok_(__FILE__, line)(wnddata->res == 0, "got reserved as %ld\n", wnddata->res); /* redirect class name (versioned or not) is stored just after header data */ - ok_(__FILE__, line)(wnddata->name_offset == wnddata->size, "got name offset as %d\n", wnddata->name_offset); - ok_(__FILE__, line)(wnddata->module_len > 0, "got module name length as %d\n", wnddata->module_len); + ok_(__FILE__, line)(wnddata->name_offset == wnddata->size, "got name offset as %ld\n", wnddata->name_offset); + ok_(__FILE__, line)(wnddata->module_len > 0, "got module name length as %ld\n", wnddata->module_len); /* expected versioned name */ lstrcpyW(buff, verW); @@ -1233,11 +1385,11 @@ static void test_find_window_class(HANDLE handle, LPCWSTR clsname, ULONG exid, i ptr = (WCHAR*)((BYTE*)wnddata + wnddata->name_offset); ok_(__FILE__, line)(!lstrcmpW(ptr, buff), "got wrong class name %s, expected %s\n", wine_dbgstr_w(ptr), wine_dbgstr_w(buff)); ok_(__FILE__, line)(lstrlenW(ptr)*sizeof(WCHAR) == wnddata->name_len, - "got wrong class name length %d, expected %d\n", wnddata->name_len, lstrlenW(ptr)); + "got wrong class name length %ld, expected %d\n", wnddata->name_len, lstrlenW(ptr)); /* data length is simply header length + string data length including nulls */ len = wnddata->size + wnddata->name_len + wnddata->module_len + 2*sizeof(WCHAR); - ok_(__FILE__, line)(data.ulLength == len, "got wrong data length %d, expected %d\n", data.ulLength, len); + ok_(__FILE__, line)(data.ulLength == len, "got wrong data length %ld, expected %ld\n", data.ulLength, len); if (data.ulSectionTotalLength > wnddata->module_offset) { @@ -1251,39 +1403,101 @@ static void test_find_window_class(HANDLE handle, LPCWSTR clsname, ULONG exid, i } ok_(__FILE__, line)(data.lpSectionGlobalData == NULL, "data.lpSectionGlobalData != NULL\n"); - ok_(__FILE__, line)(data.ulSectionGlobalDataLength == 0, "data.ulSectionGlobalDataLength=%u\n", + ok_(__FILE__, line)(data.ulSectionGlobalDataLength == 0, "data.ulSectionGlobalDataLength=%lu\n", data.ulSectionGlobalDataLength); ok_(__FILE__, line)(data.lpSectionBase != NULL, "data.lpSectionBase == NULL\n"); - ok_(__FILE__, line)(data.ulSectionTotalLength > 0, "data.ulSectionTotalLength=%u\n", + ok_(__FILE__, line)(data.ulSectionTotalLength > 0, "data.ulSectionTotalLength=%lu\n", data.ulSectionTotalLength); ok_(__FILE__, line)(data.hActCtx == NULL, "data.hActCtx=%p\n", data.hActCtx); - ok_(__FILE__, line)(data.ulAssemblyRosterIndex == exid, "data.ulAssemblyRosterIndex=%u, expected %u\n", + ok_(__FILE__, line)(data.ulAssemblyRosterIndex == exid, "data.ulAssemblyRosterIndex=%lu, expected %lu\n", data.ulAssemblyRosterIndex, exid); memset(&data, 0xfe, sizeof(data)); data.cbSize = sizeof(data); - ret = pFindActCtxSectionStringW(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL, - ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, - clsname, &data); - ok_(__FILE__, line)(ret, "FindActCtxSectionStringW failed: %u, class %s\n", GetLastError(), + ret = FindActCtxSectionStringW(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL, + ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, clsname, &data); + ok_(__FILE__, line)(ret, "FindActCtxSectionStringW failed: %lu, class %s\n", GetLastError(), wine_dbgstr_w(clsname)); if (!ret) return; - ok_(__FILE__, line)(data.cbSize == sizeof(data), "data.cbSize=%u\n", data.cbSize); - ok_(__FILE__, line)(data.ulDataFormatVersion == 1, "data.ulDataFormatVersion=%u\n", data.ulDataFormatVersion); + ok_(__FILE__, line)(data.cbSize == sizeof(data), "data.cbSize=%lu\n", data.cbSize); + ok_(__FILE__, line)(data.ulDataFormatVersion == 1, "data.ulDataFormatVersion=%lu\n", data.ulDataFormatVersion); ok_(__FILE__, line)(data.lpData != NULL, "data.lpData == NULL\n"); - ok_(__FILE__, line)(data.ulLength > 0, "data.ulLength=%u\n", data.ulLength); + ok_(__FILE__, line)(data.ulLength > 0, "data.ulLength=%lu\n", data.ulLength); ok_(__FILE__, line)(data.lpSectionGlobalData == NULL, "data.lpSectionGlobalData != NULL\n"); - ok_(__FILE__, line)(data.ulSectionGlobalDataLength == 0, "data.ulSectionGlobalDataLength=%u\n", + ok_(__FILE__, line)(data.ulSectionGlobalDataLength == 0, "data.ulSectionGlobalDataLength=%lu\n", data.ulSectionGlobalDataLength); ok_(__FILE__, line)(data.lpSectionBase != NULL, "data.lpSectionBase == NULL\n"); - ok_(__FILE__, line)(data.ulSectionTotalLength > 0, "data.ulSectionTotalLength=%u\n", data.ulSectionTotalLength); + ok_(__FILE__, line)(data.ulSectionTotalLength > 0, "data.ulSectionTotalLength=%lu\n", data.ulSectionTotalLength); ok_(__FILE__, line)(data.hActCtx == handle, "data.hActCtx=%p\n", data.hActCtx); - ok_(__FILE__, line)(data.ulAssemblyRosterIndex == exid, "data.ulAssemblyRosterIndex=%u, expected %u\n", + ok_(__FILE__, line)(data.ulAssemblyRosterIndex == exid, "data.ulAssemblyRosterIndex=%lu, expected %lu\n", data.ulAssemblyRosterIndex, exid); - pReleaseActCtx(handle); + ReleaseActCtx(handle); +} + +enum winrt_threading_model +{ + WINRT_THREADING_MODEL_BOTH = 0, + WINRT_THREADING_MODEL_STA = 1, + WINRT_THREADING_MODEL_MTA = 2, +}; + +struct activatable_class_data +{ + ULONG size; + DWORD unk; + DWORD module_len; + DWORD module_offset; + DWORD threading_model; +}; + +static void test_find_activatable_class(HANDLE handle, const WCHAR *classid, enum winrt_threading_model threading_model, + const WCHAR *file, ULONG exid, int line) +{ + struct activatable_class_data *activatable_class; + struct strsection_header *header; + ACTCTX_SECTION_KEYED_DATA data; + void *ptr; + BOOL ret; + + memset(&data, 0xfe, sizeof(data)); + data.cbSize = sizeof(data); + + ret = FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_WINRT_ACTIVATABLE_CLASSES, classid, &data); + ok_(__FILE__, line)(ret || broken(!ret) /* <= Win10 v1809 */, "FindActCtxSectionStringW failed, error %lu\n", GetLastError()); + if (!ret) + { + ok_(__FILE__, line)(GetLastError() == ERROR_SXS_SECTION_NOT_FOUND, "got error %lu\n", GetLastError()); + return; + } + + ok_(__FILE__, line)(data.cbSize == sizeof(data), "got cbSize %lu\n", data.cbSize); + ok_(__FILE__, line)(data.ulDataFormatVersion == 1, "got ulDataFormatVersion %lu\n", data.ulDataFormatVersion); + ok_(__FILE__, line)(data.lpData != NULL, "got lpData %p\n", data.lpData); + + header = (struct strsection_header *)data.lpSectionBase; + ok_(__FILE__, line)(data.lpSectionBase != NULL, "got lpSectionBase %p\n", data.lpSectionBase); + ok_(__FILE__, line)(header->magic == 0x64487353, "got wrong magic 0x%08lx\n", header->magic); + ok_(__FILE__, line)(data.ulSectionTotalLength > 0, "got ulSectionTotalLength %lu\n", data.ulSectionTotalLength); + ok_(__FILE__, line)(data.lpSectionGlobalData == (BYTE *)header + header->global_offset, + "got lpSectionGlobalData %p\n", data.lpSectionGlobalData); + ok_(__FILE__, line)(data.ulSectionGlobalDataLength == header->global_len, + "got ulSectionGlobalDataLength %lu\n", data.ulSectionGlobalDataLength); + ok_(__FILE__, line)(data.hActCtx == NULL, "got hActCtx %p\n", data.hActCtx); + ok_(__FILE__, line)(data.ulAssemblyRosterIndex == exid, "got ulAssemblyRosterIndex %lu\n", data.ulAssemblyRosterIndex); + + activatable_class = (struct activatable_class_data *)data.lpData; + ok_(__FILE__, line)(activatable_class->size == sizeof(*activatable_class), "got size %lu\n", + activatable_class->size); + ok_(__FILE__, line)(activatable_class->threading_model == threading_model, "got threading_model %lu\n", + activatable_class->threading_model); + + ptr = (BYTE *)header + activatable_class->module_offset; + ok_(__FILE__, line)(wcslen(ptr) * sizeof(WCHAR) == activatable_class->module_len, + "got module_len %lu\n", activatable_class->module_len); + ok_(__FILE__, line)(!wcscmp(ptr, file), "got data.lpSectionGlobalData %s\n", debugstr_w(ptr)); } static void test_find_string_fail(void) @@ -1291,36 +1505,31 @@ static void test_find_string_fail(void) ACTCTX_SECTION_KEYED_DATA data = {sizeof(data)}; BOOL ret; - ret = pFindActCtxSectionStringW(0, NULL, 100, testlib_dll, &data); + ret = FindActCtxSectionStringW(0, NULL, 100, testlib_dll, &data); ok(!ret, "FindActCtxSectionStringW succeeded\n"); - ok(GetLastError() == ERROR_SXS_SECTION_NOT_FOUND, "GetLastError()=%u\n", GetLastError()); + ok(GetLastError() == ERROR_SXS_SECTION_NOT_FOUND, "GetLastError()=%lu\n", GetLastError()); - ret = pFindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, - testlib2_dll, &data); + ret = FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, testlib2_dll, &data); ok(!ret, "FindActCtxSectionStringW succeeded\n"); - ok(GetLastError() == ERROR_SXS_KEY_NOT_FOUND, "GetLastError()=%u\n", GetLastError()); + ok(GetLastError() == ERROR_SXS_KEY_NOT_FOUND, "GetLastError()=%lu\n", GetLastError()); - ret = pFindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, - testlib_dll, NULL); + ret = FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, testlib_dll, NULL); ok(!ret, "FindActCtxSectionStringW succeeded\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError()=%u\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError()=%lu\n", GetLastError()); - ret = pFindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, - NULL, &data); + ret = FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, NULL, &data); ok(!ret, "FindActCtxSectionStringW succeeded\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError()=%u\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError()=%lu\n", GetLastError()); data.cbSize = 0; - ret = pFindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, - testlib_dll, &data); + ret = FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, testlib_dll, &data); ok(!ret, "FindActCtxSectionStringW succeeded\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError()=%u\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError()=%lu\n", GetLastError()); data.cbSize = 35; - ret = pFindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, - testlib_dll, &data); + ret = FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, testlib_dll, &data); ok(!ret, "FindActCtxSectionStringW succeeded\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError()=%u\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError()=%lu\n", GetLastError()); } @@ -1330,17 +1539,15 @@ static void test_basic_info(HANDLE handle, int line) SIZE_T size; BOOL b; - b = pQueryActCtxW(QUERY_ACTCTX_FLAG_NO_ADDREF, handle, NULL, - ActivationContextBasicInformation, &basic, + b = QueryActCtxW(QUERY_ACTCTX_FLAG_NO_ADDREF, handle, NULL, ActivationContextBasicInformation, &basic, sizeof(basic), &size); ok_(__FILE__, line) (b,"ActivationContextBasicInformation failed\n"); ok_(__FILE__, line) (size == sizeof(ACTIVATION_CONTEXT_BASIC_INFORMATION),"size mismatch\n"); - ok_(__FILE__, line) (basic.dwFlags == 0, "unexpected flags %x\n",basic.dwFlags); + ok_(__FILE__, line) (basic.dwFlags == 0, "unexpected flags %lx\n",basic.dwFlags); ok_(__FILE__, line) (basic.hActCtx == handle, "unexpected handle\n"); - b = pQueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX | - QUERY_ACTCTX_FLAG_NO_ADDREF, handle, NULL, + b = QueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX | QUERY_ACTCTX_FLAG_NO_ADDREF, handle, NULL, ActivationContextBasicInformation, &basic, sizeof(basic), &size); if (handle) @@ -1348,14 +1555,14 @@ static void test_basic_info(HANDLE handle, int line) ok_(__FILE__, line) (!b,"ActivationContextBasicInformation succeeded\n"); ok_(__FILE__, line) (size == 0,"size mismatch\n"); ok_(__FILE__, line) (GetLastError() == ERROR_INVALID_PARAMETER, "Wrong last error\n"); - ok_(__FILE__, line) (basic.dwFlags == 0, "unexpected flags %x\n",basic.dwFlags); + ok_(__FILE__, line) (basic.dwFlags == 0, "unexpected flags %lx\n",basic.dwFlags); ok_(__FILE__, line) (basic.hActCtx == handle, "unexpected handle\n"); } else { ok_(__FILE__, line) (b,"ActivationContextBasicInformation failed\n"); ok_(__FILE__, line) (size == sizeof(ACTIVATION_CONTEXT_BASIC_INFORMATION),"size mismatch\n"); - ok_(__FILE__, line) (basic.dwFlags == 0, "unexpected flags %x\n",basic.dwFlags); + ok_(__FILE__, line) (basic.dwFlags == 0, "unexpected flags %lx\n",basic.dwFlags); ok_(__FILE__, line) (basic.hActCtx == handle, "unexpected handle\n"); } } @@ -1378,9 +1585,7 @@ enum comclass_miscfields { struct comclassredirect_data { ULONG size; - BYTE res; - BYTE miscmask; - BYTE res1[2]; + ULONG flags; DWORD model; GUID clsid; GUID alias; @@ -1411,6 +1616,29 @@ struct clrclass_data { DWORD res2[2]; }; +static void validate_guid_index(const ACTCTX_SECTION_KEYED_DATA *data, int line) +{ +#define GUIDSECTION_MAGIC 0x64487347 /* dHsG */ + struct guidsection_header *header; + struct guid_index *index; + unsigned int i; + + header = (struct guidsection_header *)data->lpSectionBase; + + ok_(__FILE__, line)(header->magic == GUIDSECTION_MAGIC, "Unexpected magic %#lx.\n", header->magic); + ok_(__FILE__, line)(header->size == sizeof(*header), "Unexpected size %ld.\n", header->size); + ok_(__FILE__, line)(header->index_offset >= sizeof(*header), "Unexpected index offset %lu.\n", header->index_offset); + + index = (struct guid_index *)((BYTE *)data->lpSectionBase + header->index_offset); + for (i = 0; i < header->count; ++i) + { + ok_(__FILE__, line)(index[i].data_len <= data->ulSectionTotalLength, "Unexpected data length.\n"); + ok_(__FILE__, line)(index[i].data_offset <= data->ulSectionTotalLength - index[i].data_len, + "Unexpected data offset %ld, section total length %lu, data length %lu.\n", + index[i].data_offset, data->ulSectionTotalLength, index[i].data_len); + } +} + static void test_find_com_redirection(HANDLE handle, const GUID *clsid, const GUID *tlid, const WCHAR *progid, ULONG exid, int line) { struct comclassredirect_data *comclass, *comclass2; @@ -1421,75 +1649,72 @@ static void test_find_com_redirection(HANDLE handle, const GUID *clsid, const GU memset(&data, 0xfe, sizeof(data)); data.cbSize = sizeof(data); - ret = pFindActCtxSectionGuid(0, NULL, - ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, - clsid, &data); + ret = FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, clsid, &data); if (!ret) { skip("failed for guid %s\n", wine_dbgstr_guid(clsid)); return; } - ok_(__FILE__, line)(ret, "FindActCtxSectionGuid failed: %u\n", GetLastError()); + ok_(__FILE__, line)(ret, "FindActCtxSectionGuid failed: %lu\n", GetLastError()); comclass = (struct comclassredirect_data*)data.lpData; - ok_(__FILE__, line)(data.cbSize == sizeof(data), "data.cbSize=%u\n", data.cbSize); - ok_(__FILE__, line)(data.ulDataFormatVersion == 1, "data.ulDataFormatVersion=%u\n", data.ulDataFormatVersion); + ok_(__FILE__, line)(data.cbSize == sizeof(data), "data.cbSize=%lu\n", data.cbSize); + ok_(__FILE__, line)(data.ulDataFormatVersion == 1, "data.ulDataFormatVersion=%lu\n", data.ulDataFormatVersion); ok_(__FILE__, line)(data.lpData != NULL, "data.lpData == NULL\n"); - ok_(__FILE__, line)(comclass->size == sizeof(*comclass), "got %d for header size\n", comclass->size); + ok_(__FILE__, line)(comclass->size == sizeof(*comclass), "got %ld for header size\n", comclass->size); if (data.lpData && comclass->size == sizeof(*comclass)) { + ULONG len, miscmask; WCHAR *ptr; - ULONG len; - ok_(__FILE__, line)(comclass->res == 0, "got res as %d\n", comclass->res); - ok_(__FILE__, line)(comclass->res1[0] == 0, "got res1[0] as %02x\n", comclass->res1[0]); - ok_(__FILE__, line)(comclass->res1[1] == 0, "got res1[1] as %02x\n", comclass->res1[1]); - ok_(__FILE__, line)(comclass->model == ThreadingModel_Neutral, "got model %d\n", comclass->model); + ok_(__FILE__, line)(comclass->model == ThreadingModel_Neutral, "got model %ld\n", comclass->model); ok_(__FILE__, line)(IsEqualGUID(&comclass->clsid, clsid), "got wrong clsid %s\n", wine_dbgstr_guid(&comclass->clsid)); ok_(__FILE__, line)(IsEqualGUID(&comclass->clsid2, clsid), "got wrong clsid2 %s\n", wine_dbgstr_guid(&comclass->clsid2)); if (tlid) ok_(__FILE__, line)(IsEqualGUID(&comclass->tlid, tlid), "got wrong tlid %s\n", wine_dbgstr_guid(&comclass->tlid)); - ok_(__FILE__, line)(comclass->name_len > 0, "got modulename len %d\n", comclass->name_len); + ok_(__FILE__, line)(comclass->name_len > 0, "got modulename len %ld\n", comclass->name_len); if (progid) { len = comclass->size + comclass->clrdata_len; - ok_(__FILE__, line)(comclass->progid_offset == len, "got progid offset %d, expected %d\n", comclass->progid_offset, len); + ok_(__FILE__, line)(comclass->progid_offset == len, "got progid offset %ld, expected %ld\n", comclass->progid_offset, len); } else - ok_(__FILE__, line)(comclass->progid_offset == 0, "got progid offset %d, expected 0\n", comclass->progid_offset); + ok_(__FILE__, line)(comclass->progid_offset == 0, "got progid offset %ld, expected 0\n", comclass->progid_offset); if (comclass->progid_offset) { ptr = (WCHAR*)((BYTE*)comclass + comclass->progid_offset); ok_(__FILE__, line)(!lstrcmpW(ptr, progid), "got wrong progid %s, expected %s\n", wine_dbgstr_w(ptr), wine_dbgstr_w(progid)); ok_(__FILE__, line)(lstrlenW(progid)*sizeof(WCHAR) == comclass->progid_len, - "got progid name length %d\n", comclass->progid_len); + "got progid name length %ld\n", comclass->progid_len); } /* data length is simply header length + string data length including nulls */ len = comclass->size + comclass->clrdata_len; if (comclass->progid_len) len += comclass->progid_len + sizeof(WCHAR); - ok_(__FILE__, line)(data.ulLength == len, "got wrong data length %d, expected %d\n", data.ulLength, len); + ok_(__FILE__, line)(data.ulLength == len, "got wrong data length %ld, expected %ld\n", data.ulLength, len); /* keyed data structure doesn't include module name, it's available from section data */ - ok_(__FILE__, line)(data.ulSectionTotalLength > comclass->name_offset, "got wrong offset %d\n", comclass->name_offset); + ok_(__FILE__, line)(data.ulSectionTotalLength > comclass->name_offset, "got wrong offset %ld\n", comclass->name_offset); /* check misc fields are set */ - if (comclass->miscmask) + miscmask = (comclass->flags >> 8) & 0xff; + if (miscmask) { - if (comclass->miscmask & MiscStatus) - ok_(__FILE__, line)(comclass->miscstatus != 0, "got miscstatus 0x%08x\n", comclass->miscstatus); - if (comclass->miscmask & MiscStatusIcon) - ok_(__FILE__, line)(comclass->miscstatusicon != 0, "got miscstatusicon 0x%08x\n", comclass->miscstatusicon); - if (comclass->miscmask & MiscStatusContent) - ok_(__FILE__, line)(comclass->miscstatuscontent != 0, "got miscstatuscontent 0x%08x\n", comclass->miscstatuscontent); - if (comclass->miscmask & MiscStatusThumbnail) - ok_(__FILE__, line)(comclass->miscstatusthumbnail != 0, "got miscstatusthumbnail 0x%08x\n", comclass->miscstatusthumbnail); - if (comclass->miscmask & MiscStatusDocPrint) - ok_(__FILE__, line)(comclass->miscstatusdocprint != 0, "got miscstatusdocprint 0x%08x\n", comclass->miscstatusdocprint); + if (miscmask & MiscStatus) + ok_(__FILE__, line)(comclass->miscstatus != 0, "got miscstatus 0x%08lx\n", comclass->miscstatus); + if (miscmask & MiscStatusIcon) + ok_(__FILE__, line)(comclass->miscstatusicon != 0, "got miscstatusicon 0x%08lx\n", comclass->miscstatusicon); + if (miscmask & MiscStatusContent) + ok_(__FILE__, line)(comclass->miscstatuscontent != 0, "got miscstatuscontent 0x%08lx\n", comclass->miscstatuscontent); + if (miscmask & MiscStatusThumbnail) + ok_(__FILE__, line)(comclass->miscstatusthumbnail != 0, "got miscstatusthumbnail 0x%08lx\n", comclass->miscstatusthumbnail); + if (miscmask & MiscStatusDocPrint) + ok_(__FILE__, line)(comclass->miscstatusdocprint != 0, "got miscstatusdocprint 0x%08lx\n", comclass->miscstatusdocprint); } + ok_(__FILE__, line)(!(comclass->flags & 0xffff00ff), "Unexpected flags %#lx.\n", comclass->flags); /* part used for clrClass only */ if (comclass->clrdata_len) @@ -1500,24 +1725,24 @@ static void test_find_com_redirection(HANDLE handle, const GUID *clsid, const GU WCHAR *ptrW; clrclass = (struct clrclass_data*)((BYTE*)data.lpData + comclass->clrdata_offset); - ok_(__FILE__, line)(clrclass->size == sizeof(*clrclass), "clrclass: got size %d\n", clrclass->size); - ok_(__FILE__, line)(clrclass->res[0] == 0, "clrclass: got res[0]=0x%08x\n", clrclass->res[0]); - ok_(__FILE__, line)(clrclass->res[1] == 2, "clrclass: got res[1]=0x%08x\n", clrclass->res[1]); - ok_(__FILE__, line)(clrclass->module_len == lstrlenW(mscoreeW)*sizeof(WCHAR), "clrclass: got module len %d\n", clrclass->module_len); - ok_(__FILE__, line)(clrclass->module_offset > 0, "clrclass: got module offset %d\n", clrclass->module_offset); + ok_(__FILE__, line)(clrclass->size == sizeof(*clrclass), "clrclass: got size %ld\n", clrclass->size); + ok_(__FILE__, line)(clrclass->res[0] == 0, "clrclass: got res[0]=0x%08lx\n", clrclass->res[0]); + ok_(__FILE__, line)(clrclass->res[1] == 2, "clrclass: got res[1]=0x%08lx\n", clrclass->res[1]); + ok_(__FILE__, line)(clrclass->module_len == lstrlenW(mscoreeW)*sizeof(WCHAR), "clrclass: got module len %ld\n", clrclass->module_len); + ok_(__FILE__, line)(clrclass->module_offset > 0, "clrclass: got module offset %ld\n", clrclass->module_offset); - ok_(__FILE__, line)(clrclass->name_len > 0, "clrclass: got name len %d\n", clrclass->name_len); - ok_(__FILE__, line)(clrclass->name_offset == clrclass->size, "clrclass: got name offset %d\n", clrclass->name_offset); - ok_(__FILE__, line)(clrclass->version_len > 0, "clrclass: got version len %d\n", clrclass->version_len); - ok_(__FILE__, line)(clrclass->version_offset > 0, "clrclass: got version offset %d\n", clrclass->version_offset); + ok_(__FILE__, line)(clrclass->name_len > 0, "clrclass: got name len %ld\n", clrclass->name_len); + ok_(__FILE__, line)(clrclass->name_offset == clrclass->size, "clrclass: got name offset %ld\n", clrclass->name_offset); + ok_(__FILE__, line)(clrclass->version_len > 0, "clrclass: got version len %ld\n", clrclass->version_len); + ok_(__FILE__, line)(clrclass->version_offset > 0, "clrclass: got version offset %ld\n", clrclass->version_offset); - ok_(__FILE__, line)(clrclass->res2[0] == 0, "clrclass: got res2[0]=0x%08x\n", clrclass->res2[0]); - ok_(__FILE__, line)(clrclass->res2[1] == 0, "clrclass: got res2[1]=0x%08x\n", clrclass->res2[1]); + ok_(__FILE__, line)(clrclass->res2[0] == 0, "clrclass: got res2[0]=0x%08lx\n", clrclass->res2[0]); + ok_(__FILE__, line)(clrclass->res2[1] == 0, "clrclass: got res2[1]=0x%08lx\n", clrclass->res2[1]); /* clrClass uses mscoree.dll as module name, but in two variants - comclass data points to module name in lower case, clsclass subsection - in upper case */ - ok_(__FILE__, line)(comclass->name_len == lstrlenW(mscoree2W)*sizeof(WCHAR), "clrclass: got com name len %d\n", comclass->name_len); - ok_(__FILE__, line)(comclass->name_offset > 0, "clrclass: got name offset %d\n", clrclass->name_offset); + ok_(__FILE__, line)(comclass->name_len == lstrlenW(mscoree2W)*sizeof(WCHAR), "clrclass: got com name len %ld\n", comclass->name_len); + ok_(__FILE__, line)(comclass->name_offset > 0, "clrclass: got name offset %ld\n", clrclass->name_offset); ptrW = (WCHAR*)((BYTE*)data.lpSectionBase + comclass->name_offset); ok_(__FILE__, line)(!lstrcmpW(ptrW, mscoreeW), "clrclass: module name %s\n", wine_dbgstr_w(ptrW)); @@ -1528,26 +1753,25 @@ static void test_find_com_redirection(HANDLE handle, const GUID *clsid, const GU } header = (struct guidsection_header*)data.lpSectionBase; - ok_(__FILE__, line)(data.lpSectionGlobalData == ((BYTE*)header + header->names_offset), "data.lpSectionGlobalData == NULL\n"); - ok_(__FILE__, line)(data.ulSectionGlobalDataLength == header->names_len, "data.ulSectionGlobalDataLength=%u\n", - data.ulSectionGlobalDataLength); ok_(__FILE__, line)(data.lpSectionBase != NULL, "data.lpSectionBase == NULL\n"); - ok_(__FILE__, line)(data.ulSectionTotalLength > 0, "data.ulSectionTotalLength=%u\n", + ok_(__FILE__, line)(data.lpSectionGlobalData == ((BYTE*)header + header->names_offset), "data.lpSectionGlobalData == NULL\n"); + ok_(__FILE__, line)(data.ulSectionGlobalDataLength == header->names_len, "data.ulSectionGlobalDataLength=%lu\n", + data.ulSectionGlobalDataLength); + ok_(__FILE__, line)(data.ulSectionTotalLength > 0, "data.ulSectionTotalLength=%lu\n", data.ulSectionTotalLength); ok_(__FILE__, line)(data.hActCtx == NULL, "data.hActCtx=%p\n", data.hActCtx); - ok_(__FILE__, line)(data.ulAssemblyRosterIndex == exid, "data.ulAssemblyRosterIndex=%u, expected %u\n", + ok_(__FILE__, line)(data.ulAssemblyRosterIndex == exid, "data.ulAssemblyRosterIndex=%lu, expected %lu\n", data.ulAssemblyRosterIndex, exid); + validate_guid_index(&data, line); /* generated guid for this class works as key guid in search */ memset(&data2, 0xfe, sizeof(data2)); data2.cbSize = sizeof(data2); - ret = pFindActCtxSectionGuid(0, NULL, - ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, - &comclass->alias, &data2); - ok_(__FILE__, line)(ret, "FindActCtxSectionGuid failed: %u\n", GetLastError()); + ret = FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, &comclass->alias, &data2); + ok_(__FILE__, line)(ret, "FindActCtxSectionGuid failed: %lu\n", GetLastError()); comclass2 = (struct comclassredirect_data*)data2.lpData; - ok_(__FILE__, line)(comclass->size == comclass2->size, "got wrong data length %d, expected %d\n", comclass2->size, comclass->size); + ok_(__FILE__, line)(comclass->size == comclass2->size, "got wrong data length %ld, expected %ld\n", comclass2->size, comclass->size); ok_(__FILE__, line)(!memcmp(comclass, comclass2, comclass->size), "got wrong data\n"); } @@ -1579,17 +1803,15 @@ static void test_find_ifaceps_redirection(HANDLE handle, const GUID *iid, const memset(&data, 0xfe, sizeof(data)); data.cbSize = sizeof(data); - ret = pFindActCtxSectionGuid(0, NULL, - ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION, - iid, &data); - ok_(__FILE__, line)(ret, "FindActCtxSectionGuid failed: %u\n", GetLastError()); + ret = FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION, iid, &data); + ok_(__FILE__, line)(ret, "FindActCtxSectionGuid failed: %lu\n", GetLastError()); ifaceps = (struct ifacepsredirect_data*)data.lpData; - ok_(__FILE__, line)(data.cbSize == sizeof(data), "data.cbSize=%u\n", data.cbSize); - ok_(__FILE__, line)(data.ulDataFormatVersion == 1, "data.ulDataFormatVersion=%u\n", data.ulDataFormatVersion); + ok_(__FILE__, line)(data.cbSize == sizeof(data), "data.cbSize=%lu\n", data.cbSize); + ok_(__FILE__, line)(data.ulDataFormatVersion == 1, "data.ulDataFormatVersion=%lu\n", data.ulDataFormatVersion); ok_(__FILE__, line)(data.lpData != NULL, "data.lpData == NULL\n"); - ok_(__FILE__, line)(ifaceps->size == sizeof(*ifaceps), "got %d for header size\n", ifaceps->size); + ok_(__FILE__, line)(ifaceps->size == sizeof(*ifaceps), "got %ld for header size\n", ifaceps->size); if (data.lpData && ifaceps->size == sizeof(*ifaceps)) { ULONG len; @@ -1603,30 +1825,32 @@ static void test_find_ifaceps_redirection(HANDLE handle, const GUID *iid, const ok_(__FILE__, line)(IsEqualGUID(&ifaceps->iid, iid), "got wrong iid %s\n", wine_dbgstr_guid(&ifaceps->iid)); ok_(__FILE__, line)(IsEqualGUID(&ifaceps->tlbid, tlbid), "got wrong tlid %s\n", wine_dbgstr_guid(&ifaceps->tlbid)); - ok_(__FILE__, line)(ifaceps->name_len > 0, "got modulename len %d\n", ifaceps->name_len); - ok_(__FILE__, line)(ifaceps->name_offset == ifaceps->size, "got progid offset %d\n", ifaceps->name_offset); + ok_(__FILE__, line)(ifaceps->name_len > 0, "got modulename len %ld\n", ifaceps->name_len); + ok_(__FILE__, line)(ifaceps->name_offset == ifaceps->size, "got progid offset %ld\n", ifaceps->name_offset); /* data length is simply header length + string data length including nulls */ len = ifaceps->size + ifaceps->name_len + sizeof(WCHAR); - ok_(__FILE__, line)(data.ulLength == len, "got wrong data length %d, expected %d\n", data.ulLength, len); + ok_(__FILE__, line)(data.ulLength == len, "got wrong data length %ld, expected %ld\n", data.ulLength, len); /* mask purpose is to indicate if attribute was specified, for testing purposes assume that manifest always has non-zero value for it */ if (ifaceps->mask & NumMethods) - ok_(__FILE__, line)(ifaceps->nummethods != 0, "got nummethods %d\n", ifaceps->nummethods); + ok_(__FILE__, line)(ifaceps->nummethods != 0, "got nummethods %ld\n", ifaceps->nummethods); if (ifaceps->mask & BaseIface) ok_(__FILE__, line)(IsEqualGUID(&ifaceps->base, base), "got base %s\n", wine_dbgstr_guid(&ifaceps->base)); } ok_(__FILE__, line)(data.lpSectionGlobalData == NULL, "data.lpSectionGlobalData != NULL\n"); - ok_(__FILE__, line)(data.ulSectionGlobalDataLength == 0, "data.ulSectionGlobalDataLength=%u\n", + ok_(__FILE__, line)(data.ulSectionGlobalDataLength == 0, "data.ulSectionGlobalDataLength=%lu\n", data.ulSectionGlobalDataLength); ok_(__FILE__, line)(data.lpSectionBase != NULL, "data.lpSectionBase == NULL\n"); - ok_(__FILE__, line)(data.ulSectionTotalLength > 0, "data.ulSectionTotalLength=%u\n", + ok_(__FILE__, line)(data.ulSectionTotalLength > 0, "data.ulSectionTotalLength=%lu\n", data.ulSectionTotalLength); ok_(__FILE__, line)(data.hActCtx == NULL, "data.hActCtx=%p\n", data.hActCtx); - ok_(__FILE__, line)(data.ulAssemblyRosterIndex == exid, "data.ulAssemblyRosterIndex=%u, expected %u\n", + ok_(__FILE__, line)(data.ulAssemblyRosterIndex == exid, "data.ulAssemblyRosterIndex=%lu, expected %lu\n", data.ulAssemblyRosterIndex, exid); + + validate_guid_index(&data, line); } struct clrsurrogate_data @@ -1641,47 +1865,51 @@ struct clrsurrogate_data }; static void test_find_surrogate(HANDLE handle, const GUID *clsid, const WCHAR *name, const WCHAR *version, - ULONG exid, int line) + ULONG exid, int line) { struct clrsurrogate_data *surrogate; ACTCTX_SECTION_KEYED_DATA data; BOOL ret; +#ifdef __REACTOS__ + if (is_reactos()) { + ok(FALSE, "FIXME: This test crashes on ReactOS\n"); + return; + } +#endif memset(&data, 0xfe, sizeof(data)); data.cbSize = sizeof(data); - ret = pFindActCtxSectionGuid(0, NULL, - ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES, - clsid, &data); + ret = FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES, clsid, &data); if (!ret) { skip("surrogate sections are not supported\n"); return; } - ok_(__FILE__, line)(ret, "FindActCtxSectionGuid failed: %u\n", GetLastError()); + ok_(__FILE__, line)(ret, "FindActCtxSectionGuid failed: %lu\n", GetLastError()); surrogate = (struct clrsurrogate_data*)data.lpData; - ok_(__FILE__, line)(data.cbSize == sizeof(data), "data.cbSize=%u\n", data.cbSize); - ok_(__FILE__, line)(data.ulDataFormatVersion == 1, "data.ulDataFormatVersion=%u\n", data.ulDataFormatVersion); + ok_(__FILE__, line)(data.cbSize == sizeof(data), "data.cbSize=%lu\n", data.cbSize); + ok_(__FILE__, line)(data.ulDataFormatVersion == 1, "data.ulDataFormatVersion=%lu\n", data.ulDataFormatVersion); ok_(__FILE__, line)(data.lpData != NULL, "data.lpData == NULL\n"); - ok_(__FILE__, line)(surrogate->size == sizeof(*surrogate), "got %d for header size\n", surrogate->size); + ok_(__FILE__, line)(surrogate->size == sizeof(*surrogate), "got %ld for header size\n", surrogate->size); if (data.lpData && surrogate->size == sizeof(*surrogate)) { WCHAR *ptrW; ULONG len; - ok_(__FILE__, line)(surrogate->res == 0, "invalid res value %d\n", surrogate->res); + ok_(__FILE__, line)(surrogate->res == 0, "invalid res value %ld\n", surrogate->res); ok_(__FILE__, line)(IsEqualGUID(&surrogate->clsid, clsid), "got wrong clsid %s\n", wine_dbgstr_guid(&surrogate->clsid)); - ok_(__FILE__, line)(surrogate->version_len == lstrlenW(version)*sizeof(WCHAR), "got version len %d\n", surrogate->version_len); - ok_(__FILE__, line)(surrogate->version_offset == surrogate->size, "got version offset %d\n", surrogate->version_offset); + ok_(__FILE__, line)(surrogate->version_len == lstrlenW(version)*sizeof(WCHAR), "got version len %ld\n", surrogate->version_len); + ok_(__FILE__, line)(surrogate->version_offset == surrogate->size, "got version offset %ld\n", surrogate->version_offset); - ok_(__FILE__, line)(surrogate->name_len == lstrlenW(name)*sizeof(WCHAR), "got name len %d\n", surrogate->name_len); - ok_(__FILE__, line)(surrogate->name_offset > surrogate->version_offset, "got name offset %d\n", surrogate->name_offset); + ok_(__FILE__, line)(surrogate->name_len == lstrlenW(name)*sizeof(WCHAR), "got name len %ld\n", surrogate->name_len); + ok_(__FILE__, line)(surrogate->name_offset > surrogate->version_offset, "got name offset %ld\n", surrogate->name_offset); len = surrogate->size + surrogate->name_len + surrogate->version_len + 2*sizeof(WCHAR); - ok_(__FILE__, line)(data.ulLength == len, "got wrong data length %d, expected %d\n", data.ulLength, len); + ok_(__FILE__, line)(data.ulLength == len, "got wrong data length %ld, expected %ld\n", data.ulLength, len); ptrW = (WCHAR*)((BYTE*)surrogate + surrogate->name_offset); ok(!lstrcmpW(ptrW, name), "got wrong name %s\n", wine_dbgstr_w(ptrW)); @@ -1691,14 +1919,16 @@ static void test_find_surrogate(HANDLE handle, const GUID *clsid, const WCHAR *n } ok_(__FILE__, line)(data.lpSectionGlobalData == NULL, "data.lpSectionGlobalData != NULL\n"); - ok_(__FILE__, line)(data.ulSectionGlobalDataLength == 0, "data.ulSectionGlobalDataLength=%u\n", + ok_(__FILE__, line)(data.ulSectionGlobalDataLength == 0, "data.ulSectionGlobalDataLength=%lu\n", data.ulSectionGlobalDataLength); ok_(__FILE__, line)(data.lpSectionBase != NULL, "data.lpSectionBase == NULL\n"); - ok_(__FILE__, line)(data.ulSectionTotalLength > 0, "data.ulSectionTotalLength=%u\n", + ok_(__FILE__, line)(data.ulSectionTotalLength > 0, "data.ulSectionTotalLength=%lu\n", data.ulSectionTotalLength); ok_(__FILE__, line)(data.hActCtx == NULL, "data.hActCtx=%p\n", data.hActCtx); - ok_(__FILE__, line)(data.ulAssemblyRosterIndex == exid, "data.ulAssemblyRosterIndex=%u, expected %u\n", + ok_(__FILE__, line)(data.ulAssemblyRosterIndex == exid, "data.ulAssemblyRosterIndex=%lu, expected %lu\n", data.ulAssemblyRosterIndex, exid); + + validate_guid_index(&data, line); } static void test_find_progid_redirection(HANDLE handle, const GUID *clsid, const char *progid, ULONG exid, int line) @@ -1709,49 +1939,53 @@ static void test_find_progid_redirection(HANDLE handle, const GUID *clsid, const struct strsection_header *header; BOOL ret; +#if defined(__REACTOS__) && defined(_MSC_VER) + if (is_reactos()) { + ok(FALSE, "FIXME: This crashes on MSVC ReactOS\n"); + return; + } +#endif memset(&data, 0xfe, sizeof(data)); data.cbSize = sizeof(data); - ret = pFindActCtxSectionStringA(0, NULL, - ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION, - progid, &data); - ok_(__FILE__, line)(ret, "FindActCtxSectionStringA failed: %u\n", GetLastError()); + ret = FindActCtxSectionStringA(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION, progid, &data); + ok_(__FILE__, line)(ret, "FindActCtxSectionStringA failed: %lu\n", GetLastError()); progiddata = (struct progidredirect_data*)data.lpData; - ok_(__FILE__, line)(data.cbSize == sizeof(data), "data.cbSize=%u\n", data.cbSize); - ok_(__FILE__, line)(data.ulDataFormatVersion == 1, "data.ulDataFormatVersion=%u\n", data.ulDataFormatVersion); + ok_(__FILE__, line)(data.cbSize == sizeof(data), "data.cbSize=%lu\n", data.cbSize); + ok_(__FILE__, line)(data.ulDataFormatVersion == 1, "data.ulDataFormatVersion=%lu\n", data.ulDataFormatVersion); ok_(__FILE__, line)(data.lpData != NULL, "data.lpData == NULL\n"); - ok_(__FILE__, line)(progiddata->size == sizeof(*progiddata), "got %d for header size\n", progiddata->size); + ok_(__FILE__, line)(progiddata->size == sizeof(*progiddata), "got %ld for header size\n", progiddata->size); if (data.lpData && progiddata->size == sizeof(*progiddata)) { GUID *guid; - ok_(__FILE__, line)(progiddata->reserved == 0, "got reserved as %d\n", progiddata->reserved); - ok_(__FILE__, line)(progiddata->clsid_offset > 0, "got clsid_offset as %d\n", progiddata->clsid_offset); + ok_(__FILE__, line)(progiddata->reserved == 0, "got reserved as %ld\n", progiddata->reserved); + ok_(__FILE__, line)(progiddata->clsid_offset > 0, "got clsid_offset as %ld\n", progiddata->clsid_offset); /* progid data points to generated alias guid */ guid = (GUID*)((BYTE*)data.lpSectionBase + progiddata->clsid_offset); memset(&data2, 0, sizeof(data2)); data2.cbSize = sizeof(data2); - ret = pFindActCtxSectionGuid(0, NULL, - ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, - guid, &data2); - ok_(__FILE__, line)(ret, "FindActCtxSectionGuid failed: %u\n", GetLastError()); + ret = FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, guid, &data2); + ok_(__FILE__, line)(ret, "FindActCtxSectionGuid failed: %lu\n", GetLastError()); comclass = (struct comclassredirect_data*)data2.lpData; ok_(__FILE__, line)(IsEqualGUID(guid, &comclass->alias), "got wrong alias referenced from progid %s, %s\n", progid, wine_dbgstr_guid(guid)); ok_(__FILE__, line)(IsEqualGUID(clsid, &comclass->clsid), "got wrong class referenced from progid %s, %s\n", progid, wine_dbgstr_guid(clsid)); + + validate_guid_index(&data2, line); } header = (struct strsection_header*)data.lpSectionBase; - ok_(__FILE__, line)(data.lpSectionGlobalData == (BYTE*)header + header->global_offset, "data.lpSectionGlobalData == NULL\n"); - ok_(__FILE__, line)(data.ulSectionGlobalDataLength == header->global_len, "data.ulSectionGlobalDataLength=%u\n", data.ulSectionGlobalDataLength); ok_(__FILE__, line)(data.lpSectionBase != NULL, "data.lpSectionBase == NULL\n"); - ok_(__FILE__, line)(data.ulSectionTotalLength > 0, "data.ulSectionTotalLength=%u\n", data.ulSectionTotalLength); + ok_(__FILE__, line)(data.lpSectionGlobalData == (BYTE*)header + header->global_offset, "data.lpSectionGlobalData == NULL\n"); + ok_(__FILE__, line)(data.ulSectionGlobalDataLength == header->global_len, "data.ulSectionGlobalDataLength=%lu\n", data.ulSectionGlobalDataLength); + ok_(__FILE__, line)(data.ulSectionTotalLength > 0, "data.ulSectionTotalLength=%lu\n", data.ulSectionTotalLength); ok_(__FILE__, line)(data.hActCtx == NULL, "data.hActCtx=%p\n", data.hActCtx); - ok_(__FILE__, line)(data.ulAssemblyRosterIndex == exid, "data.ulAssemblyRosterIndex=%u, expected %u\n", + ok_(__FILE__, line)(data.ulAssemblyRosterIndex == exid, "data.ulAssemblyRosterIndex=%lu, expected %lu\n", data.ulAssemblyRosterIndex, exid); } @@ -1772,14 +2006,14 @@ static void test_wndclass_section(void) create_manifest_file("main_wndcls.manifest", manifest_wndcls_main, -1, NULL, NULL); handle = test_create("main_wndcls.manifest"); - ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError()); DeleteFileA("testdep1.manifest"); DeleteFileA("testdep2.manifest"); DeleteFileA("main_wndcls.manifest"); - ret = pActivateActCtx(handle, &cookie); - ok(ret, "ActivateActCtx failed: %u\n", GetLastError()); + ret = ActivateActCtx(handle, &cookie); + ok(ret, "ActivateActCtx failed: %lu\n", GetLastError()); memset(&data, 0, sizeof(data)); memset(&data2, 0, sizeof(data2)); @@ -1787,22 +2021,18 @@ static void test_wndclass_section(void) data2.cbSize = sizeof(data2); /* get data for two classes from different assemblies */ - ret = pFindActCtxSectionStringW(0, NULL, - ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, - wndClass1W, &data); + ret = FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, wndClass1W, &data); ok(ret, "got %d\n", ret); - ret = pFindActCtxSectionStringW(0, NULL, - ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, - wndClass3W, &data2); + ret = FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, wndClass3W, &data2); ok(ret, "got %d\n", ret); section = (struct strsection_header*)data.lpSectionBase; - ok(section->count == 4, "got %d\n", section->count); - ok(section->size == sizeof(*section), "got %d\n", section->size); + ok(section->count == 4, "got %ld\n", section->count); + ok(section->size == sizeof(*section), "got %ld\n", section->size); /* For both string same section is returned, meaning it's one wndclass section per context */ ok(data.lpSectionBase == data2.lpSectionBase, "got %p, %p\n", data.lpSectionBase, data2.lpSectionBase); - ok(data.ulSectionTotalLength == data2.ulSectionTotalLength, "got %u, %u\n", data.ulSectionTotalLength, + ok(data.ulSectionTotalLength == data2.ulSectionTotalLength, "got %lu, %lu\n", data.ulSectionTotalLength, data2.ulSectionTotalLength); /* wndClass1 is versioned, wndClass3 is not */ @@ -1814,10 +2044,10 @@ static void test_wndclass_section(void) ptrW = (WCHAR*)((BYTE*)data2.lpData + classdata->name_offset); ok(!lstrcmpW(ptrW, wndClass3W), "got %s\n", wine_dbgstr_w(ptrW)); - ret = pDeactivateActCtx(0, cookie); - ok(ret, "DeactivateActCtx failed: %u\n", GetLastError()); + ret = DeactivateActCtx(0, cookie); + ok(ret, "DeactivateActCtx failed: %lu\n", GetLastError()); - pReleaseActCtx(handle); + ReleaseActCtx(handle); } static void test_dllredirect_section(void) @@ -1836,14 +2066,14 @@ static void test_dllredirect_section(void) create_manifest_file("main_wndcls.manifest", manifest_wndcls_main, -1, NULL, NULL); handle = test_create("main_wndcls.manifest"); - ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError()); DeleteFileA("testdep1.manifest"); DeleteFileA("testdep2.manifest"); DeleteFileA("main_wndcls.manifest"); - ret = pActivateActCtx(handle, &cookie); - ok(ret, "ActivateActCtx failed: %u\n", GetLastError()); + ret = ActivateActCtx(handle, &cookie); + ok(ret, "ActivateActCtx failed: %lu\n", GetLastError()); memset(&data, 0, sizeof(data)); memset(&data2, 0, sizeof(data2)); @@ -1851,28 +2081,24 @@ static void test_dllredirect_section(void) data2.cbSize = sizeof(data2); /* get data for two files from different assemblies */ - ret = pFindActCtxSectionStringW(0, NULL, - ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, - testlib1W, &data); + ret = FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, testlib1W, &data); ok(ret, "got %d\n", ret); - ret = pFindActCtxSectionStringW(0, NULL, - ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, - testlib2W, &data2); + ret = FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, testlib2W, &data2); ok(ret, "got %d\n", ret); section = (struct strsection_header*)data.lpSectionBase; - ok(section->count == 4, "got %d\n", section->count); - ok(section->size == sizeof(*section), "got %d\n", section->size); + ok(section->count == 4, "got %ld\n", section->count); + ok(section->size == sizeof(*section), "got %ld\n", section->size); /* For both string same section is returned, meaning it's one dll redirect section per context */ ok(data.lpSectionBase == data2.lpSectionBase, "got %p, %p\n", data.lpSectionBase, data2.lpSectionBase); - ok(data.ulSectionTotalLength == data2.ulSectionTotalLength, "got %u, %u\n", data.ulSectionTotalLength, + ok(data.ulSectionTotalLength == data2.ulSectionTotalLength, "got %lu, %lu\n", data.ulSectionTotalLength, data2.ulSectionTotalLength); - ret = pDeactivateActCtx(0, cookie); - ok(ret, "DeactivateActCtx failed: %u\n", GetLastError()); + ret = DeactivateActCtx(0, cookie); + ok(ret, "DeactivateActCtx failed: %lu\n", GetLastError()); - pReleaseActCtx(handle); + ReleaseActCtx(handle); } static void test_typelib_section(void) @@ -1891,14 +2117,14 @@ static void test_typelib_section(void) create_manifest_file("main_wndcls.manifest", manifest_wndcls_main, -1, NULL, NULL); handle = test_create("main_wndcls.manifest"); - ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError()); DeleteFileA("testdep1.manifest"); DeleteFileA("testdep2.manifest"); DeleteFileA("main_wndcls.manifest"); - ret = pActivateActCtx(handle, &cookie); - ok(ret, "ActivateActCtx failed: %u\n", GetLastError()); + ret = ActivateActCtx(handle, &cookie); + ok(ret, "ActivateActCtx failed: %lu\n", GetLastError()); memset(&data, 0, sizeof(data)); memset(&data2, 0, sizeof(data2)); @@ -1906,42 +2132,40 @@ static void test_typelib_section(void) data2.cbSize = sizeof(data2); /* get data for two typelibs from different assemblies */ - ret = pFindActCtxSectionGuid(0, NULL, - ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION, - &IID_TlibTest, &data); + ret = FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION, &IID_TlibTest, &data); ok(ret, "got %d\n", ret); - ret = pFindActCtxSectionGuid(0, NULL, - ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION, - &IID_TlibTest4, &data2); + ret = FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION, + &IID_TlibTest4, &data2); ok(ret, "got %d\n", ret); section = (struct guidsection_header*)data.lpSectionBase; - ok(section->count == 4, "got %d\n", section->count); - ok(section->size == sizeof(*section), "got %d\n", section->size); + ok(section->count == 4, "got %ld\n", section->count); + ok(section->size == sizeof(*section), "got %ld\n", section->size); + validate_guid_index(&data, __LINE__); /* For both GUIDs same section is returned */ ok(data.lpSectionBase == data2.lpSectionBase, "got %p, %p\n", data.lpSectionBase, data2.lpSectionBase); - ok(data.ulSectionTotalLength == data2.ulSectionTotalLength, "got %u, %u\n", data.ulSectionTotalLength, + ok(data.ulSectionTotalLength == data2.ulSectionTotalLength, "got %lu, %lu\n", data.ulSectionTotalLength, data2.ulSectionTotalLength); ok(data.lpSectionGlobalData == ((BYTE*)section + section->names_offset), "data.lpSectionGlobalData == NULL\n"); - ok(data.ulSectionGlobalDataLength == section->names_len, "data.ulSectionGlobalDataLength=%u\n", + ok(data.ulSectionGlobalDataLength == section->names_len, "data.ulSectionGlobalDataLength=%lu\n", data.ulSectionGlobalDataLength); /* test some actual data */ tlib = (struct tlibredirect_data*)data.lpData; - ok(tlib->size == sizeof(*tlib), "got %d\n", tlib->size); + ok(tlib->size == sizeof(*tlib), "got %ld\n", tlib->size); ok(tlib->major_version == 1, "got %d\n", tlib->major_version); ok(tlib->minor_version == 0, "got %d\n", tlib->minor_version); - ok(tlib->help_offset > 0, "got %d\n", tlib->help_offset); - ok(tlib->help_len == sizeof(helpW), "got %d\n", tlib->help_len); + ok(tlib->help_offset > 0, "got %ld\n", tlib->help_offset); + ok(tlib->help_len == sizeof(helpW), "got %ld\n", tlib->help_len); ok(tlib->flags == (LIBFLAG_FHIDDEN|LIBFLAG_FCONTROL|LIBFLAG_FRESTRICTED), "got %x\n", tlib->flags); - ret = pDeactivateActCtx(0, cookie); - ok(ret, "DeactivateActCtx failed: %u\n", GetLastError()); + ret = DeactivateActCtx(0, cookie); + ok(ret, "DeactivateActCtx failed: %lu\n", GetLastError()); - pReleaseActCtx(handle); + ReleaseActCtx(handle); } static void test_allowDelayedBinding(void) @@ -1963,7 +2187,7 @@ static void test_allowDelayedBinding(void) DeleteFileA("testdep.manifest"); if (handle != INVALID_HANDLE_VALUE) { test_basic_info(handle, __LINE__); - pReleaseActCtx(handle); + ReleaseActCtx(handle); } } @@ -1975,22 +2199,22 @@ static void test_actctx(void) trace("default actctx\n"); - b = pGetCurrentActCtx(&handle); + b = GetCurrentActCtx(&handle); ok(handle == NULL, "handle = %p, expected NULL\n", handle); - ok(b, "GetCurrentActCtx failed: %u\n", GetLastError()); + ok(b, "GetCurrentActCtx failed: %lu\n", GetLastError()); if(b) { test_basic_info(handle, __LINE__); test_detailed_info(handle, &detailed_info0, __LINE__); test_runlevel_info(handle, &runlevel_info0, __LINE__); - pReleaseActCtx(handle); + ReleaseActCtx(handle); } /* test for whitespace handling in Eq ::= S? '=' S? */ create_manifest_file("test1_1.manifest", manifest1_1, -1, NULL, NULL); handle = test_create("test1_1.manifest"); - ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError()); DeleteFileA("test1_1.manifest"); - pReleaseActCtx(handle); + ReleaseActCtx(handle); if(!create_manifest_file("test1.manifest", manifest1, -1, NULL, NULL)) { skip("Could not create manifest file\n"); @@ -2000,22 +2224,22 @@ static void test_actctx(void) trace("manifest1\n"); handle = test_create("test1.manifest"); - ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError()); DeleteFileA("test1.manifest"); if(handle != INVALID_HANDLE_VALUE) { test_basic_info(handle, __LINE__); test_detailed_info(handle, &detailed_info1, __LINE__); test_info_in_assembly(handle, 1, &manifest1_info, __LINE__); - if (pIsDebuggerPresent && !pIsDebuggerPresent()) + if (!IsDebuggerPresent()) { /* CloseHandle will generate an exception if a debugger is present */ b = CloseHandle(handle); ok(!b, "CloseHandle succeeded\n"); - ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError() == %u\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError() == %lu\n", GetLastError()); } - pReleaseActCtx(handle); + ReleaseActCtx(handle); } if(!create_manifest_file("test2.manifest", manifest2, -1, "testdep.manifest", testdep_manifest1)) { @@ -2026,7 +2250,7 @@ static void test_actctx(void) trace("manifest2 depmanifest1\n"); handle = test_create("test2.manifest"); - ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError()); DeleteFileA("test2.manifest"); DeleteFileA("testdep.manifest"); if(handle != INVALID_HANDLE_VALUE) { @@ -2034,7 +2258,7 @@ static void test_actctx(void) test_detailed_info(handle, &detailed_info2, __LINE__); test_info_in_assembly(handle, 1, &manifest2_info, __LINE__); test_info_in_assembly(handle, 2, &depmanifest1_info, __LINE__); - pReleaseActCtx(handle); + ReleaseActCtx(handle); } if(!create_manifest_file("test2-2.manifest", manifest2, -1, "testdep.manifest", testdep_manifest2)) { @@ -2045,7 +2269,7 @@ static void test_actctx(void) trace("manifest2 depmanifest2\n"); handle = test_create("test2-2.manifest"); - ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError()); DeleteFileA("test2-2.manifest"); DeleteFileA("testdep.manifest"); if(handle != INVALID_HANDLE_VALUE) { @@ -2056,14 +2280,14 @@ static void test_actctx(void) test_file_info(handle, 1, 0, testlib_dll, __LINE__); test_file_info(handle, 1, 1, testlib2_dll, __LINE__); - b = pActivateActCtx(handle, &cookie); - ok(b, "ActivateActCtx failed: %u\n", GetLastError()); + b = ActivateActCtx(handle, &cookie); + ok(b, "ActivateActCtx failed: %lu\n", GetLastError()); test_find_dll_redirection(handle, testlib_dll, 2, __LINE__); test_find_dll_redirection(handle, testlib2_dll, 2, __LINE__); - b = pDeactivateActCtx(0, cookie); - ok(b, "DeactivateActCtx failed: %u\n", GetLastError()); + b = DeactivateActCtx(0, cookie); + ok(b, "DeactivateActCtx failed: %lu\n", GetLastError()); - pReleaseActCtx(handle); + ReleaseActCtx(handle); } trace("manifest2 depmanifest3\n"); @@ -2074,7 +2298,7 @@ static void test_actctx(void) } handle = test_create("test2-3.manifest"); - ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError()); DeleteFileA("test2-3.manifest"); DeleteFileA("testdep.manifest"); if(handle != INVALID_HANDLE_VALUE) { @@ -2085,16 +2309,16 @@ static void test_actctx(void) test_file_info(handle, 1, 0, testlib_dll, __LINE__); test_file_info(handle, 1, 1, testlib2_dll, __LINE__); - b = pActivateActCtx(handle, &cookie); - ok(b, "ActivateActCtx failed: %u\n", GetLastError()); + b = ActivateActCtx(handle, &cookie); + ok(b, "ActivateActCtx failed: %lu\n", GetLastError()); test_find_dll_redirection(handle, testlib_dll, 2, __LINE__); test_find_dll_redirection(handle, testlib2_dll, 2, __LINE__); test_find_window_class(handle, wndClassW, 2, __LINE__); test_find_window_class(handle, wndClass2W, 2, __LINE__); - b = pDeactivateActCtx(0, cookie); - ok(b, "DeactivateActCtx failed: %u\n", GetLastError()); + b = DeactivateActCtx(0, cookie); + ok(b, "DeactivateActCtx failed: %lu\n", GetLastError()); - pReleaseActCtx(handle); + ReleaseActCtx(handle); } trace("manifest3\n"); @@ -2106,7 +2330,7 @@ static void test_actctx(void) handle = test_create("test3.manifest"); ok(handle != INVALID_HANDLE_VALUE || broken(handle == INVALID_HANDLE_VALUE) /* XP pre-SP2, win2k3 w/o SP */, - "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError()); + "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError()); if (handle == INVALID_HANDLE_VALUE) win_skip("Some activation context features not supported, skipping a test (possibly old XP/Win2k3 system\n"); DeleteFileA("test3.manifest"); @@ -2121,8 +2345,8 @@ static void test_actctx(void) test_info_in_assembly(handle, 1, &manifest3_info, __LINE__); test_file_info(handle, 0, 0, testlib_dll, __LINE__); - b = pActivateActCtx(handle, &cookie); - ok(b, "ActivateActCtx failed: %u\n", GetLastError()); + b = ActivateActCtx(handle, &cookie); + ok(b, "ActivateActCtx failed: %lu\n", GetLastError()); test_find_dll_redirection(handle, testlib_dll, 1, __LINE__); test_find_dll_redirection(handle, testlib_dll, 1, __LINE__); test_find_com_redirection(handle, &IID_CoTest, &IID_TlibTest, progidW, 1, __LINE__); @@ -2147,10 +2371,14 @@ static void test_actctx(void) test_find_ifaceps_redirection(handle, &IID_Iifaceps2, &IID_TlibTest4, &IID_Ibifaceps, &IID_PS32, 1, __LINE__); test_find_ifaceps_redirection(handle, &IID_Iifaceps3, &IID_TlibTest4, &IID_Ibifaceps, NULL, 1, __LINE__); test_find_string_fail(); + test_find_activatable_class(handle, L"Wine.Test.Class1", WINRT_THREADING_MODEL_MTA, L"testlib.dll", 1, __LINE__); + test_find_activatable_class(handle, L"Wine.Test.Class2", WINRT_THREADING_MODEL_BOTH, L"testlib.dll", 1, __LINE__); + test_find_activatable_class(handle, L"Wine.Test.Class3", WINRT_THREADING_MODEL_STA, L"testlib.dll", 1, __LINE__); + test_find_activatable_class(handle, L"Wine.Test.Class4", WINRT_THREADING_MODEL_STA, L"Wine.Test.dll", 1, __LINE__); - b = pDeactivateActCtx(0, cookie); - ok(b, "DeactivateActCtx failed: %u\n", GetLastError()); - pReleaseActCtx(handle); + b = DeactivateActCtx(0, cookie); + ok(b, "DeactivateActCtx failed: %lu\n", GetLastError()); + ReleaseActCtx(handle); } trace("manifest6\n"); @@ -2164,7 +2392,7 @@ static void test_actctx(void) if(handle != INVALID_HANDLE_VALUE) { test_runlevel_info(handle, &runlevel_info6, __LINE__); - pReleaseActCtx(handle); + ReleaseActCtx(handle); } } else @@ -2174,13 +2402,13 @@ static void test_actctx(void) if(create_manifest_file("test7.manifest", manifest7, -1, NULL, NULL)) { handle = test_create("test7.manifest"); - ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError()); DeleteFileA("test7.manifest"); DeleteFileA("testdep.manifest"); if(handle != INVALID_HANDLE_VALUE) { test_runlevel_info(handle, &runlevel_info7, __LINE__); - pReleaseActCtx(handle); + ReleaseActCtx(handle); } } else @@ -2190,13 +2418,13 @@ static void test_actctx(void) if(create_manifest_file("test8.manifest", manifest8, -1, NULL, NULL)) { handle = test_create("test8.manifest"); - ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError()); DeleteFileA("test8.manifest"); DeleteFileA("testdep.manifest"); if(handle != INVALID_HANDLE_VALUE) { test_runlevel_info(handle, &runlevel_info8, __LINE__); - pReleaseActCtx(handle); + ReleaseActCtx(handle); } } else @@ -2206,18 +2434,44 @@ static void test_actctx(void) if(create_manifest_file("test9.manifest", manifest9, -1, NULL, NULL)) { handle = test_create("test9.manifest"); - ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError()); DeleteFileA("test9.manifest"); DeleteFileA("testdep.manifest"); if(handle != INVALID_HANDLE_VALUE) { test_runlevel_info(handle, &runlevel_info9, __LINE__); - pReleaseActCtx(handle); + ReleaseActCtx(handle); } } else skip("Could not create manifest file 9\n"); + if(create_manifest_file("test10.manifest", manifest10, -1, NULL, NULL)) { + handle = test_create("test10.manifest"); + ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError()); + DeleteFileA("test10.manifest"); + DeleteFileA("testdep.manifest"); + if(handle != INVALID_HANDLE_VALUE) + { + test_runlevel_info(handle, &runlevel_info8, __LINE__); + ReleaseActCtx(handle); + } + } + else + skip("Could not create manifest file 10\n"); + + if (create_manifest_file("test11.manifest", manifest11, -1, NULL, NULL)) + { + handle = test_create("test11.manifest"); + ok(handle != INVALID_HANDLE_VALUE, "Failed to create activation context for %s, error %lu\n", + "manifest11", GetLastError()); + DeleteFileA("test11.manifest"); + if (handle != INVALID_HANDLE_VALUE) + ReleaseActCtx(handle); + } + else + skip("Could not create manifest file 11\n"); + trace("manifest4\n"); if(!create_manifest_file("test4.manifest", manifest4, -1, NULL, NULL)) { @@ -2226,7 +2480,7 @@ static void test_actctx(void) } handle = test_create("test4.manifest"); - ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError()); DeleteFileA("test4.manifest"); DeleteFileA("testdep.manifest"); if(handle != INVALID_HANDLE_VALUE) { @@ -2234,7 +2488,7 @@ static void test_actctx(void) test_detailed_info(handle, &detailed_info2, __LINE__); test_info_in_assembly(handle, 1, &manifest4_info, __LINE__); test_info_in_assembly(handle, 2, &manifest_comctrl_info, __LINE__); - pReleaseActCtx(handle); + ReleaseActCtx(handle); } trace("manifest1 in subdir\n"); @@ -2247,13 +2501,13 @@ static void test_actctx(void) return; } handle = test_create("..\\test1.manifest"); - ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError()); DeleteFileA("..\\test1.manifest"); if(handle != INVALID_HANDLE_VALUE) { test_basic_info(handle, __LINE__); test_detailed_info(handle, &detailed_info1, __LINE__); test_info_in_assembly(handle, 1, &manifest1_info, __LINE__); - pReleaseActCtx(handle); + ReleaseActCtx(handle); } SetCurrentDirectoryW(work_dir); } @@ -2268,13 +2522,13 @@ static void test_actctx(void) } handle = test_create("test1.manifest"); - ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError()); DeleteFileA("test1.manifest"); if (handle != INVALID_HANDLE_VALUE) { test_basic_info(handle, __LINE__); test_detailed_info(handle, &detailed_info1, __LINE__); test_info_in_assembly(handle, 1, &manifest1_info, __LINE__); - pReleaseActCtx(handle); + ReleaseActCtx(handle); } trace("UTF-16 manifest1, reverse endian, with BOM\n"); @@ -2284,13 +2538,24 @@ static void test_actctx(void) } handle = test_create("test1.manifest"); - ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError()); DeleteFileA("test1.manifest"); if (handle != INVALID_HANDLE_VALUE) { test_basic_info(handle, __LINE__); test_detailed_info(handle, &detailed_info1, __LINE__); test_info_in_assembly(handle, 1, &manifest1_info, __LINE__); - pReleaseActCtx(handle); + ReleaseActCtx(handle); + } + + /* Empty element. */ + create_manifest_file("empty_assembly.manifest", empty_assembly_manifest, -1, NULL, NULL); + handle = test_create("empty_assembly.manifest"); + ok(handle != INVALID_HANDLE_VALUE, "Failed to create activation context.\n"); + DeleteFileA("empty_assembly.manifest"); + if (handle != INVALID_HANDLE_VALUE) + { + test_basic_info(handle, __LINE__); + ReleaseActCtx(handle); } test_wndclass_section(); @@ -2306,14 +2571,14 @@ static void test_app_manifest(void) trace("child process manifest1\n"); - b = pGetCurrentActCtx(&handle); + b = GetCurrentActCtx(&handle); ok(handle == NULL, "handle != NULL\n"); - ok(b, "GetCurrentActCtx failed: %u\n", GetLastError()); + ok(b, "GetCurrentActCtx failed: %lu\n", GetLastError()); if(b) { test_basic_info(handle, __LINE__); test_detailed_info(handle, &detailed_info1_child, __LINE__); test_info_in_assembly(handle, 1, &manifest1_child_info, __LINE__); - pReleaseActCtx(handle); + ReleaseActCtx(handle); } } @@ -2324,13 +2589,13 @@ static HANDLE create_manifest(const char *filename, const char *data, int line) handle = test_create(filename); ok_(__FILE__, line)(handle != INVALID_HANDLE_VALUE, - "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError()); + "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError()); DeleteFileA(filename); return handle; } -static void kernel32_find(ULONG section, const char *string_to_find, BOOL should_find, int line) +static void kernel32_find(ULONG section, const char *string_to_find, BOOL should_find, BOOL todo, int line) { UNICODE_STRING string_to_findW; ACTCTX_SECTION_KEYED_DATA data; @@ -2343,44 +2608,46 @@ static void kernel32_find(ULONG section, const char *string_to_find, BOOL should data.cbSize = sizeof(data); SetLastError(0); - ret = pFindActCtxSectionStringA(0, NULL, section, string_to_find, &data); + ret = FindActCtxSectionStringA(0, NULL, section, string_to_find, &data); err = GetLastError(); ok_(__FILE__, line)(ret == should_find, "FindActCtxSectionStringA: expected ret = %u, got %u\n", should_find, ret); + todo_wine_if(todo) ok_(__FILE__, line)(err == (should_find ? ERROR_SUCCESS : ERROR_SXS_KEY_NOT_FOUND), - "FindActCtxSectionStringA: unexpected error %u\n", err); + "FindActCtxSectionStringA: unexpected error %lu\n", err); memset(&data, 0xfe, sizeof(data)); data.cbSize = sizeof(data); SetLastError(0); - ret = pFindActCtxSectionStringW(0, NULL, section, string_to_findW.Buffer, &data); + ret = FindActCtxSectionStringW(0, NULL, section, string_to_findW.Buffer, &data); err = GetLastError(); ok_(__FILE__, line)(ret == should_find, "FindActCtxSectionStringW: expected ret = %u, got %u\n", should_find, ret); + todo_wine_if(todo) ok_(__FILE__, line)(err == (should_find ? ERROR_SUCCESS : ERROR_SXS_KEY_NOT_FOUND), - "FindActCtxSectionStringW: unexpected error %u\n", err); + "FindActCtxSectionStringW: unexpected error %lu\n", err); SetLastError(0); - ret = pFindActCtxSectionStringA(0, NULL, section, string_to_find, NULL); + ret = FindActCtxSectionStringA(0, NULL, section, string_to_find, NULL); err = GetLastError(); ok_(__FILE__, line)(!ret, "FindActCtxSectionStringA: expected failure, got %u\n", ret); ok_(__FILE__, line)(err == ERROR_INVALID_PARAMETER, - "FindActCtxSectionStringA: unexpected error %u\n", err); + "FindActCtxSectionStringA: unexpected error %lu\n", err); SetLastError(0); - ret = pFindActCtxSectionStringW(0, NULL, section, string_to_findW.Buffer, NULL); + ret = FindActCtxSectionStringW(0, NULL, section, string_to_findW.Buffer, NULL); err = GetLastError(); ok_(__FILE__, line)(!ret, "FindActCtxSectionStringW: expected failure, got %u\n", ret); ok_(__FILE__, line)(err == ERROR_INVALID_PARAMETER, - "FindActCtxSectionStringW: unexpected error %u\n", err); + "FindActCtxSectionStringW: unexpected error %lu\n", err); pRtlFreeUnicodeString(&string_to_findW); } -static void ntdll_find(ULONG section, const char *string_to_find, BOOL should_find, int line) +static void ntdll_find(ULONG section, const char *string_to_find, BOOL should_find, BOOL todo, int line) { UNICODE_STRING string_to_findW; ACTCTX_SECTION_KEYED_DATA data; @@ -2392,12 +2659,14 @@ static void ntdll_find(ULONG section, const char *string_to_find, BOOL should_fi data.cbSize = sizeof(data); ret = pRtlFindActivationContextSectionString(0, NULL, section, &string_to_findW, &data); + todo_wine_if(todo) ok_(__FILE__, line)(ret == (should_find ? STATUS_SUCCESS : STATUS_SXS_KEY_NOT_FOUND), - "RtlFindActivationContextSectionString: unexpected status 0x%x\n", ret); + "RtlFindActivationContextSectionString: unexpected status 0x%lx\n", ret); ret = pRtlFindActivationContextSectionString(0, NULL, section, &string_to_findW, NULL); + todo_wine_if(todo) ok_(__FILE__, line)(ret == (should_find ? STATUS_SUCCESS : STATUS_SXS_KEY_NOT_FOUND), - "RtlFindActivationContextSectionString: unexpected status 0x%x\n", ret); + "RtlFindActivationContextSectionString: unexpected status 0x%lx\n", ret); pRtlFreeUnicodeString(&string_to_findW); } @@ -2409,30 +2678,36 @@ static void test_findsectionstring(void) ULONG_PTR cookie; handle = create_manifest("test.manifest", testdep_manifest3, __LINE__); - ret = pActivateActCtx(handle, &cookie); - ok(ret, "ActivateActCtx failed: %u\n", GetLastError()); + ret = ActivateActCtx(handle, &cookie); + ok(ret, "ActivateActCtx failed: %lu\n", GetLastError()); /* first we show the parameter validation from kernel32 */ - kernel32_find(ACTIVATION_CONTEXT_SECTION_ASSEMBLY_INFORMATION, "testdep", FALSE, __LINE__); - kernel32_find(ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, "testlib.dll", TRUE, __LINE__); - kernel32_find(ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, "testlib2.dll", TRUE, __LINE__); - kernel32_find(ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, "testlib3.dll", FALSE, __LINE__); - kernel32_find(ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, "wndClass", TRUE, __LINE__); - kernel32_find(ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, "wndClass2", TRUE, __LINE__); - kernel32_find(ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, "wndClass3", FALSE, __LINE__); + kernel32_find(ACTIVATION_CONTEXT_SECTION_ASSEMBLY_INFORMATION, "testdep", FALSE, TRUE, __LINE__); + kernel32_find(ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, "testlib.dll", TRUE, FALSE, __LINE__); + kernel32_find(ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, "testlib2.dll", TRUE, FALSE, __LINE__); + kernel32_find(ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, "testlib3.dll", FALSE, FALSE, __LINE__); + kernel32_find(ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, "wndClass", TRUE, FALSE, __LINE__); + kernel32_find(ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, "wndClass2", TRUE, FALSE, __LINE__); + kernel32_find(ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, "wndClass3", FALSE, FALSE, __LINE__); /* then we show that ntdll plays by different rules */ - ntdll_find(ACTIVATION_CONTEXT_SECTION_ASSEMBLY_INFORMATION, "testdep", FALSE, __LINE__); - ntdll_find(ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, "testlib.dll", TRUE, __LINE__); - ntdll_find(ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, "testlib2.dll", TRUE, __LINE__); - ntdll_find(ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, "testlib3.dll", FALSE, __LINE__); - ntdll_find(ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, "wndClass", TRUE, __LINE__); - ntdll_find(ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, "wndClass2", TRUE, __LINE__); - ntdll_find(ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, "wndClass3", FALSE, __LINE__); + ntdll_find(ACTIVATION_CONTEXT_SECTION_ASSEMBLY_INFORMATION, "testdep", FALSE, TRUE, __LINE__); + ntdll_find(ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, "testlib.dll", TRUE, FALSE, __LINE__); + ntdll_find(ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, "testlib2.dll", TRUE, FALSE, __LINE__); + ntdll_find(ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, "testlib3.dll", FALSE, FALSE, __LINE__); + ntdll_find(ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, "wndClass", TRUE, FALSE, __LINE__); + ntdll_find(ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, "wndClass2", TRUE, FALSE, __LINE__); + ntdll_find(ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, "wndClass3", FALSE, FALSE, __LINE__); - ret = pDeactivateActCtx(0, cookie); - ok(ret, "DeactivateActCtx failed: %u\n", GetLastError()); - pReleaseActCtx(handle); +#ifdef __REACTOS__ + if (is_reactos()) { + trace("HACK: ReactOS crashes on DeactivateActCtx() below.\n"); + ret = FALSE; + } else +#endif + ret = DeactivateActCtx(0, cookie); + ok(ret, "DeactivateActCtx failed: %lu\n", GetLastError()); + ReleaseActCtx(handle); } static void run_child_process(void) @@ -2466,8 +2741,8 @@ static void run_child_process(void) } sprintf(cmdline, "\"%s\" %s manifest1", argv[0], argv[1]); ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); - ok(ret, "Could not create process: %u\n", GetLastError()); - winetest_wait_child_process( pi.hProcess ); + ok(ret, "Could not create process: %lu\n", GetLastError()); + wait_child_process( pi.hProcess ); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); DeleteFileA(path); @@ -2481,7 +2756,7 @@ static void init_paths(void) static const WCHAR backslash[] = {'\\',0}; static const WCHAR subdir[] = {'T','e','s','t','S','u','b','d','i','r','\\',0}; - GetModuleFileNameW(NULL, exe_path, sizeof(exe_path)/sizeof(WCHAR)); + GetModuleFileNameW(NULL, exe_path, ARRAY_SIZE(exe_path)); lstrcpyW(app_dir, exe_path); for(ptr=app_dir+lstrlenW(app_dir); *ptr != '\\' && *ptr != '/'; ptr--); ptr[1] = 0; @@ -2493,7 +2768,7 @@ static void init_paths(void) lstrcpyW(work_dir_subdir, work_dir); lstrcatW(work_dir_subdir, subdir); - GetModuleFileNameW(NULL, app_manifest_path, sizeof(app_manifest_path)/sizeof(WCHAR)); + GetModuleFileNameW(NULL, app_manifest_path, ARRAY_SIZE(app_manifest_path)); lstrcpyW(app_manifest_path+lstrlenW(app_manifest_path), dot_manifest); } @@ -2503,11 +2778,11 @@ static void write_manifest(const char *filename, const char *manifest) DWORD size; CHAR path[MAX_PATH]; - GetTempPathA(sizeof(path)/sizeof(CHAR), path); + GetTempPathA(ARRAY_SIZE(path), path); strcat(path, filename); file = CreateFileA(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError()); + ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %lu\n", GetLastError()); WriteFile(file, manifest, strlen(manifest), &size, NULL); CloseHandle(file); } @@ -2516,35 +2791,157 @@ static void delete_manifest_file(const char *filename) { CHAR path[MAX_PATH]; - GetTempPathA(sizeof(path)/sizeof(CHAR), path); + GetTempPathA(ARRAY_SIZE(path), path); strcat(path, filename); DeleteFileA(path); } +static void extract_resource(const char *name, const char *type, const char *path) +{ + DWORD written; + HANDLE file; + HRSRC res; + void *ptr; + + file = CreateFileA(path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %ld\n", path, GetLastError()); + + res = FindResourceA(NULL, name, type); + ok( res != 0, "couldn't find resource\n" ); + ptr = LockResource( LoadResource( GetModuleHandleA(NULL), res )); + WriteFile( file, ptr, SizeofResource( GetModuleHandleA(NULL), res ), &written, NULL ); + ok( written == SizeofResource( GetModuleHandleA(NULL), res ), "couldn't write resource\n" ); + CloseHandle( file ); +} + static void test_CreateActCtx(void) { - CHAR path[MAX_PATH], dir[MAX_PATH]; + static const DWORD flags[] = {LOAD_LIBRARY_AS_DATAFILE, LOAD_LIBRARY_AS_IMAGE_RESOURCE, + LOAD_LIBRARY_AS_IMAGE_RESOURCE | LOAD_LIBRARY_AS_DATAFILE}; + static const struct + { + DWORD size, flags, error; + } test[] = + { + { FIELD_OFFSET(ACTCTXW, lpSource), 0, ERROR_INVALID_PARAMETER }, + { FIELD_OFFSET(ACTCTXW, wProcessorArchitecture), 0, 0 }, + { FIELD_OFFSET(ACTCTXW, lpAssemblyDirectory), ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID, ERROR_INVALID_PARAMETER }, + { FIELD_OFFSET(ACTCTXW, lpResourceName), ACTCTX_FLAG_RESOURCE_NAME_VALID, ERROR_INVALID_PARAMETER }, + { FIELD_OFFSET(ACTCTXW, hModule), ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID, ERROR_INVALID_PARAMETER }, + }; + char path[MAX_PATH], dir[MAX_PATH], dll[MAX_PATH], source[MAX_PATH]; + WCHAR pathW[MAX_PATH], dirW[MAX_PATH], sourceW[MAX_PATH]; ACTCTXA actctx; + ACTCTXW ctxW; HANDLE handle; + int i; - GetTempPathA(sizeof(path)/sizeof(CHAR), path); + GetTempPathA(ARRAY_SIZE(path), path); + strcpy(dir, path); strcat(path, "main_wndcls.manifest"); write_manifest("testdep1.manifest", manifest_wndcls1); write_manifest("testdep2.manifest", manifest_wndcls2); write_manifest("main_wndcls.manifest", manifest_wndcls_main); + GetModuleFileNameA(NULL, source, ARRAY_SIZE(source)); + GetModuleFileNameW(NULL, sourceW, ARRAY_SIZE(sourceW)); + + GetTempPathW(ARRAY_SIZE(pathW), pathW); + wcscpy(dirW, pathW); + wcscat(pathW, L"main_wndcls.manifest"); + + memset(&ctxW, 0, sizeof(ctxW)); + ctxW.cbSize = sizeof(ctxW); + ctxW.dwFlags = ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID | ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID; + ctxW.lpSource = pathW; + ctxW.lpAssemblyDirectory = dirW; + ctxW.lpResourceName = (LPWSTR)124; + ctxW.hModule = GetModuleHandleW(NULL); + handle = CreateActCtxW(&ctxW); + ok(handle != INVALID_HANDLE_VALUE, "CreateActCtx error %lu\n", GetLastError()); + ReleaseActCtx(handle); + + for (i = 0; i < ARRAY_SIZE(test); i++) + { + winetest_push_context("%i", i); + ctxW.cbSize = test[i].size; + ctxW.dwFlags = test[i].flags; + SetLastError(0xdeadbeef); + handle = CreateActCtxW(&ctxW); + if (!test[i].error) + { + ok(handle != INVALID_HANDLE_VALUE, "CreateActCtx error %lu\n", GetLastError()); + ReleaseActCtx(handle); + } + else + { + ok(handle == INVALID_HANDLE_VALUE, "CreateActCtx should fail\n"); + ok(test[i].error == GetLastError(), "expected %lu, got %lu\n", test[i].error, GetLastError()); + } + + ctxW.cbSize += sizeof(void *); + if ((ctxW.dwFlags & (ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID)) == ACTCTX_FLAG_RESOURCE_NAME_VALID) + ctxW.lpSource = sourceW; /* source without hModule must point to valid PE */ + SetLastError(0xdeadbeef); + handle = CreateActCtxW(&ctxW); + ok(handle != INVALID_HANDLE_VALUE, "CreateActCtx error %lu\n", GetLastError()); + ReleaseActCtx(handle); + + winetest_pop_context(); + } + + memset(&actctx, 0, sizeof(actctx)); + actctx.cbSize = sizeof(actctx); + actctx.dwFlags = ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID | ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID; + actctx.lpSource = path; + actctx.lpAssemblyDirectory = dir; + actctx.lpResourceName = (LPSTR)124; + actctx.hModule = GetModuleHandleW(NULL); + handle = CreateActCtxA(&actctx); + ok(handle != INVALID_HANDLE_VALUE, "CreateActCtx error %lu\n", GetLastError()); + ReleaseActCtx(handle); + + for (i = 0; i < ARRAY_SIZE(test); i++) + { + winetest_push_context("%i", i); + actctx.cbSize = test[i].size; + actctx.dwFlags = test[i].flags; + SetLastError(0xdeadbeef); + handle = CreateActCtxA(&actctx); + if (!test[i].error) + { + ok(handle != INVALID_HANDLE_VALUE, "CreateActCtx error %lu\n", GetLastError()); + ReleaseActCtx(handle); + } + else + { + ok(handle == INVALID_HANDLE_VALUE, "CreateActCtx should fail\n"); + ok(test[i].error == GetLastError(), "expected %lu, got %lu\n", test[i].error, GetLastError()); + } + + actctx.cbSize += sizeof(void *); + if ((actctx.dwFlags & (ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID)) == ACTCTX_FLAG_RESOURCE_NAME_VALID) + actctx.lpSource = source; /* source without hModule must point to valid PE */ + SetLastError(0xdeadbeef); + handle = CreateActCtxA(&actctx); + ok(handle != INVALID_HANDLE_VALUE, "CreateActCtx error %lu\n", GetLastError()); + ReleaseActCtx(handle); + + winetest_pop_context(); + } + memset(&actctx, 0, sizeof(ACTCTXA)); actctx.cbSize = sizeof(ACTCTXA); actctx.lpSource = path; /* create using lpSource without specified directory */ - handle = pCreateActCtxA(&actctx); - ok(handle != INVALID_HANDLE_VALUE, "failed to generate context, error %u\n", GetLastError()); - pReleaseActCtx(handle); + handle = CreateActCtxA(&actctx); + ok(handle != INVALID_HANDLE_VALUE, "failed to generate context, error %lu\n", GetLastError()); + ReleaseActCtx(handle); /* with specified directory, that doesn't contain dependent assembly */ - GetWindowsDirectoryA(dir, sizeof(dir)/sizeof(CHAR)); + GetWindowsDirectoryA(dir, ARRAY_SIZE(dir)); memset(&actctx, 0, sizeof(ACTCTXA)); actctx.cbSize = sizeof(ACTCTXA); @@ -2553,28 +2950,33 @@ static void test_CreateActCtx(void) actctx.lpSource = path; SetLastError(0xdeadbeef); - handle = pCreateActCtxA(&actctx); + handle = CreateActCtxA(&actctx); todo_wine { ok(handle == INVALID_HANDLE_VALUE, "got handle %p\n", handle); - ok(GetLastError() == ERROR_SXS_CANT_GEN_ACTCTX, "got error %d\n", GetLastError()); + ok(GetLastError() == ERROR_SXS_CANT_GEN_ACTCTX, "got error %ld\n", GetLastError()); } - if (handle != INVALID_HANDLE_VALUE) pReleaseActCtx(handle); + if (handle != INVALID_HANDLE_VALUE) ReleaseActCtx(handle); + + /* with specified directory, that does contain dependent assembly */ + GetTempPathA(ARRAY_SIZE(dir), dir); + actctx.lpAssemblyDirectory = dir; + handle = CreateActCtxA(&actctx); + ok(handle != INVALID_HANDLE_VALUE, "got handle %p\n", handle); + ReleaseActCtx(handle); + + /* Should still work if we add a dll with the same name, but without manifest */ + strcpy(dll, dir); + strcat(dll, "testdep1.dll"); + extract_resource("dummy.dll", "TESTDLL", dll); + handle = CreateActCtxA(&actctx); + ok(handle != INVALID_HANDLE_VALUE || broken(GetLastError() == ERROR_SXS_CANT_GEN_ACTCTX) , "got error %ld\n", GetLastError()); + ReleaseActCtx(handle); + DeleteFileA(dll); delete_manifest_file("main_wndcls.manifest"); delete_manifest_file("testdep1.manifest"); delete_manifest_file("testdep2.manifest"); - /* ACTCTX_FLAG_HMODULE_VALID but hModule is not set */ - memset(&actctx, 0, sizeof(ACTCTXA)); - actctx.cbSize = sizeof(ACTCTXA); - actctx.dwFlags = ACTCTX_FLAG_HMODULE_VALID; - SetLastError(0xdeadbeef); - handle = pCreateActCtxA(&actctx); - ok(handle == INVALID_HANDLE_VALUE, "got handle %p\n", handle); -todo_wine - ok(GetLastError() == ERROR_SXS_CANT_GEN_ACTCTX || broken(GetLastError() == ERROR_NOT_ENOUGH_MEMORY) /* XP, win2k3 */, - "got error %d\n", GetLastError()); - /* create from HMODULE - resource doesn't exist, lpSource is set */ memset(&actctx, 0, sizeof(ACTCTXA)); actctx.cbSize = sizeof(ACTCTXA); @@ -2584,13 +2986,13 @@ todo_wine actctx.hModule = GetModuleHandleA(NULL); SetLastError(0xdeadbeef); - handle = pCreateActCtxA(&actctx); + handle = CreateActCtxA(&actctx); ok(handle == INVALID_HANDLE_VALUE, "got handle %p\n", handle); - ok(GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND, "got error %d\n", GetLastError()); + ok(GetLastError() == ERROR_RESOURCE_NAME_NOT_FOUND, "got error %ld\n", GetLastError()); /* load manifest from lpAssemblyDirectory directory */ write_manifest("testdir.manifest", manifest1); - GetTempPathA(sizeof(path)/sizeof(path[0]), path); + GetTempPathA(ARRAY_SIZE(path), path); SetCurrentDirectoryA(path); strcat(path, "assembly_dir"); strcpy(dir, path); @@ -2603,11 +3005,11 @@ todo_wine actctx.lpAssemblyDirectory = dir; SetLastError(0xdeadbeef); - handle = pCreateActCtxA(&actctx); + handle = CreateActCtxA(&actctx); ok(handle == INVALID_HANDLE_VALUE, "got handle %p\n", handle); ok(GetLastError()==ERROR_PATH_NOT_FOUND || broken(GetLastError()==ERROR_FILE_NOT_FOUND) /* WinXP */, - "got error %d\n", GetLastError()); + "got error %ld\n", GetLastError()); CreateDirectoryA(dir, NULL); memset(&actctx, 0, sizeof(actctx)); @@ -2617,9 +3019,9 @@ todo_wine actctx.lpAssemblyDirectory = dir; SetLastError(0xdeadbeef); - handle = pCreateActCtxA(&actctx); + handle = CreateActCtxA(&actctx); ok(handle == INVALID_HANDLE_VALUE, "got handle %p\n", handle); - ok(GetLastError() == ERROR_FILE_NOT_FOUND, "got error %d\n", GetLastError()); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "got error %ld\n", GetLastError()); SetCurrentDirectoryW(work_dir); write_manifest("assembly_dir\\testdir.manifest", manifest1); @@ -2629,9 +3031,9 @@ todo_wine actctx.lpSource = "testdir.manifest"; actctx.lpAssemblyDirectory = dir; - handle = pCreateActCtxA(&actctx); + handle = CreateActCtxA(&actctx); ok(handle != INVALID_HANDLE_VALUE, "got handle %p\n", handle); - pReleaseActCtx(handle); + ReleaseActCtx(handle); memset(&actctx, 0, sizeof(actctx)); actctx.cbSize = sizeof(actctx); @@ -2639,13 +3041,70 @@ todo_wine actctx.lpSource = path; actctx.lpAssemblyDirectory = dir; - handle = pCreateActCtxA(&actctx); + handle = CreateActCtxA(&actctx); ok(handle != INVALID_HANDLE_VALUE, "got handle %p\n", handle); - pReleaseActCtx(handle); + ReleaseActCtx(handle); delete_manifest_file("testdir.manifest"); delete_manifest_file("assembly_dir\\testdir.manifest"); RemoveDirectoryA(dir); + + /* create using lpSource with a DLL relative name */ + memset(&actctx, 0, sizeof(actctx)); + actctx.cbSize = sizeof(actctx); + actctx.lpSource = "shell32.dll"; + actctx.lpResourceName = MAKEINTRESOURCEA(124); + actctx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID; + handle = CreateActCtxA(&actctx); + ok(handle == INVALID_HANDLE_VALUE, "CreateActCtxA succeeded\n"); + + /* create from module loaded as data file */ + memset(&actctx, 0, sizeof(actctx)); + actctx.cbSize = sizeof(actctx); + actctx.lpResourceName = MAKEINTRESOURCEA(1); + actctx.dwFlags = ACTCTX_FLAG_HMODULE_VALID | ACTCTX_FLAG_RESOURCE_NAME_VALID; + for (i = 0; i < ARRAY_SIZE(flags); ++i) + { + winetest_push_context("%lu", flags[i]); + +#ifdef __REACTOS__ + if (GetNTVersion() < _WIN32_WINNT_VISTA && i > 0) + break; // Only the first test is valid for WS03. +#endif + /* use explorer.exe because using modules already loaded has a different behavior */ + actctx.hModule = LoadLibraryExA("C:\\windows\\explorer.exe", NULL, flags[i]); + ok(actctx.hModule != NULL, "LoadLibraryExA failed, error %lu\n", GetLastError()); + handle = CreateActCtxA(&actctx); + ok(handle == INVALID_HANDLE_VALUE, "CreateActCtxA succeeded\n"); + FreeLibrary(actctx.hModule); + + winetest_pop_context(); + } +} + +static void test_CreateActCtx_share_mode(void) +{ + WCHAR tmp_manifest_pathname[MAX_PATH]; + HANDLE handle, manifest_file; + ACTCTXW actctx; + + manifest_file = create_temp_manifest_file(manifest1, tmp_manifest_pathname); + + memset(&actctx, 0, sizeof(ACTCTXW)); + actctx.cbSize = sizeof(ACTCTXW); + actctx.lpSource = tmp_manifest_pathname; + + handle = CreateActCtxW(&actctx); +#ifdef __REACTOS__ + ok(handle != INVALID_HANDLE_VALUE || GetLastError() == ERROR_SHARING_VIOLATION /* WS03 */, "CreateActCtxW returned error %lu\n", GetLastError()); +#else + ok(handle != INVALID_HANDLE_VALUE, "CreateActCtxW returned error %lu\n", GetLastError()); +#endif + ok(handle != NULL, "CreateActCtxW returned %p\n", handle); + + ReleaseActCtx(handle); + + CloseHandle(manifest_file); } static BOOL init_funcs(void) @@ -2653,18 +3112,7 @@ static BOOL init_funcs(void) HMODULE hLibrary = GetModuleHandleA("kernel32.dll"); #define X(f) if (!(p##f = (void*)GetProcAddress(hLibrary, #f))) return FALSE; - X(ActivateActCtx); - X(CreateActCtxA); - X(CreateActCtxW); - X(DeactivateActCtx); - X(FindActCtxSectionStringA); - X(FindActCtxSectionStringW); - X(GetCurrentActCtx); - X(IsDebuggerPresent); - X(QueryActCtxW); - X(ReleaseActCtx); - X(FindActCtxSectionGuid); - X(ZombifyActCtx); + pQueryActCtxSettingsW = (void *)GetProcAddress( hLibrary, "QueryActCtxSettingsW" ); hLibrary = GetModuleHandleA("ntdll.dll"); X(RtlFindActivationContextSectionString); @@ -2683,67 +3131,71 @@ static void test_ZombifyActCtx(void) BOOL ret; SetLastError(0xdeadbeef); - ret = pZombifyActCtx(NULL); -todo_wine - ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError()); + ret = ZombifyActCtx(NULL); + todo_wine + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %ld\n", ret, GetLastError()); handle = create_manifest("test.manifest", testdep_manifest3, __LINE__); - ret = pGetCurrentActCtx(¤t); - ok(ret, "got %d, error %d\n", ret, GetLastError()); + ret = GetCurrentActCtx(¤t); + ok(ret, "got %d, error %ld\n", ret, GetLastError()); ok(current == NULL, "got %p\n", current); - ret = pActivateActCtx(handle, &cookie); - ok(ret, "ActivateActCtx failed: %u\n", GetLastError()); + ret = ActivateActCtx(handle, &cookie); + ok(ret, "ActivateActCtx failed: %lu\n", GetLastError()); - ret = pGetCurrentActCtx(¤t); - ok(ret, "got %d, error %d\n", ret, GetLastError()); + ret = GetCurrentActCtx(¤t); + ok(ret, "got %d, error %ld\n", ret, GetLastError()); ok(handle == current, "got %p, %p\n", current, handle); memset(&basicinfo, 0xff, sizeof(basicinfo)); - ret = pQueryActCtxW(0, handle, 0, ActivationContextBasicInformation, - &basicinfo, sizeof(basicinfo), NULL); - ok(ret, "got %d, error %d\n", ret, GetLastError()); + ret = QueryActCtxW(0, handle, 0, ActivationContextBasicInformation, &basicinfo, sizeof(basicinfo), NULL); + ok(ret, "got %d, error %ld\n", ret, GetLastError()); ok(basicinfo.hActCtx == handle, "got %p\n", basicinfo.hActCtx); - ok(basicinfo.dwFlags == 0, "got %x\n", basicinfo.dwFlags); + ok(basicinfo.dwFlags == 0, "got %lx\n", basicinfo.dwFlags); memset(&basicinfo, 0xff, sizeof(basicinfo)); - ret = pQueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, NULL, 0, ActivationContextBasicInformation, + ret = QueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, NULL, 0, ActivationContextBasicInformation, &basicinfo, sizeof(basicinfo), NULL); - ok(ret, "got %d, error %d\n", ret, GetLastError()); + ok(ret, "got %d, error %ld\n", ret, GetLastError()); ok(basicinfo.hActCtx == handle, "got %p\n", basicinfo.hActCtx); - ok(basicinfo.dwFlags == 0, "got %x\n", basicinfo.dwFlags); + ok(basicinfo.dwFlags == 0, "got %lx\n", basicinfo.dwFlags); - ret = pZombifyActCtx(handle); -todo_wine + ret = ZombifyActCtx(handle); + todo_wine ok(ret, "got %d\n", ret); memset(&basicinfo, 0xff, sizeof(basicinfo)); - ret = pQueryActCtxW(0, handle, 0, ActivationContextBasicInformation, - &basicinfo, sizeof(basicinfo), NULL); - ok(ret, "got %d, error %d\n", ret, GetLastError()); + ret = QueryActCtxW(0, handle, 0, ActivationContextBasicInformation, &basicinfo, sizeof(basicinfo), NULL); + ok(ret, "got %d, error %ld\n", ret, GetLastError()); ok(basicinfo.hActCtx == handle, "got %p\n", basicinfo.hActCtx); - ok(basicinfo.dwFlags == 0, "got %x\n", basicinfo.dwFlags); + ok(basicinfo.dwFlags == 0, "got %lx\n", basicinfo.dwFlags); memset(&basicinfo, 0xff, sizeof(basicinfo)); - ret = pQueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, NULL, 0, ActivationContextBasicInformation, - &basicinfo, sizeof(basicinfo), NULL); - ok(ret, "got %d, error %d\n", ret, GetLastError()); + ret = QueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, NULL, 0, ActivationContextBasicInformation, + &basicinfo, sizeof(basicinfo), NULL); + ok(ret, "got %d, error %ld\n", ret, GetLastError()); ok(basicinfo.hActCtx == handle, "got %p\n", basicinfo.hActCtx); - ok(basicinfo.dwFlags == 0, "got %x\n", basicinfo.dwFlags); + ok(basicinfo.dwFlags == 0, "got %lx\n", basicinfo.dwFlags); - ret = pGetCurrentActCtx(¤t); - ok(ret, "got %d, error %d\n", ret, GetLastError()); + ret = GetCurrentActCtx(¤t); + ok(ret, "got %d, error %ld\n", ret, GetLastError()); ok(current == handle, "got %p\n", current); /* one more time */ - ret = pZombifyActCtx(handle); -todo_wine + ret = ZombifyActCtx(handle); + todo_wine ok(ret, "got %d\n", ret); - ret = pDeactivateActCtx(0, cookie); - ok(ret, "DeactivateActCtx failed: %u\n", GetLastError()); - pReleaseActCtx(handle); +#ifdef __REACTOS__ + if (is_reactos()) { + trace("HACK: ReactOS crashes on DeactivateActCtx() below.\n"); + ret = FALSE; + } else +#endif + ret = DeactivateActCtx(0, cookie); + ok(ret, "DeactivateActCtx failed: %lu\n", GetLastError()); + ReleaseActCtx(handle); } /* Test structure to verify alignment */ @@ -2752,6 +3204,20 @@ typedef struct _test_act_ctx_compat_info { COMPATIBILITY_CONTEXT_ELEMENT Elements[10]; } test_act_ctx_compat_info; +/* Win10 versions before 1909 don't have the MaxVersionTested field */ +typedef struct +{ + GUID Id; + ACTCTX_COMPATIBILITY_ELEMENT_TYPE Type; +} old_win10_COMPATIBILITY_CONTEXT_ELEMENT; + +typedef struct +{ + DWORD ElementCount; + old_win10_COMPATIBILITY_CONTEXT_ELEMENT Elements[10]; +} old_win10_test_act_ctx_compat_info; + + static void test_no_compat(HANDLE handle, int line) { test_act_ctx_compat_info compat_info; @@ -2759,41 +3225,69 @@ static void test_no_compat(HANDLE handle, int line) BOOL b; memset(&compat_info, 0, sizeof(compat_info)); - b = pQueryActCtxW(QUERY_ACTCTX_FLAG_NO_ADDREF, handle, NULL, - CompatibilityInformationInActivationContext, &compat_info, - sizeof(compat_info), &size); + b = QueryActCtxW(QUERY_ACTCTX_FLAG_NO_ADDREF, handle, NULL, CompatibilityInformationInActivationContext, + &compat_info, sizeof(compat_info), &size); ok_(__FILE__, line)(b, "CompatibilityInformationInActivationContext failed\n"); - ok_(__FILE__, line)(size == sizeof(DWORD), "size mismatch (got %lu, expected 4)\n", size); - ok_(__FILE__, line)(compat_info.ElementCount == 0, "unexpected ElementCount %u\n", compat_info.ElementCount); + ok_(__FILE__, line)(size == offsetof(test_act_ctx_compat_info,Elements[0]) || + broken(size == offsetof(old_win10_test_act_ctx_compat_info,Elements[0])), + "size mismatch got %Iu\n", size); + ok_(__FILE__, line)(compat_info.ElementCount == 0, "unexpected ElementCount %lu\n", compat_info.ElementCount); } -static void test_with_compat(HANDLE handle, DWORD num_compat, const GUID* expected_compat[], int line) +static void test_with_compat(HANDLE handle, DWORD num_compat, DWORD num_version, + const GUID *expected_compat[], const ULONGLONG expected_version[], int line) { test_act_ctx_compat_info compat_info; SIZE_T size; - SIZE_T expected = sizeof(COMPATIBILITY_CONTEXT_ELEMENT) * num_compat + sizeof(DWORD); DWORD n; BOOL b; memset(&compat_info, 0, sizeof(compat_info)); - b = pQueryActCtxW(QUERY_ACTCTX_FLAG_NO_ADDREF, handle, NULL, - CompatibilityInformationInActivationContext, &compat_info, - sizeof(compat_info), &size); + b = QueryActCtxW(QUERY_ACTCTX_FLAG_NO_ADDREF, handle, NULL, CompatibilityInformationInActivationContext, + &compat_info, sizeof(compat_info), &size); ok_(__FILE__, line)(b, "CompatibilityInformationInActivationContext failed\n"); - ok_(__FILE__, line)(size == expected, "size mismatch (got %lu, expected %lu)\n", size, expected); - ok_(__FILE__, line)(compat_info.ElementCount == num_compat, "unexpected ElementCount %u\n", compat_info.ElementCount); + ok_(__FILE__, line)(size == offsetof(test_act_ctx_compat_info,Elements[num_compat + num_version]) || + broken(size == offsetof(old_win10_test_act_ctx_compat_info,Elements[num_compat])), + "size mismatch got %Iu\n", size); + ok_(__FILE__, line)(compat_info.ElementCount == num_compat + num_version || + broken(compat_info.ElementCount == num_compat), + "unexpected ElementCount %lu\n", compat_info.ElementCount); - for (n = 0; n < num_compat; ++n) + if (size == offsetof(old_win10_test_act_ctx_compat_info,Elements[num_compat])) { - ok_(__FILE__, line)(IsEqualGUID(&compat_info.Elements[n].Id, expected_compat[n]), - "got wrong clsid %s, expected %s for %u\n", - wine_dbgstr_guid(&compat_info.Elements[n].Id), - wine_dbgstr_guid(expected_compat[n]), - n); - ok_(__FILE__, line)(compat_info.Elements[n].Type == ACTCTX_COMPATIBILITY_ELEMENT_TYPE_OS, - "Wrong type, got %u for %u\n", (DWORD)compat_info.Elements[n].Type, n); + for (n = 0; n < num_compat; ++n) + { + old_win10_test_act_ctx_compat_info *info = (old_win10_test_act_ctx_compat_info *)&compat_info; + ok_(__FILE__, line)(IsEqualGUID(&info->Elements[n].Id, expected_compat[n]), + "got wrong clsid %s, expected %s for %lu\n", + wine_dbgstr_guid(&info->Elements[n].Id), + wine_dbgstr_guid(expected_compat[n]), + n); + ok_(__FILE__, line)(info->Elements[n].Type == ACTCTX_COMPATIBILITY_ELEMENT_TYPE_OS, + "Wrong type, got %lu for %lu\n", (DWORD)info->Elements[n].Type, n); + } + } + else + { + for (n = 0; n < num_compat; ++n) + { + ok_(__FILE__, line)(IsEqualGUID(&compat_info.Elements[n].Id, expected_compat[n]), + "got wrong clsid %s, expected %s for %lu\n", + wine_dbgstr_guid(&compat_info.Elements[n].Id), + wine_dbgstr_guid(expected_compat[n]), + n); + ok_(__FILE__, line)(compat_info.Elements[n].Type == ACTCTX_COMPATIBILITY_ELEMENT_TYPE_OS, + "Wrong type, got %lu for %lu\n", (DWORD)compat_info.Elements[n].Type, n); + } + for (; n < num_compat + num_version; ++n) + { + ok_(__FILE__, line)(compat_info.Elements[n].Type == ACTCTX_COMPATIBILITY_ELEMENT_TYPE_MAXVERSIONTESTED, + "Wrong type, got %lu for %lu\n", (DWORD)compat_info.Elements[n].Type, n); + ok_(__FILE__, line)(compat_info.Elements[n].MaxVersionTested == expected_version[n - num_compat], + "Wrong version, got %s for %lu\n", wine_dbgstr_longlong(compat_info.Elements[n].MaxVersionTested), n); + } } } @@ -2809,7 +3303,7 @@ static void test_compatibility(void) return; } handle = test_create("test1.manifest"); - ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError()); DeleteFileA("test1.manifest"); if(handle != INVALID_HANDLE_VALUE) { @@ -2818,20 +3312,19 @@ static void test_compatibility(void) BOOL b; memset(buffer, 0, sizeof(buffer)); - b = pQueryActCtxW(QUERY_ACTCTX_FLAG_NO_ADDREF, handle, NULL, - CompatibilityInformationInActivationContext, buffer, - sizeof(buffer), &size); + b = QueryActCtxW(QUERY_ACTCTX_FLAG_NO_ADDREF, handle, NULL, CompatibilityInformationInActivationContext, + buffer, sizeof(buffer), &size); if (!b && GetLastError() == ERROR_INVALID_PARAMETER) { win_skip("CompatibilityInformationInActivationContext not supported.\n"); - pReleaseActCtx(handle); + ReleaseActCtx(handle); return; } test_basic_info(handle, __LINE__); test_no_compat(handle, __LINE__); - pReleaseActCtx(handle); + ReleaseActCtx(handle); } /* Still no compat results returned */ @@ -2842,13 +3335,13 @@ static void test_compatibility(void) return; } handle = test_create("no_supportedOs.manifest"); - ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError()); DeleteFileA("no_supportedOs.manifest"); if(handle != INVALID_HANDLE_VALUE) { test_basic_info(handle, __LINE__); test_no_compat(handle, __LINE__); - pReleaseActCtx(handle); + ReleaseActCtx(handle); } /* Just one result returned */ @@ -2859,7 +3352,7 @@ static void test_compatibility(void) return; } handle = test_create("manifest_vista.manifest"); - ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError()); DeleteFileA("manifest_vista.manifest"); if(handle != INVALID_HANDLE_VALUE) { @@ -2868,8 +3361,8 @@ static void test_compatibility(void) &VISTA_COMPAT_GUID }; test_basic_info(handle, __LINE__); - test_with_compat(handle, 1, expect_manifest, __LINE__); - pReleaseActCtx(handle); + test_with_compat(handle, 1, 0, expect_manifest, NULL, __LINE__); + ReleaseActCtx(handle); } /* Show that the order is retained */ @@ -2880,7 +3373,7 @@ static void test_compatibility(void) return; } handle = test_create("manifest_vista_7_8_10_81.manifest"); - ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError()); DeleteFileA("manifest_vista_7_8_10_81.manifest"); if(handle != INVALID_HANDLE_VALUE) { @@ -2892,9 +3385,14 @@ static void test_compatibility(void) &WIN10_COMPAT_GUID, &WIN81_COMPAT_GUID, }; + static const ULONGLONG expect_version[] = + { + 0x000a000047b60000ull, /* 10.0.18358.0 */ + 0x0002000300040005ull, /* 2.3.4.5 */ + }; test_basic_info(handle, __LINE__); - test_with_compat(handle, 5, expect_manifest, __LINE__); - pReleaseActCtx(handle); + test_with_compat(handle, 5, 2, expect_manifest, expect_version, __LINE__); + ReleaseActCtx(handle); } /* Show that even unknown GUID's are stored */ @@ -2905,7 +3403,7 @@ static void test_compatibility(void) return; } handle = test_create("manifest_other_guid.manifest"); - ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError()); DeleteFileA("manifest_other_guid.manifest"); if(handle != INVALID_HANDLE_VALUE) { @@ -2914,11 +3412,1052 @@ static void test_compatibility(void) &OTHER_COMPAT_GUID, }; test_basic_info(handle, __LINE__); - test_with_compat(handle, 1, expect_manifest, __LINE__); - pReleaseActCtx(handle); + test_with_compat(handle, 1, 0, expect_manifest, NULL, __LINE__); + ReleaseActCtx(handle); } } +static void test_settings(void) +{ + static const WCHAR dpiAwareW[] = {'d','p','i','A','w','a','r','e',0}; + static const WCHAR dpiAwarenessW[] = {'d','p','i','A','w','a','r','e','n','e','s','s',0}; + static const WCHAR dummyW[] = {'d','u','m','m','y',0}; + static const WCHAR trueW[] = {'t','r','u','e',0}; + static const WCHAR namespace2005W[] = {'h','t','t','p',':','/','/','s','c','h','e','m','a','s','.','m','i','c','r','o','s','o','f','t','.','c','o','m','/','S','M','I','/','2','0','0','5','/','W','i','n','d','o','w','s','S','e','t','t','i','n','g','s',0}; + static const WCHAR namespace2016W[] = {'h','t','t','p',':','/','/','s','c','h','e','m','a','s','.','m','i','c','r','o','s','o','f','t','.','c','o','m','/','S','M','I','/','2','0','1','6','/','W','i','n','d','o','w','s','S','e','t','t','i','n','g','s',0}; + WCHAR buffer[80]; + SIZE_T size; + HANDLE handle; + BOOL ret; + +#if defined(__REACTOS__) && DLL_EXPORT_VERSION >= 0x600 + /* FIXME: QueryActCtxSettingsW() is a STUB on ReactOS. */ + if (is_reactos() || !pQueryActCtxSettingsW) +#else + if (!pQueryActCtxSettingsW) +#endif + { + win_skip( "QueryActCtxSettingsW is missing\n" ); + return; + } + create_manifest_file( "manifest_settings.manifest", settings_manifest, -1, NULL, NULL ); + handle = test_create("manifest_settings.manifest"); + ok( handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError() ); + DeleteFileA( "manifest_settings.manifest" ); + + SetLastError( 0xdeadbeef ); + ret = pQueryActCtxSettingsW( 1, handle, NULL, dpiAwareW, buffer, 80, &size ); + ok( !ret, "QueryActCtxSettingsW failed err %lu\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = pQueryActCtxSettingsW( 0, handle, dummyW, dpiAwareW, buffer, 80, &size ); + ok( !ret, "QueryActCtxSettingsW failed err %lu\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + size = 0xdead; + memset( buffer, 0xcc, sizeof(buffer) ); + ret = pQueryActCtxSettingsW( 0, handle, NULL, dpiAwareW, buffer, 80, &size ); + ok( ret, "QueryActCtxSettingsW failed err %lu\n", GetLastError() ); + ok( !lstrcmpW( buffer, trueW ), "got %s\n", wine_dbgstr_w(buffer) ); + ok( size == lstrlenW( buffer ) + 1, "wrong len %Iu\n", size ); + SetLastError( 0xdeadbeef ); + size = 0xdead; + memset( buffer, 0xcc, sizeof(buffer) ); + ret = pQueryActCtxSettingsW( 0, handle, NULL, dummyW, buffer, 80, &size ); + ok( !ret, "QueryActCtxSettingsW succeeded\n" ); + ok( GetLastError() == ERROR_SXS_KEY_NOT_FOUND, "wrong error %lu\n", GetLastError() ); + ok( buffer[0] == 0xcccc, "got %s\n", wine_dbgstr_w(buffer) ); + SetLastError( 0xdeadbeef ); + size = 0xdead; + memset( buffer, 0xcc, sizeof(buffer) ); + ret = pQueryActCtxSettingsW( 0, handle, namespace2005W, dpiAwareW, buffer, 80, &size ); + ok( ret, "QueryActCtxSettingsW failed err %lu\n", GetLastError() ); + ok( !lstrcmpW( buffer, trueW ), "got %s\n", wine_dbgstr_w(buffer) ); + ok( size == ARRAY_SIZE(trueW), "wrong len %Iu\n", size ); + SetLastError( 0xdeadbeef ); + size = 0xdead; + memset( buffer, 0xcc, sizeof(buffer) ); + ret = pQueryActCtxSettingsW( 0, handle, namespace2005W, dpiAwareW, buffer, lstrlenW(trueW) + 1, &size ); + ok( ret, "QueryActCtxSettingsW failed err %lu\n", GetLastError() ); + ok( !lstrcmpW( buffer, trueW ), "got %s\n", wine_dbgstr_w(buffer) ); + ok( size == ARRAY_SIZE(trueW), "wrong len %Iu\n", size ); + SetLastError( 0xdeadbeef ); + size = 0xdead; + memset( buffer, 0xcc, sizeof(buffer) ); + ret = pQueryActCtxSettingsW( 0, handle, namespace2016W, dpiAwareW, buffer, lstrlenW(trueW) + 1, &size ); + ok( !ret, "QueryActCtxSettingsW succeeded\n" ); + ok( GetLastError() == ERROR_SXS_KEY_NOT_FOUND || broken( GetLastError() == ERROR_INVALID_PARAMETER ), + "wrong error %lu\n", GetLastError() ); + ok( buffer[0] == 0xcccc, "got %s\n", wine_dbgstr_w(buffer) ); + SetLastError( 0xdeadbeef ); + size = 0xdead; + memset( buffer, 0xcc, sizeof(buffer) ); + ret = pQueryActCtxSettingsW( 0, handle, NULL, dpiAwarenessW, buffer, lstrlenW(trueW) + 1, &size ); + ok( !ret, "QueryActCtxSettingsW succeeded\n" ); + ok( GetLastError() == ERROR_SXS_KEY_NOT_FOUND, "wrong error %lu\n", GetLastError() ); + ok( buffer[0] == 0xcccc, "got %s\n", wine_dbgstr_w(buffer) ); + SetLastError( 0xdeadbeef ); + size = 0xdead; + memset( buffer, 0xcc, sizeof(buffer) ); + ret = pQueryActCtxSettingsW( 0, handle, namespace2005W, dpiAwarenessW, buffer, lstrlenW(trueW) + 1, &size ); + ok( !ret, "QueryActCtxSettingsW succeeded\n" ); + ok( GetLastError() == ERROR_SXS_KEY_NOT_FOUND, "wrong error %lu\n", GetLastError() ); + ok( buffer[0] == 0xcccc, "got %s\n", wine_dbgstr_w(buffer) ); + SetLastError( 0xdeadbeef ); + size = 0xdead; + memset( buffer, 0xcc, sizeof(buffer) ); + ret = pQueryActCtxSettingsW( 0, handle, namespace2016W, dpiAwarenessW, buffer, lstrlenW(trueW) + 1, &size ); + ok( ret || broken( GetLastError() == ERROR_INVALID_PARAMETER ), + "QueryActCtxSettingsW failed err %lu\n", GetLastError() ); + if (ret) + { + ok( !lstrcmpW( buffer, trueW ), "got %s\n", wine_dbgstr_w(buffer) ); + ok( size == ARRAY_SIZE(trueW), "wrong len %Iu\n", size ); + } + else ok( buffer[0] == 0xcccc, "got %s\n", wine_dbgstr_w(buffer) ); + SetLastError( 0xdeadbeef ); + size = 0xdead; + memset( buffer, 0xcc, sizeof(buffer) ); + ret = pQueryActCtxSettingsW( 0, handle, NULL, dpiAwareW, buffer, lstrlenW(trueW), &size ); + ok( ret, "QueryActCtxSettingsW failed err %lu\n", GetLastError() ); + ok( !lstrcmpW( buffer, trueW ), "got %s\n", wine_dbgstr_w(buffer) ); + ok( size == ARRAY_SIZE(trueW), "wrong len %Iu\n", size ); + SetLastError( 0xdeadbeef ); + size = 0xdead; + memset( buffer, 0xcc, sizeof(buffer) ); + ret = pQueryActCtxSettingsW( 0, handle, NULL, dpiAwareW, buffer, lstrlenW(trueW) - 1, &size ); + ok( !ret, "QueryActCtxSettingsW failed err %lu\n", GetLastError() ); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "wrong error %lu\n", GetLastError() ); + ok( buffer[0] == 0xcccc, "got %s\n", wine_dbgstr_w(buffer) ); + ok( size == ARRAY_SIZE(trueW), "wrong len %Iu\n", size ); + ReleaseActCtx(handle); + + create_manifest_file( "manifest_settings2.manifest", settings_manifest2, -1, NULL, NULL ); + handle = test_create("manifest_settings2.manifest"); + ok( handle != INVALID_HANDLE_VALUE || broken( handle == INVALID_HANDLE_VALUE ), /* <= vista */ + "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError() ); + DeleteFileA( "manifest_settings2.manifest" ); + if (handle != INVALID_HANDLE_VALUE) + { + SetLastError( 0xdeadbeef ); + size = 0xdead; + memset( buffer, 0xcc, sizeof(buffer) ); + ret = pQueryActCtxSettingsW( 0, handle, NULL, dpiAwareW, buffer, 80, &size ); + ok( ret, "QueryActCtxSettingsW failed err %lu\n", GetLastError() ); + ok( !lstrcmpW( buffer, trueW ), "got %s\n", wine_dbgstr_w(buffer) ); + ok( size == lstrlenW( buffer ) + 1, "wrong len %Iu\n", size ); + ReleaseActCtx(handle); + } + + create_manifest_file( "manifest_settings3.manifest", settings_manifest3, -1, NULL, NULL ); + handle = test_create("manifest_settings3.manifest"); + ok( handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError() ); + DeleteFileA( "manifest_settings3.manifest" ); + SetLastError( 0xdeadbeef ); + size = 0xdead; + memset( buffer, 0xcc, sizeof(buffer) ); + ret = pQueryActCtxSettingsW( 0, handle, NULL, dpiAwareW, buffer, 80, &size ); + ok( !ret, "QueryActCtxSettingsW succeeded\n" ); + ok( GetLastError() == ERROR_SXS_KEY_NOT_FOUND, "wrong error %lu\n", GetLastError() ); + ReleaseActCtx(handle); + + /* lookup occurs in first non empty node */ + create_manifest_file( "manifest_settings4.manifest", settings_manifest4, -1, NULL, NULL ); + handle = test_create("manifest_settings4.manifest"); + ok( handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError() ); + DeleteFileA( "manifest_settings4.manifest" ); + SetLastError( 0xdeadbeef ); + size = 0xdead; + memset( buffer, 0xcc, sizeof(buffer) ); + ret = pQueryActCtxSettingsW( 0, handle, NULL, dpiAwareW, buffer, 80, &size ); + ok( ret, "QueryActCtxSettingsW failed\n" ); + SetLastError( 0xdeadbeef ); + size = 0xdead; + memset( buffer, 0xcc, sizeof(buffer) ); + ret = pQueryActCtxSettingsW( 0, handle, NULL, dpiAwarenessW, buffer, 80, &size ); + ok( !ret, "QueryActCtxSettingsW succeeded\n" ); + ReleaseActCtx(handle); +} + +typedef struct +{ + char path_tmp[MAX_PATH]; + char path_dll[MAX_PATH + 11]; + char path_manifest_exe[MAX_PATH + 12]; + char path_manifest_dll[MAX_PATH + 16]; + ACTCTXA context; + ULONG_PTR cookie; + HANDLE handle_context; + HMODULE module; + void (WINAPI *get_path)(char *buffer, int buffer_size); +} sxs_info; + +static BOOL fill_sxs_info(sxs_info *info, const char *temp, const char *path_dll, const char *exe_manifest, const char *dll_manifest, BOOL do_load) +{ + BOOL success; + + GetTempPathA(MAX_PATH, info->path_tmp); + strcat(info->path_tmp, temp); + strcat(info->path_tmp, "\\"); + CreateDirectoryA(info->path_tmp, NULL); + + sprintf(info->path_dll, "%s%s", info->path_tmp, "sxs_dll.dll"); + extract_resource(path_dll, "TESTDLL", info->path_dll); + + sprintf(info->path_manifest_exe, "%s%s", info->path_tmp, "exe.manifest"); + create_manifest_file(info->path_manifest_exe, exe_manifest, -1, NULL, NULL); + + sprintf(info->path_manifest_dll, "%s%s", info->path_tmp, "sxs_dll.manifest"); + create_manifest_file(info->path_manifest_dll, dll_manifest, -1, NULL, NULL); + + info->context.cbSize = sizeof(ACTCTXA); + info->context.lpSource = info->path_manifest_exe; + info->context.lpAssemblyDirectory = info->path_tmp; + info->context.dwFlags = ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID; + + info->handle_context = CreateActCtxA(&info->context); + ok((info->handle_context != NULL && info->handle_context != INVALID_HANDLE_VALUE ) + || broken(GetLastError() == ERROR_SXS_CANT_GEN_ACTCTX), /* XP doesn't support manifests outside of PE files */ + "CreateActCtxA failed: %ld\n", GetLastError()); + if (GetLastError() == ERROR_SXS_CANT_GEN_ACTCTX) + { + skip("Failed to create activation context.\n"); + return FALSE; + } + + if (do_load) + { + success = ActivateActCtx(info->handle_context, &info->cookie); + ok(success, "ActivateActCtx failed: %ld\n", GetLastError()); + + info->module = LoadLibraryA("sxs_dll.dll"); + ok(info->module != NULL, "LoadLibrary failed\n"); + + info->get_path = (void *)GetProcAddress(info->module, "get_path"); + ok(info->get_path != NULL, "GetProcAddress failed\n"); + + DeactivateActCtx(0, info->cookie); + } + return TRUE; +} + +static void clean_sxs_info(sxs_info *info) +{ + if (info->handle_context) + ReleaseActCtx(info->handle_context); + if (*info->path_dll) + { + BOOL ret = DeleteFileA(info->path_dll); + ok(ret, "DeleteFileA failed for %s: %ld\n", info->path_dll, GetLastError()); + } + if (*info->path_manifest_exe) + { + BOOL ret = DeleteFileA(info->path_manifest_exe); + ok(ret, "DeleteFileA failed for %s: %ld\n", info->path_manifest_exe, GetLastError()); + } + if (*info->path_manifest_dll) + { + BOOL ret = DeleteFileA(info->path_manifest_dll); + ok(ret, "DeleteFileA failed for %s: %ld\n", info->path_manifest_dll, GetLastError()); + } + if (*info->path_tmp) + { + BOOL ret = RemoveDirectoryA(info->path_tmp); + ok(ret, "RemoveDirectoryA failed for %s: %ld\n", info->path_tmp, GetLastError()); + } +} + +static void get_application_directory(char *buffer, int buffer_size) +{ + char *end; + GetModuleFileNameA(NULL, buffer, buffer_size); + end = strrchr(buffer, '\\'); + end[1] = 0; +} + +/* Test loading two sxs dlls at the same time */ +static void test_two_dlls_at_same_time(void) +{ + sxs_info dll_1; + sxs_info dll_2; + char path1[MAX_PATH], path2[MAX_PATH]; + + if (!fill_sxs_info(&dll_1, "1", "dummy.dll", two_dll_manifest_exe, two_dll_manifest_dll, TRUE)) + goto cleanup1; + if (!fill_sxs_info(&dll_2, "2", "dummy.dll", two_dll_manifest_exe, two_dll_manifest_dll, TRUE)) + goto cleanup2; + + ok(dll_1.module != dll_2.module, "Libraries are the same\n"); + dll_1.get_path(path1, sizeof(path1)); + ok(strcmp(path1, dll_1.path_dll) == 0, "Got '%s', expected '%s'\n", path1, dll_1.path_dll); + dll_2.get_path(path2, sizeof(path2)); + ok(strcmp(path2, dll_2.path_dll) == 0, "Got '%s', expected '%s'\n", path2, dll_2.path_dll); + +cleanup2: + if (dll_2.module) + FreeLibrary(dll_2.module); + clean_sxs_info(&dll_2); +cleanup1: + if (dll_1.module) + FreeLibrary(dll_1.module); + clean_sxs_info(&dll_1); +} + +/* Test loading a normal dll and then a sxs dll with the same name */ +static void test_one_sxs_and_one_local_1(void) +{ + sxs_info dll; + char path_dll_local[MAX_PATH + 11]; + char path_application[MAX_PATH]; + HMODULE module = NULL; + char path1[MAX_PATH], path2[MAX_PATH]; + void (WINAPI *get_path)(char *buffer, int buffer_size); + + get_application_directory(path_application, sizeof(path_application)); + + sprintf(path_dll_local, "%s%s", path_application, "sxs_dll.dll"); + extract_resource("dummy.dll", "TESTDLL", path_dll_local); + + module = LoadLibraryA(path_dll_local); + get_path = (void *)GetProcAddress(module, "get_path"); + + if (!fill_sxs_info(&dll, "1", "dummy.dll", two_dll_manifest_exe, two_dll_manifest_dll, TRUE)) + goto cleanup; + + ok(dll.module != module, "Libraries are the same\n"); + dll.get_path(path1, sizeof(path1)); + ok(strcmp(path1, dll.path_dll) == 0, "Got '%s', expected '%s'\n", path1, dll.path_dll); + get_path(path2, sizeof(path2)); + ok(strcmp(path2, path_dll_local) == 0, "Got '%s', expected '%s'\n", path2, path_dll_local); + +cleanup: + if (module) + FreeLibrary(module); + if (dll.module) + FreeLibrary(dll.module); + if (*path_dll_local) + { + BOOL success = DeleteFileA(path_dll_local); + ok(success, "DeleteFileA failed for %s: %ld\n", path_dll_local, GetLastError()); + } + clean_sxs_info(&dll); +} + +/* Test if sxs dll has priority over normal dll */ +static void test_one_sxs_and_one_local_2(void) +{ + sxs_info dll; + char path_dll_local[MAX_PATH + 11]; + char path_application[MAX_PATH]; + HMODULE module = NULL; + char path1[MAX_PATH], path2[MAX_PATH]; + void (WINAPI *get_path)(char *buffer, int buffer_size); + + get_application_directory(path_application, sizeof(path_application)); + + sprintf(path_dll_local, "%s%s", path_application, "sxs_dll.dll"); + extract_resource("dummy.dll", "TESTDLL", path_dll_local); + + if (!fill_sxs_info(&dll, "1", "dummy.dll", two_dll_manifest_exe, two_dll_manifest_dll, TRUE)) + goto cleanup; + + module = LoadLibraryA(path_dll_local); + get_path = (void *)GetProcAddress(module, "get_path"); + + ok(dll.module != module, "Libraries are the same\n"); + dll.get_path(path1, sizeof(path1)); + ok(strcmp(path1, dll.path_dll) == 0, "Got '%s', expected '%s'\n", path1, dll.path_dll); + get_path(path2, sizeof(path2)); + ok(strcmp(path2, path_dll_local) == 0, "Got '%s', expected '%s'\n", path2, path_dll_local); + +cleanup: + if (module) + FreeLibrary(module); + if (dll.module) + FreeLibrary(dll.module); + if (*path_dll_local) + { + BOOL success = DeleteFileA(path_dll_local); + ok(success, "DeleteFileA failed for %s: %ld\n", path_dll_local, GetLastError()); + } + clean_sxs_info(&dll); +} + + +/* Test if we can get a module handle from loaded normal dll while context is active */ +static void test_one_with_sxs_and_GetModuleHandleA(void) +{ + sxs_info dll; + char path_dll_local[MAX_PATH + 11]; + char path_tmp[MAX_PATH]; + HMODULE module = NULL, module_temp; + BOOL success; + + GetTempPathA(sizeof(path_tmp), path_tmp); + + sprintf(path_dll_local, "%s%s", path_tmp, "sxs_dll.dll"); + extract_resource("dummy.dll", "TESTDLL", path_dll_local); + + module = LoadLibraryA(path_dll_local); + + if (!fill_sxs_info(&dll, "1", "dummy.dll", two_dll_manifest_exe, two_dll_manifest_dll, FALSE)) + goto cleanup; + + success = ActivateActCtx(dll.handle_context, &dll.cookie); + ok(success, "ActivateActCtx failed: %ld\n", GetLastError()); + + module_temp = GetModuleHandleA("sxs_dll.dll"); + ok (module_temp == 0, "Expected 0, got %p\n", module_temp); + + DeactivateActCtx(0, dll.cookie); + +cleanup: + if (module) + FreeLibrary(module); + if (dll.module) + FreeLibrary(dll.module); + if (*path_dll_local) + { + success = DeleteFileA(path_dll_local); + ok(success, "DeleteFileA failed for %s: %ld\n", path_dll_local, GetLastError()); + } + clean_sxs_info(&dll); +} + +static void test_builtin_sxs(void) +{ + char path_manifest[MAX_PATH + 12]; + char path_tmp[MAX_PATH]; + HMODULE module_msvcp = 0, module_msvcr = 0; + char path_msvcp[MAX_PATH], path_msvcr[MAX_PATH]; + ACTCTXA context; + ULONG_PTR cookie; + HANDLE handle_context; + BOOL success; + static const char *expected_path = "C:\\Windows\\WinSxS"; + + GetTempPathA(sizeof(path_tmp), path_tmp); + + sprintf(path_manifest, "%s%s", path_tmp, "exe.manifest"); + create_manifest_file(path_manifest, builtin_dll_manifest, -1, NULL, NULL); + + context.cbSize = sizeof(ACTCTXA); + context.lpSource = path_manifest; + context.lpAssemblyDirectory = path_tmp; + context.dwFlags = ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID; + + handle_context = CreateActCtxA(&context); + ok((handle_context != NULL && handle_context != INVALID_HANDLE_VALUE ) + || broken(GetLastError() == ERROR_SXS_CANT_GEN_ACTCTX), /* XP doesn't support manifests outside of PE files */ + "CreateActCtxA failed: %ld\n", GetLastError()); + if (GetLastError() == ERROR_SXS_CANT_GEN_ACTCTX) + { + skip("Failed to create activation context.\n"); + goto cleanup; + } + + + success = ActivateActCtx(handle_context, &cookie); + ok(success, "ActivateActCtx failed: %ld\n", GetLastError()); + + module_msvcp = LoadLibraryA("msvcp90.dll"); + ok (module_msvcp != 0 || broken(module_msvcp == 0), "LoadLibraryA failed, %ld\n", GetLastError()); + module_msvcr = LoadLibraryA("msvcr90.dll"); + ok (module_msvcr != 0 || broken(module_msvcr == 0), "LoadLibraryA failed, %ld\n", GetLastError()); + if (!module_msvcp || !module_msvcr) + { + skip("Failed to find msvcp90 or msvcr90.\n"); + goto cleanup; + } + + GetModuleFileNameA(module_msvcp, path_msvcp, sizeof(path_msvcp)); + GetModuleFileNameA(module_msvcr, path_msvcr, sizeof(path_msvcr)); + ok(strnicmp(expected_path, path_msvcp, strlen(expected_path)) == 0, "Expected path to start with %s, got %s\n", expected_path, path_msvcp); + ok(strnicmp(expected_path, path_msvcr, strlen(expected_path)) == 0, "Expected path to start with %s, got %s\n", expected_path, path_msvcr); + + DeactivateActCtx(0, cookie); + +cleanup: + if (module_msvcp) + FreeLibrary(module_msvcp); + if (module_msvcr) + FreeLibrary(module_msvcr); + if (*path_manifest) + { + success = DeleteFileA(path_manifest); + ok(success, "DeleteFileA failed for %s: %ld\n", path_manifest, GetLastError()); + } +} + +struct manifest_res_spec +{ + const char *name; + LANGID lang; + const char *override_manifest; +}; + +struct manifest_res_spec_list +{ + size_t count; + const struct manifest_res_spec *items; +}; + +static void add_sxs_dll_manifest(const char *pathname, + const struct manifest_res_spec_list *res_lists, + size_t num_lists, + const char *manifest) +{ + HANDLE update_h; + BOOL ret; + size_t i, j; + + update_h = BeginUpdateResourceA(pathname, FALSE); + ok(update_h != NULL, "BeginUpdateResourceA returned error %lu.\n", GetLastError()); + + for (i = 0; i < num_lists; i++) + { + for (j = 0; j < res_lists[i].count; j++) + { + const struct manifest_res_spec *res_spec = &res_lists[i].items[j]; + const char *cur_manifest = res_spec->override_manifest ? res_spec->override_manifest : manifest; + ret = UpdateResourceA(update_h, + MAKEINTRESOURCEA(RT_MANIFEST), + res_spec->name, + res_spec->lang, + (void *)cur_manifest, + strlen(cur_manifest)); + ok(ret, "UpdateResourceA returned error %lu.\n", GetLastError()); + } + } + + ret = EndUpdateResourceA(update_h, FALSE); + ok(ret, "EndUpdateResourceA returned error %lu.\n", GetLastError()); +} + +struct multiple_manifest_test +{ + struct manifest_res_spec manifest_inline; /* optional */ + const struct manifest_res_spec *manifests; /* optional */ + DWORD expected_error; +}; + +#define subtest_manifest_res(d,e,t,l) subtest_manifest_res_(__LINE__,d,e,t,l) +static DWORD subtest_manifest_res_(int line, const char *manifest_exe, const char *manifest_dll, + const struct multiple_manifest_test *test_data, LANGID lang) +{ + char path_tmp[MAX_PATH] = "", path_dll[MAX_PATH] = "", path_manifest_exe[MAX_PATH] = ""; + static const char path_tmp_suffix[] = "winek32t\\"; + WCHAR locale_name[LOCALE_NAME_MAX_LENGTH] = {0}; + struct manifest_res_spec_list res_lists[2]; + char path_tmp_lang[MAX_PATH] = ""; + static volatile LONG last_uniqid; + DWORD err, prefix_len; + ACTCTXA actctx; + HANDLE handle; + BOOL ret; + int r; + + prefix_len = GetTempPathA(MAX_PATH - ARRAY_SIZE(path_tmp_suffix), path_tmp); + ok_(__FILE__, line)(prefix_len > 0, "GetTempPathA returned error %lu.\n", GetLastError()); + + memcpy(&path_tmp[prefix_len], path_tmp_suffix, sizeof(path_tmp_suffix) - sizeof(*path_tmp_suffix)); + ret = CreateDirectoryA(path_tmp, NULL); + ok_(__FILE__, line)(ret || GetLastError() == ERROR_ALREADY_EXISTS, + "CreateDirectoryA returned error %lu.\n", GetLastError()); + + if (lang) + { +#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600 + r = LCIDToLocaleName(MAKELCID(lang, SORT_DEFAULT), + locale_name, ARRAY_SIZE(locale_name), LOCALE_ALLOW_NEUTRAL_NAMES); + ok(r > 0, "lang 0x%04x, error %lu.\n", lang, GetLastError()); +#endif + } + + if (locale_name[0]) + { + r = snprintf(path_tmp_lang, ARRAY_SIZE(path_tmp_lang), "%s%ls\\", path_tmp, locale_name); + ok_(__FILE__, line)(r > 0 && r < ARRAY_SIZE(path_tmp_lang), "got %d\n", r); + + ret = CreateDirectoryA(path_tmp_lang, NULL); + ok_(__FILE__, line)(ret || GetLastError() == ERROR_ALREADY_EXISTS, + "CreateDirectoryA returned error %lu.\n", GetLastError()); + } + else + { + r = snprintf(path_tmp_lang, ARRAY_SIZE(path_tmp_lang), "%s", path_tmp); + ok_(__FILE__, line)(r > 0 && r < ARRAY_SIZE(path_tmp_lang), "got %d\n", r); + } + + r = snprintf(path_dll, ARRAY_SIZE(path_dll), "%s%s", path_tmp_lang, "sxs_dll.dll"); + ok_(__FILE__, line)(r > 0 && r < ARRAY_SIZE(path_dll), "got %d\n", r); + + r = snprintf(path_manifest_exe, ARRAY_SIZE(path_manifest_exe), "%sexe%08lx.manifest", + path_tmp, InterlockedIncrement(&last_uniqid)); + ok_(__FILE__, line)(r > 0 && r < ARRAY_SIZE(path_manifest_exe), "got %d\n", r); + create_manifest_file(path_manifest_exe, manifest_exe, -1, NULL, NULL); + + extract_resource("dummy.dll", "TESTDLL", path_dll); + + res_lists[0].count = test_data->manifest_inline.name ? 1 : 0; + res_lists[0].items = &test_data->manifest_inline; + + if (test_data->manifests) + { + size_t n = 0; + + while (test_data->manifests[n].name) + n++; + + res_lists[1].count = n; + res_lists[1].items = test_data->manifests; + } + else + { + res_lists[1].count = 0; + res_lists[1].items = NULL; + } + + add_sxs_dll_manifest(path_dll, res_lists, ARRAY_SIZE(res_lists), manifest_dll); + + memset(&actctx, 0, sizeof(actctx)); + actctx.cbSize = sizeof(actctx); + actctx.lpSource = path_manifest_exe; + actctx.lpAssemblyDirectory = path_tmp; + actctx.dwFlags = ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID; + + SetLastError(0xccccccccUL); + handle = CreateActCtxA(&actctx); + if (handle == INVALID_HANDLE_VALUE) + { + err = GetLastError(); + ok_(__FILE__, line)(err != ERROR_SUCCESS, "got %#lx.\n", err); + } + else + { + err = ERROR_SUCCESS; + ok_(__FILE__, line)(handle != NULL, "CreateActCtxA returned %p (error %lu)\n", handle, err); + ReleaseActCtx(handle); + } + ok_(__FILE__, line)(err == test_data->expected_error, + "expected error %lu, got %lu\n", test_data->expected_error, err); + + ret = DeleteFileA(path_manifest_exe); + ok_(__FILE__, line)(ret, "DeleteFileA(%s) returned error %lu\n.", + debugstr_a(path_manifest_exe), GetLastError()); + + ret = DeleteFileA(path_dll); + ok_(__FILE__, line)(ret, "DeleteFileA(%s) returned error %lu\n.", debugstr_a(path_dll), GetLastError()); + + if (locale_name[0]) + { + ret = RemoveDirectoryA(path_tmp_lang); + ok_(__FILE__, line)(ret, "RemoveDirectoryA(%s) returned error %lu\n.", + debugstr_a(path_tmp_lang), GetLastError()); + } + + ret = RemoveDirectoryA(path_tmp); + ok_(__FILE__, line)(ret, "RemoveDirectoryA(%s) returned error %lu %s\n.", + debugstr_a(path_tmp), GetLastError(), debugstr_a(path_tmp_lang)); + + return err; +} + +/* Test loading DLL with dependency assembly in manifest resource */ +static void test_manifest_resources(void) +{ +#ifdef __REACTOS__ + skip("test_manifest_resources() is invalid for WS03 - Win10 1607.\n"); +#else + static const struct manifest_res_spec wrong_manifest_resources_numbered[] = { + { (char *)2, MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), wrong_manifest1 }, + { (char *)2, MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), wrong_manifest1 }, + { (char *)3, 0, wrong_manifest1 }, + { (char *)0x1234, 0, wrong_manifest1 }, + { NULL }, + }; + static const struct manifest_res_spec correct_manifest_resources_numbered[] = { + { (char *)2, MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT) }, + { (char *)2, MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT) }, + { (char *)3, 0 }, + { (char *)0x1234, 0 }, + { NULL }, + }; + static const struct manifest_res_spec wrong_manifest_resources_gte_3[] = { + { (char *)3, 0, wrong_manifest1 }, + { (char *)3, MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), wrong_manifest1 }, + { NULL }, + }; + static const struct manifest_res_spec correct_manifest_resources_gte_3[] = { + { (char *)3, 0 }, + { (char *)3, MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT) }, + { NULL }, + }; + static const struct manifest_res_spec wrong_manifest_resources_named[] = { + { "foo", 0, wrong_manifest1 }, + { "bar", MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), wrong_manifest1 }, + { NULL }, + }; + static const struct manifest_res_spec correct_manifest_resources_named[] = { + { "foo", 0 }, + { "bar", MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT) }, + { NULL }, + }; + struct multiple_manifest_test tests[] = { + /* Test well-known manifest resource IDs */ + { { (char *)CREATEPROCESS_MANIFEST_RESOURCE_ID }, NULL, ERROR_SUCCESS }, + { { (char *)ISOLATIONAWARE_MANIFEST_RESOURCE_ID }, NULL, ERROR_SUCCESS }, + { { (char *)ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID }, NULL, ERROR_SUCCESS }, + + /* Test remaining reserved manifest resource IDs */ + { { (char *)4 }, NULL, ERROR_SUCCESS }, + { { (char *)5 }, NULL, ERROR_SUCCESS }, + { { (char *)6 }, NULL, ERROR_SUCCESS }, + { { (char *)7 }, NULL, ERROR_SUCCESS }, + { { (char *)8 }, NULL, ERROR_SUCCESS }, + { { (char *)9 }, NULL, ERROR_SUCCESS }, + { { (char *)10 }, NULL, ERROR_SUCCESS }, + { { (char *)11 }, NULL, ERROR_SUCCESS }, + { { (char *)12 }, NULL, ERROR_SUCCESS }, + { { (char *)13 }, NULL, ERROR_SUCCESS }, + { { (char *)14 }, NULL, ERROR_SUCCESS }, + { { (char *)15 }, NULL, ERROR_SUCCESS }, + { { (char *)MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID }, NULL, ERROR_SUCCESS }, + + /* Test arbitrary resource IDs */ + { { (char *)0x1234 }, NULL, ERROR_SUCCESS }, + { { (char *)0x89ab }, NULL, ERROR_SUCCESS }, + { { (char *)0xffff }, NULL, ERROR_SUCCESS }, + + /* Test arbitrary LANGID */ + { { (char *)2, MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT) }, NULL, ERROR_SUCCESS }, + { { (char *)2, MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT) }, NULL, ERROR_SUCCESS }, + { { (char *)2, 0x1234 }, NULL, ERROR_SUCCESS }, + { { (char *)2, 0xffff }, NULL, ERROR_SUCCESS }, + + /* Test multiple manifest resources coexisting inside a module */ + { { (char *)2, 0 }, wrong_manifest_resources_numbered, ERROR_SUCCESS }, + { { (char *)2, 0, wrong_manifest1 }, correct_manifest_resources_numbered, + ERROR_SXS_CANT_GEN_ACTCTX }, + + /* Test that smaller resource ID takes precedence regardless of language ID */ + { { (char *)2, MAKELANGID(LANG_INVARIANT,SUBLANG_NEUTRAL) }, + wrong_manifest_resources_gte_3, ERROR_SUCCESS }, + { { (char *)2, MAKELANGID(LANG_INVARIANT,SUBLANG_NEUTRAL), wrong_manifest1 }, + correct_manifest_resources_gte_3, ERROR_SXS_CANT_GEN_ACTCTX }, + + /* Test multiple manifest resources (ID / name) coexisting inside a module */ + { { (char *)2, 0 }, wrong_manifest_resources_named, ERROR_SUCCESS }, + { { (char *)2, 0, wrong_manifest1 }, + correct_manifest_resources_named, ERROR_SXS_CANT_GEN_ACTCTX }, + + /* Test name-only RT_MANIFEST resources */ + { { NULL }, correct_manifest_resources_named, ERROR_SXS_CANT_GEN_ACTCTX }, + }; + size_t i; + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + winetest_push_context("tests[%Iu] (%p 0x%04x)", i, + tests[i].manifest_inline.name, tests[i].manifest_inline.lang); + subtest_manifest_res(two_dll_manifest_exe, two_dll_manifest_dll, &tests[i], 0); + winetest_pop_context(); + } +#endif +} + +#define LANGID_PREC_MAX_COUNT 5 + +static void get_langid_precedence(LANGID *langs_arr, size_t *lang_count) +{ + LANGID src_langs[LANGID_PREC_MAX_COUNT]; + LANGID user_ui_lang; + size_t i, j, n = 0; + + user_ui_lang = GetUserDefaultUILanguage(); + + src_langs[0] = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL); + src_langs[1] = user_ui_lang; + src_langs[2] = MAKELANGID(PRIMARYLANGID(user_ui_lang), SUBLANG_NEUTRAL); + src_langs[3] = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); + src_langs[4] = 0x1; /* least number that is a valid LANGID */ + + for (i = 0; i < ARRAY_SIZE(src_langs); i++) + { + LANGID item = src_langs[i]; + BOOL is_item_duplicate = FALSE; + + for (j = 0; j < n; j++) + { + if (langs_arr[j] == item) + { + is_item_duplicate = TRUE; + break; + } + } + + if (!is_item_duplicate) + { + langs_arr[n++] = item; + } + } + + *lang_count = n; +} + +static void subtest_valid_manifest_resources_locale(LANGID actctx_lang) +{ + static const char manifest_exe_fmt[] = + "" + "" + "" + "" + "" + "" + ""; + static const char manifest_dll_fmt[] = + "" + "" + ""; + static const char manifest_dll_nofmt[] = + "" + "" + ""; + char manifest_exe[1024], manifest_dll[1024]; + WCHAR locale_name[LOCALE_NAME_MAX_LENGTH]; + UINT16 langs_arr[LANGID_PREC_MAX_COUNT]; + size_t lang_count = 0, i, j; + int ret; + + if (actctx_lang == MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)) + { + wcscpy(locale_name, L"*"); + strcpy(manifest_dll, manifest_dll_nofmt); + } + else + { + actctx_lang = ConvertDefaultLocale(actctx_lang); + ok(actctx_lang != MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), + "unexpected neutral locale\n"); +#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600 + ret = LCIDToLocaleName(MAKELCID(actctx_lang, SORT_DEFAULT), + locale_name, ARRAY_SIZE(locale_name), LOCALE_ALLOW_NEUTRAL_NAMES); + ok(ret > 0, "error %lu.\n", GetLastError()); +#endif + + ret = snprintf(manifest_dll, ARRAY_SIZE(manifest_dll), manifest_dll_fmt, locale_name); + ok(ret > 0 && ret < ARRAY_SIZE(manifest_dll), "ret %d.\n", ret); + } + + ret = snprintf(manifest_exe, ARRAY_SIZE(manifest_exe), manifest_exe_fmt, locale_name); + ok(ret > 0 && ret < ARRAY_SIZE(manifest_exe), "ret %d.\n", ret); + + get_langid_precedence(langs_arr, &lang_count); + + for (i = 0; i < lang_count; i++) + { + struct manifest_res_spec specs[ARRAY_SIZE(langs_arr) + 1]; + struct multiple_manifest_test test = { { NULL } }; + size_t num_specs; + DWORD err; + + winetest_push_context("langs[%Id:]", i); + + /* Generate manifest spec list from language IDs. + * + * All manifest spec items point to the wrong manifest, expect for the + * current language ID. + */ + num_specs = 0; + for (j = i; j < lang_count; j++) + { + struct manifest_res_spec spec = {(char *)2}; + spec.lang = langs_arr[j]; + if (j != i) spec.override_manifest = wrong_manifest1; + ok(num_specs < ARRAY_SIZE(specs), "overrun\n"); + specs[num_specs++] = spec; + } + memset(&specs[num_specs++], 0, sizeof(*specs)); + + test.manifests = specs; + test.expected_error = ERROR_SUCCESS; + err = subtest_manifest_res(manifest_exe, manifest_dll, &test, actctx_lang); + + if (winetest_debug > 1 && err != ERROR_SUCCESS) + { + for (j = 0; j < lang_count; j++) + { + trace("langs[%Id] = 0x%04x %c\n", j, langs_arr[j], j == i ? '<' : ' '); + } + } + + winetest_pop_context(); + } +} + +static void test_valid_manifest_resources_locale(void) +{ +#ifdef __REACTOS__ + skip("test_valid_manifest_resources_locale() is invalid for WS03 - Win10 1607.\n"); +#else + static const LANGID langs[] = { + MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), + MAKELANGID(LANG_INVARIANT, SUBLANG_NEUTRAL), + }; + size_t i; + + for (i = 0; i < ARRAY_SIZE(langs); i++) + { + winetest_push_context("[%Iu]lang=0x%04x", i, langs[i]); + subtest_valid_manifest_resources_locale(langs[i]); + winetest_pop_context(); + } +#endif +} + +static void run_sxs_test(int run) +{ + switch(run) + { + case 1: + test_two_dlls_at_same_time(); + break; + case 2: + test_one_sxs_and_one_local_1(); + break; + case 3: + test_one_sxs_and_one_local_2(); + break; + case 4: + test_one_with_sxs_and_GetModuleHandleA(); + break; + case 5: + test_builtin_sxs(); + break; + } +} + +static void run_child_process_two_dll(int run) +{ + char cmdline[MAX_PATH]; + char exe[MAX_PATH]; + char **argv; + PROCESS_INFORMATION pi; + STARTUPINFOA si = { 0 }; + BOOL ret; + + winetest_get_mainargs( &argv ); + + if (strstr(argv[0], ".exe")) + sprintf(exe, "%s", argv[0]); + else + sprintf(exe, "%s.exe", argv[0]); + sprintf(cmdline, "\"%s\" %s two_dll %d", argv[0], argv[1], run); + + si.cb = sizeof(si); + ret = CreateProcessA(exe, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + ok(ret, "Could not create process: %lu\n", GetLastError()); + + wait_child_process( pi.hProcess ); + + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); +} + +static const detailed_info_t detailed_info3 = +{ + 1, 1, 1, ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE, exe_path, + ACTIVATION_CONTEXT_PATH_TYPE_NONE, ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE, + app_dir, +}; + +static void test_manifest_in_module(void) +{ + ACTCTXW ctx; + HANDLE handle; + +#ifdef __REACTOS__ + if (GetNTVersion() < _WIN32_WINNT_VISTA) { + skip("test_manifest_in_module() crashes on WS03.\n"); + return; + } +#endif + memset(&ctx, 0, sizeof(ctx)); + ctx.cbSize = sizeof(ctx); + ctx.dwFlags = ACTCTX_FLAG_HMODULE_VALID | ACTCTX_FLAG_RESOURCE_NAME_VALID; + ctx.lpResourceName = (LPWSTR)124; + ctx.hModule = GetModuleHandleW(NULL); + handle = CreateActCtxW(&ctx); + ok(handle != INVALID_HANDLE_VALUE, "CreateActCtx error %lu\n", GetLastError()); + + test_basic_info(handle, __LINE__); + test_detailed_info(handle, &detailed_info3, __LINE__); + + ReleaseActCtx(handle); +} + +static void test_manifest_resource_name_omitted(void) +{ + WCHAR pathbuf[MAX_PATH]; + HANDLE handle; + ACTCTXW ctx; + DWORD err, len; + + memset(&ctx, 0, sizeof(ctx)); + ctx.cbSize = sizeof(ctx); + ctx.dwFlags = ACTCTX_FLAG_HMODULE_VALID; + ctx.hModule = GetModuleHandleW(NULL); + handle = CreateActCtxW(&ctx); + err = GetLastError(); + ok(handle == INVALID_HANDLE_VALUE, "CreateActCtxW shall fail\n"); + todo_wine +#ifdef __REACTOS__ + ok(err == ERROR_RESOURCE_TYPE_NOT_FOUND || broken(err == ERROR_NOT_ENOUGH_MEMORY) /* WS03 */, "got %lu\n", err); +#else + ok(err == ERROR_RESOURCE_TYPE_NOT_FOUND, "got %lu\n", err); +#endif + + memset(&ctx, 0, sizeof(ctx)); + ctx.cbSize = sizeof(ctx); + ctx.dwFlags = ACTCTX_FLAG_HMODULE_VALID | ACTCTX_FLAG_RESOURCE_NAME_VALID; + ctx.hModule = GetModuleHandleW(NULL); + ctx.lpResourceName = NULL; + handle = CreateActCtxW(&ctx); + err = GetLastError(); + ok(handle == INVALID_HANDLE_VALUE, "CreateActCtxW shall fail\n"); +#ifdef __REACTOS__ + ok(err == ERROR_INVALID_PARAMETER || broken(err == ERROR_NOT_ENOUGH_MEMORY) /* WS03 */, "got %lu\n", err); +#else + ok(err == ERROR_INVALID_PARAMETER, "got %lu\n", err); +#endif + + len = GetModuleFileNameW(NULL, pathbuf, ARRAY_SIZE(pathbuf)); + ok(len > 0 && len < ARRAY_SIZE(pathbuf), "GetModuleFileNameW returned error %lu\n", GetLastError()); + + memset(&ctx, 0, sizeof(ctx)); + ctx.cbSize = sizeof(ctx); + ctx.lpSource = pathbuf; + ctx.dwFlags = 0; + handle = CreateActCtxW(&ctx); + err = GetLastError(); + ok(handle == INVALID_HANDLE_VALUE, "CreateActCtxW shall fail\n"); + todo_wine + ok(err == ERROR_RESOURCE_TYPE_NOT_FOUND, "got %lu\n", err); + + memset(&ctx, 0, sizeof(ctx)); + ctx.cbSize = sizeof(ctx); + ctx.lpSource = pathbuf; + ctx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID; + ctx.lpResourceName = NULL; + handle = CreateActCtxW(&ctx); + err = GetLastError(); + ok(handle == INVALID_HANDLE_VALUE, "CreateActCtxW shall fail\n"); + ok(err == ERROR_INVALID_PARAMETER, "got %lu\n", err); +} + START_TEST(actctx) { int argc; @@ -2938,11 +4477,35 @@ START_TEST(actctx) return; } + if (argc > 2 && !strcmp(argv[2], "two_dll")) + { + int run = atoi(argv[3]); + run_sxs_test(run); + return; + } + + test_manifest_in_module(); + test_manifest_resource_name_omitted(); + test_manifest_resources(); + test_valid_manifest_resources_locale(); test_actctx(); test_create_fail(); test_CreateActCtx(); + test_CreateActCtx_share_mode(); test_findsectionstring(); test_ZombifyActCtx(); run_child_process(); test_compatibility(); + test_settings(); +#ifdef __REACTOS__ + if (GetNTVersion() > _WIN32_WINNT_VISTA) { +#endif + run_child_process_two_dll(1); + run_child_process_two_dll(2); + run_child_process_two_dll(3); + run_child_process_two_dll(4); + run_child_process_two_dll(5); +#ifdef __REACTOS__ + } +#endif } diff --git a/modules/rostests/winetests/kernel32/atom.c b/modules/rostests/winetests/kernel32/atom.c index 0c1740869ac..6d37c97388f 100644 --- a/modules/rostests/winetests/kernel32/atom.c +++ b/modules/rostests/winetests/kernel32/atom.c @@ -86,7 +86,7 @@ static void test_add_atom(void) if (unicode_OS) { - ok( w_atom == atom, "Unicode atom does not match ASCII\n" ); + ok( w_atom == atom, "Unicode atom does not match ANSI one\n" ); ok( GetLastError() == 0xdeadbeef, "GlobalAddAtomW set last error\n" ); } @@ -115,20 +115,20 @@ static void test_add_atom(void) { SetLastError( 0xdeadbeef ); ok( GlobalAddAtomA((LPCSTR)i) == i && GetLastError() == 0xdeadbeef, - "failed to add atom %lx\n", i ); + "failed to add atom %Ix\n", i ); if (unicode_OS) { SetLastError( 0xdeadbeef ); ok( GlobalAddAtomW((LPCWSTR)i) == i && GetLastError() == 0xdeadbeef, - "failed to add atom %lx\n", i ); + "failed to add atom %Ix\n", i ); } } for (i = 0xc000; i <= 0xffff; i++) { - ok( !GlobalAddAtomA((LPCSTR)i), "succeeded adding %lx\n", i ); + ok( !GlobalAddAtomA((LPCSTR)i), "succeeded adding %Ix\n", i ); if (unicode_OS) - ok( !GlobalAddAtomW((LPCWSTR)i), "succeeded adding %lx\n", i ); + ok( !GlobalAddAtomW((LPCWSTR)i), "succeeded adding %Ix\n", i ); } } @@ -196,7 +196,7 @@ static void test_get_atom_name(void) len = GlobalGetAtomNameA( (ATOM)i, buf, 2); ok(!len, "bad length %d\n", len); ok(GetLastError() == ERROR_MORE_DATA || GetLastError() == ERROR_INVALID_PARAMETER, - "wrong error conditions %u for %u\n", GetLastError(), i); + "wrong error conditions %lu for %u\n", GetLastError(), i); } memset( buf, '.', sizeof(buf) ); @@ -229,7 +229,7 @@ static void test_get_atom_name(void) SetLastError(0xdeadbeef); len = GlobalGetAtomNameA(atom, out, 10); ok(!len, "bad length %d\n", len); - ok(GetLastError() == ERROR_MORE_DATA, "wrong error code (%u instead of %u)\n", GetLastError(), ERROR_MORE_DATA); + ok(GetLastError() == ERROR_MORE_DATA, "wrong error code (%lu instead of %u)\n", GetLastError(), ERROR_MORE_DATA); for (i = 0; i < 9; i++) { ok(out[i] == "abcdefghij"[i % 10], "wrong string at %i (%c instead of %c)\n", i, out[i], "abcdefghij"[i % 10]); @@ -266,7 +266,7 @@ static void test_get_atom_name(void) { /* len == 0 with ERROR_MORE_DATA is on NT3.51 */ ok(len == 1 || (len == 0 && GetLastError() == ERROR_MORE_DATA), - "0x%04x: got %u with %d (expected '1' or '0' with " + "0x%04x: got %u with %ld (expected '1' or '0' with " "ERROR_MORE_DATA)\n", i, len, GetLastError()); ok(outW[1] == DOUBLE('.'), "buffer overwrite\n"); } @@ -276,7 +276,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)/sizeof(outW[0])); + len = GlobalGetAtomNameW(atom, outW, ARRAY_SIZE(outW)); ok(len == 255, "length mismatch (%u instead of 255)\n", len); for (i = 0; i < 255; i++) { @@ -344,7 +344,7 @@ static void test_local_add_atom(void) if (unicode_OS) { - ok( w_atom == atom, "Unicode atom does not match ASCII\n" ); + ok( w_atom == atom, "Unicode atom does not match ANSI one\n" ); ok( GetLastError() == 0xdeadbeef, "AddAtomW set last error\n" ); } @@ -373,20 +373,20 @@ static void test_local_add_atom(void) { SetLastError( 0xdeadbeef ); ok( AddAtomA((LPCSTR)i) == i && GetLastError() == 0xdeadbeef, - "failed to add atom %lx\n", i ); + "failed to add atom %Ix\n", i ); if (unicode_OS) { SetLastError( 0xdeadbeef ); ok( AddAtomW((LPCWSTR)i) == i && GetLastError() == 0xdeadbeef, - "failed to add atom %lx\n", i ); + "failed to add atom %Ix\n", i ); } } for (i = 0xc000; i <= 0xffff; i++) { - ok( !AddAtomA((LPCSTR)i), "succeeded adding %lx\n", i ); + ok( !AddAtomA((LPCSTR)i), "succeeded adding %Ix\n", i ); if (unicode_OS) - ok( !AddAtomW((LPCWSTR)i), "succeeded adding %lx\n", i ); + ok( !AddAtomW((LPCWSTR)i), "succeeded adding %Ix\n", i ); } } @@ -472,11 +472,11 @@ static void test_local_get_atom_name(void) if (i) ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER || GetLastError() == ERROR_MORE_DATA, - "wrong error conditions %u for %u\n", GetLastError(), i); + "wrong error conditions %lu for %u\n", GetLastError(), i); else ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_MORE_DATA, - "wrong error conditions %u for %u\n", GetLastError(), i); + "wrong error conditions %lu for %u\n", GetLastError(), i); } /* test string limits & overflow */ do_initA(in, "abcdefghij", 255); @@ -505,7 +505,7 @@ static void test_local_get_atom_name(void) /* ERROR_MORE_DATA is on nt3.51 sp5 */ ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_MORE_DATA, - "wrong error code (%u)\n", GetLastError()); + "wrong error code (%lu)\n", GetLastError()); if (unicode_OS) { @@ -532,12 +532,12 @@ static void test_local_get_atom_name(void) /* ERROR_MORE_DATA is on nt3.51 sp5 */ ok(GetLastError() == ERROR_MORE_DATA || GetLastError() == (i ? ERROR_INSUFFICIENT_BUFFER : ERROR_INVALID_PARAMETER), - "wrong error conditions %u for %u\n", GetLastError(), i); + "wrong error conditions %lu for %u\n", GetLastError(), i); } do_initW(inW, "abcdefghij", 255); atom = AddAtomW(inW); ok(atom, "couldn't add atom for %s\n", in); - len = GetAtomNameW(atom, outW, sizeof(outW)/sizeof(outW[0])); + len = GetAtomNameW(atom, outW, ARRAY_SIZE(outW)); ok(len == 255, "length mismatch (%u instead of 255)\n", len); for (i = 0; i < 255; i++) { @@ -560,7 +560,7 @@ static void test_local_get_atom_name(void) /* ERROR_MORE_DATA is on nt3.51 sp5 */ ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_MORE_DATA, - "wrong error code (%u)\n", GetLastError()); + "wrong error code (%lu)\n", GetLastError()); } } diff --git a/modules/rostests/winetests/kernel32/change.c b/modules/rostests/winetests/kernel32/change.c index f4abad48c58..f89d3ba5943 100644 --- a/modules/rostests/winetests/kernel32/change.c +++ b/modules/rostests/winetests/kernel32/change.c @@ -51,7 +51,7 @@ static DWORD CALLBACK NotificationThread(LPVOID arg) } ret = FindCloseChangeNotification(change); - ok( ret, "FindCloseChangeNotification error: %d\n", + ok( ret, "FindCloseChangeNotification error: %ld\n", GetLastError()); ExitThread((DWORD)notified); @@ -63,10 +63,10 @@ static HANDLE StartNotificationThread(LPCSTR path, BOOL subtree, DWORD flags) DWORD threadId; change = FindFirstChangeNotificationA(path, subtree, flags); - ok(change != INVALID_HANDLE_VALUE, "FindFirstChangeNotification error: %d\n", GetLastError()); + ok(change != INVALID_HANDLE_VALUE, "FindFirstChangeNotification error: %ld\n", GetLastError()); thread = CreateThread(NULL, 0, NotificationThread, change, 0, &threadId); - ok(thread != NULL, "CreateThread error: %d\n", GetLastError()); + ok(thread != NULL, "CreateThread error: %ld\n", GetLastError()); return thread; } @@ -76,7 +76,7 @@ static DWORD FinishNotificationThread(HANDLE thread) DWORD status, exitcode; status = WaitForSingleObject(thread, 5000); - ok(status == WAIT_OBJECT_0, "WaitForSingleObject status %d error %d\n", status, GetLastError()); + ok(status == WAIT_OBJECT_0, "WaitForSingleObject status %ld error %ld\n", status, GetLastError()); ok(GetExitCodeThread(thread, &exitcode), "Could not retrieve thread exit code\n"); CloseHandle(thread); @@ -99,47 +99,47 @@ static void test_FindFirstChangeNotification(void) change = FindFirstChangeNotificationA("not-a-file", FALSE, FILE_NOTIFY_CHANGE_FILE_NAME); ok(change == INVALID_HANDLE_VALUE, "Expected INVALID_HANDLE_VALUE, got %p\n", change); - ok(GetLastError() == ERROR_FILE_NOT_FOUND || - GetLastError() == ERROR_NO_MORE_FILES, /* win95 */ - "FindFirstChangeNotification error: %d\n", GetLastError()); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, + "FindFirstChangeNotification error: %ld\n", GetLastError()); - if (0) /* This documents win2k behavior. It crashes on win98. */ - { - change = FindFirstChangeNotificationA(NULL, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME); - ok(change == NULL && GetLastError() == ERROR_PATH_NOT_FOUND, - "FindFirstChangeNotification error: %d\n", GetLastError()); - } + change = FindFirstChangeNotificationA(NULL, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME); + ok(change == INVALID_HANDLE_VALUE || broken(change == NULL) /* < win7 */, + "Expected INVALID_HANDLE_VALUE, got %p\n", change); + ok(GetLastError() == ERROR_PATH_NOT_FOUND, + "FindFirstChangeNotification error: %lu\n", GetLastError()); ret = FindNextChangeNotification(NULL); - ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "FindNextChangeNotification error: %d\n", + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "FindNextChangeNotification error: %ld\n", GetLastError()); ret = FindCloseChangeNotification(NULL); - ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "FindCloseChangeNotification error: %d\n", + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "FindCloseChangeNotification error: %ld\n", GetLastError()); - ret = GetTempPathA(MAX_PATH, workdir); - ok(ret, "GetTempPathA error: %d\n", GetLastError()); + ret = GetTempPathA(MAX_PATH, dirname1); + ok(ret, "GetTempPathA error: %ld\n", GetLastError()); - lstrcatA(workdir, "testFileChangeNotification"); + ret = GetTempFileNameA(dirname1, "ffc", 0, workdir); + ok(ret, "GetTempFileNameA error: %ld\n", GetLastError()); + DeleteFileA( workdir ); ret = CreateDirectoryA(workdir, NULL); - ok(ret, "CreateDirectoryA error: %d\n", GetLastError()); + ok(ret, "CreateDirectoryA error: %ld\n", GetLastError()); ret = GetTempFileNameA(workdir, prefix, 0, filename1); - ok(ret, "GetTempFileNameA error: %d\n", GetLastError()); + ok(ret, "GetTempFileNameA error: %ld\n", GetLastError()); file = CreateFileA(filename1, GENERIC_WRITE|GENERIC_READ, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - ok(file != INVALID_HANDLE_VALUE, "CreateFileA error: %d\n", GetLastError()); + ok(file != INVALID_HANDLE_VALUE, "CreateFileA error: %ld\n", GetLastError()); ret = CloseHandle(file); - ok( ret, "CloseHandle error: %d\n", GetLastError()); + ok( ret, "CloseHandle error: %ld\n", GetLastError()); - /* Try to register notification for a file. win98 and win2k behave differently here */ + /* Try to register notification for a file */ change = FindFirstChangeNotificationA(filename1, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME); - ok(change == INVALID_HANDLE_VALUE && (GetLastError() == ERROR_DIRECTORY || - GetLastError() == ERROR_FILE_NOT_FOUND), - "FindFirstChangeNotification error: %d\n", GetLastError()); + ok(change == INVALID_HANDLE_VALUE, "Expected INVALID_HANDLE_VALUE, got %p\n", change); + ok(GetLastError() == ERROR_DIRECTORY, + "FindFirstChangeNotification error: %ld\n", GetLastError()); lstrcpyA(dirname1, filename1); lstrcatA(dirname1, "dir"); @@ -148,40 +148,39 @@ static void test_FindFirstChangeNotification(void) lstrcatA(dirname2, "new"); ret = CreateDirectoryA(dirname1, NULL); - ok(ret, "CreateDirectoryA error: %d\n", GetLastError()); + ok(ret, "CreateDirectoryA error: %ld\n", GetLastError()); /* What if we move the directory we registered notification for? */ thread = StartNotificationThread(dirname1, FALSE, FILE_NOTIFY_CHANGE_DIR_NAME); ret = MoveFileA(dirname1, dirname2); - ok(ret, "MoveFileA error: %d\n", GetLastError()); - /* win9x and win2k behave differently here, don't check result */ - FinishNotificationThread(thread); + ok(ret, "MoveFileA error: %ld\n", GetLastError()); + ok(!FinishNotificationThread(thread), "Got notification\n"); /* What if we remove the directory we registered notification for? */ thread = StartNotificationThread(dirname2, FALSE, FILE_NOTIFY_CHANGE_DIR_NAME); ret = RemoveDirectoryA(dirname2); - ok(ret, "RemoveDirectoryA error: %d\n", GetLastError()); - /* win9x and win2k behave differently here, don't check result */ - FinishNotificationThread(thread); + ok(ret, "RemoveDirectoryA error: %ld\n", GetLastError()); + ret = FinishNotificationThread(thread); + todo_wine ok(ret, "Missed notification\n"); /* functional checks */ /* Create a directory */ thread = StartNotificationThread(workdir, FALSE, FILE_NOTIFY_CHANGE_DIR_NAME); ret = CreateDirectoryA(dirname1, NULL); - ok(ret, "CreateDirectoryA error: %d\n", GetLastError()); + ok(ret, "CreateDirectoryA error: %ld\n", GetLastError()); ok(FinishNotificationThread(thread), "Missed notification\n"); /* Rename a directory */ thread = StartNotificationThread(workdir, FALSE, FILE_NOTIFY_CHANGE_DIR_NAME); ret = MoveFileA(dirname1, dirname2); - ok(ret, "MoveFileA error: %d\n", GetLastError()); + ok(ret, "MoveFileA error: %ld\n", GetLastError()); ok(FinishNotificationThread(thread), "Missed notification\n"); /* Delete a directory */ thread = StartNotificationThread(workdir, FALSE, FILE_NOTIFY_CHANGE_DIR_NAME); ret = RemoveDirectoryA(dirname2); - ok(ret, "RemoveDirectoryA error: %d\n", GetLastError()); + ok(ret, "RemoveDirectoryA error: %ld\n", GetLastError()); ok(FinishNotificationThread(thread), "Missed notification\n"); lstrcpyA(filename2, filename1); @@ -190,91 +189,87 @@ static void test_FindFirstChangeNotification(void) /* Rename a file */ thread = StartNotificationThread(workdir, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME); ret = MoveFileA(filename1, filename2); - ok(ret, "MoveFileA error: %d\n", GetLastError()); + ok(ret, "MoveFileA error: %ld\n", GetLastError()); ok(FinishNotificationThread(thread), "Missed notification\n"); /* Delete a file */ thread = StartNotificationThread(workdir, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME); ret = DeleteFileA(filename2); - ok(ret, "DeleteFileA error: %d\n", GetLastError()); + ok(ret, "DeleteFileA error: %ld\n", GetLastError()); ok(FinishNotificationThread(thread), "Missed notification\n"); /* Create a file */ thread = StartNotificationThread(workdir, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME); file = CreateFileA(filename2, GENERIC_WRITE|GENERIC_READ, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - ok(file != INVALID_HANDLE_VALUE, "CreateFileA error: %d\n", GetLastError()); + ok(file != INVALID_HANDLE_VALUE, "CreateFileA error: %ld\n", GetLastError()); ret = CloseHandle(file); - ok( ret, "CloseHandle error: %d\n", GetLastError()); + ok( ret, "CloseHandle error: %ld\n", GetLastError()); ok(FinishNotificationThread(thread), "Missed notification\n"); attributes = GetFileAttributesA(filename2); - ok(attributes != INVALID_FILE_ATTRIBUTES, "GetFileAttributesA error: %d\n", GetLastError()); + ok(attributes != INVALID_FILE_ATTRIBUTES, "GetFileAttributesA error: %ld\n", GetLastError()); attributes &= FILE_ATTRIBUTE_READONLY; /* Change file attributes */ thread = StartNotificationThread(workdir, FALSE, FILE_NOTIFY_CHANGE_ATTRIBUTES); ret = SetFileAttributesA(filename2, attributes); - ok(ret, "SetFileAttributesA error: %d\n", GetLastError()); + ok(ret, "SetFileAttributesA error: %ld\n", GetLastError()); ok(FinishNotificationThread(thread), "Missed notification\n"); /* Change last write time by writing to a file */ thread = StartNotificationThread(workdir, FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE); file = CreateFileA(filename2, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - ok(file != INVALID_HANDLE_VALUE, "CreateFileA error: %d\n", GetLastError()); + ok(file != INVALID_HANDLE_VALUE, "CreateFileA error: %ld\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()); + ok(ret && count == sizeof(buffer), "WriteFile error: %ld\n", GetLastError()); ret = CloseHandle(file); - ok( ret, "CloseHandle error: %d\n", GetLastError()); + ok( ret, "CloseHandle error: %ld\n", GetLastError()); ok(FinishNotificationThread(thread), "Missed notification\n"); /* Change file size by truncating a file */ thread = StartNotificationThread(workdir, FALSE, FILE_NOTIFY_CHANGE_SIZE); file = CreateFileA(filename2, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - ok(file != INVALID_HANDLE_VALUE, "CreateFileA error: %d\n", GetLastError()); + ok(file != INVALID_HANDLE_VALUE, "CreateFileA error: %ld\n", GetLastError()); ret = WriteFile(file, buffer, sizeof(buffer) / 2, &count, NULL); - ok(ret && count == sizeof(buffer) / 2, "WriteFileA error: %d\n", GetLastError()); + ok(ret && count == sizeof(buffer) / 2, "WriteFileA error: %ld\n", GetLastError()); ret = CloseHandle(file); - ok( ret, "CloseHandle error: %d\n", GetLastError()); + ok( ret, "CloseHandle error: %ld\n", GetLastError()); ok(FinishNotificationThread(thread), "Missed notification\n"); /* clean up */ ret = DeleteFileA(filename2); - ok(ret, "DeleteFileA error: %d\n", GetLastError()); + ok(ret, "DeleteFileA error: %ld\n", GetLastError()); ret = RemoveDirectoryA(workdir); - ok(ret, "RemoveDirectoryA error: %d\n", GetLastError()); + ok(ret, "RemoveDirectoryA error: %ld\n", GetLastError()); } /* this test concentrates more on the wait behaviour of the handle */ static void test_ffcn(void) { DWORD filter; - HANDLE handle; + HANDLE handle, file; LONG r; - WCHAR path[MAX_PATH], subdir[MAX_PATH]; + WCHAR path[MAX_PATH], subdir[MAX_PATH], filename[MAX_PATH]; static const WCHAR szBoo[] = { '\\','b','o','o',0 }; static const WCHAR szHoo[] = { '\\','h','o','o',0 }; + static const WCHAR szZoo[] = { '\\','z','o','o',0 }; - SetLastError(0xdeadbeef); r = GetTempPathW( MAX_PATH, path ); - if (!r && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) - { - win_skip("GetTempPathW is not implemented\n"); - return; - } ok( r != 0, "temp path failed\n"); - if (!r) - return; lstrcatW( path, szBoo ); lstrcpyW( subdir, path ); lstrcatW( subdir, szHoo ); + lstrcpyW( filename, path ); + lstrcatW( filename, szZoo ); + RemoveDirectoryW( subdir ); RemoveDirectoryW( path ); @@ -290,10 +285,42 @@ static void test_ffcn(void) r = WaitForSingleObject( handle, 0 ); ok( r == STATUS_TIMEOUT, "should time out\n"); + file = CreateFileW( filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0 ); + ok( file != INVALID_HANDLE_VALUE, "CreateFile error %lu\n", GetLastError() ); + CloseHandle(file); + + r = WaitForSingleObject( handle, 1000 ); + ok( r == WAIT_OBJECT_0, "should be ready\n"); + + r = WaitForSingleObject( handle, 0 ); + ok( r == WAIT_OBJECT_0, "should be ready\n"); + + r = FindNextChangeNotification(handle); + ok( r == TRUE, "find next failed\n"); + + r = WaitForSingleObject( handle, 0 ); + ok( r == STATUS_TIMEOUT, "should time out\n"); + + r = DeleteFileW( filename ); + ok( r == TRUE, "failed to remove file\n"); + + r = WaitForSingleObject( handle, 1000 ); + ok( r == WAIT_OBJECT_0, "should be ready\n"); + + r = WaitForSingleObject( handle, 0 ); + ok( r == WAIT_OBJECT_0, "should be ready\n"); + + r = FindNextChangeNotification(handle); + ok( r == TRUE, "find next failed\n"); + + r = WaitForSingleObject( handle, 0 ); + ok( r == STATUS_TIMEOUT, "should time out\n"); + r = CreateDirectoryW( subdir, NULL ); ok( r == TRUE, "failed to create subdir\n"); - r = WaitForSingleObject( handle, 0 ); + r = WaitForSingleObject( handle, 1000 ); ok( r == WAIT_OBJECT_0, "should be ready\n"); r = WaitForSingleObject( handle, 0 ); @@ -308,7 +335,7 @@ static void test_ffcn(void) r = RemoveDirectoryW( subdir ); ok( r == TRUE, "failed to remove subdir\n"); - r = WaitForSingleObject( handle, 0 ); + r = WaitForSingleObject( handle, 1000 ); ok( r == WAIT_OBJECT_0, "should be ready\n"); r = WaitForSingleObject( handle, 0 ); @@ -334,23 +361,23 @@ static void test_ffcnMultipleThreads(void) LONG r; DWORD filter, threadId, status, exitcode; HANDLE handles[2]; - char path[MAX_PATH]; + char tmp[MAX_PATH], path[MAX_PATH]; - r = GetTempPathA(MAX_PATH, path); - ok(r, "GetTempPathA error: %d\n", GetLastError()); + r = GetTempPathA(MAX_PATH, tmp); + ok(r, "GetTempPathA error: %ld\n", GetLastError()); - lstrcatA(path, "ffcnTestMultipleThreads"); - - RemoveDirectoryA(path); + r = GetTempFileNameA(tmp, "ffc", 0, path); + ok(r, "GetTempFileNameA error: %ld\n", GetLastError()); + DeleteFileA( path ); r = CreateDirectoryA(path, NULL); - ok(r, "CreateDirectoryA error: %d\n", GetLastError()); + ok(r, "CreateDirectoryA error: %ld\n", GetLastError()); filter = FILE_NOTIFY_CHANGE_FILE_NAME; filter |= FILE_NOTIFY_CHANGE_DIR_NAME; handles[0] = FindFirstChangeNotificationA(path, FALSE, filter); - ok(handles[0] != INVALID_HANDLE_VALUE, "FindFirstChangeNotification error: %d\n", GetLastError()); + ok(handles[0] != INVALID_HANDLE_VALUE, "FindFirstChangeNotification error: %ld\n", GetLastError()); /* Test behavior if a waiting thread holds the last reference to a change * directory object with an empty wine user APC queue for this thread (bug #7286) */ @@ -358,10 +385,10 @@ static void test_ffcnMultipleThreads(void) /* Create our notification thread */ handles[1] = CreateThread(NULL, 0, NotificationThread, handles[0], 0, &threadId); - ok(handles[1] != NULL, "CreateThread error: %d\n", GetLastError()); + ok(handles[1] != NULL, "CreateThread error: %ld\n", GetLastError()); status = WaitForMultipleObjects(2, handles, FALSE, 5000); - ok(status == WAIT_OBJECT_0 || status == WAIT_OBJECT_0+1, "WaitForMultipleObjects status %d error %d\n", status, GetLastError()); + ok(status == WAIT_OBJECT_0 || status == WAIT_OBJECT_0+1, "WaitForMultipleObjects status %ld error %ld\n", status, GetLastError()); ok(GetExitCodeThread(handles[1], &exitcode), "Could not retrieve thread exit code\n"); /* Clean up */ @@ -369,9 +396,6 @@ static void test_ffcnMultipleThreads(void) ok( r == TRUE, "failed to remove dir\n"); } -static BOOL (WINAPI *pReadDirectoryChangesW)(HANDLE,LPVOID,DWORD,BOOL,DWORD, - LPDWORD,LPOVERLAPPED,LPOVERLAPPED_COMPLETION_ROUTINE); - static void test_readdirectorychanges(void) { HANDLE hdir; @@ -385,22 +409,8 @@ static void test_readdirectorychanges(void) PFILE_NOTIFY_INFORMATION pfni; BOOL got_subdir_change = FALSE; - if (!pReadDirectoryChangesW) - { - win_skip("ReadDirectoryChangesW is not available\n"); - return; - } - - SetLastError(0xdeadbeef); r = GetTempPathW( MAX_PATH, path ); - if (!r && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) - { - win_skip("GetTempPathW is not implemented\n"); - return; - } ok( r != 0, "temp path failed\n"); - if (!r) - return; lstrcatW( path, szBoo ); lstrcpyW( subdir, path ); @@ -417,7 +427,7 @@ static void test_readdirectorychanges(void) ok( r == TRUE, "failed to create directory\n"); SetLastError(0xd0b00b00); - r = pReadDirectoryChangesW(NULL,NULL,0,FALSE,0,NULL,NULL,NULL); + r = ReadDirectoryChangesW(NULL,NULL,0,FALSE,0,NULL,NULL,NULL); ok(GetLastError()==ERROR_INVALID_PARAMETER,"last error wrong\n"); ok(r==FALSE, "should return false\n"); @@ -430,12 +440,12 @@ static void test_readdirectorychanges(void) ov.hEvent = CreateEventW( NULL, 1, 0, NULL ); SetLastError(0xd0b00b00); - r = pReadDirectoryChangesW(hdir,NULL,0,FALSE,0,NULL,NULL,NULL); + r = ReadDirectoryChangesW(hdir,NULL,0,FALSE,0,NULL,NULL,NULL); ok(GetLastError()==ERROR_INVALID_PARAMETER,"last error wrong\n"); ok(r==FALSE, "should return false\n"); SetLastError(0xd0b00b00); - r = pReadDirectoryChangesW(hdir,NULL,0,FALSE,0,NULL,&ov,NULL); + r = ReadDirectoryChangesW(hdir,NULL,0,FALSE,0,NULL,&ov,NULL); ok(GetLastError()==ERROR_INVALID_PARAMETER,"last error wrong\n"); ok(r==FALSE, "should return false\n"); @@ -453,15 +463,15 @@ static void test_readdirectorychanges(void) ov.InternalHigh = 0; memset( buffer, 0, sizeof buffer ); - r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,-1,NULL,&ov,NULL); + r = ReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,-1,NULL,&ov,NULL); ok(GetLastError()==ERROR_INVALID_PARAMETER,"last error wrong\n"); ok(r==FALSE, "should return false\n"); - r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,0,NULL,&ov,NULL); + r = ReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,0,NULL,&ov,NULL); ok(GetLastError()==ERROR_INVALID_PARAMETER,"last error wrong\n"); ok(r==FALSE, "should return false\n"); - r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,TRUE,filter,NULL,&ov,NULL); + r = ReadDirectoryChangesW(hdir,buffer,sizeof buffer,TRUE,filter,NULL,&ov,NULL); ok(r==TRUE, "should return true\n"); r = WaitForSingleObject( ov.hEvent, 10 ); @@ -484,11 +494,11 @@ static void test_readdirectorychanges(void) ResetEvent(ov.hEvent); SetLastError(0xd0b00b00); - r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,0,NULL,NULL,NULL); + r = ReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,0,NULL,NULL,NULL); ok(GetLastError()==ERROR_INVALID_PARAMETER,"last error wrong\n"); ok(r==FALSE, "should return false\n"); - r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,0,NULL,&ov,NULL); + r = ReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,0,NULL,&ov,NULL); ok(GetLastError()==ERROR_INVALID_PARAMETER,"last error wrong\n"); ok(r==FALSE, "should return false\n"); @@ -497,10 +507,10 @@ static void test_readdirectorychanges(void) SetEvent(ov.hEvent); ov.Internal = 1; ov.InternalHigh = 1; - S(U(ov)).Offset = 0; - S(U(ov)).OffsetHigh = 0; + ov.Offset = 0; + ov.OffsetHigh = 0; memset( buffer, 0, sizeof buffer ); - r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,filter,NULL,&ov,NULL); + r = ReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,filter,NULL,&ov,NULL); ok(r==TRUE, "should return true\n"); ok( (NTSTATUS)ov.Internal == STATUS_PENDING, "ov.Internal wrong\n"); @@ -532,7 +542,7 @@ static void test_readdirectorychanges(void) ok( !memcmp(pfni->FileName,&szHoo[1],6), "name wrong\n" ); /* what happens if the buffer is too small? */ - r = pReadDirectoryChangesW(hdir,buffer,0x10,FALSE,filter,NULL,&ov,NULL); + r = ReadDirectoryChangesW(hdir,buffer,0x10,FALSE,filter,NULL,&ov,NULL); ok(r==TRUE, "should return true\n"); r = CreateDirectoryW( subdir, NULL ); @@ -545,7 +555,7 @@ static void test_readdirectorychanges(void) ok( ov.InternalHigh == 0, "ov.InternalHigh wrong\n"); /* test the recursive watch */ - r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,filter,NULL,&ov,NULL); + r = ReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,filter,NULL,&ov,NULL); ok(r==TRUE, "should return true\n"); r = CreateDirectoryW( subsubdir, NULL ); @@ -581,7 +591,7 @@ static void test_readdirectorychanges(void) if (got_subdir_change) break; - r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,filter,NULL,&ov,NULL); + r = ReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,filter,NULL,&ov,NULL); ok(r==TRUE, "should return true\n"); } ok(got_subdir_change, "didn't get subdir change\n"); @@ -591,7 +601,7 @@ static void test_readdirectorychanges(void) ov.Internal = 1; ov.InternalHigh = 1; - r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,filter,NULL,&ov,NULL); + r = ReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,filter,NULL,&ov,NULL); ok(r==TRUE, "should return true\n"); r = RemoveDirectoryW( subdir ); @@ -604,18 +614,18 @@ static void test_readdirectorychanges(void) /* 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( pfni->FileNameLength == 3*sizeof(WCHAR), "len wrong %lu\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( pfni->NextEntryOffset == 0, "offset wrong %lu\n", pfni->NextEntryOffset ); + ok( pfni->Action == FILE_ACTION_REMOVED, "action wrong %lu\n", pfni->Action ); + ok( pfni->FileNameLength == 6*sizeof(WCHAR), "len wrong %lu\n", pfni->FileNameLength ); ok( !memcmp(pfni->FileName,&szGa[1],6*sizeof(WCHAR)), "name wrong\n" ); ok( (NTSTATUS)ov.Internal == STATUS_SUCCESS, "ov.Internal wrong\n"); dwCount = (char *)&pfni->FileName[pfni->FileNameLength/sizeof(WCHAR)] - buffer; - ok( ov.InternalHigh == dwCount, "ov.InternalHigh wrong %lu/%u\n",ov.InternalHigh, dwCount ); + ok( ov.InternalHigh == dwCount, "ov.InternalHigh wrong %Iu/%lu\n",ov.InternalHigh, dwCount ); CloseHandle(hdir); @@ -636,21 +646,8 @@ static void test_readdirectorychanges_null(void) static const WCHAR szHoo[] = { '\\','h','o','o',0 }; PFILE_NOTIFY_INFORMATION pfni; - if (!pReadDirectoryChangesW) - { - win_skip("ReadDirectoryChangesW is not available\n"); - return; - } - SetLastError(0xdeadbeef); r = GetTempPathW( MAX_PATH, path ); - if (!r && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) - { - win_skip("GetTempPathW is not implemented\n"); - return; - } ok( r != 0, "temp path failed\n"); - if (!r) - return; lstrcatW( path, szBoo ); lstrcpyW( subdir, path ); @@ -678,7 +675,7 @@ static void test_readdirectorychanges_null(void) ov.InternalHigh = 0; memset( buffer, 0, sizeof buffer ); - r = pReadDirectoryChangesW(hdir,NULL,0,FALSE,filter,NULL,&ov,NULL); + r = ReadDirectoryChangesW(hdir,NULL,0,FALSE,filter,NULL,&ov,NULL); ok(r==TRUE, "should return true\n"); r = WaitForSingleObject( ov.hEvent, 0 ); @@ -695,11 +692,11 @@ static void test_readdirectorychanges_null(void) ov.Internal = 0; ov.InternalHigh = 0; - S(U(ov)).Offset = 0; - S(U(ov)).OffsetHigh = 0; + ov.Offset = 0; + ov.OffsetHigh = 0; memset( buffer, 0, sizeof buffer ); - r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,filter,NULL,&ov,NULL); + r = ReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,filter,NULL,&ov,NULL); ok(r==TRUE, "should return true\n"); r = WaitForSingleObject( ov.hEvent, 0 ); @@ -736,16 +733,8 @@ static void test_readdirectorychanges_filedir(void) static const WCHAR szFoo[] = { '\\','f','o','o',0 }; PFILE_NOTIFY_INFORMATION pfni; - SetLastError(0xdeadbeef); r = GetTempPathW( MAX_PATH, path ); - if (!r && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) - { - win_skip("GetTempPathW is not implemented\n"); - return; - } ok( r != 0, "temp path failed\n"); - if (!r) - return; lstrcatW( path, szBoo ); lstrcpyW( subdir, path ); @@ -771,7 +760,7 @@ static void test_readdirectorychanges_filedir(void) filter = FILE_NOTIFY_CHANGE_FILE_NAME; - r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,TRUE,filter,NULL,&ov,NULL); + r = ReadDirectoryChangesW(hdir,buffer,sizeof buffer,TRUE,filter,NULL,&ov,NULL); ok(r==TRUE, "should return true\n"); r = WaitForSingleObject( ov.hEvent, 10 ); @@ -810,7 +799,7 @@ static void test_readdirectorychanges_filedir(void) static void CALLBACK readdirectorychanges_cr(DWORD error, DWORD len, LPOVERLAPPED ov) { - ok(error == 0, "ReadDirectoryChangesW error %d\n", error); + ok(error == 0, "ReadDirectoryChangesW error %ld\n", error); ok(ov->hEvent == (void*)0xdeadbeef, "hEvent should not have changed\n"); } @@ -827,22 +816,8 @@ static void test_readdirectorychanges_cr(void) HANDLE hdir, hfile; NTSTATUS r; - if (!pReadDirectoryChangesW) - { - win_skip("ReadDirectoryChangesW is not available\n"); - return; - } - - SetLastError(0xdeadbeef); r = GetTempPathW(MAX_PATH, path); - if (!r && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) - { - win_skip("GetTempPathW is not implemented\n"); - return; - } ok(r != 0, "temp path failed\n"); - if (!r) - return; lstrcatW(path, szBoo); lstrcpyW(dir, path); @@ -867,9 +842,9 @@ static void test_readdirectorychanges_cr(void) memset(&ov, 0, sizeof(ov)); ov.hEvent = (void*)0xdeadbeef; - r = pReadDirectoryChangesW(hdir, fni, sizeof(fni), FALSE, + r = ReadDirectoryChangesW(hdir, fni, sizeof(fni), FALSE, FILE_NOTIFY_CHANGE_FILE_NAME, NULL, &ov, readdirectorychanges_cr); - ok(r == TRUE, "pReadDirectoryChangesW failed\n"); + ok(r == TRUE, "ReadDirectoryChangesW failed\n"); hfile = CreateFileW(file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); ok(hfile != INVALID_HANDLE_VALUE, "failed to create file\n"); @@ -878,15 +853,15 @@ static void test_readdirectorychanges_cr(void) r = SleepEx(1000, TRUE); ok(r != 0, "failed to receive file creation event\n"); ok(fni->NextEntryOffset == 0, "there should be no more events in buffer\n"); - ok(fni->Action == FILE_ACTION_ADDED, "Action = %d\n", fni->Action); + ok(fni->Action == FILE_ACTION_ADDED, "Action = %ld\n", fni->Action); ok(fni->FileNameLength == lstrlenW(szFile)*sizeof(WCHAR), - "FileNameLength = %d\n", fni->FileNameLength); + "FileNameLength = %ld\n", fni->FileNameLength); ok(!memcmp(fni->FileName, szFile, lstrlenW(szFile)*sizeof(WCHAR)), "FileName = %s\n", wine_dbgstr_wn(fni->FileName, fni->FileNameLength/sizeof(WCHAR))); - r = pReadDirectoryChangesW(hdir, fni, sizeof(fni), FALSE, + r = ReadDirectoryChangesW(hdir, fni, sizeof(fni), FALSE, FILE_NOTIFY_CHANGE_FILE_NAME, NULL, &ov, readdirectorychanges_cr); - ok(r == TRUE, "pReadDirectoryChangesW failed\n"); + ok(r == TRUE, "ReadDirectoryChangesW failed\n"); /* This event will not be reported */ r = CreateDirectoryW(dir, NULL); @@ -898,15 +873,15 @@ static void test_readdirectorychanges_cr(void) r = SleepEx(1000, TRUE); ok(r != 0, "failed to receive file move event\n"); ok(fni->NextEntryOffset == 0, "there should be no more events in buffer\n"); - ok(fni->Action == FILE_ACTION_REMOVED, "Action = %d\n", fni->Action); + ok(fni->Action == FILE_ACTION_REMOVED, "Action = %ld\n", fni->Action); ok(fni->FileNameLength == lstrlenW(szFile)*sizeof(WCHAR), - "FileNameLength = %d\n", fni->FileNameLength); + "FileNameLength = %ld\n", fni->FileNameLength); ok(!memcmp(fni->FileName, szFile, lstrlenW(szFile)*sizeof(WCHAR)), "FileName = %s\n", wine_dbgstr_wn(fni->FileName, fni->FileNameLength/sizeof(WCHAR))); - r = pReadDirectoryChangesW(hdir, fni, sizeof(fni), FALSE, + r = ReadDirectoryChangesW(hdir, fni, sizeof(fni), FALSE, FILE_NOTIFY_CHANGE_FILE_NAME, NULL, &ov, readdirectorychanges_cr); - ok(r == TRUE, "pReadDirectoryChangesW failed\n"); + ok(r == TRUE, "ReadDirectoryChangesW failed\n"); r = MoveFileW(sub_file, file); ok(r == TRUE, "failed to move file\n"); @@ -914,15 +889,15 @@ static void test_readdirectorychanges_cr(void) r = SleepEx(1000, TRUE); ok(r != 0, "failed to receive file move event\n"); ok(fni->NextEntryOffset == 0, "there should be no more events in buffer\n"); - ok(fni->Action == FILE_ACTION_ADDED, "Action = %d\n", fni->Action); + ok(fni->Action == FILE_ACTION_ADDED, "Action = %ld\n", fni->Action); ok(fni->FileNameLength == lstrlenW(szFile)*sizeof(WCHAR), - "FileNameLength = %d\n", fni->FileNameLength); + "FileNameLength = %ld\n", fni->FileNameLength); ok(!memcmp(fni->FileName, szFile, lstrlenW(szFile)*sizeof(WCHAR)), "FileName = %s\n", wine_dbgstr_wn(fni->FileName, fni->FileNameLength/sizeof(WCHAR))); - r = pReadDirectoryChangesW(hdir, fni, sizeof(fni), FALSE, + r = ReadDirectoryChangesW(hdir, fni, sizeof(fni), FALSE, FILE_NOTIFY_CHANGE_FILE_NAME, NULL, &ov, readdirectorychanges_cr); - ok(r == TRUE, "pReadDirectoryChangesW failed\n"); + ok(r == TRUE, "ReadDirectoryChangesW failed\n"); r = DeleteFileW(file); ok(r == TRUE, "failed to delete file\n"); @@ -930,9 +905,9 @@ static void test_readdirectorychanges_cr(void) r = SleepEx(1000, TRUE); ok(r != 0, "failed to receive file removal event\n"); ok(fni->NextEntryOffset == 0, "there should be no more events in buffer\n"); - ok(fni->Action == FILE_ACTION_REMOVED, "Action = %d\n", fni->Action); + ok(fni->Action == FILE_ACTION_REMOVED, "Action = %ld\n", fni->Action); ok(fni->FileNameLength == lstrlenW(szFile)*sizeof(WCHAR), - "FileNameLength = %d\n", fni->FileNameLength); + "FileNameLength = %ld\n", fni->FileNameLength); ok(!memcmp(fni->FileName, szFile, lstrlenW(szFile)*sizeof(WCHAR)), "FileName = %s\n", wine_dbgstr_wn(fni->FileName, fni->FileNameLength/sizeof(WCHAR))); @@ -943,9 +918,9 @@ static void test_readdirectorychanges_cr(void) FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL); ok(hdir != INVALID_HANDLE_VALUE, "failed to open directory\n"); - r = pReadDirectoryChangesW(hdir, fni, sizeof(fni), FALSE, + r = ReadDirectoryChangesW(hdir, fni, sizeof(fni), FALSE, FILE_NOTIFY_CHANGE_DIR_NAME, NULL, &ov, readdirectorychanges_cr); - ok(r == TRUE, "pReadDirectoryChangesW failed\n"); + ok(r == TRUE, "ReadDirectoryChangesW failed\n"); r = MoveFileW(dir, file); ok(r == TRUE, "failed to move directory\n"); @@ -954,17 +929,17 @@ static void test_readdirectorychanges_cr(void) ok(r != 0, "failed to receive directory move event\n"); if (fni->Action == FILE_ACTION_RENAMED_OLD_NAME) { - ok(fni->Action == FILE_ACTION_RENAMED_OLD_NAME, "Action = %d\n", fni->Action); + ok(fni->Action == FILE_ACTION_RENAMED_OLD_NAME, "Action = %ld\n", fni->Action); ok(fni->FileNameLength == lstrlenW(szDir)*sizeof(WCHAR), - "FileNameLength = %d\n", fni->FileNameLength); + "FileNameLength = %ld\n", fni->FileNameLength); ok(!memcmp(fni->FileName, szDir, lstrlenW(szDir)*sizeof(WCHAR)), "FileName = %s\n", wine_dbgstr_wn(fni->FileName, fni->FileNameLength/sizeof(WCHAR))); ok(fni->NextEntryOffset != 0, "no next entry in movement event\n"); fni_next = (FILE_NOTIFY_INFORMATION*)((char*)fni+fni->NextEntryOffset); ok(fni_next->NextEntryOffset == 0, "there should be no more events in buffer\n"); - ok(fni_next->Action == FILE_ACTION_RENAMED_NEW_NAME, "Action = %d\n", fni_next->Action); + ok(fni_next->Action == FILE_ACTION_RENAMED_NEW_NAME, "Action = %ld\n", fni_next->Action); ok(fni_next->FileNameLength == lstrlenW(szFile)*sizeof(WCHAR), - "FileNameLength = %d\n", fni_next->FileNameLength); + "FileNameLength = %ld\n", fni_next->FileNameLength); ok(!memcmp(fni_next->FileName, szFile, lstrlenW(szFile)*sizeof(WCHAR)), "FileName = %s\n", wine_dbgstr_wn(fni_next->FileName, fni_next->FileNameLength/sizeof(WCHAR))); } @@ -974,9 +949,9 @@ static void test_readdirectorychanges_cr(void) if (fni->NextEntryOffset == 0) { - r = pReadDirectoryChangesW(hdir, fni, sizeof(fni), FALSE, + r = ReadDirectoryChangesW(hdir, fni, sizeof(fni), FALSE, FILE_NOTIFY_CHANGE_DIR_NAME, NULL, &ov, readdirectorychanges_cr); - ok(r == TRUE, "pReadDirectoryChangesW failed\n"); + ok(r == TRUE, "ReadDirectoryChangesW failed\n"); r = SleepEx(1000, TRUE); ok(r != 0, "failed to receive directory move event\n"); @@ -989,33 +964,33 @@ static void test_readdirectorychanges_cr(void) r = RemoveDirectoryW(dir); ok(r == TRUE, "failed to remove directory\n"); - r = pReadDirectoryChangesW(hdir, fni, sizeof(fni), FALSE, + r = ReadDirectoryChangesW(hdir, fni, sizeof(fni), FALSE, FILE_NOTIFY_CHANGE_DIR_NAME, NULL, &ov, readdirectorychanges_cr); - ok(r == TRUE, "pReadDirectoryChangesW failed\n"); + ok(r == TRUE, "ReadDirectoryChangesW failed\n"); r = SleepEx(1000, TRUE); ok(r != 0, "failed to receive directory creation event\n"); - ok(fni->Action == FILE_ACTION_ADDED, "Action = %d\n", fni->Action); + ok(fni->Action == FILE_ACTION_ADDED, "Action = %ld\n", fni->Action); ok(fni->FileNameLength == lstrlenW(szDir)*sizeof(WCHAR), - "FileNameLength = %d\n", fni->FileNameLength); + "FileNameLength = %ld\n", fni->FileNameLength); ok(!memcmp(fni->FileName, szDir, lstrlenW(szDir)*sizeof(WCHAR)), "FileName = %s\n", wine_dbgstr_wn(fni->FileName, fni->FileNameLength/sizeof(WCHAR))); if (fni->NextEntryOffset) fni_next = (FILE_NOTIFY_INFORMATION*)((char*)fni+fni->NextEntryOffset); else { - r = pReadDirectoryChangesW(hdir, fni, sizeof(fni), FALSE, + r = ReadDirectoryChangesW(hdir, fni, sizeof(fni), FALSE, FILE_NOTIFY_CHANGE_DIR_NAME, NULL, &ov, readdirectorychanges_cr); - ok(r == TRUE, "pReadDirectoryChangesW failed\n"); + ok(r == TRUE, "ReadDirectoryChangesW failed\n"); r = SleepEx(1000, TRUE); ok(r != 0, "failed to receive directory removal event\n"); fni_next = fni; } ok(fni_next->NextEntryOffset == 0, "there should be no more events in buffer\n"); - ok(fni_next->Action == FILE_ACTION_REMOVED, "Action = %d\n", fni_next->Action); + ok(fni_next->Action == FILE_ACTION_REMOVED, "Action = %ld\n", fni_next->Action); ok(fni_next->FileNameLength == lstrlenW(szDir)*sizeof(WCHAR), - "FileNameLength = %d\n", fni_next->FileNameLength); + "FileNameLength = %ld\n", fni_next->FileNameLength); ok(!memcmp(fni_next->FileName, szDir, lstrlenW(szDir)*sizeof(WCHAR)), "FileName = %s\n", wine_dbgstr_wn(fni_next->FileName, fni_next->FileNameLength/sizeof(WCHAR))); @@ -1035,21 +1010,21 @@ static void test_ffcn_directory_overlap(void) /* Setup directory hierarchy */ ret = GetTempPathA(MAX_PATH, workdir); ok((ret > 0) && (ret <= MAX_PATH), - "GetTempPathA error: %d\n", GetLastError()); + "GetTempPathA error: %ld\n", GetLastError()); ret = GetTempFileNameA(workdir, "fcn", 0, tempfile); - ok(ret, "GetTempFileNameA error: %d\n", GetLastError()); + ok(ret, "GetTempFileNameA error: %ld\n", GetLastError()); ret = DeleteFileA(tempfile); - ok(ret, "DeleteFileA error: %d\n", GetLastError()); + ok(ret, "DeleteFileA error: %ld\n", GetLastError()); lstrcpyA(parentdir, tempfile); ret = CreateDirectoryA(parentdir, NULL); - ok(ret, "CreateDirectoryA error: %d\n", GetLastError()); + ok(ret, "CreateDirectoryA error: %ld\n", GetLastError()); lstrcpyA(childdir, parentdir); lstrcatA(childdir, "\\c"); ret = CreateDirectoryA(childdir, NULL); - ok(ret, "CreateDirectoryA error: %d\n", GetLastError()); + ok(ret, "CreateDirectoryA error: %ld\n", GetLastError()); /* When recursively watching overlapping directories, changes in child @@ -1061,7 +1036,7 @@ static void test_ffcn_directory_overlap(void) /* Create a file in child */ ret = GetTempFileNameA(childdir, "fcn", 0, tempfile); - ok(ret, "GetTempFileNameA error: %d\n", GetLastError()); + ok(ret, "GetTempFileNameA error: %ld\n", GetLastError()); /* Both watches should trigger */ ret = FinishNotificationThread(parent_thread); @@ -1070,7 +1045,7 @@ static void test_ffcn_directory_overlap(void) ok(ret, "Missed child notification\n"); ret = DeleteFileA(tempfile); - ok(ret, "DeleteFileA error: %d\n", GetLastError()); + ok(ret, "DeleteFileA error: %ld\n", GetLastError()); /* Removing a recursive parent watch should not affect child watches. Doing @@ -1078,22 +1053,22 @@ static void test_ffcn_directory_overlap(void) parent_watch = FindFirstChangeNotificationA(parentdir, TRUE, FILE_NOTIFY_CHANGE_FILE_NAME); ok(parent_watch != INVALID_HANDLE_VALUE, - "FindFirstChangeNotification error: %d\n", GetLastError()); + "FindFirstChangeNotification error: %ld\n", GetLastError()); child_watch = FindFirstChangeNotificationA(childdir, TRUE, FILE_NOTIFY_CHANGE_FILE_NAME); ok(child_watch != INVALID_HANDLE_VALUE, - "FindFirstChangeNotification error: %d\n", GetLastError()); + "FindFirstChangeNotification error: %ld\n", GetLastError()); ret = FindCloseChangeNotification(parent_watch); - ok(ret, "FindCloseChangeNotification error: %d\n", GetLastError()); + ok(ret, "FindCloseChangeNotification error: %ld\n", GetLastError()); child_thread = CreateThread(NULL, 0, NotificationThread, child_watch, 0, &threadId); - ok(child_thread != NULL, "CreateThread error: %d\n", GetLastError()); + ok(child_thread != NULL, "CreateThread error: %ld\n", GetLastError()); /* Create a file in child */ ret = GetTempFileNameA(childdir, "fcn", 0, tempfile); - ok(ret, "GetTempFileNameA error: %d\n", GetLastError()); + ok(ret, "GetTempFileNameA error: %ld\n", GetLastError()); /* Child watch should trigger */ ret = FinishNotificationThread(child_thread); @@ -1101,20 +1076,17 @@ static void test_ffcn_directory_overlap(void) /* clean up */ ret = DeleteFileA(tempfile); - ok(ret, "DeleteFileA error: %d\n", GetLastError()); + ok(ret, "DeleteFileA error: %ld\n", GetLastError()); ret = RemoveDirectoryA(childdir); - ok(ret, "RemoveDirectoryA error: %d\n", GetLastError()); + ok(ret, "RemoveDirectoryA error: %ld\n", GetLastError()); ret = RemoveDirectoryA(parentdir); - ok(ret, "RemoveDirectoryA error: %d\n", GetLastError()); + ok(ret, "RemoveDirectoryA error: %ld\n", GetLastError()); } START_TEST(change) { - HMODULE hkernel32 = GetModuleHandleA("kernel32.dll"); - pReadDirectoryChangesW = (void *)GetProcAddress(hkernel32, "ReadDirectoryChangesW"); - test_ffcnMultipleThreads(); /* The above function runs a test that must occur before FindCloseChangeNotification is run in the current thread to preserve the emptiness of the wine user APC queue. To ensure this it should be diff --git a/modules/rostests/winetests/kernel32/codepage.c b/modules/rostests/winetests/kernel32/codepage.c index ac8b90298b4..8653c388365 100644 --- a/modules/rostests/winetests/kernel32/codepage.c +++ b/modules/rostests/winetests/kernel32/codepage.c @@ -40,7 +40,7 @@ static void test_destination_buffer(void) SetLastError(0xdeadbeef); needed = WideCharToMultiByte(CP_ACP, 0, foobarW, -1, NULL, 0, NULL, NULL); - ok( (needed > 0), "returned %d with %u (expected '> 0')\n", + ok( (needed > 0), "returned %d with %lu (expected '> 0')\n", needed, GetLastError()); maxsize = needed*2; @@ -52,41 +52,47 @@ static void test_destination_buffer(void) buffer[maxsize] = '\0'; SetLastError(0xdeadbeef); len = WideCharToMultiByte(CP_ACP, 0, foobarW, -1, buffer, needed+1, NULL, NULL); - ok( (len > 0), "returned %d with %u and '%s' (expected '> 0')\n", + ok( (len > 0), "returned %d with %lu and '%s' (expected '> 0')\n", len, GetLastError(), buffer); + ok(!lstrcmpA(buffer, "foobar"), "expected \"foobar\" got \"%s\"\n", buffer); memset(buffer, 'x', maxsize); buffer[maxsize] = '\0'; SetLastError(0xdeadbeef); len = WideCharToMultiByte(CP_ACP, 0, foobarW, -1, buffer, needed, NULL, NULL); - ok( (len > 0), "returned %d with %u and '%s' (expected '> 0')\n", + ok( (len > 0), "returned %d with %lu and '%s' (expected '> 0')\n", len, GetLastError(), buffer); + ok(!lstrcmpA(buffer, "foobar"), "expected \"foobar\" got \"%s\"\n", buffer); memset(buffer, 'x', maxsize); buffer[maxsize] = '\0'; SetLastError(0xdeadbeef); len = WideCharToMultiByte(CP_ACP, 0, foobarW, -1, buffer, needed-1, NULL, NULL); ok( !len && (GetLastError() == ERROR_INSUFFICIENT_BUFFER), - "returned %d with %u and '%s' (expected '0' with " + "returned %d with %lu and '%s' (expected '0' with " "ERROR_INSUFFICIENT_BUFFER)\n", len, GetLastError(), buffer); + ok(!strncmp(buffer, "foobar", 6), "expected \"foobar\" got \"%s\"\n", buffer); + ok(buffer[6] == 'x', "expected buf[5]=='x', got \"%s\"\n", buffer); memset(buffer, 'x', maxsize); buffer[maxsize] = '\0'; SetLastError(0xdeadbeef); len = WideCharToMultiByte(CP_ACP, 0, foobarW, -1, buffer, 1, NULL, NULL); ok( !len && (GetLastError() == ERROR_INSUFFICIENT_BUFFER), - "returned %d with %u and '%s' (expected '0' with " + "returned %d with %lu and '%s' (expected '0' with " "ERROR_INSUFFICIENT_BUFFER)\n", len, GetLastError(), buffer); + ok(buffer[0] == 'f', "expected buf[1]=='f', got \"%s\"\n", buffer); + ok(buffer[1] == 'x', "expected buf[1]=='x', got \"%s\"\n", buffer); SetLastError(0xdeadbeef); len = WideCharToMultiByte(CP_ACP, 0, foobarW, -1, buffer, 0, NULL, NULL); - ok( (len > 0), "returned %d with %u (expected '> 0')\n", + ok( (len > 0), "returned %d with %lu (expected '> 0')\n", len, GetLastError()); SetLastError(0xdeadbeef); len = WideCharToMultiByte(CP_ACP, 0, foobarW, -1, NULL, needed, NULL, NULL); ok( !len && (GetLastError() == ERROR_INVALID_PARAMETER), - "returned %d with %u (expected '0' with " + "returned %d with %lu (expected '0' with " "ERROR_INVALID_PARAMETER)\n", len, GetLastError()); HeapFree(GetProcessHeap(), 0, buffer); @@ -102,14 +108,14 @@ static void test_null_source(void) len = WideCharToMultiByte(CP_ACP, 0, NULL, 0, NULL, 0, NULL, NULL); GLE = GetLastError(); ok(!len && GLE == ERROR_INVALID_PARAMETER, - "WideCharToMultiByte returned %d with GLE=%u (expected 0 with ERROR_INVALID_PARAMETER)\n", + "WideCharToMultiByte returned %d with GLE=%lu (expected 0 with ERROR_INVALID_PARAMETER)\n", len, GLE); SetLastError(0); len = WideCharToMultiByte(CP_ACP, 0, NULL, -1, NULL, 0, NULL, NULL); GLE = GetLastError(); ok(!len && GLE == ERROR_INVALID_PARAMETER, - "WideCharToMultiByte returned %d with GLE=%u (expected 0 with ERROR_INVALID_PARAMETER)\n", + "WideCharToMultiByte returned %d with GLE=%lu (expected 0 with ERROR_INVALID_PARAMETER)\n", len, GLE); } @@ -124,7 +130,7 @@ static void test_negative_source_length(void) memset(buf,'x',sizeof(buf)); len = WideCharToMultiByte(CP_ACP, 0, foobarW, -2002, buf, 10, NULL, NULL); ok(len == 7 && GetLastError() == 0xdeadbeef, - "WideCharToMultiByte(-2002): len=%d error=%u\n", len, GetLastError()); + "WideCharToMultiByte(-2002): len=%d error=%lu\n", len, GetLastError()); ok(!lstrcmpA(buf, "foobar"), "WideCharToMultiByte(-2002): expected \"foobar\" got \"%s\"\n", buf); @@ -132,13 +138,13 @@ static void test_negative_source_length(void) memset(bufW,'x',sizeof(bufW)); len = MultiByteToWideChar(CP_ACP, 0, "foobar", -2002, bufW, 10); ok(len == 7 && !lstrcmpW(bufW, foobarW) && GetLastError() == 0xdeadbeef, - "MultiByteToWideChar(-2002): len=%d error=%u\n", len, GetLastError()); + "MultiByteToWideChar(-2002): len=%d error=%lu\n", len, GetLastError()); SetLastError(0xdeadbeef); memset(bufW, 'x', sizeof(bufW)); len = MultiByteToWideChar(CP_ACP, 0, "foobar", -1, bufW, 6); ok(len == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "MultiByteToWideChar(-1): len=%d error=%u\n", len, GetLastError()); + "MultiByteToWideChar(-1): len=%d error=%lu\n", len, GetLastError()); } #define LONGBUFLEN 100000 @@ -156,33 +162,33 @@ static void test_negative_dest_length(void) memset(bufA,'x',sizeof(bufA)); len = WideCharToMultiByte(CP_ACP, 0, foobarW, -1, bufA, -1, NULL, NULL); ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, - "WideCharToMultiByte(destlen -1): len=%d error=%x\n", len, GetLastError()); + "WideCharToMultiByte(destlen -1): len=%d error=%lx\n", len, GetLastError()); SetLastError( 0xdeadbeef ); memset(bufW,'x',sizeof(bufW)); len = MultiByteToWideChar(CP_ACP, 0, foobarA, -1, bufW, -1); ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, - "MultiByteToWideChar(destlen -1): len=%d error=%x\n", len, GetLastError()); + "MultiByteToWideChar(destlen -1): len=%d error=%lx\n", len, GetLastError()); /* Test return on -1000 dest length */ SetLastError( 0xdeadbeef ); memset(bufA,'x',sizeof(bufA)); len = WideCharToMultiByte(CP_ACP, 0, foobarW, -1, bufA, -1000, NULL, NULL); ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, - "WideCharToMultiByte(destlen -1000): len=%d error=%x\n", len, GetLastError()); + "WideCharToMultiByte(destlen -1000): len=%d error=%lx\n", len, GetLastError()); SetLastError( 0xdeadbeef ); memset(bufW,'x',sizeof(bufW)); len = MultiByteToWideChar(CP_ACP, 0, foobarA, -1000, bufW, -1); ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, - "MultiByteToWideChar(destlen -1000): len=%d error=%x\n", len, GetLastError()); + "MultiByteToWideChar(destlen -1000): len=%d error=%lx\n", len, GetLastError()); /* Test return on INT_MAX dest length */ SetLastError( 0xdeadbeef ); memset(bufA,'x',sizeof(bufA)); len = WideCharToMultiByte(CP_ACP, 0, foobarW, -1, bufA, INT_MAX, NULL, NULL); ok(len == 7 && !lstrcmpA(bufA, "foobar") && GetLastError() == 0xdeadbeef, - "WideCharToMultiByte(destlen INT_MAX): len=%d error=%x\n", len, GetLastError()); + "WideCharToMultiByte(destlen INT_MAX): len=%d error=%lx\n", len, GetLastError()); /* Test return on INT_MAX dest length and very long input */ SetLastError( 0xdeadbeef ); @@ -196,7 +202,7 @@ static void test_negative_dest_length(void) len = WideCharToMultiByte(CP_ACP, 0, originalW, -1, bufA, INT_MAX, NULL, NULL); theError = GetLastError(); ok(len == LONGBUFLEN && !lstrcmpA(bufA, originalA) && theError == 0xdeadbeef, - "WideCharToMultiByte(srclen %d, destlen INT_MAX): len %d error=%x\n", LONGBUFLEN, len, theError); + "WideCharToMultiByte(srclen %d, destlen INT_MAX): len %d error=%lx\n", LONGBUFLEN, len, theError); } @@ -205,92 +211,94 @@ static void test_other_invalid_parameters(void) char c_string[] = "Hello World"; size_t c_string_len = sizeof(c_string); WCHAR w_string[] = {'H','e','l','l','o',' ','W','o','r','l','d',0}; - size_t w_string_len = sizeof(w_string) / sizeof(WCHAR); + size_t w_string_len = ARRAY_SIZE(w_string); BOOL used; INT len; /* Unrecognized flag => ERROR_INVALID_FLAGS */ SetLastError(0xdeadbeef); len = WideCharToMultiByte(CP_ACP, 0x100, w_string, -1, c_string, c_string_len, NULL, NULL); - ok(len == 0 && GetLastError() == ERROR_INVALID_FLAGS, "len=%d error=%x\n", len, GetLastError()); + ok(len == 0 && GetLastError() == ERROR_INVALID_FLAGS, "len=%d error=%lx\n", len, GetLastError()); SetLastError(0xdeadbeef); len = WideCharToMultiByte(CP_ACP, 0x800, w_string, -1, c_string, c_string_len, NULL, NULL); - ok(len == 0 && GetLastError() == ERROR_INVALID_FLAGS, "len=%d error=%x\n", len, GetLastError()); + ok(len == 0 && GetLastError() == ERROR_INVALID_FLAGS, "len=%d error=%lx\n", len, GetLastError()); SetLastError(0xdeadbeef); len = MultiByteToWideChar(CP_ACP, 0x10, c_string, -1, w_string, w_string_len); - ok(len == 0 && GetLastError() == ERROR_INVALID_FLAGS, "len=%d error=%x\n", len, GetLastError()); + ok(len == 0 && GetLastError() == ERROR_INVALID_FLAGS, "len=%d error=%lx\n", len, GetLastError()); /* Unrecognized flag and invalid codepage => ERROR_INVALID_PARAMETER */ SetLastError(0xdeadbeef); len = WideCharToMultiByte(0xdeadbeef, 0x100, w_string, w_string_len, c_string, c_string_len, NULL, NULL); - ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError()); + ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%lx\n", len, GetLastError()); SetLastError(0xdeadbeef); len = MultiByteToWideChar(0xdeadbeef, 0x10, c_string, c_string_len, w_string, w_string_len); - ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError()); + ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%lx\n", len, GetLastError()); /* Unrecognized flag and src is NULL => ERROR_INVALID_PARAMETER */ SetLastError(0xdeadbeef); len = WideCharToMultiByte(CP_ACP, 0x100, NULL, -1, c_string, c_string_len, NULL, NULL); - ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError()); + ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%lx\n", len, GetLastError()); SetLastError(0xdeadbeef); len = MultiByteToWideChar(CP_ACP, 0x10, NULL, -1, w_string, w_string_len); - ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError()); + ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%lx\n", len, GetLastError()); /* srclen=0 => ERROR_INVALID_PARAMETER */ SetLastError(0xdeadbeef); len = WideCharToMultiByte(CP_ACP, 0, w_string, 0, c_string, c_string_len, NULL, NULL); - ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError()); + ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%lx\n", len, GetLastError()); SetLastError(0xdeadbeef); len = MultiByteToWideChar(CP_ACP, 0, c_string, 0, w_string, w_string_len); - ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError()); + ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%lx\n", len, GetLastError()); /* dst=NULL but dstlen not 0 => ERROR_INVALID_PARAMETER */ SetLastError(0xdeadbeef); len = WideCharToMultiByte(CP_ACP, 0, w_string, w_string_len, NULL, c_string_len, NULL, NULL); - ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError()); + ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%lx\n", len, GetLastError()); SetLastError(0xdeadbeef); len = MultiByteToWideChar(CP_ACP, 0, c_string, c_string_len, NULL, w_string_len); - ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError()); + ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%lx\n", len, GetLastError()); - /* CP_UTF7, CP_UTF8, or CP_SYMBOL and defchar not NULL => ERROR_INVALID_PARAMETER */ - /* CP_SYMBOL's behavior here is undocumented */ + /* CP_UTF7 or CP_SYMBOL and defchar not NULL => ERROR_INVALID_PARAMETER */ + /* CP_UTF8 allows it since win10 1709 */ SetLastError(0xdeadbeef); len = WideCharToMultiByte(CP_UTF7, 0, w_string, w_string_len, c_string, c_string_len, c_string, NULL); - ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError()); + ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%lx\n", len, GetLastError()); SetLastError(0xdeadbeef); len = WideCharToMultiByte(CP_UTF8, 0, w_string, w_string_len, c_string, c_string_len, c_string, NULL); - ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError()); + ok(len == 12 || broken(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER), + "len=%d error=%lx\n", len, GetLastError()); SetLastError(0xdeadbeef); len = WideCharToMultiByte(CP_SYMBOL, 0, w_string, w_string_len, c_string, c_string_len, c_string, NULL); - ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError()); + ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%lx\n", len, GetLastError()); - /* CP_UTF7, CP_UTF8, or CP_SYMBOL and used not NULL => ERROR_INVALID_PARAMETER */ - /* CP_SYMBOL's behavior here is undocumented */ + /* CP_UTF7 or CP_SYMBOL and used not NULL => ERROR_INVALID_PARAMETER */ + /* CP_UTF8 allows it since win10 1709 */ SetLastError(0xdeadbeef); len = WideCharToMultiByte(CP_UTF7, 0, w_string, w_string_len, c_string, c_string_len, NULL, &used); - ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError()); + ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%lx\n", len, GetLastError()); SetLastError(0xdeadbeef); len = WideCharToMultiByte(CP_UTF8, 0, w_string, w_string_len, c_string, c_string_len, NULL, &used); - ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError()); + ok(len == 12 || broken(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER), + "len=%d error=%lx\n", len, GetLastError()); SetLastError(0xdeadbeef); len = WideCharToMultiByte(CP_SYMBOL, 0, w_string, w_string_len, c_string, c_string_len, NULL, &used); - ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError()); + ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%lx\n", len, GetLastError()); /* CP_UTF7, flags not 0 and used not NULL => ERROR_INVALID_PARAMETER */ @@ -299,12 +307,14 @@ static void test_other_invalid_parameters(void) instead except on Windows NT4 */ SetLastError(0xdeadbeef); len = WideCharToMultiByte(CP_UTF7, 1, w_string, w_string_len, c_string, c_string_len, NULL, &used); - ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError()); + ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%lx\n", len, GetLastError()); /* CP_UTF8, unrecognized flag and used not NULL => ERROR_INVALID_PARAMETER */ SetLastError(0xdeadbeef); len = WideCharToMultiByte(CP_UTF8, 0x100, w_string, w_string_len, c_string, c_string_len, NULL, &used); - ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError()); + ok(len == 0, "wrong ret %d\n", len); + ok(GetLastError() == ERROR_INVALID_PARAMETER + || GetLastError() == ERROR_INVALID_FLAGS /* Win10 1709+ */, "wrong error %lu\n", GetLastError()); } static void test_overlapped_buffers(void) @@ -314,12 +324,22 @@ static void test_overlapped_buffers(void) char buf[256]; int ret; + /* limit such that strA's NUL terminator overlaps strW's NUL */ + size_t overlap_limit = (sizeof(strW)-sizeof(strA)) - (sizeof(strW[0])-sizeof(strA[0])); + SetLastError(0xdeadbeef); memcpy(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()); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + memcpy(buf + overlap_limit, strA, sizeof(strA)); + ret = MultiByteToWideChar(CP_ACP, 0, buf + overlap_limit, -1, (WCHAR *)buf, sizeof(buf) / sizeof(WCHAR)); + ok(ret == ARRAY_SIZE(strW), "unexpected ret %d\n", ret); + ok(!memcmp(buf, strW, sizeof(strW)), "conversion failed: %s\n", wine_dbgstr_wn((WCHAR *)buf, ARRAY_SIZE(strW))); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %lu\n", GetLastError()); } static void test_string_conversion(LPBOOL bUsedDefaultChar) @@ -339,14 +359,14 @@ static void test_string_conversion(LPBOOL bUsedDefaultChar) ok(ret == 1, "ret is %d\n", ret); ok(mbc == '\xe4', "mbc is %d\n", mbc); if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); - ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %lu\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()); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %lu\n", GetLastError()); if (IsValidCodePage(1251)) { @@ -357,14 +377,14 @@ static void test_string_conversion(LPBOOL bUsedDefaultChar) if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); ok(GetLastError() == 0xdeadbeef || broken(GetLastError() == 0), /* win95 */ - "GetLastError() is %u\n", GetLastError()); + "GetLastError() is %lu\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()); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %lu\n", GetLastError()); } else skip("Codepage 1251 not available\n"); @@ -375,14 +395,14 @@ static void test_string_conversion(LPBOOL 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()); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetLastError() is %lu\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()); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %lu\n", GetLastError()); mbs[0] = 0; /* WideCharToMultiByte mustn't add any null character automatically. @@ -392,7 +412,7 @@ static void test_string_conversion(LPBOOL 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()); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %lu\n", GetLastError()); ZeroMemory(mbs, 5); /* Now this shouldn't be the case like above as we zeroed the complete string buffer. */ @@ -401,7 +421,7 @@ static void test_string_conversion(LPBOOL 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()); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %lu\n", GetLastError()); /* Double-byte tests */ ret = WideCharToMultiByte(1252, 0, dbwcs, 3, mbs, sizeof(mbs), NULL, bUsedDefaultChar); @@ -414,18 +434,35 @@ static void test_string_conversion(LPBOOL bUsedDefaultChar) ok(!strcmp(mbs, "\xf3\xe7\x3d\xa3\xbf\xa3\xbf\xa3\xbf"), "mbs is %s\n", mbs); if(bUsedDefaultChar) ok(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + /* Show that characters are not truncated */ + ZeroMemory(mbs, 5); + ret = WideCharToMultiByte(936, 0, dbwcs2, -1, mbs, 1, (const char *)default_char, bUsedDefaultChar); + ok(!ret, "ret is %d\n", ret); + ok(mbs[0] == '\0', "mbs is %s\n", mbs); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetLastError() is %lu\n", GetLastError()); + + /* And destination is not null-terminated even when too short */ + FillMemory(mbs, 5, 'x'); + mbs[5] = '\0'; + ret = WideCharToMultiByte(936, 0, dbwcs2, -1, mbs, 2, (const char *)default_char, bUsedDefaultChar); + ok(!ret, "ret is %d\n", ret); + ok(!strcmp(mbs, "\xf3\xe7""xxx"), "mbs is %s\n", mbs); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetLastError() is %lu\n", GetLastError()); + /* 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()); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %lu\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()); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %lu\n", GetLastError()); if (!IsValidCodePage(950)) { @@ -439,13 +476,13 @@ static void test_string_conversion(LPBOOL bUsedDefaultChar) ok(ret == 5, "ret is %d\n", ret); ok(!strcmp(mbs, "\xb5H\xa9\xd2"), "mbs is %s\n", mbs); if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); - ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %lu\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()); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetLastError() is %lu\n", GetLastError()); ZeroMemory(mbs, 5); SetLastError(0xdeadbeef); @@ -453,20 +490,20 @@ static void test_string_conversion(LPBOOL bUsedDefaultChar) ok(ret == 2, "ret is %d\n", ret); ok(!strcmp(mbs, "\xb5H"), "mbs is %s\n", mbs); if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); - ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %lu\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()); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %lu\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()); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %lu\n", GetLastError()); } static void test_utf7_encoding(void) @@ -531,12 +568,20 @@ static void test_utf7_encoding(void) /* tests dry run with dst=NULL and dstlen=0 */ { {0x4F60,0x597D,0x5417,0}, -1, NULL, 0, +#if defined(__REACTOS__) && defined(_MSC_VER) {0}, 0, 11 +#else + {}, 0, 11 +#endif }, /* tests dry run with dst!=NULL and dstlen=0 */ { {0x4F60,0x597D,0x5417,0}, -1, output, 0, +#if defined(__REACTOS__) && defined(_MSC_VER) {0}, 0, 11 +#else + {}, 0, 11 +#endif }, /* tests srclen < strlenW(src) with directly encodable chars */ { @@ -683,7 +728,7 @@ static void test_utf7_encoding(void) i, expected_len, expected_len, output[expected_len]); } - for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) + for (i = 0; i < ARRAY_SIZE(tests); i++) { memset(output, '#', sizeof(output) - 1); output[sizeof(output) - 1] = 0; @@ -695,7 +740,7 @@ static void test_utf7_encoding(void) if (!tests[i].len) { ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "tests[%i]: expected error=0x%x, got error=0x%x\n", + "tests[%i]: expected error=0x%x, got error=0x%lx\n", i, ERROR_INSUFFICIENT_BUFFER, GetLastError()); } ok(len == tests[i].len, "tests[%i]: expected len=%i, got len=%i\n", i, tests[i].len, len); @@ -746,12 +791,12 @@ static void test_utf7_decoding(void) { /* tests string conversion with srclen=-1 */ { - "+T2BZfQ-", -1, output, sizeof(output) / sizeof(WCHAR) - 1, + "+T2BZfQ-", -1, output, ARRAY_SIZE(output) - 1, {0x4F60,0x597D,0}, 3, 3 }, /* tests string conversion with srclen=-2 */ { - "+T2BZfQ-", -2, output, sizeof(output) / sizeof(WCHAR) - 1, + "+T2BZfQ-", -2, output, ARRAY_SIZE(output) - 1, {0x4F60,0x597D,0}, 3, 3 }, /* tests string conversion with dstlen=strlen(expected_dst) */ @@ -772,81 +817,93 @@ static void test_utf7_decoding(void) /* tests dry run with dst=NULL and dstlen=0 */ { "+T2BZfQ-", -1, NULL, 0, +#if defined(__REACTOS__) && defined(_MSC_VER) {0}, 0, 3 +#else + {}, 0, 3 +#endif }, /* tests dry run with dst!=NULL and dstlen=0 */ { "+T2BZfQ-", -1, output, 0, +#if defined(__REACTOS__) && defined(_MSC_VER) {0}, 0, 3 +#else + {}, 0, 3 +#endif }, /* tests ill-formed UTF-7: 6 bits, not enough for a byte pair */ { - "+T-+T-+T-hello", -1, output, sizeof(output) / sizeof(WCHAR) - 1, + "+T-+T-+T-hello", -1, output, ARRAY_SIZE(output) - 1, {'h','e','l','l','o',0}, 6, 6 }, /* tests ill-formed UTF-7: 12 bits, not enough for a byte pair */ { - "+T2-+T2-+T2-hello", -1, output, sizeof(output) / sizeof(WCHAR) - 1, + "+T2-+T2-+T2-hello", -1, output, ARRAY_SIZE(output) - 1, {'h','e','l','l','o',0}, 6, 6 }, /* tests ill-formed UTF-7: 18 bits, not a multiple of 16 and the last bit is a 1 */ { - "+T2B-+T2B-+T2B-hello", -1, output, sizeof(output) / sizeof(WCHAR) - 1, + "+T2B-+T2B-+T2B-hello", -1, output, ARRAY_SIZE(output) - 1, {0x4F60,0x4F60,0x4F60,'h','e','l','l','o',0}, 9, 9 }, /* tests ill-formed UTF-7: 24 bits, a multiple of 8 but not a multiple of 16 */ { - "+T2BZ-+T2BZ-+T2BZ-hello", -1, output, sizeof(output) / sizeof(WCHAR) - 1, + "+T2BZ-+T2BZ-+T2BZ-hello", -1, output, ARRAY_SIZE(output) - 1, {0x4F60,0x4F60,0x4F60,'h','e','l','l','o',0}, 9, 9 }, /* tests UTF-7 followed by characters that should be encoded but aren't */ { - "+T2BZ-\x82\xFE", -1, output, sizeof(output) / sizeof(WCHAR) - 1, + "+T2BZ-\x82\xFE", -1, output, ARRAY_SIZE(output) - 1, {0x4F60,0x0082,0x00FE,0}, 4, 4 }, /* tests srclen > strlen(src) */ { - "a\0b", 4, output, sizeof(output) / sizeof(WCHAR) - 1, + "a\0b", 4, output, ARRAY_SIZE(output) - 1, {'a',0,'b',0}, 4, 4 }, /* tests srclen < strlen(src) outside of a UTF-7 sequence */ { - "hello", 2, output, sizeof(output) / sizeof(WCHAR) - 1, + "hello", 2, output, ARRAY_SIZE(output) - 1, {'h','e'}, 2, 2 }, /* tests srclen < strlen(src) inside of a UTF-7 sequence */ { - "+T2BZfQ-", 4, output, sizeof(output) / sizeof(WCHAR) - 1, + "+T2BZfQ-", 4, output, ARRAY_SIZE(output) - 1, {0x4F60}, 1, 1 }, /* tests srclen < strlen(src) right at the beginning of a UTF-7 sequence */ { - "hi+T2A-", 3, output, sizeof(output) / sizeof(WCHAR) - 1, + "hi+T2A-", 3, output, ARRAY_SIZE(output) - 1, {'h','i'}, 2, 2 }, /* tests srclen < strlen(src) right at the end of a UTF-7 sequence */ { - "+T2A-hi", 5, output, sizeof(output) / sizeof(WCHAR) - 1, + "+T2A-hi", 5, output, ARRAY_SIZE(output) - 1, {0x4F60}, 1, 1 }, /* tests srclen < strlen(src) at the beginning of an escaped + sign */ { - "hi+-", 3, output, sizeof(output) / sizeof(WCHAR) - 1, + "hi+-", 3, output, ARRAY_SIZE(output) - 1, {'h','i'}, 2, 2 }, /* tests srclen < strlen(src) at the end of an escaped + sign */ { - "+-hi", 2, output, sizeof(output) / sizeof(WCHAR) - 1, + "+-hi", 2, output, ARRAY_SIZE(output) - 1, {'+'}, 1, 1 }, /* tests len=0 but no error */ { - "+", 1, output, sizeof(output) / sizeof(WCHAR) - 1, + "+", 1, output, ARRAY_SIZE(output) - 1, +#if defined(__REACTOS__) && defined(_MSC_VER) {0}, 0, 0 +#else + {}, 0, 0 +#endif }, /* tests a single null char */ { - "", -1, output, sizeof(output) / sizeof(WCHAR) - 1, + "", -1, output, ARRAY_SIZE(output) - 1, {0}, 1, 1 }, /* tests a buffer that runs out while not decoding a UTF-7 sequence */ @@ -867,9 +924,9 @@ static void test_utf7_decoding(void) sprintf(input, "+%c+AAA", i); memset(output, 0x23, sizeof(output) - sizeof(WCHAR)); - output[sizeof(output) / sizeof(WCHAR) - 1] = 0; + output[ARRAY_SIZE(output) - 1] = 0; - len = MultiByteToWideChar(CP_UTF7, 0, input, 7, output, sizeof(output) / sizeof(WCHAR) - 1); + len = MultiByteToWideChar(CP_UTF7, 0, input, 7, output, ARRAY_SIZE(output) - 1); if (i == '-') { @@ -909,9 +966,9 @@ static void test_utf7_decoding(void) sprintf(input, "+B%c+AAA", i); memset(output, 0x23, sizeof(output) - sizeof(WCHAR)); - output[sizeof(output) / sizeof(WCHAR) - 1] = 0; + output[ARRAY_SIZE(output) - 1] = 0; - len = MultiByteToWideChar(CP_UTF7, 0, input, 8, output, sizeof(output) / sizeof(WCHAR) - 1); + len = MultiByteToWideChar(CP_UTF7, 0, input, 8, output, ARRAY_SIZE(output) - 1); if (i == '-') { @@ -955,10 +1012,10 @@ static void test_utf7_decoding(void) i, wine_dbgstr_wn(expected, expected_len + 1), wine_dbgstr_wn(output, expected_len + 1)); } - for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) + for (i = 0; i < ARRAY_SIZE(tests); i++) { memset(output, 0x23, sizeof(output) - sizeof(WCHAR)); - output[sizeof(output) / sizeof(WCHAR) - 1] = 0; + output[ARRAY_SIZE(output) - 1] = 0; SetLastError(0xdeadbeef); len = MultiByteToWideChar(CP_UTF7, 0, tests[i].src, tests[i].srclen, @@ -969,7 +1026,7 @@ static void test_utf7_decoding(void) if (!tests[i].len && tests[i].chars_written) { ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "tests[%i]: expected error=0x%x, got error=0x%x\n", + "tests[%i]: expected error=0x%x, got error=0x%lx\n", i, ERROR_INSUFFICIENT_BUFFER, GetLastError()); } ok(len == tests[i].len, "tests[%i]: expected len=%i, got len=%i\n", i, tests[i].len, len); @@ -987,24 +1044,28 @@ static void test_utf7_decoding(void) static void test_undefined_byte_char(void) { static const struct tag_testset { - INT codepage; + UINT codepage; LPCSTR str; BOOL is_error; } testset[] = { + { 37, "\x6f", FALSE }, { 874, "\xdd", TRUE }, { 932, "\xfe", TRUE }, { 932, "\x80", FALSE }, + { 932, "\x81\x45", FALSE }, { 936, "\xff", TRUE }, { 949, "\xff", TRUE }, { 950, "\xff", TRUE }, + { 1252, "?", FALSE }, { 1252, "\x90", FALSE }, { 1253, "\xaa", TRUE }, { 1255, "\xff", TRUE }, { 1257, "\xa5", TRUE }, }; INT i, ret; + DWORD err; - for (i = 0; i < (sizeof(testset) / sizeof(testset[0])); i++) { + for (i = 0; i < ARRAY_SIZE(testset); i++) { if (! IsValidCodePage(testset[i].codepage)) { skip("Codepage %d not available\n", testset[i].codepage); @@ -1014,23 +1075,22 @@ static void test_undefined_byte_char(void) SetLastError(0xdeadbeef); ret = MultiByteToWideChar(testset[i].codepage, MB_ERR_INVALID_CHARS, testset[i].str, -1, NULL, 0); + err = GetLastError(); if (testset[i].is_error) { - ok(ret == 0 && GetLastError() == ERROR_NO_UNICODE_TRANSLATION, - "ret is %d, GetLastError is %u (cp %d)\n", - ret, GetLastError(), testset[i].codepage); + ok(err == ERROR_NO_UNICODE_TRANSLATION, "Test %u: err is %lu\n", i, err); + ok(ret == 0, "Test %u: ret is %d\n", i, ret); } else { - ok(ret == strlen(testset[i].str)+1 && GetLastError() == 0xdeadbeef, - "ret is %d, GetLastError is %u (cp %d)\n", - ret, GetLastError(), testset[i].codepage); + ok(err == 0xdeadbeef, "Test %u: err is %lu\n", i, err); + ok(ret == 2, "Test %u: ret is %d\n", i, ret); } SetLastError(0xdeadbeef); ret = MultiByteToWideChar(testset[i].codepage, 0, testset[i].str, -1, NULL, 0); - ok(ret == strlen(testset[i].str)+1 && GetLastError() == 0xdeadbeef, - "ret is %d, GetLastError is %u (cp %d)\n", - ret, GetLastError(), testset[i].codepage); + err = GetLastError(); + ok(err == 0xdeadbeef, "Test %u: err is %lu\n", i, err); + ok(ret == 2, "Test %u: ret is %d\n", i, ret); } } @@ -1043,7 +1103,7 @@ static void test_threadcp(void) static const LCID JAPANESE = MAKELCID(MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN), SORT_DEFAULT); static const LCID CHINESE = MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT); - BOOL islead, islead_acp; + BOOL islead, islead_default; CPINFOEXA cpi; UINT cp, acp; int i, num; @@ -1106,69 +1166,73 @@ static void test_threadcp(void) last = GetThreadLocale(); acp = GetACP(); - for (i = 0; i < sizeof(lcids)/sizeof(lcids[0]); i++) + for (i = 0; i < ARRAY_SIZE(lcids); i++) { SetThreadLocale(lcids[i].lcid); cp = 0xdeadbeef; GetLocaleInfoA(lcids[i].lcid, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER, (LPSTR)&cp, sizeof(cp)); - ok(cp == lcids[i].threadcp, "wrong codepage %u for lcid %04x, should be %u\n", cp, lcids[i].threadcp, cp); + ok(cp == lcids[i].threadcp, "wrong codepage %u for lcid %04lx, should be %u\n", cp, lcids[i].lcid, lcids[i].threadcp); /* GetCPInfoEx/GetCPInfo - CP_ACP */ SetLastError(0xdeadbeef); memset(&cpi, 0, sizeof(cpi)); ret = GetCPInfoExA(CP_ACP, 0, &cpi); - ok(ret, "GetCPInfoExA failed for lcid %04x, error %d\n", lcids[i].lcid, GetLastError()); - ok(cpi.CodePage == acp, "wrong codepage %u for lcid %04x, should be %u\n", cpi.CodePage, lcids[i].lcid, acp); + ok(ret, "GetCPInfoExA failed for lcid %04lx, error %ld\n", lcids[i].lcid, GetLastError()); + ok(cpi.CodePage == acp, "wrong codepage %u for lcid %04lx, should be %u\n", cpi.CodePage, lcids[i].lcid, acp); /* WideCharToMultiByte - CP_ACP */ num = WideCharToMultiByte(CP_ACP, 0, foobarW, -1, NULL, 0, NULL, NULL); - ok(num == 7, "ret is %d (%04x)\n", num, lcids[i].lcid); + ok(num == 7, "ret is %d (%04lx)\n", num, lcids[i].lcid); /* MultiByteToWideChar - CP_ACP */ num = MultiByteToWideChar(CP_ACP, 0, "foobar", -1, NULL, 0); - ok(num == 7, "ret is %d (%04x)\n", num, lcids[i].lcid); + ok(num == 7, "ret is %d (%04lx)\n", num, lcids[i].lcid); /* GetCPInfoEx/GetCPInfo - CP_THREAD_ACP */ SetLastError(0xdeadbeef); memset(&cpi, 0, sizeof(cpi)); ret = GetCPInfoExA(CP_THREAD_ACP, 0, &cpi); - ok(ret, "GetCPInfoExA failed for lcid %04x, error %d\n", lcids[i].lcid, GetLastError()); + ok(ret, "GetCPInfoExA failed for lcid %04lx, error %ld\n", lcids[i].lcid, GetLastError()); if (lcids[i].threadcp) - ok(cpi.CodePage == lcids[i].threadcp, "wrong codepage %u for lcid %04x, should be %u\n", + ok(cpi.CodePage == lcids[i].threadcp || cpi.CodePage == CP_UTF8 /* Win10 1809+ */, + "wrong codepage %u for lcid %04lx, should be %u\n", cpi.CodePage, lcids[i].lcid, lcids[i].threadcp); else - ok(cpi.CodePage == acp, "wrong codepage %u for lcid %04x, should be %u\n", - cpi.CodePage, lcids[i].lcid, acp); + ok(cpi.CodePage == acp || cpi.CodePage == CP_UTF8 /* Win10 1809+ */, + "wrong codepage %u for lcid %04lx, should be %u\n", cpi.CodePage, lcids[i].lcid, acp); /* WideCharToMultiByte - CP_THREAD_ACP */ num = WideCharToMultiByte(CP_THREAD_ACP, 0, foobarW, -1, NULL, 0, NULL, NULL); - ok(num == 7, "ret is %d (%04x)\n", num, lcids[i].lcid); + ok(num == 7, "ret is %d (%04lx)\n", num, lcids[i].lcid); /* MultiByteToWideChar - CP_THREAD_ACP */ num = MultiByteToWideChar(CP_THREAD_ACP, 0, "foobar", -1, NULL, 0); - ok(num == 7, "ret is %d (%04x)\n", num, lcids[i].lcid); + ok(num == 7, "ret is %d (%04lx)\n", num, lcids[i].lcid); } /* IsDBCSLeadByteEx - locales without codepage */ - for (i = 0; i < sizeof(isleads_nocp)/sizeof(isleads_nocp[0]); i++) + for (i = 0; i < ARRAY_SIZE(isleads_nocp); i++) { SetThreadLocale(isleads_nocp[i].lcid); - islead_acp = IsDBCSLeadByteEx(CP_ACP, isleads_nocp[i].testchar); - islead = IsDBCSLeadByteEx(CP_THREAD_ACP, isleads_nocp[i].testchar); + GetCPInfoExA(CP_THREAD_ACP, 0, &cpi); + islead_default = IsDBCSLeadByteEx(cpi.CodePage, isleads_nocp[i].testchar); + islead = IsDBCSLeadByteEx(CP_THREAD_ACP, isleads_nocp[i].testchar); - ok(islead == islead_acp, "wrong islead %i for test char %x in lcid %04x. should be %i\n", - islead, isleads_nocp[i].testchar, isleads_nocp[i].lcid, islead_acp); + ok(islead == islead_default, "wrong islead %i for test char %x in lcid %04lx. should be %i\n", + islead, isleads_nocp[i].testchar, isleads_nocp[i].lcid, islead_default); } /* IsDBCSLeadByteEx - locales with codepage */ - for (i = 0; i < sizeof(isleads)/sizeof(isleads[0]); i++) + for (i = 0; i < ARRAY_SIZE(isleads); i++) { SetThreadLocale(isleads[i].lcid); + GetCPInfoExA(CP_THREAD_ACP, 0, &cpi); islead = IsDBCSLeadByteEx(CP_THREAD_ACP, isleads[i].testchar); - ok(islead == isleads[i].islead, "wrong islead %i for test char %x in lcid %04x. should be %i\n", + ok(islead == isleads[i].islead || (cpi.CodePage == CP_UTF8 && !islead), + "wrong islead %i for test char %x in lcid %04lx. should be %i\n", islead, isleads[i].testchar, isleads[i].lcid, isleads[i].islead); } @@ -1194,19 +1258,19 @@ static void test_dbcs_to_widechar(void) MB_COMPOSITE |MB_ERR_INVALID_CHARS|MB_USEGLYPHCHARS, }; - for (i = 0; i < sizeof(flags)/sizeof(DWORD); ++i) + for (i = 0; i < ARRAY_SIZE(flags); ++i) { memset(wbuf, 0xff, sizeof(wbuf)); count = MultiByteToWideChar(936, flags[i], (char*)&buf[0], 2, NULL, 0); count2 = MultiByteToWideChar(936, flags[i], (char*)&buf[0], 2, wbuf, count); - ok(count == 1, "%04x: returned %d (expected 1)\n", flags[i], count); - ok(count2 == 1, "%04x: returned %d (expected 1)\n", flags[i], count2); - ok(wbuf[0] == 0x770b, "%04x: returned %04x (expected 770b)\n", flags[i], wbuf[0]); - ok(wbuf[1] == 0xffff, "%04x: returned %04x (expected ffff)\n", flags[i], wbuf[1]); + ok(count == 1, "%04lx: returned %d (expected 1)\n", flags[i], count); + ok(count2 == 1, "%04lx: returned %d (expected 1)\n", flags[i], count2); + ok(wbuf[0] == 0x770b, "%04lx: returned %04x (expected 770b)\n", flags[i], wbuf[0]); + ok(wbuf[1] == 0xffff, "%04lx: returned %04x (expected ffff)\n", flags[i], wbuf[1]); } - for (i = 0; i < sizeof(flags)/sizeof(DWORD); ++i) + for (i = 0; i < ARRAY_SIZE(flags); ++i) { memset(wbuf, 0xff, sizeof(wbuf)); count = MultiByteToWideChar(936, flags[i], (char*)&buf[0], 3, NULL, 0); @@ -1215,35 +1279,35 @@ static void test_dbcs_to_widechar(void) if (flags[i] & MB_ERR_INVALID_CHARS) { - ok(count == 0, "%04x: returned %d (expected 0)\n", flags[i], count); - ok(count2 == 0, "%04x: returned %d (expected 0)\n", flags[i], count2); - ok(GetLastError() == ERROR_NO_UNICODE_TRANSLATION, "%04x: returned %d (expected %d)\n", + ok(count == 0, "%04lx: returned %d (expected 0)\n", flags[i], count); + ok(count2 == 0, "%04lx: returned %d (expected 0)\n", flags[i], count2); + ok(GetLastError() == ERROR_NO_UNICODE_TRANSLATION, "%04lx: returned %ld (expected %d)\n", flags[i], GetLastError(), ERROR_NO_UNICODE_TRANSLATION); } else { - ok(count == 2, "%04x: returned %d (expected 2)\n", flags[i], count); - ok(count2 == 2, "%04x: returned %d (expected 2)\n", flags[i], count2); - ok(wbuf[0] == 0x770b, "%04x: returned %04x (expected 770b)\n", flags[i], wbuf[0]); + ok(count == 2, "%04lx: returned %d (expected 2)\n", flags[i], count); + ok(count2 == 2, "%04lx: returned %d (expected 2)\n", flags[i], count2); + ok(wbuf[0] == 0x770b, "%04lx: returned %04x (expected 770b)\n", flags[i], wbuf[0]); ok(wbuf[1] == 0x003f || broken(wbuf[1] == 0), /*windows xp*/ - "%04x: wrong wide char: %04x\n", flags[i], wbuf[1]); - ok(wbuf[2] == 0xffff, "%04x: returned %04x (expected ffff)\n", flags[i], wbuf[2]); + "%04lx: wrong wide char: %04x\n", flags[i], wbuf[1]); + ok(wbuf[2] == 0xffff, "%04lx: returned %04x (expected ffff)\n", flags[i], wbuf[2]); } } /* src ends with null character */ - for (i = 0; i < sizeof(flags)/sizeof(DWORD); ++i) + for (i = 0; i < ARRAY_SIZE(flags); ++i) { memset(wbuf, 0xff, sizeof(wbuf)); count = MultiByteToWideChar(936, flags[i], (char*)&buf[0], 4, NULL, 0); SetLastError( 0xdeadbeef ); count2 = MultiByteToWideChar(936, flags[i], (char*)&buf[0], 4, wbuf, count); - ok(count == count2, "%04x: returned %d (expected %d)\n", flags[i], count2, count); + ok(count == count2, "%04lx: returned %d (expected %d)\n", flags[i], count2, count); if (flags[i] & MB_ERR_INVALID_CHARS) { - ok(count == 0, "%04x: returned %d (expected 0)\n", flags[i], count); - ok(GetLastError() == ERROR_NO_UNICODE_TRANSLATION, "%04x: returned %d (expected %d)\n", + ok(count == 0, "%04lx: returned %d (expected 0)\n", flags[i], count); + ok(GetLastError() == ERROR_NO_UNICODE_TRANSLATION, "%04lx: returned %ld (expected %d)\n", flags[i], GetLastError(), ERROR_NO_UNICODE_TRANSLATION); } else @@ -1251,28 +1315,28 @@ static void test_dbcs_to_widechar(void) WCHAR wbuf_ok[] = { 0x770b, 0x003f, '\0', 0xffff }; WCHAR wbuf_broken[] = { 0x770b, '\0', 0xffff, 0xffff }; ok(count == 3 || broken(count == 2 /*windows xp*/), - "%04x: returned %d (expected 3)\n", flags[i], count); + "%04lx: returned %d (expected 3)\n", flags[i], count); ok(!memcmp(wbuf, wbuf_ok, sizeof(wbuf_ok)) || broken(!memcmp(wbuf, wbuf_broken, sizeof(wbuf_broken))), - "%04x: returned %04x %04x %04x %04x (expected %04x %04x %04x %04x)\n", + "%04lx: returned %04x %04x %04x %04x (expected %04x %04x %04x %04x)\n", flags[i], wbuf[0], wbuf[1], wbuf[2], wbuf[3], wbuf_ok[0], wbuf_ok[1], wbuf_ok[2], wbuf_ok[3]); } } /* src has null character, but not ends with it */ - for (i = 0; i < sizeof(flags)/sizeof(DWORD); ++i) + for (i = 0; i < ARRAY_SIZE(flags); ++i) { memset(wbuf, 0xff, sizeof(wbuf)); count = MultiByteToWideChar(936, flags[i], (char*)&buf[0], 5, NULL, 0); SetLastError( 0xdeadbeef ); count2 = MultiByteToWideChar(936, flags[i], (char*)&buf[0], 5, wbuf, count); - ok(count == count2, "%04x: returned %d (expected %d)\n", flags[i], count2, count); + ok(count == count2, "%04lx: returned %d (expected %d)\n", flags[i], count2, count); if (flags[i] & MB_ERR_INVALID_CHARS) { - ok(count == 0, "%04x: returned %d (expected 0)\n", flags[i], count); - ok(GetLastError() == ERROR_NO_UNICODE_TRANSLATION, "%04x: returned %d (expected %d)\n", + ok(count == 0, "%04lx: returned %d (expected 0)\n", flags[i], count); + ok(GetLastError() == ERROR_NO_UNICODE_TRANSLATION, "%04lx: returned %ld (expected %d)\n", flags[i], GetLastError(), ERROR_NO_UNICODE_TRANSLATION); } else @@ -1280,10 +1344,10 @@ static void test_dbcs_to_widechar(void) WCHAR wbuf_ok[] = { 0x770b, 0x003f, '\0', 'x', 0xffff }; WCHAR wbuf_broken[] = { 0x770b, '\0', 'x', 0xffff, 0xffff }; ok(count == 4 || broken(count == 3), - "%04x: returned %d (expected 4)\n", flags[i], count); + "%04lx: returned %d (expected 4)\n", flags[i], count); ok(!memcmp(wbuf, wbuf_ok, sizeof(wbuf_ok)) || broken(!memcmp(wbuf, wbuf_broken, sizeof(wbuf_broken))), - "%04x: returned %04x %04x %04x %04x %04x (expected %04x %04x %04x %04x %04x)\n", + "%04lx: returned %04x %04x %04x %04x %04x (expected %04x %04x %04x %04x %04x)\n", flags[i], wbuf[0], wbuf[1], wbuf[2], wbuf[3], wbuf[4], wbuf_ok[0], wbuf_ok[1], wbuf_ok[2], wbuf_ok[3], wbuf_ok[4]); } diff --git a/modules/rostests/winetests/kernel32/comm.c b/modules/rostests/winetests/kernel32/comm.c index 4fb9de1268e..b4659034ddf 100644 --- a/modules/rostests/winetests/kernel32/comm.c +++ b/modules/rostests/winetests/kernel32/comm.c @@ -410,8 +410,6 @@ static const TEST test[] = }, }; -#define TEST_COUNT (sizeof(test) / sizeof(TEST)) - /* This function can be useful if you are modifying the test cases and want to output the contents of a DCB structure. */ /*static print_dcb(DCB *pdcb) @@ -452,7 +450,7 @@ static void check_result(const char *function, const TEST *ptest, int initial_va DWORD LastError = GetLastError(); DWORD CorrectError = (ptest->result ? 0xdeadbeef : ERROR_INVALID_PARAMETER); - ok(LastError == CorrectError, "%s(\"%s\"), 0x%02x: GetLastError() returned %d, should be %d\n", function, ptest->string, initial_value, LastError, CorrectError); + ok(LastError == CorrectError, "%s(\"%s\"), 0x%02x: GetLastError() returned %ld, should be %ld\n", function, ptest->string, initial_value, LastError, CorrectError); ok(result == ptest->result, "%s(\"%s\"), 0x%02x: return value should be %s\n", function, ptest->string, initial_value, ptest->result ? "TRUE" : "FALSE"); } @@ -463,7 +461,7 @@ static void check_dcb(const char *function, const TEST *ptest, int initial_value { /* DCBlength is a special case since Win 9x sets it but NT does not. We will accept either as correct. */ - check_dcb_member2(DCBlength, (DWORD)sizeof(DCB), "%u"); + check_dcb_member2(DCBlength, (DWORD)sizeof(DCB), "%lu"); /* For old style control strings Win 9x does not set the next five members, NT does. */ if(ptest->old_style && ptest->result) @@ -507,7 +505,7 @@ static void check_dcb(const char *function, const TEST *ptest, int initial_value } /* Check the result of the DCB members. */ - check_dcb_member(BaudRate, "%u"); + check_dcb_member(BaudRate, "%lu"); check_dcb_member(fBinary, "%u"); check_dcb_member(fParity, "%u"); check_dcb_member(fTXContinueOnXoff, "%u"); @@ -529,7 +527,7 @@ static void check_dcb(const char *function, const TEST *ptest, int initial_value check_dcb_member(wReserved1, "%u"); } -#define check_timeouts_member(a) ok(ptimeouts1->a == ptimeouts2->a, "%s(\"%s\"), 0x%02x: "#a" is %u, should be %u\n", function, ptest->string, initial_value, ptimeouts1->a, ptimeouts2->a); +#define check_timeouts_member(a) ok(ptimeouts1->a == ptimeouts2->a, "%s(\"%s\"), 0x%02x: "#a" is %lu, should be %lu\n", function, ptest->string, initial_value, ptimeouts1->a, ptimeouts2->a); static void check_timeouts(const char *function, const TEST *ptest, int initial_value, const COMMTIMEOUTS *ptimeouts1, const COMMTIMEOUTS *ptimeouts2) { @@ -582,7 +580,7 @@ static void test_BuildCommDCBW(const char *string, const TEST *ptest, int initia WCHAR wide_string[sizeof(ptest->string)]; static int reportedDCBW = 0; - MultiByteToWideChar(CP_ACP, 0, string, -1, wide_string, sizeof(wide_string) / sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, string, -1, wide_string, ARRAY_SIZE(wide_string)); /* set initial conditions */ memset(&dcb, initial_value, sizeof(DCB)); @@ -610,7 +608,7 @@ static void test_BuildCommDCBAndTimeoutsW(const char *string, const TEST *ptest, WCHAR wide_string[sizeof(ptest->string)]; static int reportedDCBAndTW = 0; - MultiByteToWideChar(CP_ACP, 0, string, -1, wide_string, sizeof(wide_string) / sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, string, -1, wide_string, ARRAY_SIZE(wide_string)); /* set initial conditions */ memset(&dcb, initial_value, sizeof(DCB)); @@ -656,7 +654,7 @@ static void test_BuildCommDCB(void) if(!port) trace("Could not find a valid COM port. Some tests will be skipped.\n"); - for(i = 0; i < TEST_COUNT; i++) + for(i = 0; i < ARRAY_SIZE(test); i++) { char string[sizeof(test[i].string)]; @@ -725,10 +723,10 @@ static HANDLE test_OpenComm(BOOL doOverlap) return INVALID_HANDLE_VALUE; } - ok(ret, "Unexpected error %u on open\n", GetLastError()); - ok(comstat.cbInQue == 0, "Unexpected %d chars in InQueue\n",comstat.cbInQue); - ok(comstat.cbOutQue == 0, "Still pending %d charcters in OutQueue\n", comstat.cbOutQue); - ok(errors == 0, "Unexpected errors 0x%08x\n", errors); + ok(ret, "Unexpected error %lu on open\n", GetLastError()); + ok(comstat.cbInQue == 0, "Unexpected %ld chars in InQueue\n",comstat.cbInQue); + ok(comstat.cbOutQue == 0, "Still pending %ld characters in OutQueue\n", comstat.cbOutQue); + ok(errors == 0, "Unexpected errors 0x%08lx\n", errors); } return hcom; } @@ -738,7 +736,7 @@ static void test_GetModemStatus(HANDLE hcom) DWORD ModemStat = 0; ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n"); - trace("GetCommModemStatus returned 0x%08x->%s%s%s%s\n", ModemStat, + trace("GetCommModemStatus returned 0x%08lx->%s%s%s%s\n", ModemStat, (ModemStat &MS_RLSD_ON)?"MS_RLSD_ON ":"", (ModemStat &MS_RING_ON)?"MS_RING_ON ":"", (ModemStat &MS_DSR_ON)?"MS_DSR_ON ":"", @@ -779,10 +777,10 @@ static void test_ReadTimeOut(void) LastError = GetLastError(); after = GetTickCount(); ok( res == TRUE, "A timed-out read should return TRUE\n"); - ok( LastError == 0xdeadbeef, "err=%d\n", LastError); + ok( LastError == 0xdeadbeef, "err=%ld\n", LastError); timediff = after - before; ok( timediff > TIMEOUT>>2 && timediff < TIMEOUT *2, - "Unexpected TimeOut %d, expected %d\n", timediff, TIMEOUT); + "Unexpected TimeOut %ld, expected %d\n", timediff, TIMEOUT); CloseHandle(hcom); } @@ -804,7 +802,7 @@ static void test_waittxempty(void) /* set a low baud rate to have ample time*/ res = GetCommState(hcom, &dcb); - ok(res, "GetCommState error %d\n", GetLastError()); + ok(res, "GetCommState error %ld\n", GetLastError()); dcb.BaudRate = baud; dcb.ByteSize = 8; dcb.Parity = NOPARITY; @@ -812,58 +810,58 @@ static void test_waittxempty(void) dcb.fDtrControl=DTR_CONTROL_ENABLE; dcb.StopBits = ONESTOPBIT; res = SetCommState(hcom, &dcb); - ok(res, "SetCommState error %d\n", GetLastError()); + ok(res, "SetCommState error %ld\n", GetLastError()); ZeroMemory( &timeouts, sizeof(timeouts)); timeouts.ReadTotalTimeoutConstant = TIMEOUT; res = SetCommTimeouts(hcom, &timeouts); - ok(res,"SetCommTimeouts error %d\n", GetLastError()); + ok(res,"SetCommTimeouts error %ld\n", GetLastError()); res = SetupComm(hcom, 1024, 1024); - ok(res, "SetUpComm error %d\n", GetLastError()); + ok(res, "SetUpComm error %ld\n", GetLastError()); /* calling SetCommMask after WriteFile leads to WaitCommEvent failures * due to timeout (no events) under testbot VMs and VirtualBox */ res = SetCommMask(hcom, EV_TXEMPTY); - ok(res, "SetCommMask error %d\n", GetLastError()); + ok(res, "SetCommMask error %ld\n", GetLastError()); SetLastError(0xdeadbeef); res = WriteFile(hcom, tbuf, sizeof(tbuf), &bytes, NULL); ok(!res, "WriteFile on an overlapped handle without ovl structure should fail\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); - S(U(ovl_write)).Offset = 0; - S(U(ovl_write)).OffsetHigh = 0; + ovl_write.Offset = 0; + ovl_write.OffsetHigh = 0; ovl_write.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); before = GetTickCount(); SetLastError(0xdeadbeef); res = WriteFile(hcom, tbuf, sizeof(tbuf), &bytes, &ovl_write); after = GetTickCount(); ok((!res && GetLastError() == ERROR_IO_PENDING) || (res && bytes == sizeof(tbuf)), - "WriteFile returned %d, written %u bytes, error %d\n", res, bytes, GetLastError()); - if (!res) ok(!bytes, "expected 0, got %u\n", bytes); - ok(after - before < 30, "WriteFile took %d ms to write %d Bytes at %d Baud\n", + "WriteFile returned %d, written %lu bytes, error %ld\n", res, bytes, GetLastError()); + if (!res) ok(!bytes, "expected 0, got %lu\n", bytes); + ok(after - before < 30, "WriteFile took %ld ms to write %ld Bytes at %ld Baud\n", after - before, bytes, baud); /* don't wait for WriteFile completion */ - S(U(ovl_wait)).Offset = 0; - S(U(ovl_wait)).OffsetHigh = 0; + ovl_wait.Offset = 0; + ovl_wait.OffsetHigh = 0; ovl_wait.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); evtmask = 0; before = GetTickCount(); SetLastError(0xdeadbeef); res = WaitCommEvent(hcom, &evtmask, &ovl_wait); - ok(!res && GetLastError() == ERROR_IO_PENDING, "WaitCommEvent error %d\n", GetLastError()); + ok(res || GetLastError() == ERROR_IO_PENDING, "WaitCommEvent error %ld\n", GetLastError()); after = GetTickCount(); - ok(after - before < 30, "WaitCommEvent should have returned immediately, took %d ms\n", after - before); + ok(after - before < 30, "WaitCommEvent should have returned immediately, took %ld ms\n", after - before); res = WaitForSingleObject(ovl_wait.hEvent, 1500); ok(res == WAIT_OBJECT_0, "WaitCommEvent failed with a timeout\n"); if (res == WAIT_OBJECT_0) { res = GetOverlappedResult(hcom, &ovl_wait, &bytes, FALSE); - ok(res, "GetOverlappedResult reported error %d\n", GetLastError()); - ok(bytes == sizeof(evtmask), "expected %u, written %u\n", (UINT)sizeof(evtmask), bytes); + ok(res, "GetOverlappedResult reported error %ld\n", GetLastError()); + ok(bytes == sizeof(evtmask), "expected %u, written %lu\n", (UINT)sizeof(evtmask), bytes); res = TRUE; } else @@ -871,7 +869,7 @@ static void test_waittxempty(void) /* unblock pending wait */ trace("recovering after WAIT_TIMEOUT...\n"); res = SetCommMask(hcom, EV_TXEMPTY); - ok(res, "SetCommMask error %d\n", GetLastError()); + ok(res, "SetCommMask error %ld\n", GetLastError()); res = WaitForSingleObject(ovl_wait.hEvent, TIMEOUT); ok(res == WAIT_OBJECT_0, "WaitCommEvent failed with a timeout\n"); @@ -879,19 +877,19 @@ static void test_waittxempty(void) res = FALSE; } after = GetTickCount(); - ok(res, "WaitCommEvent error %d\n", GetLastError()); - ok(evtmask & EV_TXEMPTY, "WaitCommEvent: expected EV_TXEMPTY, got %#x\n", evtmask); + ok(res, "WaitCommEvent error %ld\n", GetLastError()); + ok(evtmask & EV_TXEMPTY, "WaitCommEvent: expected EV_TXEMPTY, got %#lx\n", evtmask); CloseHandle(ovl_wait.hEvent); timediff = after - before; - trace("WaitCommEvent for EV_TXEMPTY took %d ms (timeout 1500)\n", timediff); - ok(timediff < 1200, "WaitCommEvent used %d ms for waiting\n", timediff); + trace("WaitCommEvent for EV_TXEMPTY took %ld ms (timeout 1500)\n", timediff); + ok(timediff < 1200, "WaitCommEvent used %ld ms for waiting\n", timediff); res = WaitForSingleObject(ovl_write.hEvent, 0); ok(res == WAIT_OBJECT_0, "WriteFile failed with a timeout\n"); res = GetOverlappedResult(hcom, &ovl_write, &bytes, FALSE); - ok(res, "GetOverlappedResult reported error %d\n", GetLastError()); - ok(bytes == sizeof(tbuf), "expected %u, written %u\n", (UINT)sizeof(tbuf), bytes); + ok(res, "GetOverlappedResult reported error %ld\n", GetLastError()); + ok(bytes == sizeof(tbuf), "expected %u, written %lu\n", (UINT)sizeof(tbuf), bytes); CloseHandle(ovl_write.hEvent); CloseHandle(hcom); @@ -902,47 +900,46 @@ static void test_waittxempty(void) if (hcom == INVALID_HANDLE_VALUE) return; res = SetCommMask(hcom, EV_TXEMPTY); - ok(res, "SetCommMask error %d\n", GetLastError()); + ok(res, "SetCommMask error %ld\n", GetLastError()); if (i == 0) { - S(U(ovl_write)).Offset = 0; - S(U(ovl_write)).OffsetHigh = 0; + ovl_write.Offset = 0; + ovl_write.OffsetHigh = 0; ovl_write.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); - before = GetTickCount(); SetLastError(0xdeadbeef); res = WriteFile(hcom, tbuf, sizeof(tbuf), &bytes, &ovl_write); ok((!res && GetLastError() == ERROR_IO_PENDING) || (res && bytes == sizeof(tbuf)), - "WriteFile returned %d, written %u bytes, error %d\n", res, bytes, GetLastError()); - if (!res) ok(!bytes, "expected 0, got %u\n", bytes); + "WriteFile returned %d, written %lu bytes, error %ld\n", res, bytes, GetLastError()); + if (!res) ok(!bytes, "expected 0, got %lu\n", bytes); ClearCommError(hcom, &errors, &stat); - ok(stat.cbInQue == 0, "InQueue should be empty, got %d bytes\n", stat.cbInQue); + ok(stat.cbInQue == 0, "InQueue should be empty, got %ld bytes\n", stat.cbInQue); ok(stat.cbOutQue != 0 || broken(stat.cbOutQue == 0) /* VM */, "OutQueue should not be empty\n"); - ok(errors == 0, "ClearCommErrors: Unexpected error 0x%08x\n", errors); + ok(errors == 0, "ClearCommErrors: Unexpected error 0x%08lx\n", errors); res = GetOverlappedResult(hcom, &ovl_write, &bytes, TRUE); - ok(res, "GetOverlappedResult reported error %d\n", GetLastError()); - ok(bytes == sizeof(tbuf), "expected %u, written %u\n", (UINT)sizeof(tbuf), bytes); + ok(res, "GetOverlappedResult reported error %ld\n", GetLastError()); + ok(bytes == sizeof(tbuf), "expected %u, written %lu\n", (UINT)sizeof(tbuf), bytes); CloseHandle(ovl_write.hEvent); res = FlushFileBuffers(hcom); - ok(res, "FlushFileBuffers error %d\n", GetLastError()); + ok(res, "FlushFileBuffers error %ld\n", GetLastError()); } ClearCommError(hcom, &errors, &stat); - ok(stat.cbInQue == 0, "InQueue should be empty, got %d bytes\n", stat.cbInQue); - ok(stat.cbOutQue == 0, "OutQueue should be empty, got %d bytes\n", stat.cbOutQue); - ok(errors == 0, "ClearCommErrors: Unexpected error 0x%08x\n", errors); + ok(stat.cbInQue == 0, "InQueue should be empty, got %ld bytes\n", stat.cbInQue); + ok(stat.cbOutQue == 0, "OutQueue should be empty, got %ld bytes\n", stat.cbOutQue); + ok(errors == 0, "ClearCommErrors: Unexpected error 0x%08lx\n", errors); - S(U(ovl_wait)).Offset = 0; - S(U(ovl_wait)).OffsetHigh = 0; + ovl_wait.Offset = 0; + ovl_wait.OffsetHigh = 0; ovl_wait.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); evtmask = 0; SetLastError(0xdeadbeef); res = WaitCommEvent(hcom, &evtmask, &ovl_wait); ok(res /* busy system */ || GetLastError() == ERROR_IO_PENDING, - "%d: WaitCommEvent error %d\n", i, GetLastError()); + "%ld: WaitCommEvent error %ld\n", i, GetLastError()); res = WaitForSingleObject(ovl_wait.hEvent, TIMEOUT); if (i == 0) @@ -952,28 +949,28 @@ static void test_waittxempty(void) if (res == WAIT_OBJECT_0) { res = GetOverlappedResult(hcom, &ovl_wait, &bytes, FALSE); - ok(res, "GetOverlappedResult reported error %d\n", GetLastError()); - ok(bytes == sizeof(evtmask), "expected %u, written %u\n", (UINT)sizeof(evtmask), bytes); - ok(res, "WaitCommEvent error %d\n", GetLastError()); - ok(evtmask & EV_TXEMPTY, "WaitCommEvent: expected EV_TXEMPTY, got %#x\n", evtmask); + ok(res, "GetOverlappedResult reported error %ld\n", GetLastError()); + ok(bytes == sizeof(evtmask), "expected %u, written %lu\n", (UINT)sizeof(evtmask), bytes); + ok(res, "WaitCommEvent error %ld\n", GetLastError()); + ok(evtmask & EV_TXEMPTY, "WaitCommEvent: expected EV_TXEMPTY, got %#lx\n", evtmask); } else { - ok(!evtmask, "WaitCommEvent: expected 0, got %#x\n", evtmask); + ok(!evtmask, "WaitCommEvent: expected 0, got %#lx\n", evtmask); - S(U(ovl_wait2)).Offset = 0; - S(U(ovl_wait2)).OffsetHigh = 0; + ovl_wait2.Offset = 0; + ovl_wait2.OffsetHigh = 0; ovl_wait2.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); SetLastError(0xdeadbeef); res = WaitCommEvent(hcom, &evtmask, &ovl_wait2); ok(!res, "WaitCommEvent should fail if there is a pending wait\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); CloseHandle(ovl_wait2.hEvent); /* unblock pending wait */ trace("recovering after WAIT_TIMEOUT...\n"); res = SetCommMask(hcom, EV_TXEMPTY); - ok(res, "SetCommMask error %d\n", GetLastError()); + ok(res, "SetCommMask error %ld\n", GetLastError()); res = WaitForSingleObject(ovl_wait.hEvent, TIMEOUT); ok(res == WAIT_OBJECT_0, "WaitCommEvent failed with a timeout\n"); @@ -995,9 +992,9 @@ static void test_ClearCommError(void) if (hcom == INVALID_HANDLE_VALUE) return; ok(ClearCommError(hcom, &errors, &lpStat), "ClearCommError failed\n"); - ok(lpStat.cbInQue == 0, "Unexpected %d chars in InQueue\n", lpStat.cbInQue); - ok(lpStat.cbOutQue == 0, "Unexpected %d chars in OutQueue\n", lpStat.cbOutQue); - ok(errors == 0, "ClearCommErrors: Unexpected error 0x%08x\n", errors); + ok(lpStat.cbInQue == 0, "Unexpected %ld chars in InQueue\n", lpStat.cbInQue); + ok(lpStat.cbOutQue == 0, "Unexpected %ld chars in OutQueue\n", lpStat.cbOutQue); + ok(errors == 0, "ClearCommErrors: Unexpected error 0x%08lx\n", errors); CloseHandle(hcom); } @@ -1015,7 +1012,7 @@ static void test_non_pending_errors(void) dcb.ByteSize = 255; /* likely bogus */ ok(!SetCommState(hcom, &dcb), "SetCommState should have failed\n"); ok(ClearCommError(hcom, &err, NULL), "ClearCommError should succeed\n"); - ok(!(err & CE_MODE), "ClearCommError shouldn't set CE_MODE byte in this case (%x)\n", err); + ok(!(err & CE_MODE), "ClearCommError shouldn't set CE_MODE byte in this case (%lx)\n", err); CloseHandle(hcom); } @@ -1054,20 +1051,20 @@ static void test_LoopbackRead(void) before = GetTickCount(); ok(WriteFile(hcom,tbuf,sizeof(tbuf),&written, NULL), "WriteFile failed\n"); after = GetTickCount(); - ok(written == sizeof(tbuf),"WriteFile %d bytes written\n", written); + ok(written == sizeof(tbuf),"WriteFile %ld bytes written\n", written); diff = after -before; /* make sure all bytes are written, so Readfile will succeed in one call*/ ok(WaitCommEvent(hcom, &evtmask, NULL), "WaitCommEvent failed\n"); before = GetTickCount(); ok(evtmask == EV_TXEMPTY, - "WaitCommEvent: Unexpected EvtMask 0x%08x, expected 0x%08x\n", + "WaitCommEvent: Unexpected EvtMask 0x%08lx, expected 0x%08x\n", evtmask, EV_TXEMPTY); - trace("Write %d ms WaitCommEvent EV_TXEMPTY %d ms\n", diff, before- after); + trace("Write %ld ms WaitCommEvent EV_TXEMPTY %ld ms\n", diff, before- after); read=0; ok(ReadFile(hcom, rbuf, sizeof(rbuf), &read, NULL), "Readfile failed\n"); - ok(read == sizeof(tbuf),"ReadFile read %d bytes, expected \"%s\"\n", read,rbuf); + ok(read == sizeof(tbuf),"ReadFile read %ld bytes, expected \"%s\"\n", read,rbuf); /* Now do the same with a slower Baud rate. As we request more characters than written, we will hit the timeout @@ -1084,22 +1081,22 @@ static void test_LoopbackRead(void) ok(SetCommMask(hcom, EV_RXCHAR), "SetCommMask failed\n"); ok(WriteFile(hcom,tbuf,sizeof(tbuf),&written, NULL), "WriteFile failed\n"); - ok(written == sizeof(tbuf),"WriteFile %d bytes written\n", written); + ok(written == sizeof(tbuf),"WriteFile %ld bytes written\n", written); trace("WaitCommEventEV_RXCHAR\n"); ok(WaitCommEvent(hcom, &evtmask, NULL), "WaitCommEvent failed\n"); - ok(evtmask == EV_RXCHAR, "WaitCommEvent: Unexpected EvtMask 0x%08x, expected 0x%08x\n", + ok(evtmask == EV_RXCHAR, "WaitCommEvent: Unexpected EvtMask 0x%08lx, expected 0x%08x\n", evtmask, EV_RXCHAR); before = GetTickCount(); res = ReadFile(hcom, rbuf, sizeof(rbuf), &read, NULL); after = GetTickCount(); ok(res, "Readfile failed\n"); - ok(read == sizeof(tbuf),"ReadFile read %d bytes\n", read); + ok(read == sizeof(tbuf),"ReadFile read %ld bytes\n", read); diff = after - before; - trace("Readfile for %d chars took %d ms\n", read, diff); + trace("Readfile for %ld chars took %ld ms\n", read, diff); ok( (diff > TIMEOUT - TIMEDELTA) && (diff < TIMEOUT + TIMEDELTA), - "Timedout Wait took %d ms, expected around %d\n", diff, TIMEOUT); + "Timedout Wait took %ld ms, expected around %d\n", diff, TIMEOUT); /* now do a plain read with slow speed * This will result in several low level reads and a timeout to happen @@ -1120,8 +1117,8 @@ static void test_LoopbackRead(void) } while ((read < sizeof(tbuf)) && (i <10)); after = GetTickCount(); - ok( read == sizeof(tbuf),"ReadFile read %d bytes\n", read); - trace("Plain Read for %d char at %d baud took %d ms\n", read, SLOWBAUD, after-before); + ok( read == sizeof(tbuf),"ReadFile read %ld bytes\n", read); + trace("Plain Read for %ld char at %d baud took %ld ms\n", read, SLOWBAUD, after-before); CloseHandle(hcom); } @@ -1152,11 +1149,11 @@ static void test_LoopbackCtsRts(void) { ok(EscapeCommFunction(hcom, CLRRTS), "EscapeCommFunction failed to clear RTS\n"); ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n"); - ok ((ModemStat & MS_CTS_ON) == 0, "CTS didn't react: 0x%04x, expected 0x%04x\n", + ok ((ModemStat & MS_CTS_ON) == 0, "CTS didn't react: 0x%04lx, expected 0x%04lx\n", ModemStat, (defaultStat & ~MS_CTS_ON)); ok(EscapeCommFunction(hcom, SETRTS), "EscapeCommFunction failed to clear RTS\n"); ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n"); - ok (ModemStat == defaultStat, "Failed to restore CTS: 0x%04x, expected 0x%04x\n", + ok (ModemStat == defaultStat, "Failed to restore CTS: 0x%04lx, expected 0x%04lx\n", ModemStat, defaultStat); } else @@ -1164,11 +1161,11 @@ static void test_LoopbackCtsRts(void) ok(EscapeCommFunction(hcom, SETRTS), "EscapeCommFunction failed to set RTS\n"); ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n"); ok ((ModemStat & MS_CTS_ON) == MS_CTS_ON, - "CTS didn't react: 0x%04x, expected 0x%04x\n", + "CTS didn't react: 0x%04lx, expected 0x%04lx\n", ModemStat, (defaultStat | MS_CTS_ON)); ok(EscapeCommFunction(hcom, CLRRTS), "EscapeCommFunction failed to clear RTS\n"); ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n"); - ok (ModemStat == defaultStat, "Failed to restore CTS: 0x%04x, expected 0x%04x\n", + ok (ModemStat == defaultStat, "Failed to restore CTS: 0x%04lx, expected 0x%04lx\n", ModemStat, defaultStat); } @@ -1200,11 +1197,11 @@ static void test_LoopbackDtrDcd(void) { ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n"); ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n"); - ok ((ModemStat & MS_RLSD_ON) == 0, "RLSD didn't react: 0x%04x, expected 0x%04x\n", + ok ((ModemStat & MS_RLSD_ON) == 0, "RLSD didn't react: 0x%04lx, expected 0x%04lx\n", ModemStat, (defaultStat & ~MS_RLSD_ON)); ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to set DTR\n"); ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n"); - ok (ModemStat == defaultStat, "Failed to restore RLSD: 0x%04x, expected 0x%04x\n", + ok (ModemStat == defaultStat, "Failed to restore RLSD: 0x%04lx, expected 0x%04lx\n", ModemStat, defaultStat); } else @@ -1212,11 +1209,11 @@ static void test_LoopbackDtrDcd(void) ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to set DTR\n"); ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n"); ok ((ModemStat & MS_RLSD_ON) == MS_RLSD_ON, - "RLSD didn't react: 0x%04x, expected 0x%04x\n", + "RLSD didn't react: 0x%04lx, expected 0x%04lx\n", ModemStat, (defaultStat | MS_RLSD_ON)); ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n"); ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n"); - ok (ModemStat == defaultStat, "Failed to restore RLSD: 0x%04x, expected 0x%04x\n", + ok (ModemStat == defaultStat, "Failed to restore RLSD: 0x%04lx, expected 0x%04lx\n", ModemStat, defaultStat); } @@ -1248,11 +1245,11 @@ static void test_LoopbackDtrDsr(void) { ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n"); ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n"); - ok ((ModemStat & MS_DSR_ON) == 0, "CTS didn't react: 0x%04x, expected 0x%04x\n", + ok ((ModemStat & MS_DSR_ON) == 0, "CTS didn't react: 0x%04lx, expected 0x%04lx\n", ModemStat, (defaultStat & ~MS_DSR_ON)); ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to clear DTR\n"); ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n"); - ok (ModemStat == defaultStat, "Failed to restore DSR: 0x%04x, expected 0x%04x\n", + ok (ModemStat == defaultStat, "Failed to restore DSR: 0x%04lx, expected 0x%04lx\n", ModemStat, defaultStat); } else @@ -1260,11 +1257,11 @@ static void test_LoopbackDtrDsr(void) ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to set DTR\n"); ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n"); ok ((ModemStat & MS_DSR_ON) == MS_DSR_ON, - "CTS didn't react: 0x%04x,expected 0x%04x\n", + "CTS didn't react: 0x%04lx,expected 0x%04lx\n", ModemStat, (defaultStat | MS_DSR_ON)); ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n"); ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n"); - ok (ModemStat == defaultStat, "Failed to restore DSR: 0x%04x, expected 0x%04x\n", + ok (ModemStat == defaultStat, "Failed to restore DSR: 0x%04lx, expected 0x%04lx\n", ModemStat, defaultStat); } @@ -1296,11 +1293,11 @@ static void test_LoopbackDtrRing(void) { ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n"); ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n"); - ok ((ModemStat & MS_RING_ON) == 0, "RING didn't react: 0x%04x, expected 0x%04x\n", + ok ((ModemStat & MS_RING_ON) == 0, "RING didn't react: 0x%04lx, expected 0x%04lx\n", ModemStat, (defaultStat & ~MS_RING_ON)); ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to set DTR\n"); ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n"); - ok (ModemStat == defaultStat, "Failed to restore RING: 0x%04x, expected 0x%04x\n", + ok (ModemStat == defaultStat, "Failed to restore RING: 0x%04lx, expected 0x%04lx\n", ModemStat, defaultStat); } else @@ -1308,11 +1305,11 @@ static void test_LoopbackDtrRing(void) ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to set DTR\n"); ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n"); ok ((ModemStat & MS_RING_ON) == MS_RING_ON, - "RING didn't react: 0x%04x,expected 0x%04x\n", + "RING didn't react: 0x%04lx,expected 0x%04lx\n", ModemStat, (defaultStat | MS_RING_ON)); ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n"); ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n"); - ok (ModemStat == defaultStat, "Failed to restore RING: 0x%04x, expected 0x%04x\n", + ok (ModemStat == defaultStat, "Failed to restore RING: 0x%04lx, expected 0x%04lx\n", ModemStat, defaultStat); } @@ -1345,7 +1342,7 @@ static void test_WaitRx(void) overlapped.hEvent = hComPortEvent; hComWriteEvent = CreateEventW( NULL, TRUE, FALSE, NULL ); - ok(hComWriteEvent != NULL, "CreateEvent res %d\n", GetLastError()); + ok(hComWriteEvent != NULL, "CreateEvent res %ld\n", GetLastError()); ZeroMemory( &overlapped_w, sizeof(overlapped_w)); overlapped_w.hEvent = hComWriteEvent; @@ -1353,47 +1350,47 @@ static void test_WaitRx(void) success_wait = WaitCommEvent(hcom, &evtmask, &overlapped); err_wait = GetLastError(); after = GetTickCount(); - trace("Success 0x%08x err %d evtmask 0x%08x\n", success_wait, err_wait, evtmask); + trace("Success 0x%08lx err %ld evtmask 0x%08lx\n", success_wait, err_wait, evtmask); ok(success_wait || err_wait == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n"); trace("overlapped WaitCommEvent returned.\n"); success_write= WriteFile(hcom, "X", 1, &written, &overlapped_w); err_write = GetLastError(); ok(success_write || err_write == ERROR_IO_PENDING, - "overlapped WriteFile failed, err %d\n", + "overlapped WriteFile failed, err %ld\n", err_write); if (!success_write && (err_write == ERROR_IO_PENDING)) { success_write = WaitForSingleObjectEx(hComWriteEvent, TIMEOUT, TRUE); err_write = GetLastError(); - ok(success_write == WAIT_OBJECT_0, "WaitForSingleObjectEx, res %d, err %d\n", + ok(success_write == WAIT_OBJECT_0, "WaitForSingleObjectEx, res %ld, err %ld\n", success_write, err_write); } Sleep(TIMEOUT >>1); success_write = GetOverlappedResult(hcom, &overlapped_w, &written, FALSE); err_write = GetLastError(); - trace("Write after Wait res 0x%08x err %d\n",success_write, err_write); - ok(success_write && written ==1, "Write after Wait res 0x%08x err %d\n", + trace("Write after Wait res 0x%08lx err %ld\n",success_write, err_write); + ok(success_write && written ==1, "Write after Wait res 0x%08lx err %ld\n", success_write, err_write); if (!success_wait && (err_wait == ERROR_IO_PENDING)) { success_wait = WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE); err_wait = GetLastError(); - ok(success_wait == WAIT_OBJECT_0, "wait hComPortEvent, res 0x%08x, err %d\n", + ok(success_wait == WAIT_OBJECT_0, "wait hComPortEvent, res 0x%08lx, err %ld\n", success_wait, err_wait); } success_wait = GetOverlappedResult(hcom, &overlapped, &written, FALSE); err_wait = GetLastError(); after1 = GetTickCount(); - trace("Success 0x%08x err %d evtmask 0x%08x diff1 %d, diff2 %d\n", + trace("Success 0x%08lx err %ld evtmask 0x%08lx diff1 %ld, diff2 %ld\n", success_wait, err_wait, evtmask, after-before, after1-before); - ok(evtmask & EV_RXCHAR, "Detect EV_RXCHAR: 0x%08x, expected 0x%08x\n", + ok(evtmask & EV_RXCHAR, "Detect EV_RXCHAR: 0x%08lx, expected 0x%08x\n", evtmask, EV_RXCHAR); diff = after1 - before; ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA), - "Unexpected time %d, expected around %d\n", diff, TIMEOUT>>1); + "Unexpected time %ld, expected around %d\n", diff, TIMEOUT>>1); CloseHandle(hcom); } @@ -1410,13 +1407,13 @@ static DWORD CALLBACK toggle_ctlLine(LPVOID arg) HANDLE hComPortEvent = (HANDLE) args[3]; DWORD success, err; - trace("toggle_ctlLine timeout %d ctl 0x%08x handle %p\n", timeout, ctl, hcom ); + trace("toggle_ctlLine timeout %ld ctl 0x%08lx handle %p\n", timeout, ctl, hcom ); Sleep(timeout); - ok(EscapeCommFunction(hcom, ctl),"EscapeCommFunction 0x%08x failed\n", ctl); + ok(EscapeCommFunction(hcom, ctl),"EscapeCommFunction 0x%08lx failed\n", ctl); trace("toggle_ctline done\n"); success = WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE); err = GetLastError(); - trace("toggle_ctline WaitForSingleObjectEx res 0x%08x err %d\n", + trace("toggle_ctline WaitForSingleObjectEx res 0x%08lx err %ld\n", success, err); return 0; } @@ -1456,7 +1453,7 @@ static void test_WaitCts(void) args[1] = SETRTS; args[2]=(DWORD_PTR)hcom; - trace("test_WaitCts timeout %ld clt 0x%08lx handle %p\n",args[0], args[1], hcom); + trace("test_WaitCts timeout %Id clt 0x%08Ix handle %p\n",args[0], args[1], hcom); ok(SetCommMask(hcom, EV_CTS), "SetCommMask failed\n"); hComPortEvent = CreateEventW( NULL, TRUE, FALSE, NULL ); @@ -1475,7 +1472,7 @@ static void test_WaitCts(void) err = GetLastError(); after = GetTickCount(); - trace("Success 0x%08x err %d evtmask 0x%08x\n", success, err, evtmask); + trace("Success 0x%08lx err %ld evtmask 0x%08lx\n", success, err, evtmask); ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n"); trace("overlapped WaitCommEvent returned.\n"); if (!success && (err == ERROR_IO_PENDING)) @@ -1484,10 +1481,10 @@ static void test_WaitCts(void) success = GetOverlappedResult(hcom, &overlapped, &written, FALSE); err = GetLastError(); after1 = GetTickCount(); - trace("Success 0x%08x err %d evtmask 0x%08x diff1 %d, diff2 %d\n", + trace("Success 0x%08lx err %ld evtmask 0x%08lx diff1 %ld, diff2 %ld\n", success, err, evtmask, after-before, after1-before); - ok(evtmask & EV_CTS, "Failed to detect EV_CTS: 0x%08x, expected 0x%08x\n", + ok(evtmask & EV_CTS, "Failed to detect EV_CTS: 0x%08lx, expected 0x%08x\n", evtmask, EV_CTS); ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n"); if(defaultStat & MS_CTS_ON) @@ -1497,7 +1494,7 @@ static void test_WaitCts(void) diff = after1 - before; ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA), - "Unexpected time %d, expected around %d\n", diff, TIMEOUT>>1); + "Unexpected time %ld, expected around %d\n", diff, TIMEOUT>>1); /*restore RTS Settings*/ if(defaultStat & MS_CTS_ON) @@ -1519,7 +1516,7 @@ static DWORD CALLBACK reset_CommMask(LPVOID arg) DWORD timeout = args[0]; HANDLE hcom = (HANDLE) args[1]; - trace(" Changing CommMask on the fly for handle %p after timeout %d\n", + trace(" Changing CommMask on the fly for handle %p after timeout %ld\n", hcom, timeout); Sleep(timeout); ok(SetCommMask(hcom, 0),"SetCommMask %p failed\n", hcom); @@ -1552,7 +1549,7 @@ static void test_AbortWaitCts(void) args[0]= TIMEOUT >>1; args[1]= (DWORD_PTR)hcom; - trace("test_AbortWaitCts timeout %ld handle %p\n",args[0], hcom); + trace("test_AbortWaitCts timeout %Id handle %p\n",args[0], hcom); ok(SetCommMask(hcom, EV_CTS), "SetCommMask failed\n"); hComPortEvent = CreateEventW( NULL, TRUE, FALSE, NULL ); @@ -1570,7 +1567,7 @@ static void test_AbortWaitCts(void) err = GetLastError(); after = GetTickCount(); - trace("Success 0x%08x err %d evtmask 0x%08x\n", success, err, evtmask); + trace("Success 0x%08lx err %ld evtmask 0x%08lx\n", success, err, evtmask); ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n"); trace("overlapped WaitCommEvent returned.\n"); if (!success && (err == ERROR_IO_PENDING)) @@ -1579,15 +1576,15 @@ static void test_AbortWaitCts(void) success = GetOverlappedResult(hcom, &overlapped, &written, FALSE); err = GetLastError(); after1 = GetTickCount(); - trace("Success 0x%08x err %d evtmask 0x%08x diff1 %d, diff2 %d\n", + trace("Success 0x%08lx err %ld evtmask 0x%08lx diff1 %ld, diff2 %ld\n", success, err, evtmask, after-before, after1-before); - ok(evtmask == 0, "Incorrect EventMask 0x%08x returned on Wait aborted bu SetCommMask, expected 0x%08x\n", + ok(evtmask == 0, "Incorrect EventMask 0x%08lx returned on Wait aborted bu SetCommMask, expected 0x%08x\n", evtmask, 0); ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n"); diff = after1 - before; ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA), - "Unexpected time %d, expected around %d\n", diff, TIMEOUT>>1); + "Unexpected time %ld, expected around %d\n", diff, TIMEOUT>>1); CloseHandle(hcom); ok( !WaitForSingleObject( alarmThread, 10000 ), "thread still running\n" ); @@ -1626,7 +1623,7 @@ static void test_WaitDsr(void) args[1] = SETDTR; args[2]= (DWORD_PTR)hcom; - trace("test_WaitDsr timeout %ld clt 0x%08lx handle %p\n",args[0], args[1], hcom); + trace("test_WaitDsr timeout %Id clt 0x%08Ix handle %p\n",args[0], args[1], hcom); ok(SetCommMask(hcom, EV_DSR), "SetCommMask failed\n"); hComPortEvent = CreateEventW( NULL, TRUE, FALSE, NULL ); @@ -1641,7 +1638,7 @@ static void test_WaitDsr(void) err = GetLastError(); after = GetTickCount(); - trace("Success 0x%08x err %d evtmask 0x%08x\n", success, err, evtmask); + trace("Success 0x%08lx err %ld evtmask 0x%08lx\n", success, err, evtmask); ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n"); trace("overlapped WaitCommEvent returned.\n"); if (!success && (err == ERROR_IO_PENDING)) @@ -1650,10 +1647,10 @@ static void test_WaitDsr(void) success = GetOverlappedResult(hcom, &overlapped, &written, FALSE); err = GetLastError(); after1 = GetTickCount(); - trace("Success 0x%08x err %d evtmask 0x%08x diff1 %d, diff2 %d\n", + trace("Success 0x%08lx err %ld evtmask 0x%08lx diff1 %ld, diff2 %ld\n", success, err, evtmask, after-before, after1-before); - ok(evtmask & EV_DSR, "Failed to detect EV_DSR: 0x%08x, expected 0x%08x\n", + ok(evtmask & EV_DSR, "Failed to detect EV_DSR: 0x%08lx, expected 0x%08x\n", evtmask, EV_DSR); ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n"); if(defaultStat & MS_DSR_ON) @@ -1663,7 +1660,7 @@ static void test_WaitDsr(void) diff = after1 - before; ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA), - "Unexpected time %d, expected around %d\n", diff, TIMEOUT>>1); + "Unexpected time %ld, expected around %d\n", diff, TIMEOUT>>1); /*restore RTS Settings*/ if(defaultStat & MS_DSR_ON) @@ -1714,7 +1711,7 @@ static void test_WaitRing(void) args[1] = SETDTR; args[2]=(DWORD_PTR) hcom; - trace("test_WaitRing timeout %ld clt 0x%08lx handle %p\n",args[0], args[1], hcom); + trace("test_WaitRing timeout %Id clt 0x%08Ix handle %p\n",args[0], args[1], hcom); ok(SetCommMask(hcom, EV_RING), "SetCommMask failed\n"); hComPortEvent = CreateEventW( NULL, TRUE, FALSE, NULL ); @@ -1729,7 +1726,7 @@ static void test_WaitRing(void) err = GetLastError(); after = GetTickCount(); - trace("Success 0x%08x err %d evtmask 0x%08x\n", success, err, evtmask); + trace("Success 0x%08lx err %ld evtmask 0x%08lx\n", success, err, evtmask); ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n"); trace("overlapped WaitCommEvent returned.\n"); if (!success && (err == ERROR_IO_PENDING)) @@ -1738,10 +1735,10 @@ static void test_WaitRing(void) success = GetOverlappedResult(hcom, &overlapped, &written, FALSE); err = GetLastError(); after1 = GetTickCount(); - trace("Success 0x%08x err %d evtmask 0x%08x diff1 %d, diff2 %d\n", + trace("Success 0x%08lx err %ld evtmask 0x%08lx diff1 %ld, diff2 %ld\n", success, err, evtmask, after-before, after1-before); - ok(evtmask & EV_RING, "Failed to detect EV_RING: 0x%08x, expected 0x%08x\n", + ok(evtmask & EV_RING, "Failed to detect EV_RING: 0x%08lx, expected 0x%08x\n", evtmask, EV_RING); ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n"); if(defaultStat & MS_RING_ON) @@ -1751,7 +1748,7 @@ static void test_WaitRing(void) diff = after1 - before; ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA), - "Unexpected time %d, expected around %d\n", diff, TIMEOUT>>1); + "Unexpected time %ld, expected around %d\n", diff, TIMEOUT>>1); /*restore RTS Settings*/ if(defaultStat & MS_RING_ON) @@ -1795,7 +1792,7 @@ static void test_WaitDcd(void) args[1] = SETDTR; args[2]= (DWORD_PTR)hcom; - trace("test_WaitDcd timeout %ld clt 0x%08lx handle %p\n",args[0], args[1], hcom); + trace("test_WaitDcd timeout %Id clt 0x%08Ix handle %p\n",args[0], args[1], hcom); ok(SetCommMask(hcom, EV_RLSD), "SetCommMask failed\n"); hComPortEvent = CreateEventW( NULL, TRUE, FALSE, NULL ); @@ -1810,7 +1807,7 @@ static void test_WaitDcd(void) err = GetLastError(); after = GetTickCount(); - trace("Success 0x%08x err %d evtmask 0x%08x\n", success, err, evtmask); + trace("Success 0x%08lx err %ld evtmask 0x%08lx\n", success, err, evtmask); ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n"); trace("overlapped WaitCommEvent returned.\n"); if (!success && (err == ERROR_IO_PENDING)) @@ -1819,10 +1816,10 @@ static void test_WaitDcd(void) success = GetOverlappedResult(hcom, &overlapped, &written, FALSE); err = GetLastError(); after1 = GetTickCount(); - trace("Success 0x%08x err %d evtmask 0x%08x diff1 %d, diff2 %d\n", + trace("Success 0x%08lx err %ld evtmask 0x%08lx diff1 %ld, diff2 %ld\n", success, err, evtmask, after-before, after1-before); - ok(evtmask & EV_RLSD, "Failed to detect EV_RLSD: 0x%08x, expected 0x%08x\n", + ok(evtmask & EV_RLSD, "Failed to detect EV_RLSD: 0x%08lx, expected 0x%08x\n", evtmask, EV_RLSD); ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n"); if(defaultStat & MS_RLSD_ON) @@ -1832,7 +1829,7 @@ static void test_WaitDcd(void) diff = after1 - before; ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA), - "Unexpected time %d, expected around %d\n", diff, TIMEOUT>>1); + "Unexpected time %ld, expected around %d\n", diff, TIMEOUT>>1); /*restore RTS Settings*/ if(defaultStat & MS_RLSD_ON) @@ -1854,7 +1851,7 @@ static DWORD CALLBACK set_CommBreak(LPVOID arg) DWORD timeout = args[0]; HANDLE hcom = (HANDLE) args[1]; - trace("SetCommBreak for handle %p after timeout %d\n", + trace("SetCommBreak for handle %p after timeout %ld\n", hcom, timeout); Sleep(timeout); ok(SetCommBreak(hcom),"SetCommBreak %p failed\n", hcom); @@ -1898,28 +1895,28 @@ static void test_WaitBreak(void) err = GetLastError(); after = GetTickCount(); - trace("Success 0x%08x err %d evtmask 0x%08x\n", success, err, evtmask); + trace("Success 0x%08lx err %ld evtmask 0x%08lx\n", success, err, evtmask); ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n"); trace("overlapped WaitCommEvent returned.\n"); if (!success && (err == ERROR_IO_PENDING)) { success = WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE); - ok(!success, "wait hComPortEvent res %d\n", GetLastError()); + ok(!success, "wait hComPortEvent res %ld\n", GetLastError()); } success = GetOverlappedResult(hcom, &overlapped, &written, FALSE); err = GetLastError(); after1 = GetTickCount(); - trace("Success 0x%08x err %d evtmask 0x%08x diff1 %d, diff2 %d\n", + trace("Success 0x%08lx err %ld evtmask 0x%08lx diff1 %ld, diff2 %ld\n", success, err, evtmask, after-before, after1-before); - ok(evtmask & EV_BREAK, "Failed to detect EV_BREAK: 0x%08x, expected 0x%08x\n", + ok(evtmask & EV_BREAK, "Failed to detect EV_BREAK: 0x%08lx, expected 0x%08x\n", evtmask, EV_BREAK); ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n"); diff = after1 - before; ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA), - "Unexpected time %d, expected around %d\n", diff, TIMEOUT>>1); + "Unexpected time %ld, expected around %d\n", diff, TIMEOUT>>1); ok(ClearCommBreak(hcom), "ClearCommBreak failed\n"); @@ -1935,7 +1932,7 @@ static void test_stdio(void) /* cygwin tries this to determine the stdin handle type */ ok( !GetCommState( GetStdHandle(STD_INPUT_HANDLE), &dcb ), "GetCommState succeeded on stdin\n" ); ok( GetLastError() == ERROR_INVALID_HANDLE || GetLastError() == ERROR_INVALID_FUNCTION, - "got error %u\n", GetLastError() ); + "got error %lu\n", GetLastError() ); } static void test_WaitCommEvent(void) @@ -1950,10 +1947,10 @@ static void test_WaitCommEvent(void) test_GetModemStatus(hcom); ret = SetCommMask(hcom, 0x1fff); - ok(ret, "SetCommMask error %d\n", GetLastError()); + ok(ret, "SetCommMask error %ld\n", GetLastError()); - S(U(ovl_wait)).Offset = 0; - S(U(ovl_wait)).OffsetHigh = 0; + ovl_wait.Offset = 0; + ovl_wait.OffsetHigh = 0; ovl_wait.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); trace("waiting 10 secs for com port events (turn on/off the device)...\n"); @@ -1964,7 +1961,7 @@ static void test_WaitCommEvent(void) evtmask = 0; SetLastError(0xdeadbeef); ret = WaitCommEvent(hcom, &evtmask, &ovl_wait); - ok(!ret && GetLastError() == ERROR_IO_PENDING, "WaitCommEvent returned %d, error %d\n", ret, GetLastError()); + ok(!ret && GetLastError() == ERROR_IO_PENDING, "WaitCommEvent returned %ld, error %ld\n", ret, GetLastError()); if (GetLastError() != ERROR_IO_PENDING) goto done; /* no point in further testing */ for (;;) { @@ -1974,9 +1971,9 @@ static void test_WaitCommEvent(void) { last_event_time = after; ret = GetOverlappedResult(hcom, &ovl_wait, &bytes, FALSE); - ok(ret, "GetOverlappedResult reported error %d\n", GetLastError()); - ok(bytes == sizeof(evtmask), "expected %u, written %u\n", (UINT)sizeof(evtmask), bytes); - trace("WaitCommEvent: got events %#x\n", evtmask); + ok(ret, "GetOverlappedResult reported error %ld\n", GetLastError()); + ok(bytes == sizeof(evtmask), "expected %u, written %lu\n", (UINT)sizeof(evtmask), bytes); + trace("WaitCommEvent: got events %#lx\n", evtmask); test_GetModemStatus(hcom); break; } @@ -2002,17 +1999,17 @@ static void test_FlushFileBuffers(void) if (hcom == INVALID_HANDLE_VALUE) return; ret = WriteFile(hcom, "\0\0\0\0\0\0\0", 7, &bytes, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); - ok(bytes == 7, "expected 7, got %u\n", bytes); + ok(ret, "WriteFile error %ld\n", GetLastError()); + ok(bytes == 7, "expected 7, got %lu\n", bytes); ret = FlushFileBuffers(hcom); - ok(ret, "FlushFileBuffers error %d\n", GetLastError()); + ok(ret, "FlushFileBuffers error %ld\n", GetLastError()); ret = ClearCommError(hcom, &errors, &stat); - ok(ret, "ClearCommError error %d\n", GetLastError()); - ok(stat.cbInQue == 0, "expected 0, got %d bytes in InQueue\n", stat.cbInQue); - ok(stat.cbOutQue == 0, "expected 0, got %d bytes in OutQueue\n", stat.cbOutQue); - ok(errors == 0, "expected errors 0, got %#x\n", errors); + ok(ret, "ClearCommError error %ld\n", GetLastError()); + ok(stat.cbInQue == 0, "expected 0, got %ld bytes in InQueue\n", stat.cbInQue); + ok(stat.cbOutQue == 0, "expected 0, got %ld bytes in OutQueue\n", stat.cbOutQue); + ok(errors == 0, "expected errors 0, got %#lx\n", errors); CloseHandle(hcom); } @@ -2040,7 +2037,7 @@ static void test_read_write(void) if (hcom == INVALID_HANDLE_VALUE) return; ret = GetCommState(hcom, &dcb); - ok(ret, "GetCommState error %d\n", GetLastError()); + ok(ret, "GetCommState error %ld\n", GetLastError()); dcb.BaudRate = 9600; dcb.ByteSize = 8; dcb.Parity = NOPARITY; @@ -2048,55 +2045,55 @@ static void test_read_write(void) dcb.fDtrControl = DTR_CONTROL_ENABLE; dcb.StopBits = ONESTOPBIT; ret = SetCommState(hcom, &dcb); - ok(ret, "SetCommState error %d\n", GetLastError()); + ok(ret, "SetCommState error %ld\n", GetLastError()); memset(&timeouts, 0, sizeof(timeouts)); timeouts.ReadTotalTimeoutConstant = TIMEOUT; ret = SetCommTimeouts(hcom, &timeouts); - ok(ret,"SetCommTimeouts error %d\n", GetLastError()); + ok(ret,"SetCommTimeouts error %ld\n", GetLastError()); ret = SetupComm(hcom, 1024, 1024); - ok(ret, "SetUpComm error %d\n", GetLastError()); + ok(ret, "SetUpComm error %ld\n", GetLastError()); bytes = 0xdeadbeef; SetLastError(0xdeadbeef); ret = WriteFile(hcom, atz, 0, &bytes, NULL); ok(!ret, "WriteFile should fail\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); - ok(bytes == 0, "bytes %u\n", bytes); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); + ok(bytes == 0, "bytes %lu\n", bytes); - U(iob).Status = -1; + iob.Status = -1; iob.Information = -1; status = pNtWriteFile(hcom, 0, NULL, NULL, &iob, atz, 0, NULL, NULL); - ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got %#x\n", status); - ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status); - ok(iob.Information == -1, "expected -1, got %ld\n", iob.Information); + ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got %#lx\n", status); + ok(iob.Status == -1, "expected -1, got %#lx\n", iob.Status); + ok(iob.Information == -1, "expected -1, got %Id\n", iob.Information); for (i = -20; i < 20; i++) { - U(iob).Status = -1; + iob.Status = -1; iob.Information = -1; offset.QuadPart = (LONGLONG)i; status = pNtWriteFile(hcom, 0, NULL, NULL, &iob, atz, 0, &offset, NULL); if (i >= 0 || i == -1) { - ok(status == STATUS_SUCCESS, "%d: expected STATUS_SUCCESS, got %#x\n", i, status); - ok(U(iob).Status == STATUS_SUCCESS, "%d: expected STATUS_SUCCESS, got %#x\n", i, U(iob).Status); - ok(iob.Information == 0, "%d: expected 0, got %lu\n", i, iob.Information); + ok(status == STATUS_SUCCESS, "%ld: expected STATUS_SUCCESS, got %#lx\n", i, status); + ok(iob.Status == STATUS_SUCCESS, "%ld: expected STATUS_SUCCESS, got %#lx\n", i, iob.Status); + ok(iob.Information == 0, "%ld: expected 0, got %Iu\n", i, iob.Information); } else { - ok(status == STATUS_INVALID_PARAMETER, "%d: expected STATUS_INVALID_PARAMETER, got %#x\n", i, status); - ok(U(iob).Status == -1, "%d: expected -1, got %#x\n", i, U(iob).Status); - ok(iob.Information == -1, "%d: expected -1, got %ld\n", i, iob.Information); + ok(status == STATUS_INVALID_PARAMETER, "%ld: expected STATUS_INVALID_PARAMETER, got %#lx\n", i, status); + ok(iob.Status == -1, "%ld: expected -1, got %#lx\n", i, iob.Status); + ok(iob.Information == -1, "%ld: expected -1, got %Id\n", i, iob.Information); } } - U(iob).Status = -1; + iob.Status = -1; iob.Information = -1; offset.QuadPart = 0; status = pNtWriteFile(hcom, 0, NULL, NULL, &iob, atz, sizeof(atz), &offset, NULL); - ok(status == STATUS_PENDING || status == STATUS_SUCCESS, "expected STATUS_PENDING or STATUS_SUCCESS, got %#x\n", status); + ok(status == STATUS_PENDING || status == STATUS_SUCCESS, "expected STATUS_PENDING or STATUS_SUCCESS, got %#lx\n", status); /* Under Windows checking IO_STATUS_BLOCK right after the call leads * to races, iob.Status is either -1 or STATUS_SUCCESS, which means * that it's set only when the operation completes. @@ -2108,15 +2105,15 @@ static void test_read_write(void) CloseHandle(hcom); return; } - ok(ret == WAIT_OBJECT_0, "WaitForSingleObject error %d\n", ret); - ok(U(iob).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iob).Status); - ok(iob.Information == sizeof(atz), "expected sizeof(atz), got %lu\n", iob.Information); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject error %ld\n", ret); + ok(iob.Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#lx\n", iob.Status); + ok(iob.Information == sizeof(atz), "expected sizeof(atz), got %Iu\n", iob.Information); ret = SetCommMask(hcom, EV_RXCHAR); - ok(ret, "SetCommMask error %d\n", GetLastError()); + ok(ret, "SetCommMask error %ld\n", GetLastError()); - S(U(ovl_wait)).Offset = 0; - S(U(ovl_wait)).OffsetHigh = 0; + ovl_wait.Offset = 0; + ovl_wait.OffsetHigh = 0; ovl_wait.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); trace("waiting 3 secs for modem response...\n"); @@ -2127,7 +2124,7 @@ static void test_read_write(void) evtmask = 0; SetLastError(0xdeadbeef); ret = WaitCommEvent(hcom, &evtmask, &ovl_wait); - ok(!ret && GetLastError() == ERROR_IO_PENDING, "WaitCommEvent returned %d, error %d\n", ret, GetLastError()); + ok(!ret && GetLastError() == ERROR_IO_PENDING, "WaitCommEvent returned %ld, error %ld\n", ret, GetLastError()); if (GetLastError() != ERROR_IO_PENDING) goto done; /* no point in further testing */ for (;;) { @@ -2139,51 +2136,51 @@ static void test_read_write(void) last_event_time = after; ret = GetOverlappedResult(hcom, &ovl_wait, &bytes, FALSE); - ok(ret, "GetOverlappedResult reported error %d\n", GetLastError()); - ok(bytes == sizeof(evtmask), "expected sizeof(evtmask), got %u\n", bytes); + ok(ret, "GetOverlappedResult reported error %ld\n", GetLastError()); + ok(bytes == sizeof(evtmask), "expected sizeof(evtmask), got %lu\n", bytes); ok(evtmask & EV_RXCHAR, "EV_RXCHAR should be set\n"); bytes = 0xdeadbeef; SetLastError(0xdeadbeef); ret = ReadFile(hcom, buf, 0, &bytes, NULL); ok(!ret, "ReadFile should fail\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); - ok(bytes == 0, "bytes %u\n", bytes); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); + ok(bytes == 0, "bytes %lu\n", bytes); - U(iob).Status = -1; + iob.Status = -1; iob.Information = -1; status = pNtReadFile(hcom, 0, NULL, NULL, &iob, buf, 0, NULL, NULL); - ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got %#x\n", status); - ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status); - ok(iob.Information == -1, "expected -1, got %ld\n", iob.Information); + ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got %#lx\n", status); + ok(iob.Status == -1, "expected -1, got %#lx\n", iob.Status); + ok(iob.Information == -1, "expected -1, got %Id\n", iob.Information); for (i = -20; i < 20; i++) { - U(iob).Status = -1; + iob.Status = -1; iob.Information = -1; offset.QuadPart = (LONGLONG)i; status = pNtReadFile(hcom, 0, NULL, NULL, &iob, buf, 0, &offset, NULL); if (i >= 0) { - ok(status == STATUS_SUCCESS, "%d: expected STATUS_SUCCESS, got %#x\n", i, status); - ok(U(iob).Status == STATUS_SUCCESS, "%d: expected STATUS_SUCCESS, got %#x\n", i, U(iob).Status); - ok(iob.Information == 0, "%d: expected 0, got %lu\n", i, iob.Information); + ok(status == STATUS_SUCCESS, "%ld: expected STATUS_SUCCESS, got %#lx\n", i, status); + ok(iob.Status == STATUS_SUCCESS, "%ld: expected STATUS_SUCCESS, got %#lx\n", i, iob.Status); + ok(iob.Information == 0, "%ld: expected 0, got %Iu\n", i, iob.Information); } else { - ok(status == STATUS_INVALID_PARAMETER, "%d: expected STATUS_INVALID_PARAMETER, got %#x\n", i, status); - ok(U(iob).Status == -1, "%d: expected -1, got %#x\n", i, U(iob).Status); - ok(iob.Information == -1, "%d: expected -1, got %ld\n", i, iob.Information); + ok(status == STATUS_INVALID_PARAMETER, "%ld: expected STATUS_INVALID_PARAMETER, got %#lx\n", i, status); + ok(iob.Status == -1, "%ld: expected -1, got %#lx\n", i, iob.Status); + ok(iob.Information == -1, "%ld: expected -1, got %Id\n", i, iob.Information); } } - U(iob).Status = -1; + iob.Status = -1; iob.Information = -1; offset.QuadPart = 0; status = pNtReadFile(hcom, 0, NULL, NULL, &iob, buf, 1, &offset, NULL); - ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", status); - ok(U(iob).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iob).Status); - ok(iob.Information == 1, "expected 1, got %lu\n", iob.Information); + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#lx\n", status); + ok(iob.Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#lx\n", iob.Status); + ok(iob.Information == 1, "expected 1, got %Iu\n", iob.Information); goto done; } else diff --git a/modules/rostests/winetests/kernel32/console.c b/modules/rostests/winetests/kernel32/console.c index 926c0526864..ff5e453fc04 100644 --- a/modules/rostests/winetests/kernel32/console.c +++ b/modules/rostests/winetests/kernel32/console.c @@ -19,16 +19,28 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "wine/test.h" +#include +#define WIN32_NO_STATUS #include +#include +#include #include +#include "wine/test.h" +#ifdef __REACTOS__ +#include "winehacks.h" +#endif + +static void (WINAPI *pClosePseudoConsole)(HPCON); +static HRESULT (WINAPI *pCreatePseudoConsole)(COORD,HANDLE,HANDLE,DWORD,HPCON*); static BOOL (WINAPI *pGetConsoleInputExeNameA)(DWORD, LPSTR); static DWORD (WINAPI *pGetConsoleProcessList)(LPDWORD, DWORD); static HANDLE (WINAPI *pOpenConsoleW)(LPCWSTR,DWORD,BOOL,DWORD); static BOOL (WINAPI *pSetConsoleInputExeNameA)(LPCSTR); static BOOL (WINAPI *pVerifyConsoleIoHandle)(HANDLE handle); +static BOOL skip_nt; + /* DEFAULT_ATTRIB is used for all initial filling of the console. * all modifications are made with TEST_ATTRIB so that we could check * what has to be modified or not @@ -65,6 +77,8 @@ static void init_function_pointers(void) if(!p##func) trace("GetProcAddress(hKernel32, '%s') failed\n", #func); hKernel32 = GetModuleHandleA("kernel32.dll"); + KERNEL32_GET_PROC(ClosePseudoConsole); + KERNEL32_GET_PROC(CreatePseudoConsole); KERNEL32_GET_PROC(GetConsoleInputExeNameA); KERNEL32_GET_PROC(GetConsoleProcessList); KERNEL32_GET_PROC(OpenConsoleW); @@ -74,6 +88,25 @@ static void init_function_pointers(void) #undef KERNEL32_GET_PROC } +static HANDLE create_unbound_handle(BOOL output, BOOL test_status) +{ + OBJECT_ATTRIBUTES attr = {sizeof(attr)}; + IO_STATUS_BLOCK iosb; + UNICODE_STRING name; + HANDLE handle; + NTSTATUS status; + + attr.ObjectName = &name; + attr.Attributes = OBJ_INHERIT; + RtlInitUnicodeString( &name, output ? L"\\Device\\ConDrv\\Output" : L"\\Device\\ConDrv\\Input" ); + status = NtCreateFile( &handle, FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE | FILE_READ_ATTRIBUTES | + FILE_WRITE_ATTRIBUTES, &attr, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_CREATE, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 ); + if (test_status) ok(!status, "NtCreateFile failed: %#lx\n", status); + return status ? NULL : handle; +} + /* FIXME: this could be optimized on a speed point of view */ static void resetContent(HANDLE hCon, COORD sbSize, BOOL content) { @@ -93,13 +126,19 @@ static void resetContent(HANDLE hCon, COORD sbSize, BOOL content) } } +/* dummy console ctrl handler to test reset of ctrl handler's list */ +static BOOL WINAPI mydummych(DWORD event) +{ + return TRUE; +} + static void testCursor(HANDLE hCon, COORD sbSize) { COORD c; c.X = c.Y = 0; ok(SetConsoleCursorPosition(0, c) == 0, "No handle\n"); - ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %u\n", + ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %lu\n", ERROR_INVALID_HANDLE, GetLastError()); c.X = c.Y = 0; @@ -114,25 +153,25 @@ static void testCursor(HANDLE hCon, COORD sbSize) c.X = sbSize.X; c.Y = sbSize.Y - 1; ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %u\n", + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %lu\n", ERROR_INVALID_PARAMETER, GetLastError()); c.X = sbSize.X - 1; c.Y = sbSize.Y; ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %u\n", + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %lu\n", ERROR_INVALID_PARAMETER, GetLastError()); c.X = -1; c.Y = 0; ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %u\n", + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %lu\n", ERROR_INVALID_PARAMETER, GetLastError()); c.X = 0; c.Y = -1; ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %u\n", + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %lu\n", ERROR_INVALID_PARAMETER, GetLastError()); } @@ -140,11 +179,12 @@ static void testCursorInfo(HANDLE hCon) { BOOL ret; CONSOLE_CURSOR_INFO info; + HANDLE pipe1, pipe2; SetLastError(0xdeadbeef); ret = GetConsoleCursorInfo(NULL, NULL); ok(!ret, "Expected failure\n"); - ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %u\n", + ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %lu\n", ERROR_INVALID_HANDLE, GetLastError()); SetLastError(0xdeadbeef); @@ -152,7 +192,7 @@ static void testCursorInfo(HANDLE hCon) 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", + ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %lu\n", ERROR_INVALID_HANDLE, GetLastError()); /* Test the correct call first to distinguish between win9x and the rest */ @@ -161,11 +201,20 @@ static void testCursorInfo(HANDLE hCon) ok(ret, "Expected success\n"); ok(info.dwSize == 25 || info.dwSize == 12 /* win9x */, - "Expected 12 or 25, got %d\n", info.dwSize); + "Expected 12 or 25, got %ld\n", info.dwSize); ok(info.bVisible, "Expected the cursor to be visible\n"); - ok(GetLastError() == 0xdeadbeef, "GetLastError: expecting %u got %u\n", + ok(GetLastError() == 0xdeadbeef, "GetLastError: expecting %u got %lu\n", 0xdeadbeef, GetLastError()); + CreatePipe(&pipe1, &pipe2, NULL, 0); + info.dwSize = -1; + ret = GetConsoleCursorInfo(pipe1, &info); + ok(!ret, "Expected failure\n"); + ok(info.dwSize == -1, "Expected no change for dwSize\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: %lu\n", GetLastError()); + CloseHandle(pipe1); + CloseHandle(pipe2); + /* Don't test NULL CONSOLE_CURSOR_INFO, it crashes on win9x and win7 */ } @@ -208,19 +257,31 @@ static void testEmptyWrite(HANDLE hCon) okCURSOR(hCon, c); } -static void testWriteSimple(HANDLE hCon) +static void simple_write_console(HANDLE console, const char *text) { - COORD c; - DWORD len; - const char* mytest = "abcdefg"; - const int mylen = strlen(mytest); + DWORD len; + COORD c = {0, 0}; + BOOL ret; /* single line write */ c.X = c.Y = 0; - ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n"); + ok(SetConsoleCursorPosition(console, c) != 0, "Cursor in upper-left\n"); + + ret = WriteConsoleA(console, text, strlen(text), &len, NULL); + ok(ret, "WriteConsoleA failed: %lu\n", GetLastError()); + ok(len == strlen(text), "unexpected len %lu\n", len); +} + +static void testWriteSimple(HANDLE hCon) +{ + const char* mytest = "abcdefg"; + int mylen = strlen(mytest); + COORD c = {0, 0}; + DWORD len; + BOOL ret; + + simple_write_console(hCon, mytest); - ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n"); - c.Y = 0; for (c.X = 0; c.X < mylen; c.X++) { okCHAR(hCon, c, mytest[c.X], TEST_ATTRIB); @@ -228,6 +289,18 @@ static void testWriteSimple(HANDLE hCon) okCURSOR(hCon, c); okCHAR(hCon, c, ' ', DEFAULT_ATTRIB); + + ret = WriteFile(hCon, mytest, mylen, &len, NULL); + ok(ret, "WriteFile failed: %lu\n", GetLastError()); + ok(len == mylen, "unexpected len = %lu\n", len); + + for (c.X = 0; c.X < 2 * mylen; c.X++) + { + okCHAR(hCon, c, mytest[c.X % mylen], TEST_ATTRIB); + } + + okCURSOR(hCon, c); + okCHAR(hCon, c, ' ', DEFAULT_ATTRIB); } static void testWriteNotWrappedNotProcessed(HANDLE hCon, COORD sbSize) @@ -236,6 +309,7 @@ static void testWriteNotWrappedNotProcessed(HANDLE hCon, COORD sbSize) DWORD len, mode; const char* mytest = "123"; const int mylen = strlen(mytest); + char ctrl_buf[32]; int ret; int p; @@ -247,7 +321,7 @@ static void testWriteNotWrappedNotProcessed(HANDLE hCon, COORD sbSize) ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n"); ret = WriteConsoleA(hCon, mytest, mylen, &len, NULL); - ok(ret != 0 && len == mylen, "Couldn't write, ret = %d, len = %d\n", ret, len); + ok(ret != 0 && len == mylen, "Couldn't write, ret = %d, len = %ld\n", ret, len); c.Y = 0; for (p = mylen - 3; p < mylen; p++) { @@ -266,6 +340,17 @@ static void testWriteNotWrappedNotProcessed(HANDLE hCon, COORD sbSize) ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n"); ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n"); + + /* test how control chars are handled. */ + c.X = c.Y = 0; + ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n"); + for (p = 0; p < 32; p++) ctrl_buf[p] = (char)p; + ok(WriteConsoleA(hCon, ctrl_buf, 32, &len, NULL) != 0 && len == 32, "WriteConsole\n"); + for (p = 0; p < 32; p++) + { + c.X = p; c.Y = 0; + okCHAR(hCon, c, (char)p, TEST_ATTRIB); + } } static void testWriteNotWrappedProcessed(HANDLE hCon, COORD sbSize) @@ -278,7 +363,8 @@ static void testWriteNotWrappedProcessed(HANDLE hCon, COORD sbSize) int p; WORD attr; - ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, (mode | ENABLE_PROCESSED_OUTPUT) & ~ENABLE_WRAP_AT_EOL_OUTPUT), + ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, (mode | ENABLE_PROCESSED_OUTPUT) & + ~(ENABLE_WRAP_AT_EOL_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING)), "clearing wrap at EOL & setting processed output\n"); /* write line, wrapping disabled, buffer exceeds sb width */ @@ -597,9 +683,23 @@ static void testScroll(HANDLE hCon, COORD sbSize) { /* Win9x will fail, Only accept ERROR_NOT_ENOUGH_MEMORY */ ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY, - "Expected ERROR_NOT_ENOUGH_MEMORY, got %u\n", GetLastError()); + "Expected ERROR_NOT_ENOUGH_MEMORY, got %lu\n", GetLastError()); } + /* no clipping, src & dst rect do overlap */ + scroll.Left = 0; + scroll.Right = W - 1; + scroll.Top = 0; + scroll.Bottom = H - 1; + dst.X = W / 2 - 3; + dst.Y = H / 2 - 3; + ci.Char.UnicodeChar = '#'; + ci.Attributes = TEST_ATTRIB; + + ret = ScrollConsoleScreenBufferA(hCon, &scroll, NULL, dst, &ci); + ok(ret, "ScrollConsoleScreenBufferA failed: %lu\n", GetLastError()); + /* no win10 1909 error here, only check the result of the clipped case */ + /* clipping, src & dst rect do overlap */ resetContent(hCon, sbSize, TRUE); @@ -617,7 +717,14 @@ static void testScroll(HANDLE hCon, COORD sbSize) clip.Top = H / 2; clip.Bottom = min(H + H / 2, sbSize.Y - 1); - ok(ScrollConsoleScreenBufferA(hCon, &scroll, &clip, dst, &ci), "Scrolling SB\n"); + /* Windows 10 1909 fails if the destination is not in the clip rect + * but the result is still ok! + */ + SetLastError(0xdeadbeef); + ret = ScrollConsoleScreenBufferA(hCon, &scroll, &clip, dst, &ci); + ok((ret && GetLastError() == 0xdeadbeef) || + broken(!ret && GetLastError() == ERROR_INVALID_PARAMETER), + "ScrollConsoleScreenBufferA failed: %lu\n", GetLastError()); for (c.Y = 0; c.Y < sbSize.Y; c.Y++) { @@ -652,7 +759,7 @@ static BOOL WINAPI mch(DWORD event) static void testCtrlHandler(void) { ok(!SetConsoleCtrlHandler(mch, FALSE), "Shouldn't succeed\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "Bad error %u\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Bad error %lu\n", GetLastError()); ok(SetConsoleCtrlHandler(mch, TRUE), "Couldn't set handler\n"); /* wine requires the event for the test, as we cannot ensure, so far, that * events are processed synchronously in GenerateConsoleCtrlEvent() @@ -662,11 +769,22 @@ static void testCtrlHandler(void) ok(GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0), "Couldn't send ctrl-c event\n"); /* FIXME: it isn't synchronous on wine but it can still happen before we test */ if (0) ok(mch_count == 1, "Event isn't synchronous\n"); +#ifdef __REACTOS__ + DWORD res = WaitForSingleObject(mch_event, 3000); + ok(res == WAIT_OBJECT_0 || broken(res == WAIT_TIMEOUT) /* ROS testbots on Windows */, "event sending didn't work (%ld)\n", res); +#else ok(WaitForSingleObject(mch_event, 3000) == WAIT_OBJECT_0, "event sending didn't work\n"); +#endif CloseHandle(mch_event); + ok(SetConsoleCtrlHandler(NULL, FALSE), "Couldn't turn on ctrl-c handling\n"); + ok((RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags & 1) == 0, + "Unexpect ConsoleFlags value %lx\n", RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags); + /* Turning off ctrl-c handling doesn't work on win9x such way ... */ ok(SetConsoleCtrlHandler(NULL, TRUE), "Couldn't turn off ctrl-c handling\n"); + ok((RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags & 1) != 0, + "Unexpect ConsoleFlags value %lx\n", RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags); mch_event = CreateEventA(NULL, TRUE, FALSE, NULL); mch_count = 0; if(!(GetVersion() & 0x80000000)) @@ -676,7 +794,7 @@ static void testCtrlHandler(void) CloseHandle(mch_event); ok(SetConsoleCtrlHandler(mch, FALSE), "Couldn't remove handler\n"); ok(!SetConsoleCtrlHandler(mch, FALSE), "Shouldn't succeed\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "Bad error %u\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Bad error %lu\n", GetLastError()); } /* @@ -758,26 +876,26 @@ static void testScreenBuffer(HANDLE hConOut) ok(!SetConsoleActiveScreenBuffer(INVALID_HANDLE_VALUE), "Shouldn't succeed\n"); ok(GetLastError() == ERROR_INVALID_HANDLE, - "GetLastError: expecting %u got %u\n", + "GetLastError: expecting %u got %lu\n", ERROR_INVALID_HANDLE, GetLastError()); /* Trying to set non-console handles */ SetLastError(0); ok(!SetConsoleActiveScreenBuffer(hFileOutRW), "Shouldn't succeed\n"); ok(GetLastError() == ERROR_INVALID_HANDLE, - "GetLastError: expecting %u got %u\n", + "GetLastError: expecting %u got %lu\n", ERROR_INVALID_HANDLE, GetLastError()); SetLastError(0); ok(!SetConsoleActiveScreenBuffer(hFileOutRO), "Shouldn't succeed\n"); ok(GetLastError() == ERROR_INVALID_HANDLE, - "GetLastError: expecting %u got %u\n", + "GetLastError: expecting %u got %lu\n", ERROR_INVALID_HANDLE, GetLastError()); SetLastError(0); ok(!SetConsoleActiveScreenBuffer(hFileOutWT), "Shouldn't succeed\n"); ok(GetLastError() == ERROR_INVALID_HANDLE, - "GetLastError: expecting %u got %u\n", + "GetLastError: expecting %u got %lu\n", ERROR_INVALID_HANDLE, GetLastError()); /* trying to write non-console handle */ @@ -786,21 +904,21 @@ static void testScreenBuffer(HANDLE hConOut) error = GetLastError(); ok(!ret, "Shouldn't succeed\n"); ok(error == ERROR_INVALID_HANDLE || error == ERROR_INVALID_FUNCTION, - "GetLastError: got %u\n", error); + "GetLastError: got %lu\n", error); SetLastError(0xdeadbeef); ret = WriteConsoleA(hFileOutRO, test_str1, lstrlenA(test_str1), &len, NULL); error = GetLastError(); ok(!ret, "Shouldn't succeed\n"); ok(error == ERROR_INVALID_HANDLE || error == ERROR_INVALID_FUNCTION, - "GetLastError: got %u\n", error); + "GetLastError: got %lu\n", error); SetLastError(0xdeadbeef); ret = WriteConsoleA(hFileOutWT, test_str1, lstrlenA(test_str1), &len, NULL); error = GetLastError(); ok(!ret, "Shouldn't succeed\n"); - todo_wine ok(error == ERROR_INVALID_HANDLE || error == ERROR_INVALID_FUNCTION, - "GetLastError: got %u\n", error); + ok(error == ERROR_INVALID_HANDLE || error == ERROR_INVALID_FUNCTION, + "GetLastError: got %lu\n", error); CloseHandle(hFileOutRW); CloseHandle(hFileOutRO); @@ -809,9 +927,8 @@ static void testScreenBuffer(HANDLE hConOut) /* Trying to set SB handles with various access modes */ SetLastError(0); ok(!SetConsoleActiveScreenBuffer(hConOutRO), "Shouldn't succeed\n"); - ok(GetLastError() == ERROR_INVALID_HANDLE, - "GetLastError: expecting %u got %u\n", - ERROR_INVALID_HANDLE, GetLastError()); + ok(GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == ERROR_ACCESS_DENIED) /* win10 1809 */, + "unexpected last error %lu\n", GetLastError()); ok(SetConsoleActiveScreenBuffer(hConOutWT), "Couldn't set new WriteOnly SB\n"); @@ -854,10 +971,16 @@ static void testScreenBuffer(HANDLE hConOut) SetConsoleCursorPosition(hConOutRW, c); ret = WriteConsoleA(hConOutRW, test_cp866, lstrlenA(test_cp866), &len, NULL); ok(ret && len == lstrlenA(test_cp866), "WriteConsoleA failed\n"); - ret = ReadConsoleOutputCharacterW(hConOutRW, str_wbuf, lstrlenA(test_cp866), c, &len); - ok(ret && len == lstrlenA(test_cp866), "ReadConsoleOutputCharacterW failed\n"); - str_wbuf[lstrlenA(test_cp866)] = 0; - ok(!lstrcmpW(str_wbuf, test_unicode), "string does not match the pattern\n"); + ret = ReadConsoleOutputCharacterW(hConOutRW, str_wbuf, lstrlenW(test_unicode), c, &len); + /* Work around some broken results under Windows with some locale (ja, cn, ko...) + * Looks like a real bug in Win10 (at least). + */ + if (ret && broken(len == lstrlenW(test_unicode) / sizeof(WCHAR))) + ret = ReadConsoleOutputCharacterW(hConOutRW, str_wbuf, lstrlenW(test_unicode) * sizeof(WCHAR), c, &len); + ok(ret, "ReadConsoleOutputCharacterW failed\n"); + ok(len == lstrlenW(test_unicode), "unexpected len %lu %u\n", len, lstrlenW(test_unicode)); + ok(!memcmp(str_wbuf, test_unicode, lstrlenW(test_unicode) * sizeof(WCHAR)), + "string does not match the pattern\n"); /* * cp866 is OK, let's switch to cp1251. @@ -908,6 +1031,145 @@ static void testScreenBuffer(HANDLE hConOut) SetConsoleOutputCP(oldcp); } +static void test_new_screen_buffer_properties(HANDLE hConOut) +{ +#if defined(__REACTOS__) && DLL_EXPORT_VERSION < 0x600 + UNREFERENCED_PARAMETER(hConOut); + skip("Cannot build test_new_screen_buffer_properties() unless DLL_EXPORT_VERSION >= 0x600.\n"); +#else + BOOL ret; + HANDLE hConOut2; + CONSOLE_FONT_INFOEX cfi, cfi2; + CONSOLE_SCREEN_BUFFER_INFO csbi, csbi2; + + /* Font information */ + cfi.cbSize = cfi2.cbSize = sizeof(CONSOLE_FONT_INFOEX); + + ret = GetCurrentConsoleFontEx(hConOut, FALSE, &cfi); + ok(ret, "GetCurrentConsoleFontEx failed: error %lu\n", GetLastError()); + + hConOut2 = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE, 0, NULL, + CONSOLE_TEXTMODE_BUFFER, NULL); + ok(hConOut2 != INVALID_HANDLE_VALUE, "CreateConsoleScreenBuffer failed: error %lu\n", GetLastError()); + + ret = GetCurrentConsoleFontEx(hConOut2, FALSE, &cfi2); + ok(ret, "GetCurrentConsoleFontEx failed: error %lu\n", GetLastError()); + CloseHandle(hConOut2); + + ok(cfi2.nFont == cfi.nFont, "Font index should match: " + "got %lu, expected %lu\n", cfi2.nFont, cfi.nFont); + ok(cfi2.dwFontSize.X == cfi.dwFontSize.X, "Font width should match: " + "got %d, expected %d\n", cfi2.dwFontSize.X, cfi.dwFontSize.X); + ok(cfi2.dwFontSize.Y == cfi.dwFontSize.Y, "Font height should match: " + "got %d, expected %d\n", cfi2.dwFontSize.Y, cfi.dwFontSize.Y); + ok(cfi2.FontFamily == cfi.FontFamily, "Font family should match: " + "got %u, expected %u\n", cfi2.FontFamily, cfi.FontFamily); + ok(cfi2.FontWeight == cfi.FontWeight, "Font weight should match: " + "got %u, expected %u\n", cfi2.FontWeight, cfi.FontWeight); + ok(!lstrcmpW(cfi2.FaceName, cfi.FaceName), "Font name should match: " + "got %s, expected %s\n", wine_dbgstr_w(cfi2.FaceName), wine_dbgstr_w(cfi.FaceName)); + + /* Display window size */ + ret = GetConsoleScreenBufferInfo(hConOut, &csbi); + ok(ret, "GetConsoleScreenBufferInfo failed: error %lu\n", GetLastError()); + + hConOut2 = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE, 0, NULL, + CONSOLE_TEXTMODE_BUFFER, NULL); + ok(hConOut2 != INVALID_HANDLE_VALUE, "CreateConsoleScreenBuffer failed: error %lu\n", GetLastError()); + + ret = GetConsoleScreenBufferInfo(hConOut2, &csbi2); + ok(ret, "GetConsoleScreenBufferInfo failed: error %lu\n", GetLastError()); + CloseHandle(hConOut2); + + ok(csbi2.srWindow.Left == csbi.srWindow.Left, "Left coordinate should match\n"); + ok(csbi2.srWindow.Top == csbi.srWindow.Top, "Top coordinate should match\n"); + ok(csbi2.srWindow.Right == csbi.srWindow.Right, "Right coordinate should match\n"); + ok(csbi2.srWindow.Bottom == csbi.srWindow.Bottom, "Bottom coordinate should match\n"); +#endif +} + +static void test_new_screen_buffer_color_attributes(HANDLE hConOut) +{ +#if defined(__REACTOS__) && DLL_EXPORT_VERSION < 0x600 + UNREFERENCED_PARAMETER(hConOut); + skip("Cannot build test_new_screen_buffer_color_attributes() unless DLL_EXPORT_VERSION >= 0x600.\n"); +#else + CONSOLE_SCREEN_BUFFER_INFOEX csbi, csbi2; + BOOL ret; + HANDLE hConOut2; + WORD orig_attr, orig_popup, attr; + + csbi.cbSize = csbi2.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); + + ret = GetConsoleScreenBufferInfoEx(hConOut, &csbi); + ok(ret, "GetConsoleScreenBufferInfoEx failed: error %lu\n", GetLastError()); + orig_attr = csbi.wAttributes; + orig_popup = csbi.wPopupAttributes; + + hConOut2 = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE, 0, NULL, + CONSOLE_TEXTMODE_BUFFER, NULL); + ok(hConOut2 != INVALID_HANDLE_VALUE, "CreateConsoleScreenBuffer failed: error %lu\n", GetLastError()); + + ret = GetConsoleScreenBufferInfoEx(hConOut2, &csbi2); + ok(ret, "GetConsoleScreenBufferInfoEx failed: error %lu\n", GetLastError()); + CloseHandle(hConOut2); + + ok(csbi2.wAttributes == orig_attr, "Character Attributes should have been copied: " + "got %#x, expected %#x\n", csbi2.wAttributes, orig_attr); + ok(csbi2.wPopupAttributes != orig_popup, "Popup Attributes should not match original value\n"); + ok(csbi2.wPopupAttributes == orig_attr, "Popup Attributes should match Character Attributes\n"); + + /* Test different Character Attributes */ + attr = FOREGROUND_BLUE|BACKGROUND_GREEN; + ret = SetConsoleTextAttribute(hConOut, attr); + ok(ret, "SetConsoleTextAttribute failed: error %lu\n", GetLastError()); + + hConOut2 = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE, 0, NULL, + CONSOLE_TEXTMODE_BUFFER, NULL); + ok(hConOut2 != INVALID_HANDLE_VALUE, "CreateConsoleScreenBuffer failed: error %lu\n", GetLastError()); + + memset(&csbi2, 0, sizeof(CONSOLE_SCREEN_BUFFER_INFOEX)); + csbi2.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); + + ret = GetConsoleScreenBufferInfoEx(hConOut2, &csbi2); + ok(ret, "GetConsoleScreenBufferInfoEx failed: error %lu\n", GetLastError()); + CloseHandle(hConOut2); + + ok(csbi2.wAttributes == attr, "Character Attributes should have been copied: " + "got %#x, expected %#x\n", csbi2.wAttributes, attr); + ok(csbi2.wPopupAttributes != orig_popup, "Popup Attributes should not match original value\n"); + ok(csbi2.wPopupAttributes == attr, "Popup Attributes should match Character Attributes\n"); + + ret = SetConsoleTextAttribute(hConOut, orig_attr); + ok(ret, "SetConsoleTextAttribute failed: error %lu\n", GetLastError()); + + /* Test inheritance of different Popup Attributes */ + csbi.wPopupAttributes = attr; + ret = SetConsoleScreenBufferInfoEx(hConOut, &csbi); + ok(ret, "SetConsoleScreenBufferInfoEx failed: error %lu\n", GetLastError()); + + hConOut2 = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE, 0, NULL, + CONSOLE_TEXTMODE_BUFFER, NULL); + ok(hConOut2 != INVALID_HANDLE_VALUE, "CreateConsoleScreenBuffer failed: error %lu\n", GetLastError()); + + memset(&csbi2, 0, sizeof(CONSOLE_SCREEN_BUFFER_INFOEX)); + csbi2.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); + + ret = GetConsoleScreenBufferInfoEx(hConOut2, &csbi2); + ok(ret, "GetConsoleScreenBufferInfoEx failed: error %lu\n", GetLastError()); + CloseHandle(hConOut2); + + ok(csbi2.wAttributes == orig_attr, "Character Attributes should have been copied: " + "got %#x, expected %#x\n", csbi2.wAttributes, orig_attr); + ok(csbi2.wPopupAttributes != orig_popup, "Popup Attributes should not match original value\n"); + ok(csbi2.wPopupAttributes == orig_attr, "Popup Attributes should match Character Attributes\n"); + + csbi.wPopupAttributes = orig_popup; + ret = SetConsoleScreenBufferInfoEx(hConOut, &csbi); + ok(ret, "SetConsoleScreenBufferInfoEx failed: error %lu\n", GetLastError()); +#endif +} + static void CALLBACK signaled_function(void *p, BOOLEAN timeout) { HANDLE event = p; @@ -946,7 +1208,7 @@ static void testWaitForConsoleInput(HANDLE input_handle) /* If the callback is still running, this fails with ERROR_IO_PENDING, but that's ok and expected. */ ok(ret != 0 || GetLastError() == ERROR_IO_PENDING, - "UnregisterWait failed with error %d\n", GetLastError()); + "UnregisterWait failed with error %ld\n", GetLastError()); /* Test timeout case */ FlushConsoleInputBuffer(input_handle); @@ -954,12 +1216,133 @@ static void testWaitForConsoleInput(HANDLE input_handle) wait_ret = WaitForSingleObject(complete_event, 100); ok(wait_ret == WAIT_TIMEOUT, "Expected the wait to time out\n"); ret = UnregisterWait(wait_handle); - ok(ret, "UnregisterWait failed with error %d\n", GetLastError()); + ok(ret, "UnregisterWait failed with error %ld\n", GetLastError()); /* Clean up */ CloseHandle(complete_event); } +static BOOL filter_spurious_event(HANDLE input) +{ + INPUT_RECORD ir; + DWORD r; + + if (!ReadConsoleInputW(input, &ir, 1, &r) || r != 1) return FALSE; + + switch (ir.EventType) + { + case MOUSE_EVENT: + if (ir.Event.MouseEvent.dwEventFlags == MOUSE_MOVED) return TRUE; + ok(0, "Unexcepted mouse message: state=%lx ctrl=%lx flags=%lx (%u, %u)\n", + ir.Event.MouseEvent.dwButtonState, + ir.Event.MouseEvent.dwControlKeyState, + ir.Event.MouseEvent.dwEventFlags, + ir.Event.MouseEvent.dwMousePosition.X, + ir.Event.MouseEvent.dwMousePosition.Y); + break; + case WINDOW_BUFFER_SIZE_EVENT: + return TRUE; + default: + ok(0, "Unexpected message %u\n", ir.EventType); + } + return FALSE; +} + +static void test_wait(HANDLE input, HANDLE orig_output) +{ + HANDLE output, unbound_output, unbound_input; + LARGE_INTEGER zero; + INPUT_RECORD ir; + DWORD res, count; + NTSTATUS status; + BOOL ret; + + if (skip_nt) return; + + memset(&ir, 0, sizeof(ir)); + ir.EventType = MOUSE_EVENT; + ir.Event.MouseEvent.dwEventFlags = MOUSE_MOVED; + zero.QuadPart = 0; + + output = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + CONSOLE_TEXTMODE_BUFFER, NULL); + ok(output != INVALID_HANDLE_VALUE, "CreateConsoleScreenBuffer failed: %lu\n", GetLastError()); + + ret = SetConsoleActiveScreenBuffer(output); + ok(ret, "SetConsoleActiveScreenBuffer failed: %lu\n", GetLastError()); + ret = FlushConsoleInputBuffer(input); + ok(ret, "FlushConsoleInputBuffer failed: %lu\n", GetLastError()); + + unbound_output = create_unbound_handle(TRUE, TRUE); + unbound_input = create_unbound_handle(FALSE, TRUE); + + while ((res = WaitForSingleObject(input, 0)) == WAIT_OBJECT_0) + { + if (!filter_spurious_event(input)) break; + } + ok(res == WAIT_TIMEOUT, "WaitForSingleObject returned %lx\n", res); + while ((res = WaitForSingleObject(output, 0)) == WAIT_OBJECT_0) + { + if (!filter_spurious_event(input)) break; + } + ok(res == WAIT_TIMEOUT, "WaitForSingleObject returned %lx\n", res); + while ((res = WaitForSingleObject(orig_output, 0)) == WAIT_OBJECT_0) + { + if (!filter_spurious_event(input)) break; + } + ok(res == WAIT_TIMEOUT, "WaitForSingleObject returned %lx\n", res); + while ((res = WaitForSingleObject(unbound_output, 0)) == WAIT_OBJECT_0) + { + if (!filter_spurious_event(unbound_input)) break; + } + ok(res == WAIT_TIMEOUT, "WaitForSingleObject returned %lx\n", res); + while ((res = WaitForSingleObject(unbound_input, 0)) == WAIT_OBJECT_0) + { + if (!filter_spurious_event(unbound_input)) break; + } + ok(res == WAIT_TIMEOUT, "WaitForSingleObject returned %lx\n", res); + while ((status = NtWaitForSingleObject(input, FALSE, &zero)) == STATUS_SUCCESS) + { + if (!filter_spurious_event(input)) break; + } + ok(status == STATUS_TIMEOUT || broken(status == STATUS_ACCESS_DENIED /* win2k8 */), + "NtWaitForSingleObject returned %lx\n", status); + while ((status = NtWaitForSingleObject(output, FALSE, &zero)) == STATUS_SUCCESS) + { + if (!filter_spurious_event(input)) break; + } + ok(status == STATUS_TIMEOUT || broken(status == STATUS_ACCESS_DENIED /* win2k8 */), + "NtWaitForSingleObject returned %lx\n", status); + + ret = WriteConsoleInputW(input, &ir, 1, &count); + ok(ret, "WriteConsoleInputW failed: %lu\n", GetLastError()); + + res = WaitForSingleObject(input, 0); + ok(!res, "WaitForSingleObject returned %lx\n", res); + res = WaitForSingleObject(output, 0); + ok(!res, "WaitForSingleObject returned %lx\n", res); + res = WaitForSingleObject(orig_output, 0); + ok(!res, "WaitForSingleObject returned %lx\n", res); + res = WaitForSingleObject(unbound_output, 0); + ok(!res, "WaitForSingleObject returned %lx\n", res); + res = WaitForSingleObject(unbound_input, 0); + ok(!res, "WaitForSingleObject returned %lx\n", res); + status = NtWaitForSingleObject(input, FALSE, &zero); + ok(!status || broken(status == STATUS_ACCESS_DENIED /* win2k8 */), + "NtWaitForSingleObject returned %lx\n", status); + status = NtWaitForSingleObject(output, FALSE, &zero); + ok(!status || broken(status == STATUS_ACCESS_DENIED /* win2k8 */), + "NtWaitForSingleObject returned %lx\n", status); + + ret = SetConsoleActiveScreenBuffer(orig_output); + ok(ret, "SetConsoleActiveScreenBuffer failed: %lu\n", GetLastError()); + + CloseHandle(unbound_input); + CloseHandle(unbound_output); + CloseHandle(output); +} + static void test_GetSetConsoleInputExeName(void) { BOOL ret; @@ -971,18 +1354,18 @@ static void test_GetSetConsoleInputExeName(void) ret = pGetConsoleInputExeNameA(0, NULL); error = GetLastError(); ok(ret, "GetConsoleInputExeNameA failed\n"); - ok(error == ERROR_BUFFER_OVERFLOW, "got %u expected ERROR_BUFFER_OVERFLOW\n", error); + ok(error == ERROR_BUFFER_OVERFLOW, "got %lu expected ERROR_BUFFER_OVERFLOW\n", error); SetLastError(0xdeadbeef); ret = pGetConsoleInputExeNameA(0, buffer); error = GetLastError(); ok(ret, "GetConsoleInputExeNameA failed\n"); - ok(error == ERROR_BUFFER_OVERFLOW, "got %u expected ERROR_BUFFER_OVERFLOW\n", error); + ok(error == ERROR_BUFFER_OVERFLOW, "got %lu expected ERROR_BUFFER_OVERFLOW\n", error); GetModuleFileNameA(GetModuleHandleA(NULL), module, sizeof(module)); p = strrchr(module, '\\') + 1; - ret = pGetConsoleInputExeNameA(sizeof(buffer)/sizeof(buffer[0]), buffer); + ret = pGetConsoleInputExeNameA(ARRAY_SIZE(buffer), buffer); ok(ret, "GetConsoleInputExeNameA failed\n"); todo_wine ok(!lstrcmpA(buffer, p), "got %s expected %s\n", buffer, p); @@ -990,18 +1373,18 @@ static void test_GetSetConsoleInputExeName(void) ret = pSetConsoleInputExeNameA(NULL); error = GetLastError(); ok(!ret, "SetConsoleInputExeNameA failed\n"); - ok(error == ERROR_INVALID_PARAMETER, "got %u expected ERROR_INVALID_PARAMETER\n", error); + ok(error == ERROR_INVALID_PARAMETER, "got %lu expected ERROR_INVALID_PARAMETER\n", error); SetLastError(0xdeadbeef); ret = pSetConsoleInputExeNameA(""); error = GetLastError(); ok(!ret, "SetConsoleInputExeNameA failed\n"); - ok(error == ERROR_INVALID_PARAMETER, "got %u expected ERROR_INVALID_PARAMETER\n", error); + ok(error == ERROR_INVALID_PARAMETER, "got %lu expected ERROR_INVALID_PARAMETER\n", error); ret = pSetConsoleInputExeNameA(input_exe); ok(ret, "SetConsoleInputExeNameA failed\n"); - ret = pGetConsoleInputExeNameA(sizeof(buffer)/sizeof(buffer[0]), buffer); + ret = pGetConsoleInputExeNameA(ARRAY_SIZE(buffer), buffer); ok(ret, "GetConsoleInputExeNameA failed\n"); ok(!lstrcmpA(buffer, input_exe), "got %s expected %s\n", buffer, input_exe); } @@ -1020,19 +1403,19 @@ static void test_GetConsoleProcessList(void) ret = pGetConsoleProcessList(NULL, 0); ok(ret == 0, "Expected failure\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = pGetConsoleProcessList(NULL, 1); ok(ret == 0, "Expected failure\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); /* We should only have 1 process but only for these specific unit tests as - * we created our own console. An AttachConsole(ATTACH_PARENT_PROCESS) would - * give us two processes for example. + * we created our own console. An AttachConsole(ATTACH_PARENT_PROCESS) + * gives us two processes - see test_AttachConsole. */ list = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD)); @@ -1040,13 +1423,12 @@ static void test_GetConsoleProcessList(void) ret = pGetConsoleProcessList(list, 0); ok(ret == 0, "Expected failure\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = pGetConsoleProcessList(list, 1); - todo_wine - ok(ret == 1, "Expected 1, got %d\n", ret); + ok(ret == 1, "Expected 1, got %ld\n", ret); HeapFree(GetProcessHeap(), 0, list); @@ -1054,13 +1436,12 @@ static void test_GetConsoleProcessList(void) SetLastError(0xdeadbeef); ret = pGetConsoleProcessList(list, ret); - todo_wine - ok(ret == 1, "Expected 1, got %d\n", ret); + ok(ret == 1, "Expected 1, got %ld\n", ret); if (ret == 1) { DWORD pid = GetCurrentProcessId(); - ok(list[0] == pid, "Expected %d, got %d\n", pid, list[0]); + ok(list[0] == pid, "Expected %ld, got %ld\n", pid, list[0]); } HeapFree(GetProcessHeap(), 0, list); @@ -1074,11 +1455,11 @@ static void test_OpenCON(void) unsigned i; HANDLE h; - for (i = 0; i < sizeof(accesses) / sizeof(accesses[0]); i++) + for (i = 0; i < ARRAY_SIZE(accesses); i++) { h = CreateFileW(conW, GENERIC_WRITE, 0, NULL, accesses[i], 0, NULL); ok(h != INVALID_HANDLE_VALUE || broken(accesses[i] == TRUNCATE_EXISTING /* Win8 */), - "Expected to open the CON device on write (%x)\n", accesses[i]); + "Expected to open the CON device on write (%lx)\n", accesses[i]); CloseHandle(h); h = CreateFileW(conW, GENERIC_READ, 0, NULL, accesses[i], 0, NULL); @@ -1088,12 +1469,12 @@ static void test_OpenCON(void) * So don't test when disposition is TRUNCATE_EXISTING */ ok(h != INVALID_HANDLE_VALUE || broken(accesses[i] == TRUNCATE_EXISTING /* Win7+ */), - "Expected to open the CON device on read (%x)\n", accesses[i]); + "Expected to open the CON device on read (%lx)\n", accesses[i]); CloseHandle(h); h = CreateFileW(conW, GENERIC_READ|GENERIC_WRITE, 0, NULL, accesses[i], 0, NULL); - ok(h == INVALID_HANDLE_VALUE, "Expected not to open the CON device on read-write (%x)\n", accesses[i]); + ok(h == INVALID_HANDLE_VALUE, "Expected not to open the CON device on read-write (%lx)\n", accesses[i]); ok(GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_INVALID_PARAMETER, - "Unexpected error %x\n", GetLastError()); + "Unexpected error %lx\n", GetLastError()); } } @@ -1179,7 +1560,7 @@ static void test_OpenConsoleW(void) return; } - for (index = 0; index < sizeof(invalid_table)/sizeof(invalid_table[0]); index++) + for (index = 0; index < ARRAY_SIZE(invalid_table); index++) { SetLastError(0xdeadbeef); ret = pOpenConsoleW(invalid_table[index].name, invalid_table[index].access, @@ -1189,11 +1570,11 @@ static void test_OpenConsoleW(void) "Expected OpenConsoleW to return INVALID_HANDLE_VALUE for index %d, got %p\n", index, ret); ok(gle == invalid_table[index].gle || (gle != 0 && gle == invalid_table[index].gle2), - "Expected GetLastError() to return %u/%u for index %d, got %u\n", + "Expected GetLastError() to return %lu/%lu for index %d, got %lu\n", invalid_table[index].gle, invalid_table[index].gle2, index, gle); } - for (index = 0; index < sizeof(valid_table)/sizeof(valid_table[0]); index++) + for (index = 0; index < ARRAY_SIZE(valid_table); index++) { ret = pOpenConsoleW(valid_table[index].name, valid_table[index].access, valid_table[index].inherit, valid_table[index].creation); @@ -1217,38 +1598,48 @@ static void test_OpenConsoleW(void) static void test_CreateFileW(void) { - static const WCHAR coninW[] = {'C','O','N','I','N','$',0}; - static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0}; - static const struct { - LPCWSTR name; + BOOL input; DWORD access; BOOL inherit; DWORD creation; DWORD gle; BOOL is_broken; } cf_table[] = { - {coninW, 0, FALSE, 0, ERROR_INVALID_PARAMETER, TRUE}, - {coninW, 0, FALSE, OPEN_ALWAYS, 0, FALSE}, - {coninW, GENERIC_READ | GENERIC_WRITE, FALSE, 0, ERROR_INVALID_PARAMETER, TRUE}, - {coninW, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_NEW, 0, FALSE}, - {coninW, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_ALWAYS, 0, FALSE}, - {coninW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS, 0, FALSE}, - {conoutW, 0, FALSE, 0, ERROR_INVALID_PARAMETER, TRUE}, - {conoutW, 0, FALSE, OPEN_ALWAYS, 0, FALSE}, - {conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, 0, ERROR_INVALID_PARAMETER, TRUE}, - {conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_NEW, 0, FALSE}, - {conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_ALWAYS, 0, FALSE}, - {conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS, 0, FALSE}, + {TRUE, 0, FALSE, OPEN_ALWAYS, 0, FALSE}, + {TRUE, GENERIC_READ | GENERIC_WRITE, FALSE, 0, ERROR_INVALID_PARAMETER, TRUE}, + {TRUE, 0, FALSE, 0, ERROR_INVALID_PARAMETER, TRUE}, + {TRUE, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_NEW, 0, FALSE}, + {TRUE, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_ALWAYS, 0, FALSE}, + {TRUE, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS, 0, FALSE}, + {FALSE, 0, FALSE, 0, ERROR_INVALID_PARAMETER, TRUE}, + {FALSE, 0, FALSE, OPEN_ALWAYS, 0, FALSE}, + {FALSE, GENERIC_READ | GENERIC_WRITE, FALSE, 0, ERROR_INVALID_PARAMETER, TRUE}, + {FALSE, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_NEW, 0, FALSE}, + {FALSE, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_ALWAYS, 0, FALSE}, + {FALSE, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS, 0, FALSE}, /* TRUNCATE_EXISTING is forbidden starting with Windows 8 */ }; + static const UINT nt_disposition[5] = + { + FILE_CREATE, /* CREATE_NEW */ + FILE_OVERWRITE_IF, /* CREATE_ALWAYS */ + FILE_OPEN, /* OPEN_EXISTING */ + FILE_OPEN_IF, /* OPEN_ALWAYS */ + FILE_OVERWRITE /* TRUNCATE_EXISTING */ + }; + int index; HANDLE ret; SECURITY_ATTRIBUTES sa; + OBJECT_ATTRIBUTES attr = {sizeof(attr)}; + UNICODE_STRING string; + IO_STATUS_BLOCK iosb; + NTSTATUS status; - for (index = 0; index < sizeof(cf_table)/sizeof(cf_table[0]); index++) + for (index = 0; index < ARRAY_SIZE(cf_table); index++) { SetLastError(0xdeadbeef); @@ -1256,7 +1647,7 @@ static void test_CreateFileW(void) sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = cf_table[index].inherit; - ret = CreateFileW(cf_table[index].name, cf_table[index].access, + ret = CreateFileW(cf_table[index].input ? L"CONIN$" : L"CONOUT$", cf_table[index].access, FILE_SHARE_READ|FILE_SHARE_WRITE, &sa, cf_table[index].creation, FILE_ATTRIBUTE_NORMAL, NULL); if (ret == INVALID_HANDLE_VALUE) @@ -1264,7 +1655,7 @@ static void test_CreateFileW(void) ok(cf_table[index].gle, "Expected CreateFileW not to return INVALID_HANDLE_VALUE for index %d\n", index); ok(GetLastError() == cf_table[index].gle, - "Expected GetLastError() to return %u for index %d, got %u\n", + "Expected GetLastError() to return %lu for index %d, got %lu\n", cf_table[index].gle, index, GetLastError()); } else @@ -1273,6 +1664,44 @@ static void test_CreateFileW(void) "Expected CreateFileW to succeed for index %d\n", index); CloseHandle(ret); } + + if (skip_nt) continue; + + SetLastError(0xdeadbeef); + + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = cf_table[index].inherit; + + ret = CreateFileW(cf_table[index].input ? L"\\??\\CONIN$" : L"\\??\\CONOUT$", cf_table[index].access, + FILE_SHARE_READ|FILE_SHARE_WRITE, &sa, + cf_table[index].creation, FILE_ATTRIBUTE_NORMAL, NULL); + if (cf_table[index].gle) + ok(ret == INVALID_HANDLE_VALUE && GetLastError() == cf_table[index].gle, + "CreateFileW to returned %p %lu for index %d\n", ret, GetLastError(), index); + else + ok(ret != INVALID_HANDLE_VALUE && (!cf_table[index].gle || broken(cf_table[index].is_broken) /* Win7 */), + "CreateFileW to returned %p %lu for index %d\n", ret, GetLastError(), index); + if (ret != INVALID_HANDLE_VALUE) CloseHandle(ret); + + if (cf_table[index].gle) continue; + + RtlInitUnicodeString(&string, cf_table[index].input + ? L"\\Device\\ConDrv\\CurrentIn" : L"\\Device\\ConDrv\\CurrentOut"); + attr.ObjectName = &string; + status = NtCreateFile(&ret, cf_table[index].access | SYNCHRONIZE | FILE_READ_ATTRIBUTES, &attr, &iosb, NULL, + FILE_ATTRIBUTE_NORMAL, 0, nt_disposition[cf_table[index].creation - CREATE_NEW], + FILE_NON_DIRECTORY_FILE, NULL, 0); + ok(!status, "NtCreateFile failed %lx for %u\n", status, index); + CloseHandle(ret); + + RtlInitUnicodeString(&string, cf_table[index].input ? L"\\??\\CONIN$" : L"\\??\\CONOUT$"); + attr.ObjectName = &string; + status = NtCreateFile(&ret, cf_table[index].access | SYNCHRONIZE | FILE_READ_ATTRIBUTES, &attr, &iosb, NULL, + FILE_ATTRIBUTE_NORMAL, 0, nt_disposition[cf_table[index].creation - CREATE_NEW], + FILE_NON_DIRECTORY_FILE, NULL, 0); + ok(!status, "NtCreateFile failed %lx for %u\n", status, index); + CloseHandle(ret); } } @@ -1292,28 +1721,28 @@ static void test_VerifyConsoleIoHandle( HANDLE handle ) ret = pVerifyConsoleIoHandle((HANDLE)0xdeadbee0); error = GetLastError(); ok(!ret, "expected VerifyConsoleIoHandle to fail\n"); - ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error); + ok(error == 0xdeadbeef, "wrong GetLastError() %ld\n", error); /* invalid handle + 1 */ SetLastError(0xdeadbeef); ret = pVerifyConsoleIoHandle((HANDLE)0xdeadbee1); error = GetLastError(); ok(!ret, "expected VerifyConsoleIoHandle to fail\n"); - ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error); + ok(error == 0xdeadbeef, "wrong GetLastError() %ld\n", error); /* invalid handle + 2 */ SetLastError(0xdeadbeef); ret = pVerifyConsoleIoHandle((HANDLE)0xdeadbee2); error = GetLastError(); ok(!ret, "expected VerifyConsoleIoHandle to fail\n"); - ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error); + ok(error == 0xdeadbeef, "wrong GetLastError() %ld\n", error); /* invalid handle + 3 */ SetLastError(0xdeadbeef); ret = pVerifyConsoleIoHandle((HANDLE)0xdeadbee3); error = GetLastError(); ok(!ret, "expected VerifyConsoleIoHandle to fail\n"); - ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error); + ok(error == 0xdeadbeef, "wrong GetLastError() %ld\n", error); /* valid handle */ SetLastError(0xdeadbeef); @@ -1322,7 +1751,7 @@ static void test_VerifyConsoleIoHandle( HANDLE handle ) ok(ret || broken(!ret), /* Windows 8 and 10 */ "expected VerifyConsoleIoHandle to succeed\n"); - ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error); + ok(error == 0xdeadbeef, "wrong GetLastError() %ld\n", error); } static void test_GetSetStdHandle(void) @@ -1336,14 +1765,14 @@ static void test_GetSetStdHandle(void) handle = GetStdHandle(42); error = GetLastError(); ok(error == ERROR_INVALID_HANDLE || broken(error == ERROR_INVALID_FUNCTION)/* Win9x */, - "wrong GetLastError() %d\n", error); + "wrong GetLastError() %ld\n", error); ok(handle == INVALID_HANDLE_VALUE, "expected INVALID_HANDLE_VALUE\n"); /* get valid */ SetLastError(0xdeadbeef); handle = GetStdHandle(STD_INPUT_HANDLE); error = GetLastError(); - ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error); + ok(error == 0xdeadbeef, "wrong GetLastError() %ld\n", error); /* set invalid std handle */ SetLastError(0xdeadbeef); @@ -1351,14 +1780,40 @@ static void test_GetSetStdHandle(void) error = GetLastError(); ok(!ret, "expected SetStdHandle to fail\n"); ok(error == ERROR_INVALID_HANDLE || broken(error == ERROR_INVALID_FUNCTION)/* Win9x */, - "wrong GetLastError() %d\n", error); + "wrong GetLastError() %ld\n", error); /* set valid (restore old value) */ SetLastError(0xdeadbeef); ret = SetStdHandle(STD_INPUT_HANDLE, handle); error = GetLastError(); ok(ret, "expected SetStdHandle to succeed\n"); - ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error); + ok(error == 0xdeadbeef, "wrong GetLastError() %ld\n", error); +} + +static void test_DuplicateConsoleHandle(void) +{ + HANDLE handle, event; + BOOL ret; + + if (skip_nt) return; + + event = CreateEventW(NULL, TRUE, FALSE, NULL); + + /* duplicate an event handle with DuplicateConsoleHandle */ + handle = DuplicateConsoleHandle(event, 0, FALSE, DUPLICATE_SAME_ACCESS); + ok(handle != NULL, "DuplicateConsoleHandle failed: %lu\n", GetLastError()); + + ret = SetEvent(handle); + ok(ret, "SetEvent failed: %lu\n", GetLastError()); + + ret = CloseConsoleHandle(handle); + ok(ret, "CloseConsoleHandle failed: %lu\n", GetLastError()); + ret = CloseConsoleHandle(event); + ok(ret, "CloseConsoleHandle failed: %lu\n", GetLastError()); + + handle = DuplicateConsoleHandle((HANDLE)0xdeadbeef, 0, FALSE, DUPLICATE_SAME_ACCESS); + ok(handle == INVALID_HANDLE_VALUE, "DuplicateConsoleHandle failed: %lu\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HANDLE, "last error = %lu\n", GetLastError()); } static void test_GetNumberOfConsoleInputEvents(HANDLE input_handle) @@ -1380,7 +1835,7 @@ static void test_GetNumberOfConsoleInputEvents(HANDLE input_handle) {INVALID_HANDLE_VALUE, &count, ERROR_INVALID_HANDLE}, }; - for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++) + for (i = 0; i < ARRAY_SIZE(invalid_table); i++) { SetLastError(0xdeadbeef); if (invalid_table[i].nrofevents) count = 0xdeadbeef; @@ -1390,10 +1845,10 @@ static void test_GetNumberOfConsoleInputEvents(HANDLE input_handle) if (invalid_table[i].nrofevents) { ok(count == 0xdeadbeef, - "[%d] Expected output count to be unmodified, got %u\n", i, count); + "[%d] Expected output count to be unmodified, got %lu\n", i, count); } ok(GetLastError() == invalid_table[i].last_error, - "[%d] Expected last error to be %u, got %u\n", + "[%d] Expected last error to be %lu, got %lu\n", i, invalid_table[i].last_error, GetLastError()); } @@ -1404,7 +1859,7 @@ static void test_GetNumberOfConsoleInputEvents(HANDLE input_handle) ret = GetNumberOfConsoleInputEvents(input_handle, NULL); ok(!ret, "Expected GetNumberOfConsoleInputEvents to return FALSE, got %d\n", ret); ok(GetLastError() == ERROR_INVALID_ACCESS, - "Expected last error to be ERROR_INVALID_ACCESS, got %u\n", + "Expected last error to be ERROR_INVALID_ACCESS, got %lu\n", GetLastError()); } @@ -1462,7 +1917,7 @@ static void test_WriteConsoleInputA(HANDLE input_handle) ok(ret == TRUE, "Expected GetConsoleMode to return TRUE, got %d\n", ret); if (!ret) { - skip("GetConsoleMode failed with last error %u\n", GetLastError()); + skip("GetConsoleMode failed with last error %lu\n", GetLastError()); return; } @@ -1470,7 +1925,7 @@ static void test_WriteConsoleInputA(HANDLE input_handle) ok(ret == TRUE, "Expected SetConsoleMode to return TRUE, got %d\n", ret); if (!ret) { - skip("SetConsoleMode failed with last error %u\n", GetLastError()); + skip("SetConsoleMode failed with last error %lu\n", GetLastError()); return; } @@ -1481,7 +1936,7 @@ static void test_WriteConsoleInputA(HANDLE input_handle) event.EventType = MOUSE_EVENT; event.Event.MouseEvent = mouse_event; - for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++) + for (i = 0; i < ARRAY_SIZE(invalid_table); i++) { if (invalid_table[i].win_crash) continue; @@ -1495,24 +1950,24 @@ static void test_WriteConsoleInputA(HANDLE input_handle) ok(!ret, "[%d] Expected WriteConsoleInputA to return FALSE, got %d\n", i, ret); gle = GetLastError(); ok(gle == invalid_table[i].gle || (gle != 0 && gle == invalid_table[i].gle2), - "[%d] Expected last error to be %u or %u, got %u\n", + "[%d] Expected last error to be %lu or %lu, got %lu\n", i, invalid_table[i].gle, invalid_table[i].gle2, gle); } count = 0xdeadbeef; ret = WriteConsoleInputA(input_handle, NULL, 0, &count); ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret); - ok(count == 0, "Expected count to be 0, got %u\n", count); + ok(count == 0, "Expected count to be 0, got %lu\n", count); count = 0xdeadbeef; ret = WriteConsoleInputA(input_handle, &event, 0, &count); ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret); - ok(count == 0, "Expected count to be 0, got %u\n", count); + ok(count == 0, "Expected count to be 0, got %lu\n", count); count = 0xdeadbeef; ret = WriteConsoleInputA(input_handle, &event, 1, &count); ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); ret = FlushConsoleInputBuffer(input_handle); ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret); @@ -1523,61 +1978,61 @@ static void test_WriteConsoleInputA(HANDLE input_handle) ret = WriteConsoleInputA(input_handle, &event, 1, &count); ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); ret = GetNumberOfConsoleInputEvents(input_handle, &count); ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); ret = WriteConsoleInputA(input_handle, &event, 1, &count); ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); ret = GetNumberOfConsoleInputEvents(input_handle, &count); ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret); todo_wine - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); ret = FlushConsoleInputBuffer(input_handle); ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret); - for (i = 0; i < sizeof(event_list)/sizeof(event_list[0]); i++) + for (i = 0; i < ARRAY_SIZE(event_list); i++) { event_list[i].EventType = MOUSE_EVENT; event_list[i].Event.MouseEvent = mouse_event; } /* Writing consecutive chunks of mouse events appears to work. */ - ret = WriteConsoleInputA(input_handle, event_list, sizeof(event_list)/sizeof(event_list[0]), &count); + ret = WriteConsoleInputA(input_handle, event_list, ARRAY_SIZE(event_list), &count); ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret); - ok(count == sizeof(event_list)/sizeof(event_list[0]), - "Expected count to be event list length, got %u\n", count); + ok(count == ARRAY_SIZE(event_list), + "Expected count to be event list length, got %lu\n", count); ret = GetNumberOfConsoleInputEvents(input_handle, &count); ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret); - ok(count == sizeof(event_list)/sizeof(event_list[0]), - "Expected count to be event list length, got %u\n", count); + ok(count == ARRAY_SIZE(event_list), + "Expected count to be event list length, got %lu\n", count); - ret = WriteConsoleInputA(input_handle, event_list, sizeof(event_list)/sizeof(event_list[0]), &count); + ret = WriteConsoleInputA(input_handle, event_list, ARRAY_SIZE(event_list), &count); ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret); - ok(count == sizeof(event_list)/sizeof(event_list[0]), - "Expected count to be event list length, got %u\n", count); + ok(count == ARRAY_SIZE(event_list), + "Expected count to be event list length, got %lu\n", count); ret = GetNumberOfConsoleInputEvents(input_handle, &count); ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret); - ok(count == 2*sizeof(event_list)/sizeof(event_list[0]), - "Expected count to be twice event list length, got %u\n", count); + ok(count == 2*ARRAY_SIZE(event_list), + "Expected count to be twice event list length, got %lu\n", count); /* Again, writing a single mouse event with adjacent mouse events queued doesn't appear to affect the count. */ ret = WriteConsoleInputA(input_handle, &event, 1, &count); ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); ret = GetNumberOfConsoleInputEvents(input_handle, &count); ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret); todo_wine - ok(count == 2*sizeof(event_list)/sizeof(event_list[0]), - "Expected count to be twice event list length, got %u\n", count); + ok(count == 2*ARRAY_SIZE(event_list), + "Expected count to be twice event list length, got %lu\n", count); ret = FlushConsoleInputBuffer(input_handle); ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret); @@ -1595,19 +2050,19 @@ static void test_WriteConsoleInputA(HANDLE input_handle) /* Key events don't exhibit the same behavior as mouse events. */ ret = WriteConsoleInputA(input_handle, &event, 1, &count); ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); ret = GetNumberOfConsoleInputEvents(input_handle, &count); ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); ret = WriteConsoleInputA(input_handle, &event, 1, &count); ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); ret = GetNumberOfConsoleInputEvents(input_handle, &count); ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret); - ok(count == 2, "Expected count to be 2, got %u\n", count); + ok(count == 2, "Expected count to be 2, got %lu\n", count); ret = FlushConsoleInputBuffer(input_handle); ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret); @@ -1618,33 +2073,33 @@ static void test_WriteConsoleInputA(HANDLE input_handle) ret = WriteConsoleInputA(input_handle, &event, 1, &count); ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); ret = GetNumberOfConsoleInputEvents(input_handle, &count); ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); event.EventType = KEY_EVENT; event.Event.KeyEvent = key_event; ret = WriteConsoleInputA(input_handle, &event, 1, &count); ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); ret = GetNumberOfConsoleInputEvents(input_handle, &count); ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret); - ok(count == 2, "Expected count to be 2, got %u\n", count); + ok(count == 2, "Expected count to be 2, got %lu\n", count); event.EventType = MOUSE_EVENT; event.Event.MouseEvent = mouse_event; ret = WriteConsoleInputA(input_handle, &event, 1, &count); ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); ret = GetNumberOfConsoleInputEvents(input_handle, &count); ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret); - ok(count == 3, "Expected count to be 3, got %u\n", count); + ok(count == 3, "Expected count to be 3, got %lu\n", count); /* Restore the old console mode. */ ret = SetConsoleMode(input_handle, console_mode); @@ -1699,7 +2154,7 @@ static void test_WriteConsoleInputW(HANDLE input_handle) ok(ret == TRUE, "Expected GetConsoleMode to return TRUE, got %d\n", ret); if (!ret) { - skip("GetConsoleMode failed with last error %u\n", GetLastError()); + skip("GetConsoleMode failed with last error %lu\n", GetLastError()); return; } @@ -1707,7 +2162,7 @@ static void test_WriteConsoleInputW(HANDLE input_handle) ok(ret == TRUE, "Expected SetConsoleMode to return TRUE, got %d\n", ret); if (!ret) { - skip("SetConsoleMode failed with last error %u\n", GetLastError()); + skip("SetConsoleMode failed with last error %lu\n", GetLastError()); return; } @@ -1718,7 +2173,7 @@ static void test_WriteConsoleInputW(HANDLE input_handle) event.EventType = MOUSE_EVENT; event.Event.MouseEvent = mouse_event; - for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++) + for (i = 0; i < ARRAY_SIZE(invalid_table); i++) { if (invalid_table[i].win_crash) continue; @@ -1732,24 +2187,24 @@ static void test_WriteConsoleInputW(HANDLE input_handle) ok(!ret, "[%d] Expected WriteConsoleInputW to return FALSE, got %d\n", i, ret); gle = GetLastError(); ok(gle == invalid_table[i].gle || (gle != 0 && gle == invalid_table[i].gle2), - "[%d] Expected last error to be %u or %u, got %u\n", + "[%d] Expected last error to be %lu or %lu, got %lu\n", i, invalid_table[i].gle, invalid_table[i].gle2, gle); } count = 0xdeadbeef; ret = WriteConsoleInputW(input_handle, NULL, 0, &count); ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret); - ok(count == 0, "Expected count to be 0, got %u\n", count); + ok(count == 0, "Expected count to be 0, got %lu\n", count); count = 0xdeadbeef; ret = WriteConsoleInputW(input_handle, &event, 0, &count); ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret); - ok(count == 0, "Expected count to be 0, got %u\n", count); + ok(count == 0, "Expected count to be 0, got %lu\n", count); count = 0xdeadbeef; ret = WriteConsoleInputW(input_handle, &event, 1, &count); ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); ret = FlushConsoleInputBuffer(input_handle); ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret); @@ -1760,61 +2215,61 @@ static void test_WriteConsoleInputW(HANDLE input_handle) ret = WriteConsoleInputW(input_handle, &event, 1, &count); ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); ret = GetNumberOfConsoleInputEvents(input_handle, &count); ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); ret = WriteConsoleInputW(input_handle, &event, 1, &count); ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); ret = GetNumberOfConsoleInputEvents(input_handle, &count); ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret); todo_wine - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); ret = FlushConsoleInputBuffer(input_handle); ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret); - for (i = 0; i < sizeof(event_list)/sizeof(event_list[0]); i++) + for (i = 0; i < ARRAY_SIZE(event_list); i++) { event_list[i].EventType = MOUSE_EVENT; event_list[i].Event.MouseEvent = mouse_event; } /* Writing consecutive chunks of mouse events appears to work. */ - ret = WriteConsoleInputW(input_handle, event_list, sizeof(event_list)/sizeof(event_list[0]), &count); + ret = WriteConsoleInputW(input_handle, event_list, ARRAY_SIZE(event_list), &count); ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret); - ok(count == sizeof(event_list)/sizeof(event_list[0]), - "Expected count to be event list length, got %u\n", count); + ok(count == ARRAY_SIZE(event_list), + "Expected count to be event list length, got %lu\n", count); ret = GetNumberOfConsoleInputEvents(input_handle, &count); ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret); - ok(count == sizeof(event_list)/sizeof(event_list[0]), - "Expected count to be event list length, got %u\n", count); + ok(count == ARRAY_SIZE(event_list), + "Expected count to be event list length, got %lu\n", count); - ret = WriteConsoleInputW(input_handle, event_list, sizeof(event_list)/sizeof(event_list[0]), &count); + ret = WriteConsoleInputW(input_handle, event_list, ARRAY_SIZE(event_list), &count); ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret); - ok(count == sizeof(event_list)/sizeof(event_list[0]), - "Expected count to be event list length, got %u\n", count); + ok(count == ARRAY_SIZE(event_list), + "Expected count to be event list length, got %lu\n", count); ret = GetNumberOfConsoleInputEvents(input_handle, &count); ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret); - ok(count == 2*sizeof(event_list)/sizeof(event_list[0]), - "Expected count to be twice event list length, got %u\n", count); + ok(count == 2*ARRAY_SIZE(event_list), + "Expected count to be twice event list length, got %lu\n", count); /* Again, writing a single mouse event with adjacent mouse events queued doesn't appear to affect the count. */ ret = WriteConsoleInputW(input_handle, &event, 1, &count); ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); ret = GetNumberOfConsoleInputEvents(input_handle, &count); ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret); todo_wine - ok(count == 2*sizeof(event_list)/sizeof(event_list[0]), - "Expected count to be twice event list length, got %u\n", count); + ok(count == 2*ARRAY_SIZE(event_list), + "Expected count to be twice event list length, got %lu\n", count); ret = FlushConsoleInputBuffer(input_handle); ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret); @@ -1832,19 +2287,19 @@ static void test_WriteConsoleInputW(HANDLE input_handle) /* Key events don't exhibit the same behavior as mouse events. */ ret = WriteConsoleInputW(input_handle, &event, 1, &count); ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); ret = GetNumberOfConsoleInputEvents(input_handle, &count); ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); ret = WriteConsoleInputW(input_handle, &event, 1, &count); ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); ret = GetNumberOfConsoleInputEvents(input_handle, &count); ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret); - ok(count == 2, "Expected count to be 2, got %u\n", count); + ok(count == 2, "Expected count to be 2, got %lu\n", count); ret = FlushConsoleInputBuffer(input_handle); ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret); @@ -1855,39 +2310,96 @@ static void test_WriteConsoleInputW(HANDLE input_handle) ret = WriteConsoleInputW(input_handle, &event, 1, &count); ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); ret = GetNumberOfConsoleInputEvents(input_handle, &count); ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); event.EventType = KEY_EVENT; event.Event.KeyEvent = key_event; ret = WriteConsoleInputW(input_handle, &event, 1, &count); ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); ret = GetNumberOfConsoleInputEvents(input_handle, &count); ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret); - ok(count == 2, "Expected count to be 2, got %u\n", count); + ok(count == 2, "Expected count to be 2, got %lu\n", count); event.EventType = MOUSE_EVENT; event.Event.MouseEvent = mouse_event; ret = WriteConsoleInputW(input_handle, &event, 1, &count); ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); ret = GetNumberOfConsoleInputEvents(input_handle, &count); ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret); - ok(count == 3, "Expected count to be 3, got %u\n", count); + ok(count == 3, "Expected count to be 3, got %lu\n", count); /* Restore the old console mode. */ ret = SetConsoleMode(input_handle, console_mode); ok(ret == TRUE, "Expected SetConsoleMode to return TRUE, got %d\n", ret); } +static void test_FlushConsoleInputBuffer(HANDLE input, HANDLE output) +{ + INPUT_RECORD record; + DWORD count; + BOOL ret; + + ret = FlushConsoleInputBuffer(input); + ok(ret, "FlushConsoleInputBuffer failed: %lu\n", GetLastError()); + + ret = GetNumberOfConsoleInputEvents(input, &count); + ok(ret, "GetNumberOfConsoleInputEvents failed: %lu\n", GetLastError()); + ok(count == 0, "Expected count to be 0, got %lu\n", count); + + record.EventType = KEY_EVENT; + record.Event.KeyEvent.bKeyDown = 1; + record.Event.KeyEvent.wRepeatCount = 1; + record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN; + record.Event.KeyEvent.wVirtualScanCode = VK_RETURN; + record.Event.KeyEvent.uChar.UnicodeChar = '\r'; + record.Event.KeyEvent.dwControlKeyState = 0; + ret = WriteConsoleInputW(input, &record, 1, &count); + ok(ret, "WriteConsoleInputW failed: %lu\n", GetLastError()); + + ret = GetNumberOfConsoleInputEvents(input, &count); + ok(ret, "GetNumberOfConsoleInputEvents failed: %lu\n", GetLastError()); + ok(count == 1, "Expected count to be 0, got %lu\n", count); + + ret = FlushConsoleInputBuffer(input); + ok(ret, "FlushConsoleInputBuffer failed: %lu\n", GetLastError()); + + ret = GetNumberOfConsoleInputEvents(input, &count); + ok(ret, "GetNumberOfConsoleInputEvents failed: %lu\n", GetLastError()); + ok(count == 0, "Expected count to be 0, got %lu\n", count); + + ret = WriteConsoleInputW(input, &record, 1, &count); + ok(ret, "WriteConsoleInputW failed: %lu\n", GetLastError()); + + ret = GetNumberOfConsoleInputEvents(input, &count); + ok(ret, "GetNumberOfConsoleInputEvents failed: %lu\n", GetLastError()); + ok(count == 1, "Expected count to be 0, got %lu\n", count); + + ret = FlushFileBuffers(input); + ok(ret, "FlushFileBuffers failed: %lu\n", GetLastError()); + + ret = GetNumberOfConsoleInputEvents(input, &count); + ok(ret, "GetNumberOfConsoleInputEvents failed: %lu\n", GetLastError()); + ok(count == 0, "Expected count to be 0, got %lu\n", count); + + ret = FlushConsoleInputBuffer(output); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "FlushConsoleInputBuffer returned: %x(%lu)\n", + ret, GetLastError()); + + ret = FlushFileBuffers(output); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "FlushFileBuffers returned: %x(%lu)\n", + ret, GetLastError()); +} + static void test_WriteConsoleOutputCharacterA(HANDLE output_handle) { static const char output[] = {'a', 0}; @@ -1932,7 +2444,7 @@ static void test_WriteConsoleOutputCharacterA(HANDLE output_handle) {output_handle, output, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1}, }; - for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++) + for (i = 0; i < ARRAY_SIZE(invalid_table); i++) { if (invalid_table[i].win7_crash) continue; @@ -1945,31 +2457,44 @@ static void test_WriteConsoleOutputCharacterA(HANDLE output_handle) invalid_table[i].coord, invalid_table[i].lpNumCharsWritten); ok(!ret, "[%d] Expected WriteConsoleOutputCharacterA to return FALSE, got %d\n", i, ret); - if (invalid_table[i].lpNumCharsWritten) - { - ok(count == invalid_table[i].expected_count, - "[%d] Expected count to be %u, got %u\n", - i, invalid_table[i].expected_count, count); - } ok(GetLastError() == invalid_table[i].last_error, - "[%d] Expected last error to be %u, got %u\n", + "[%d] Expected last error to be %lu, got %lu\n", i, invalid_table[i].last_error, GetLastError()); } count = 0xdeadbeef; ret = WriteConsoleOutputCharacterA(output_handle, NULL, 0, origin, &count); ok(ret == TRUE, "Expected WriteConsoleOutputCharacterA to return TRUE, got %d\n", ret); - ok(count == 0, "Expected count to be 0, got %u\n", count); + ok(count == 0, "Expected count to be 0, got %lu\n", count); count = 0xdeadbeef; ret = WriteConsoleOutputCharacterA(output_handle, output, 0, origin, &count); ok(ret == TRUE, "Expected WriteConsoleOutputCharacterA to return TRUE, got %d\n", ret); - ok(count == 0, "Expected count to be 0, got %u\n", count); + ok(count == 0, "Expected count to be 0, got %lu\n", count); count = 0xdeadbeef; ret = WriteConsoleOutputCharacterA(output_handle, output, 1, origin, &count); ok(ret == TRUE, "Expected WriteConsoleOutputCharacterA to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); + + count = 0xdeadbeef; + origin.X = 200; + ret = WriteConsoleOutputCharacterA(output_handle, output, 0, origin, &count); + ok(ret == TRUE, "Expected WriteConsoleOutputCharacterA to return TRUE, got %d\n", ret); + ok(count == 0, "Expected count to be 0, got %lu\n", count); + + for (i = 1; i < 32; i++) + { + CONSOLE_SCREEN_BUFFER_INFO csbi; + char ch = (char)i; + COORD c = {1, 2}; + + ret = WriteConsoleOutputCharacterA(output_handle, &ch, 1, c, &count); + ok(ret == TRUE, "Expected WriteConsoleOutputCharacterA to return TRUE, got %d\n", ret); + ok(count == 1, "Expected count to be 1, got %lu\n", count); + okCHAR(output_handle, c, (char)i, 7); + ret = GetConsoleScreenBufferInfo(output_handle, &csbi); + } } static void test_WriteConsoleOutputCharacterW(HANDLE output_handle) @@ -2016,7 +2541,7 @@ static void test_WriteConsoleOutputCharacterW(HANDLE output_handle) {output_handle, outputW, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1}, }; - for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++) + for (i = 0; i < ARRAY_SIZE(invalid_table); i++) { if (invalid_table[i].win7_crash) continue; @@ -2029,31 +2554,32 @@ static void test_WriteConsoleOutputCharacterW(HANDLE output_handle) invalid_table[i].coord, invalid_table[i].lpNumCharsWritten); ok(!ret, "[%d] Expected WriteConsoleOutputCharacterW to return FALSE, got %d\n", i, ret); - if (invalid_table[i].lpNumCharsWritten) - { - ok(count == invalid_table[i].expected_count, - "[%d] Expected count to be %u, got %u\n", - i, invalid_table[i].expected_count, count); - } ok(GetLastError() == invalid_table[i].last_error, - "[%d] Expected last error to be %u, got %u\n", + "[%d] Expected last error to be %lu, got %lu\n", i, invalid_table[i].last_error, GetLastError()); } count = 0xdeadbeef; ret = WriteConsoleOutputCharacterW(output_handle, NULL, 0, origin, &count); ok(ret == TRUE, "Expected WriteConsoleOutputCharacterW to return TRUE, got %d\n", ret); - ok(count == 0, "Expected count to be 0, got %u\n", count); + ok(count == 0, "Expected count to be 0, got %lu\n", count); count = 0xdeadbeef; ret = WriteConsoleOutputCharacterW(output_handle, outputW, 0, origin, &count); ok(ret == TRUE, "Expected WriteConsoleOutputCharacterW to return TRUE, got %d\n", ret); - ok(count == 0, "Expected count to be 0, got %u\n", count); + ok(count == 0, "Expected count to be 0, got %lu\n", count); count = 0xdeadbeef; ret = WriteConsoleOutputCharacterW(output_handle, outputW, 1, origin, &count); ok(ret == TRUE, "Expected WriteConsoleOutputCharacterW to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); + + count = 0xdeadbeef; + origin.X = 200; + ret = WriteConsoleOutputCharacterW(output_handle, outputW, 0, origin, &count); + ok(ret == TRUE, "Expected WriteConsoleOutputCharacterW to return TRUE, got %d\n", ret); + ok(count == 0, "Expected count to be 0, got %lu\n", count); + } static void test_WriteConsoleOutputAttribute(HANDLE output_handle) @@ -2099,7 +2625,7 @@ static void test_WriteConsoleOutputAttribute(HANDLE output_handle) {output_handle, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1}, }; - for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++) + for (i = 0; i < ARRAY_SIZE(invalid_table); i++) { if (invalid_table[i].win7_crash) continue; @@ -2112,31 +2638,175 @@ static void test_WriteConsoleOutputAttribute(HANDLE output_handle) invalid_table[i].coord, invalid_table[i].lpNumAttrsWritten); ok(!ret, "[%d] Expected WriteConsoleOutputAttribute to return FALSE, got %d\n", i, ret); - if (invalid_table[i].lpNumAttrsWritten) - { - ok(count == invalid_table[i].expected_count, - "[%d] Expected count to be %u, got %u\n", - i, invalid_table[i].expected_count, count); - } ok(GetLastError() == invalid_table[i].last_error, - "[%d] Expected last error to be %u, got %u\n", + "[%d] Expected last error to be %lu, got %lu\n", i, invalid_table[i].last_error, GetLastError()); } count = 0xdeadbeef; ret = WriteConsoleOutputAttribute(output_handle, NULL, 0, origin, &count); ok(ret == TRUE, "Expected WriteConsoleOutputAttribute to return TRUE, got %d\n", ret); - ok(count == 0, "Expected count to be 0, got %u\n", count); + ok(count == 0, "Expected count to be 0, got %lu\n", count); count = 0xdeadbeef; ret = WriteConsoleOutputAttribute(output_handle, &attr, 0, origin, &count); ok(ret == TRUE, "Expected WriteConsoleOutputAttribute to return TRUE, got %d\n", ret); - ok(count == 0, "Expected count to be 0, got %u\n", count); + ok(count == 0, "Expected count to be 0, got %lu\n", count); count = 0xdeadbeef; ret = WriteConsoleOutputAttribute(output_handle, &attr, 1, origin, &count); ok(ret == TRUE, "Expected WriteConsoleOutputAttribute to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); + + count = 0xdeadbeef; + origin.X = 200; + ret = WriteConsoleOutputAttribute(output_handle, &attr, 0, origin, &count); + ok(ret == TRUE, "Expected WriteConsoleOutputAttribute to return TRUE, got %d\n", ret); + ok(count == 0, "Expected count to be 0, got %lu\n", count); +} + +static void set_region(SMALL_RECT *region, unsigned int left, unsigned int top, unsigned int right, unsigned int bottom) +{ + region->Left = left; + region->Top = top; + region->Right = right; + region->Bottom = bottom; +} + +#define check_region(a,b,c,d,e) check_region_(__LINE__,a,b,c,d,e) +static void check_region_(unsigned int line, const SMALL_RECT *region, unsigned int left, unsigned int top, int right, int bottom) +{ + ok_(__FILE__,line)(region->Left == left, "Left = %u, expected %u\n", region->Left, left); + ok_(__FILE__,line)(region->Top == top, "Top = %u, expected %u\n", region->Top, top); + /* In multiple places returned region depends on Windows versions: some return right < left, others leave it untouched */ + if (right >= 0) + ok_(__FILE__,line)(region->Right == right, "Right = %u, expected %u\n", region->Right, right); + else + ok_(__FILE__,line)(region->Right == -right || region->Right == region->Left - 1, + "Right = %u, expected %d\n", region->Right, right); + if (bottom > 0) + ok_(__FILE__,line)(region->Bottom == bottom, "Bottom = %u, expected %u\n", region->Bottom, bottom); + else if (bottom < 0) + ok_(__FILE__,line)(region->Bottom == -bottom || region->Bottom == region->Top - 1, + "Bottom = %u, expected %d\n", region->Bottom, bottom); +} + +static void test_WriteConsoleOutput(HANDLE console) +{ + CONSOLE_SCREEN_BUFFER_INFO info; + CHAR_INFO char_info_buf[2048]; + SMALL_RECT region; + COORD size, coord; + unsigned int i; + BOOL ret; + + for (i = 0; i < ARRAY_SIZE(char_info_buf); i++) + { + char_info_buf[i].Char.UnicodeChar = '0' + i % 10; + char_info_buf[i].Attributes = 0; + } + + ret = GetConsoleScreenBufferInfo(console, &info); + ok(ret, "GetConsoleScreenBufferInfo failed: %lu\n", GetLastError()); + + size.X = 23; + size.Y = 17; + coord.X = 2; + coord.Y = 3; + set_region(®ion, 10, 7, 15, 11); + ret = WriteConsoleOutputW(console, char_info_buf, size, coord, ®ion); + ok(ret, "WriteConsoleOutputW failed: %lu\n", GetLastError()); + check_region(®ion, 10, 7, 15, 11); + + size.X = 23; + size.Y = 17; + coord.X = 2; + coord.Y = 3; + set_region(®ion, 200, 7, 15, 211); + ret = WriteConsoleOutputW(console, char_info_buf, size, coord, ®ion); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "WriteConsoleOutputW returned: %x(%lu)\n", ret, GetLastError()); + check_region(®ion, 200, 7, 15, 211); + + size.X = 23; + size.Y = 17; + coord.X = 2; + coord.Y = 3; + set_region(®ion, 200, 7, 211, 8); + ret = WriteConsoleOutputW(console, char_info_buf, size, coord, ®ion); + ok(ret, "WriteConsoleOutputW failed: %lu\n", GetLastError()); + check_region(®ion, 200, 7, 211, 8); + + size.X = 23; + size.Y = 17; + coord.X = 2; + coord.Y = 3; + set_region(®ion, 10, 7, 9, 11); + ret = WriteConsoleOutputW(console, char_info_buf, size, coord, ®ion); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "WriteConsoleOutputW returned: %x(%lu)\n", ret, GetLastError()); + check_region(®ion, 10, 7, 9, 11); + + size.X = 23; + size.Y = 17; + coord.X = 2; + coord.Y = 3; + set_region(®ion, 10, 7, 11, 6); + ret = WriteConsoleOutputW(console, char_info_buf, size, coord, ®ion); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "WriteConsoleOutputW returned: %x(%lu)\n", ret, GetLastError()); + check_region(®ion, 10, 7, 11, 6); + + size.X = 2; + size.Y = 17; + coord.X = 2; + coord.Y = 3; + set_region(®ion, 10, 7, 15, 11); + ret = WriteConsoleOutputW(console, char_info_buf, size, coord, ®ion); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "WriteConsoleOutputW returned: %x(%lu)\n", ret, GetLastError()); + check_region(®ion, 10, 7, 15, 11); + + size.X = 23; + size.Y = 3; + coord.X = 2; + coord.Y = 3; + set_region(®ion, 10, 7, 15, 11); + ret = WriteConsoleOutputW(console, char_info_buf, size, coord, ®ion); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "WriteConsoleOutputW returned: %x(%lu)\n", ret, GetLastError()); + check_region(®ion, 10, 7, 15, 11); + + size.X = 6; + size.Y = 17; + coord.X = 2; + coord.Y = 3; + set_region(®ion, 10, 7, 15, 11); + ret = WriteConsoleOutputW(console, char_info_buf, size, coord, ®ion); + ok(ret, "WriteConsoleOutputW failed: %lu\n", GetLastError()); + check_region(®ion, 10, 7, 13, 11); + + size.X = 6; + size.Y = 17; + coord.X = 2; + coord.Y = 3; + set_region(®ion, 10, 7, 15, 11); + ret = WriteConsoleOutputW((HANDLE)0xdeadbeef, char_info_buf, size, coord, ®ion); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "WriteConsoleOutputW returned: %x(%lu)\n", ret, GetLastError()); + if (!skip_nt) check_region(®ion, 10, 7, 13, 11); + + size.X = 16; + size.Y = 7; + coord.X = 2; + coord.Y = 3; + set_region(®ion, 10, 7, 15, 11); + ret = WriteConsoleOutputW(console, char_info_buf, size, coord, ®ion); + ok(ret, "WriteConsoleOutputW failed: %lu\n", GetLastError()); + check_region(®ion, 10, 7, 15, 10); + + size.X = 16; + size.Y = 7; + coord.X = 2; + coord.Y = 3; + set_region(®ion, info.dwSize.X - 2, 7, info.dwSize.X + 2, 7); + ret = WriteConsoleOutputW(console, char_info_buf, size, coord, ®ion); + ok(ret, "WriteConsoleOutputW failed: %lu\n", GetLastError()); + check_region(®ion, info.dwSize.X - 2, 7, info.dwSize.X - 1, 7); } static void test_FillConsoleOutputCharacterA(HANDLE output_handle) @@ -2169,7 +2839,7 @@ static void test_FillConsoleOutputCharacterA(HANDLE output_handle) {output_handle, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1}, }; - for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++) + for (i = 0; i < ARRAY_SIZE(invalid_table); i++) { if (invalid_table[i].win7_crash) continue; @@ -2183,19 +2853,19 @@ static void test_FillConsoleOutputCharacterA(HANDLE output_handle) invalid_table[i].lpNumCharsWritten); ok(!ret, "[%d] Expected FillConsoleOutputCharacterA to return FALSE, got %d\n", i, ret); ok(GetLastError() == invalid_table[i].last_error, - "[%d] Expected last error to be %u, got %u\n", + "[%d] Expected last error to be %lu, got %lu\n", i, invalid_table[i].last_error, GetLastError()); } count = 0xdeadbeef; ret = FillConsoleOutputCharacterA(output_handle, 'a', 0, origin, &count); ok(ret == TRUE, "Expected FillConsoleOutputCharacterA to return TRUE, got %d\n", ret); - ok(count == 0, "Expected count to be 0, got %u\n", count); + ok(count == 0, "Expected count to be 0, got %lu\n", count); count = 0xdeadbeef; ret = FillConsoleOutputCharacterA(output_handle, 'a', 1, origin, &count); ok(ret == TRUE, "Expected FillConsoleOutputCharacterA to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); } static void test_FillConsoleOutputCharacterW(HANDLE output_handle) @@ -2228,7 +2898,7 @@ static void test_FillConsoleOutputCharacterW(HANDLE output_handle) {output_handle, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1}, }; - for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++) + for (i = 0; i < ARRAY_SIZE(invalid_table); i++) { if (invalid_table[i].win7_crash) continue; @@ -2242,19 +2912,19 @@ static void test_FillConsoleOutputCharacterW(HANDLE output_handle) invalid_table[i].lpNumCharsWritten); ok(!ret, "[%d] Expected FillConsoleOutputCharacterW to return FALSE, got %d\n", i, ret); ok(GetLastError() == invalid_table[i].last_error, - "[%d] Expected last error to be %u, got %u\n", + "[%d] Expected last error to be %lu, got %lu\n", i, invalid_table[i].last_error, GetLastError()); } count = 0xdeadbeef; ret = FillConsoleOutputCharacterW(output_handle, 'a', 0, origin, &count); ok(ret == TRUE, "Expected FillConsoleOutputCharacterW to return TRUE, got %d\n", ret); - ok(count == 0, "Expected count to be 0, got %u\n", count); + ok(count == 0, "Expected count to be 0, got %lu\n", count); count = 0xdeadbeef; ret = FillConsoleOutputCharacterW(output_handle, 'a', 1, origin, &count); ok(ret == TRUE, "Expected FillConsoleOutputCharacterW to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); } static void test_FillConsoleOutputAttribute(HANDLE output_handle) @@ -2287,7 +2957,7 @@ static void test_FillConsoleOutputAttribute(HANDLE output_handle) {output_handle, FOREGROUND_BLUE, 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1}, }; - for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++) + for (i = 0; i < ARRAY_SIZE(invalid_table); i++) { if (invalid_table[i].win7_crash) continue; @@ -2301,24 +2971,24 @@ static void test_FillConsoleOutputAttribute(HANDLE output_handle) invalid_table[i].lpNumAttrsWritten); ok(!ret, "[%d] Expected FillConsoleOutputAttribute to return FALSE, got %d\n", i, ret); ok(GetLastError() == invalid_table[i].last_error, - "[%d] Expected last error to be %u, got %u\n", + "[%d] Expected last error to be %lu, got %lu\n", i, invalid_table[i].last_error, GetLastError()); } count = 0xdeadbeef; ret = FillConsoleOutputAttribute(output_handle, FOREGROUND_BLUE, 0, origin, &count); ok(ret == TRUE, "Expected FillConsoleOutputAttribute to return TRUE, got %d\n", ret); - ok(count == 0, "Expected count to be 0, got %u\n", count); + ok(count == 0, "Expected count to be 0, got %lu\n", count); count = 0xdeadbeef; ret = FillConsoleOutputAttribute(output_handle, FOREGROUND_BLUE, 1, origin, &count); ok(ret == TRUE, "Expected FillConsoleOutputAttribute to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); count = 0xdeadbeef; ret = FillConsoleOutputAttribute(output_handle, ~0, 1, origin, &count); ok(ret == TRUE, "Expected FillConsoleOutputAttribute to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); } static void test_ReadConsoleOutputCharacterA(HANDLE output_handle) @@ -2365,7 +3035,7 @@ static void test_ReadConsoleOutputCharacterA(HANDLE output_handle) {output_handle, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1}, }; - for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++) + for (i = 0; i < ARRAY_SIZE(invalid_table); i++) { if (invalid_table[i].win7_crash) continue; @@ -2378,31 +3048,31 @@ static void test_ReadConsoleOutputCharacterA(HANDLE output_handle) invalid_table[i].coord, invalid_table[i].read_count); ok(!ret, "[%d] Expected ReadConsoleOutputCharacterA to return FALSE, got %d\n", i, ret); - if (invalid_table[i].read_count) - { - ok(count == invalid_table[i].expected_count, - "[%d] Expected count to be %u, got %u\n", - i, invalid_table[i].expected_count, count); - } ok(GetLastError() == invalid_table[i].last_error, - "[%d] Expected last error to be %u, got %u\n", + "[%d] Expected last error to be %lu, got %lu\n", i, invalid_table[i].last_error, GetLastError()); } count = 0xdeadbeef; ret = ReadConsoleOutputCharacterA(output_handle, NULL, 0, origin, &count); ok(ret == TRUE, "Expected ReadConsoleOutputCharacterA to return TRUE, got %d\n", ret); - ok(count == 0, "Expected count to be 0, got %u\n", count); + ok(count == 0, "Expected count to be 0, got %lu\n", count); count = 0xdeadbeef; ret = ReadConsoleOutputCharacterA(output_handle, &read, 0, origin, &count); ok(ret == TRUE, "Expected ReadConsoleOutputCharacterA to return TRUE, got %d\n", ret); - ok(count == 0, "Expected count to be 0, got %u\n", count); + ok(count == 0, "Expected count to be 0, got %lu\n", count); count = 0xdeadbeef; ret = ReadConsoleOutputCharacterA(output_handle, &read, 1, origin, &count); ok(ret == TRUE, "Expected ReadConsoleOutputCharacterA to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); + + count = 0xdeadbeef; + origin.X = 200; + ret = ReadConsoleOutputCharacterA(output_handle, &read, 1, origin, &count); + ok(ret == TRUE, "Expected ReadConsoleOutputCharacterA to return TRUE, got %d\n", ret); + ok(count == 0, "Expected count to be 0, got %lu\n", count); } static void test_ReadConsoleOutputCharacterW(HANDLE output_handle) @@ -2449,7 +3119,7 @@ static void test_ReadConsoleOutputCharacterW(HANDLE output_handle) {output_handle, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1}, }; - for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++) + for (i = 0; i < ARRAY_SIZE(invalid_table); i++) { if (invalid_table[i].win7_crash) continue; @@ -2462,31 +3132,31 @@ static void test_ReadConsoleOutputCharacterW(HANDLE output_handle) invalid_table[i].coord, invalid_table[i].read_count); ok(!ret, "[%d] Expected ReadConsoleOutputCharacterW to return FALSE, got %d\n", i, ret); - if (invalid_table[i].read_count) - { - ok(count == invalid_table[i].expected_count, - "[%d] Expected count to be %u, got %u\n", - i, invalid_table[i].expected_count, count); - } ok(GetLastError() == invalid_table[i].last_error, - "[%d] Expected last error to be %u, got %u\n", + "[%d] Expected last error to be %lu, got %lu\n", i, invalid_table[i].last_error, GetLastError()); } count = 0xdeadbeef; ret = ReadConsoleOutputCharacterW(output_handle, NULL, 0, origin, &count); ok(ret == TRUE, "Expected ReadConsoleOutputCharacterW to return TRUE, got %d\n", ret); - ok(count == 0, "Expected count to be 0, got %u\n", count); + ok(count == 0, "Expected count to be 0, got %lu\n", count); count = 0xdeadbeef; ret = ReadConsoleOutputCharacterW(output_handle, &read, 0, origin, &count); ok(ret == TRUE, "Expected ReadConsoleOutputCharacterW to return TRUE, got %d\n", ret); - ok(count == 0, "Expected count to be 0, got %u\n", count); + ok(count == 0, "Expected count to be 0, got %lu\n", count); count = 0xdeadbeef; ret = ReadConsoleOutputCharacterW(output_handle, &read, 1, origin, &count); ok(ret == TRUE, "Expected ReadConsoleOutputCharacterW to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); + + count = 0xdeadbeef; + origin.X = 200; + ret = ReadConsoleOutputCharacterW(output_handle, &read, 1, origin, &count); + ok(ret == TRUE, "Expected ReadConsoleOutputCharacterW to return TRUE, got %d\n", ret); + ok(count == 0, "Expected count to be 0, got %lu\n", count); } static void test_ReadConsoleOutputAttribute(HANDLE output_handle) @@ -2532,7 +3202,7 @@ static void test_ReadConsoleOutputAttribute(HANDLE output_handle) {output_handle, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1}, }; - for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++) + for (i = 0; i < ARRAY_SIZE(invalid_table); i++) { if (invalid_table[i].win7_crash) continue; @@ -2545,79 +3215,233 @@ static void test_ReadConsoleOutputAttribute(HANDLE output_handle) invalid_table[i].coord, invalid_table[i].read_count); ok(!ret, "[%d] Expected ReadConsoleOutputAttribute to return FALSE, got %d\n", i, ret); - if (invalid_table[i].read_count) - { - ok(count == invalid_table[i].expected_count, - "[%d] Expected count to be %u, got %u\n", - i, invalid_table[i].expected_count, count); - } ok(GetLastError() == invalid_table[i].last_error, - "[%d] Expected last error to be %u, got %u\n", + "[%d] Expected last error to be %lu, got %lu\n", i, invalid_table[i].last_error, GetLastError()); } count = 0xdeadbeef; ret = ReadConsoleOutputAttribute(output_handle, NULL, 0, origin, &count); ok(ret == TRUE, "Expected ReadConsoleOutputAttribute to return TRUE, got %d\n", ret); - ok(count == 0, "Expected count to be 0, got %u\n", count); + ok(count == 0, "Expected count to be 0, got %lu\n", count); count = 0xdeadbeef; ret = ReadConsoleOutputAttribute(output_handle, &attr, 0, origin, &count); ok(ret == TRUE, "Expected ReadConsoleOutputAttribute to return TRUE, got %d\n", ret); - ok(count == 0, "Expected count to be 0, got %u\n", count); + ok(count == 0, "Expected count to be 0, got %lu\n", count); count = 0xdeadbeef; ret = ReadConsoleOutputAttribute(output_handle, &attr, 1, origin, &count); ok(ret == TRUE, "Expected ReadConsoleOutputAttribute to return TRUE, got %d\n", ret); - ok(count == 1, "Expected count to be 1, got %u\n", count); + ok(count == 1, "Expected count to be 1, got %lu\n", count); + + count = 0xdeadbeef; + origin.X = 200; + ret = ReadConsoleOutputAttribute(output_handle, &attr, 1, origin, &count); + ok(ret == TRUE, "Expected ReadConsoleOutputAttribute to return TRUE, got %d\n", ret); + ok(count == 0, "Expected count to be 1, got %lu\n", count); } -static void test_ReadConsole(void) +static void test_ReadConsoleOutput(HANDLE console) +{ + CONSOLE_SCREEN_BUFFER_INFO info; + CHAR_INFO char_info_buf[2048]; + SMALL_RECT region; + COORD size, coord; + DWORD count; + WCHAR ch; + BOOL ret; + + if (skip_nt) return; + + ret = GetConsoleScreenBufferInfo(console, &info); + ok(ret, "GetConsoleScreenBufferInfo failed: %lu\n", GetLastError()); + + size.X = 23; + size.Y = 17; + coord.X = 2; + coord.Y = 3; + set_region(®ion, 10, 7, 15, 11); + ret = ReadConsoleOutputW(console, char_info_buf, size, coord, ®ion); + ok(ret, "ReadConsoleOutputW failed: %lu\n", GetLastError()); + check_region(®ion, 10, 7, 15, 11); + + size.X = 23; + size.Y = 17; + coord.X = 2; + coord.Y = 3; + set_region(®ion, 200, 7, 15, 211); + ret = ReadConsoleOutputW(console, char_info_buf, size, coord, ®ion); + ok(!ret, "ReadConsoleOutputW returned: %x(%lu)\n", ret, GetLastError()); + check_region(®ion, 200, 7, -15, 0); + + size.X = 23; + size.Y = 17; + coord.X = 2; + coord.Y = 3; + set_region(®ion, 200, 7, 211, 8); + ret = ReadConsoleOutputW(console, char_info_buf, size, coord, ®ion); + ok((!ret && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_INVALID_FUNCTION)) || broken(ret /* win8 */), + "ReadConsoleOutputW returned: %x %lu\n", ret, GetLastError()); + if (!ret && GetLastError() == ERROR_INVALID_PARAMETER) check_region(®ion, 200, 7, -211, -8); + + size.X = 23; + size.Y = 17; + coord.X = 2; + coord.Y = 3; + set_region(®ion, 10, 7, 9, 11); + ret = ReadConsoleOutputW(console, char_info_buf, size, coord, ®ion); + ok((!ret && (GetLastError() == ERROR_INVALID_FUNCTION || GetLastError() == ERROR_NOT_ENOUGH_MEMORY)) || broken(ret /* win8 */), + "ReadConsoleOutputW returned: %x(%lu)\n", ret, GetLastError()); + check_region(®ion, 10, 7, 9, -11); + + size.X = 23; + size.Y = 17; + coord.X = 2; + coord.Y = 3; + set_region(®ion, 10, 7, 11, 6); + ret = ReadConsoleOutputW(console, char_info_buf, size, coord, ®ion); + ok((!ret && (GetLastError() == ERROR_INVALID_FUNCTION || GetLastError() == ERROR_NOT_ENOUGH_MEMORY)) || broken(ret /* win8 */), + "ReadConsoleOutputW returned: %x(%lu)\n", ret, GetLastError()); + check_region(®ion, 10, 7, -11, 6); + + size.X = 2; + size.Y = 17; + coord.X = 2; + coord.Y = 3; + set_region(®ion, 10, 7, 15, 11); + ret = ReadConsoleOutputW(console, char_info_buf, size, coord, ®ion); + ok((!ret && (GetLastError() == ERROR_INVALID_FUNCTION || GetLastError() == ERROR_NOT_ENOUGH_MEMORY)) || broken(ret /* win8 */), + "ReadConsoleOutputW returned: %x(%lu)\n", ret, GetLastError()); + check_region(®ion, 10, 7, -15, -11); + + size.X = 23; + size.Y = 3; + coord.X = 2; + coord.Y = 3; + set_region(®ion, 10, 7, 15, 11); + ret = ReadConsoleOutputW(console, char_info_buf, size, coord, ®ion); + ok((!ret && (GetLastError() == ERROR_INVALID_FUNCTION || GetLastError() == ERROR_NOT_ENOUGH_MEMORY)) || broken(ret /* win8 */), + "ReadConsoleOutputW returned: %x(%lu)\n", ret, GetLastError()); + check_region(®ion, 10, 7, -15, 6); + + size.X = 6; + size.Y = 17; + coord.X = 2; + coord.Y = 3; + set_region(®ion, 10, 7, 15, 11); + ret = ReadConsoleOutputW(console, char_info_buf, size, coord, ®ion); + ok(ret, "ReadConsoleOutputW failed: %lu\n", GetLastError()); + check_region(®ion, 10, 7, 13, 11); + + size.X = 6; + size.Y = 17; + coord.X = 2; + coord.Y = 3; + set_region(®ion, 10, 7, 15, 11); + ret = ReadConsoleOutputW((HANDLE)0xdeadbeef, char_info_buf, size, coord, ®ion); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "ReadConsoleOutputW returned: %x(%lu)\n", ret, GetLastError()); + if (!skip_nt) check_region(®ion, 10, 7, 13, 11); + + size.X = 16; + size.Y = 7; + coord.X = 2; + coord.Y = 3; + set_region(®ion, 10, 7, 15, 11); + ret = ReadConsoleOutputW(console, char_info_buf, size, coord, ®ion); + ok(ret, "ReadConsoleOutputW failed: %lu\n", GetLastError()); + check_region(®ion, 10, 7, 15, 10); + + size.X = 16; + size.Y = 7; + coord.X = 2; + coord.Y = 3; + set_region(®ion, info.dwSize.X - 2, 7, info.dwSize.X + 2, 7); + ret = ReadConsoleOutputW(console, char_info_buf, size, coord, ®ion); + ok(ret || GetLastError() == ERROR_INVALID_PARAMETER, "ReadConsoleOutputW failed: %lu\n", GetLastError()); + if (ret) check_region(®ion, info.dwSize.X - 2, 7, info.dwSize.X - 1, 7); + + coord.X = 2; + coord.Y = 3; + ret = WriteConsoleOutputCharacterW(console, L"xyz", 3, coord, &count); + ok(ret, "WriteConsoleOutputCharacterW failed: %lu\n", GetLastError()); + ok(count == 3, "count = %lu\n", count); + + memset(char_info_buf, 0xc0, sizeof(char_info_buf)); + size.X = 16; + size.Y = 7; + coord.X = 5; + coord.Y = 6; + set_region(®ion, 2, 3, 5, 3); + ret = ReadConsoleOutputW(console, char_info_buf, size, coord, ®ion); + ok(ret, "ReadConsoleOutputW failed: %lu\n", GetLastError()); + check_region(®ion, 2, 3, 5, 3); + ch = char_info_buf[coord.Y * size.X + coord.X].Char.UnicodeChar; + ok(ch == 'x', "unexpected char %c/%x\n", ch, ch); + ch = char_info_buf[coord.Y * size.X + coord.X + 1].Char.UnicodeChar; + ok(ch == 'y', "unexpected char %c/%x\n", ch, ch); + ch = char_info_buf[coord.Y * size.X + coord.X + 2].Char.UnicodeChar; + ok(ch == 'z', "unexpected char %c/%x\n", ch, ch); +} + +static void test_ReadConsole(HANDLE input) { - HANDLE std_input; DWORD ret, bytes; char buf[1024]; - - std_input = GetStdHandle(STD_INPUT_HANDLE); + HANDLE output; SetLastError(0xdeadbeef); - ret = GetFileSize(std_input, NULL); - if (GetLastError() == 0xdeadbeef) - { - skip("stdin is redirected\n"); - return; - } - ok(ret == INVALID_FILE_SIZE, "expected INVALID_FILE_SIZE, got %#x\n", ret); - ok(GetLastError() == ERROR_INVALID_HANDLE || - GetLastError() == ERROR_INVALID_FUNCTION, /* Win 8, 10 */ - "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + ret = GetFileSize(input, NULL); + ok(ret == INVALID_FILE_SIZE || broken(TRUE), /* only Win7 pro64 on 64bit returns a valid file size here */ + "expected INVALID_FILE_SIZE, got %#lx\n", ret); + if (ret == INVALID_FILE_SIZE) + ok(GetLastError() == ERROR_INVALID_HANDLE || + GetLastError() == ERROR_INVALID_FUNCTION, /* Win 8, 10 */ + "expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError()); bytes = 0xdeadbeef; SetLastError(0xdeadbeef); - ret = ReadFile(std_input, buf, -128, &bytes, NULL); - ok(!ret, "expected 0, got %u\n", ret); + ret = ReadFile(input, buf, -128, &bytes, NULL); + ok(!ret, "expected 0, got %lu\n", ret); ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY || GetLastError() == ERROR_NOACCESS, /* Win 8, 10 */ - "expected ERROR_NOT_ENOUGH_MEMORY, got %d\n", GetLastError()); - ok(!bytes, "expected 0, got %u\n", bytes); + "expected ERROR_NOT_ENOUGH_MEMORY, got %ld\n", GetLastError()); + ok(!bytes, "expected 0, got %lu\n", bytes); bytes = 0xdeadbeef; SetLastError(0xdeadbeef); - ret = ReadConsoleA(std_input, buf, -128, &bytes, NULL); - ok(!ret, "expected 0, got %u\n", ret); + ret = ReadConsoleA(input, buf, -128, &bytes, NULL); + ok(!ret, "expected 0, got %lu\n", ret); ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY || GetLastError() == ERROR_NOACCESS, /* Win 8, 10 */ - "expected ERROR_NOT_ENOUGH_MEMORY, got %d\n", GetLastError()); - ok(bytes == 0xdeadbeef, "expected 0xdeadbeef, got %#x\n", bytes); + "expected ERROR_NOT_ENOUGH_MEMORY, got %ld\n", GetLastError()); + ok(bytes == 0xdeadbeef, "expected 0xdeadbeef, got %#lx\n", bytes); bytes = 0xdeadbeef; SetLastError(0xdeadbeef); - ret = ReadConsoleW(std_input, buf, -128, &bytes, NULL); - ok(!ret, "expected 0, got %u\n", ret); + ret = ReadConsoleW(input, buf, -128, &bytes, NULL); + ok(!ret, "expected 0, got %lu\n", ret); ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY || GetLastError() == ERROR_NOACCESS, /* Win 8, 10 */ - "expected ERROR_NOT_ENOUGH_MEMORY, got %d\n", GetLastError()); - ok(bytes == 0xdeadbeef, "expected 0xdeadbeef, got %#x\n", bytes); + "expected ERROR_NOT_ENOUGH_MEMORY, got %ld\n", GetLastError()); + ok(bytes == 0xdeadbeef, "expected 0xdeadbeef, got %#lx\n", bytes); + + output = CreateFileA("CONOUT$", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(output != INVALID_HANDLE_VALUE, "Could not open console\n"); + + ret = ReadConsoleW(output, buf, sizeof(buf) / sizeof(WCHAR), &bytes, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, + "ReadConsoleW returned %lx(%lu)\n", ret, GetLastError()); + + ret = ReadConsoleA(output, buf, sizeof(buf), &bytes, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, + "ReadConsoleA returned %lx(%lu)\n", ret, GetLastError()); + + ret = ReadFile(output, buf, sizeof(buf), &bytes, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, + "ReadFile returned %lx(%lu)\n", ret, GetLastError()); + + CloseHandle(output); } static void test_GetCurrentConsoleFont(HANDLE std_output) @@ -2626,13 +3450,14 @@ static void test_GetCurrentConsoleFont(HANDLE std_output) CONSOLE_FONT_INFO cfi; CONSOLE_SCREEN_BUFFER_INFO csbi; short int width, height; + HANDLE pipe1, pipe2; COORD c; memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO)); SetLastError(0xdeadbeef); ret = GetCurrentConsoleFont(NULL, FALSE, &cfi); ok(!ret, "got %d, expected 0\n", ret); - ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X); ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y); @@ -2640,7 +3465,7 @@ static void test_GetCurrentConsoleFont(HANDLE std_output) SetLastError(0xdeadbeef); ret = GetCurrentConsoleFont(NULL, TRUE, &cfi); ok(!ret, "got %d, expected 0\n", ret); - ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X); ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y); @@ -2648,7 +3473,7 @@ static void test_GetCurrentConsoleFont(HANDLE std_output) SetLastError(0xdeadbeef); ret = GetCurrentConsoleFont(GetStdHandle(STD_INPUT_HANDLE), FALSE, &cfi); ok(!ret, "got %d, expected 0\n", ret); - ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X); ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y); @@ -2656,15 +3481,26 @@ static void test_GetCurrentConsoleFont(HANDLE std_output) SetLastError(0xdeadbeef); ret = GetCurrentConsoleFont(GetStdHandle(STD_INPUT_HANDLE), TRUE, &cfi); ok(!ret, "got %d, expected 0\n", ret); - ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X); ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y); + CreatePipe(&pipe1, &pipe2, NULL, 0); + memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO)); + SetLastError(0xdeadbeef); + ret = GetCurrentConsoleFont(pipe1, TRUE, &cfi); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); + ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X); + ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y); + CloseHandle(pipe1); + CloseHandle(pipe2); + memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO)); SetLastError(0xdeadbeef); ret = GetCurrentConsoleFont(std_output, FALSE, &cfi); ok(ret, "got %d, expected non-zero\n", ret); - ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError()); GetConsoleScreenBufferInfo(std_output, &csbi); width = csbi.srWindow.Right - csbi.srWindow.Left + 1; height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; @@ -2678,13 +3514,263 @@ static void test_GetCurrentConsoleFont(HANDLE std_output) SetLastError(0xdeadbeef); ret = GetCurrentConsoleFont(std_output, TRUE, &cfi); ok(ret, "got %d, expected non-zero\n", ret); - ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError()); ok(cfi.dwFontSize.X == csbi.dwMaximumWindowSize.X, "got %d, expected %d\n", cfi.dwFontSize.X, csbi.dwMaximumWindowSize.X); ok(cfi.dwFontSize.Y == csbi.dwMaximumWindowSize.Y, "got %d, expected %d\n", cfi.dwFontSize.Y, csbi.dwMaximumWindowSize.Y); } +static void test_GetCurrentConsoleFontEx(HANDLE std_output) +{ +#if defined(__REACTOS__) && DLL_EXPORT_VERSION < 0x600 + UNREFERENCED_PARAMETER(std_output); + skip("Cannot build test_GetCurrentConsoleFontEx() unless DLL_EXPORT_VERSION >= 0x600.\n"); +#else + HANDLE hmod; + BOOL (WINAPI *pGetCurrentConsoleFontEx)(HANDLE, BOOL, CONSOLE_FONT_INFOEX *); + CONSOLE_FONT_INFO cfi; + CONSOLE_FONT_INFOEX cfix; + BOOL ret; + HANDLE std_input = GetStdHandle(STD_INPUT_HANDLE); + HANDLE pipe1, pipe2; + COORD c; + + hmod = GetModuleHandleA("kernel32.dll"); + pGetCurrentConsoleFontEx = (void *)GetProcAddress(hmod, "GetCurrentConsoleFontEx"); + if (!pGetCurrentConsoleFontEx) + { + win_skip("GetCurrentConsoleFontEx is not available\n"); + return; + } + + SetLastError(0xdeadbeef); + ret = pGetCurrentConsoleFontEx(NULL, FALSE, &cfix); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = pGetCurrentConsoleFontEx(NULL, TRUE, &cfix); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = pGetCurrentConsoleFontEx(std_input, FALSE, &cfix); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = pGetCurrentConsoleFontEx(std_input, TRUE, &cfix); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = pGetCurrentConsoleFontEx(std_output, FALSE, &cfix); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = pGetCurrentConsoleFontEx(std_output, TRUE, &cfix); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError()); + + cfix.cbSize = sizeof(CONSOLE_FONT_INFOEX); + + SetLastError(0xdeadbeef); + ret = pGetCurrentConsoleFontEx(NULL, FALSE, &cfix); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = pGetCurrentConsoleFontEx(NULL, TRUE, &cfix); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = pGetCurrentConsoleFontEx(std_input, FALSE, &cfix); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = pGetCurrentConsoleFontEx(std_input, TRUE, &cfix); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); + + CreatePipe(&pipe1, &pipe2, NULL, 0); + memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO)); + SetLastError(0xdeadbeef); + ret = pGetCurrentConsoleFontEx(pipe1, TRUE, &cfix); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); + CloseHandle(pipe1); + CloseHandle(pipe2); + + SetLastError(0xdeadbeef); + ret = pGetCurrentConsoleFontEx(std_output, FALSE, &cfix); + ok(ret, "got %d, expected non-zero\n", ret); + ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError()); + + memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO)); + SetLastError(0xdeadbeef); + ret = GetCurrentConsoleFont(std_output, FALSE, &cfi); + ok(ret, "got %d, expected non-zero\n", ret); + ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError()); + + ok(cfix.dwFontSize.X == cfi.dwFontSize.X, "expected values to match\n"); + ok(cfix.dwFontSize.Y == cfi.dwFontSize.Y, "expected values to match\n"); + + SetLastError(0xdeadbeef); + c = GetConsoleFontSize(std_output, cfix.nFont); + ok(c.X && c.Y, "GetConsoleFontSize failed; err = %lu\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError()); + + ok(cfix.dwFontSize.X == c.X, "Font width doesn't match; got %u, expected %u\n", + cfix.dwFontSize.X, c.X); + ok(cfix.dwFontSize.Y == c.Y, "Font height doesn't match; got %u, expected %u\n", + cfix.dwFontSize.Y, c.Y); + + ok(cfi.dwFontSize.X == c.X, "Font width doesn't match; got %u, expected %u\n", + cfi.dwFontSize.X, c.X); + ok(cfi.dwFontSize.Y == c.Y, "Font height doesn't match; got %u, expected %u\n", + cfi.dwFontSize.Y, c.Y); + + SetLastError(0xdeadbeef); + ret = pGetCurrentConsoleFontEx(std_output, TRUE, &cfix); + ok(ret, "got %d, expected non-zero\n", ret); + ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError()); + + memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO)); + SetLastError(0xdeadbeef); + ret = GetCurrentConsoleFont(std_output, TRUE, &cfi); + ok(ret, "got %d, expected non-zero\n", ret); + ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError()); + + ok(cfix.dwFontSize.X == cfi.dwFontSize.X, "expected values to match\n"); + ok(cfix.dwFontSize.Y == cfi.dwFontSize.Y, "expected values to match\n"); +#endif +} + +static void test_SetCurrentConsoleFontEx(HANDLE std_output) +{ +#ifdef __REACTOS__ + UNREFERENCED_PARAMETER(std_output); + skip("Cannot build test_SetCurrentConsoleFontEx() until kernelbase is synced.\n"); +#else + CONSOLE_FONT_INFOEX orig_cfix, cfix; + BOOL ret; + HANDLE pipe1, pipe2; + HANDLE std_input = GetStdHandle(STD_INPUT_HANDLE); + + orig_cfix.cbSize = sizeof(CONSOLE_FONT_INFOEX); + + ret = GetCurrentConsoleFontEx(std_output, FALSE, &orig_cfix); + ok(ret, "got %d, expected non-zero\n", ret); + + cfix = orig_cfix; + cfix.cbSize = 0; + + SetLastError(0xdeadbeef); + ret = SetCurrentConsoleFontEx(NULL, FALSE, &cfix); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = SetCurrentConsoleFontEx(NULL, TRUE, &cfix); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError()); + + CreatePipe(&pipe1, &pipe2, NULL, 0); + SetLastError(0xdeadbeef); + ret = SetCurrentConsoleFontEx(pipe1, FALSE, &cfix); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError()); + CloseHandle(pipe1); + CloseHandle(pipe2); + + CreatePipe(&pipe1, &pipe2, NULL, 0); + SetLastError(0xdeadbeef); + ret = SetCurrentConsoleFontEx(pipe1, TRUE, &cfix); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError()); + CloseHandle(pipe1); + CloseHandle(pipe2); + + SetLastError(0xdeadbeef); + ret = SetCurrentConsoleFontEx(std_input, FALSE, &cfix); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = SetCurrentConsoleFontEx(std_input, TRUE, &cfix); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = SetCurrentConsoleFontEx(std_output, FALSE, &cfix); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = SetCurrentConsoleFontEx(std_output, TRUE, &cfix); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError()); + + cfix = orig_cfix; + + SetLastError(0xdeadbeef); + ret = SetCurrentConsoleFontEx(NULL, FALSE, &cfix); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = SetCurrentConsoleFontEx(NULL, TRUE, &cfix); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); + + CreatePipe(&pipe1, &pipe2, NULL, 0); + SetLastError(0xdeadbeef); + ret = SetCurrentConsoleFontEx(pipe1, FALSE, &cfix); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); + CloseHandle(pipe1); + CloseHandle(pipe2); + + CreatePipe(&pipe1, &pipe2, NULL, 0); + SetLastError(0xdeadbeef); + ret = SetCurrentConsoleFontEx(pipe1, TRUE, &cfix); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); + CloseHandle(pipe1); + CloseHandle(pipe2); + + SetLastError(0xdeadbeef); + ret = SetCurrentConsoleFontEx(std_input, FALSE, &cfix); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = SetCurrentConsoleFontEx(std_input, TRUE, &cfix); + ok(!ret, "got %d, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = SetCurrentConsoleFontEx(std_output, FALSE, &cfix); + ok(ret, "got %d, expected non-zero\n", ret); + ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = SetCurrentConsoleFontEx(std_output, TRUE, &cfix); + ok(ret, "got %d, expected non-zero\n", ret); + ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError()); + + /* Restore original console font parameters */ + SetLastError(0xdeadbeef); + ret = SetCurrentConsoleFontEx(std_output, FALSE, &orig_cfix); + ok(ret, "got %d, expected non-zero\n", ret); + ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError()); +#endif +} + static void test_GetConsoleFontSize(HANDLE std_output) { COORD c; @@ -2695,32 +3781,43 @@ static void test_GetConsoleFontSize(HANDLE std_output) LONG font_width, font_height; HMODULE hmod; DWORD (WINAPI *pGetNumberOfConsoleFonts)(void); + HANDLE pipe1, pipe2; memset(&c, 10, sizeof(COORD)); SetLastError(0xdeadbeef); c = GetConsoleFontSize(NULL, index); - ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); ok(!c.X, "got %d, expected 0\n", c.X); ok(!c.Y, "got %d, expected 0\n", c.Y); memset(&c, 10, sizeof(COORD)); SetLastError(0xdeadbeef); c = GetConsoleFontSize(GetStdHandle(STD_INPUT_HANDLE), index); - ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); ok(!c.X, "got %d, expected 0\n", c.X); ok(!c.Y, "got %d, expected 0\n", c.Y); + CreatePipe(&pipe1, &pipe2, NULL, 0); + memset(&c, 10, sizeof(COORD)); + SetLastError(0xdeadbeef); + c = GetConsoleFontSize(pipe1, index); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); + ok(!c.X, "got %d, expected 0\n", c.X); + ok(!c.Y, "got %d, expected 0\n", c.Y); + CloseHandle(pipe1); + CloseHandle(pipe2); + GetCurrentConsoleFont(std_output, FALSE, &cfi); memset(&c, 10, sizeof(COORD)); SetLastError(0xdeadbeef); c = GetConsoleFontSize(std_output, cfi.nFont); - ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError()); GetClientRect(GetConsoleWindow(), &r); GetConsoleScreenBufferInfo(std_output, &csbi); - font_width = (r.right - r.left + 1) / csbi.srWindow.Right; - font_height = (r.bottom - r.top + 1) / csbi.srWindow.Bottom; - ok(c.X == font_width, "got %d, expected %d\n", c.X, font_width); - ok(c.Y == font_height, "got %d, expected %d\n", c.Y, font_height); + font_width = (r.right - r.left) / (csbi.srWindow.Right - csbi.srWindow.Left + 1); + font_height = (r.bottom - r.top) / (csbi.srWindow.Bottom - csbi.srWindow.Top + 1); + ok(c.X == font_width, "got %d, expected %ld\n", c.X, font_width); + ok(c.Y == font_height, "got %d, expected %ld\n", c.Y, font_height); hmod = GetModuleHandleA("kernel32.dll"); pGetNumberOfConsoleFonts = (void *)GetProcAddress(hmod, "GetNumberOfConsoleFonts"); @@ -2734,9 +3831,13 @@ static void test_GetConsoleFontSize(HANDLE std_output) memset(&c, 10, sizeof(COORD)); SetLastError(0xdeadbeef); c = GetConsoleFontSize(std_output, index); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError()); - ok(!c.X, "got %d, expected 0\n", c.X); - ok(!c.Y, "got %d, expected 0\n", c.Y); + ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef) /* win10 1809 */, + "unexpected last error %lu\n", GetLastError()); + if (GetLastError() == ERROR_INVALID_PARAMETER) + { + ok(!c.X, "got %d, expected 0\n", c.X); + ok(!c.Y, "got %d, expected 0\n", c.Y); + } } static void test_GetLargestConsoleWindowSize(HANDLE std_output) @@ -2746,6 +3847,7 @@ static void test_GetLargestConsoleWindowSize(HANDLE std_output) LONG workarea_w, workarea_h, maxcon_w, maxcon_h; CONSOLE_SCREEN_BUFFER_INFO sbi; CONSOLE_FONT_INFO cfi; + HANDLE pipe1, pipe2; DWORD index, i; HMODULE hmod; BOOL ret; @@ -2755,17 +3857,27 @@ static void test_GetLargestConsoleWindowSize(HANDLE std_output) memset(&c, 10, sizeof(COORD)); SetLastError(0xdeadbeef); c = GetLargestConsoleWindowSize(NULL); - ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); ok(!c.X, "got %d, expected 0\n", c.X); ok(!c.Y, "got %d, expected 0\n", c.Y); memset(&c, 10, sizeof(COORD)); SetLastError(0xdeadbeef); c = GetLargestConsoleWindowSize(GetStdHandle(STD_INPUT_HANDLE)); - ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); ok(!c.X, "got %d, expected 0\n", c.X); ok(!c.Y, "got %d, expected 0\n", c.Y); + CreatePipe(&pipe1, &pipe2, NULL, 0); + memset(&c, 10, sizeof(COORD)); + SetLastError(0xdeadbeef); + c = GetLargestConsoleWindowSize(pipe1); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); + ok(!c.X, "got %d, expected 0\n", c.X); + ok(!c.Y, "got %d, expected 0\n", c.Y); + CloseHandle(pipe1); + CloseHandle(pipe2); + SystemParametersInfoW(SPI_GETWORKAREA, 0, &r, 0); workarea_w = r.right - r.left; workarea_h = r.bottom - r.top - GetSystemMetrics(SM_CYCAPTION); @@ -2793,16 +3905,16 @@ static void test_GetLargestConsoleWindowSize(HANDLE std_output) memset(&c, 10, sizeof(COORD)); SetLastError(0xdeadbeef); c = GetLargestConsoleWindowSize(std_output); - ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError()); GetCurrentConsoleFont(std_output, FALSE, &cfi); font = GetConsoleFontSize(std_output, cfi.nFont); maxcon_w = workarea_w / font.X; maxcon_h = workarea_h / font.Y; - ok(c.X == maxcon_w || c.X == maxcon_w - 1 /* Win10 */, "got %d, expected %d\n", c.X, maxcon_w); - ok(c.Y == maxcon_h || c.Y == maxcon_h - 1 /* Win10 */, "got %d, expected %d\n", c.Y, maxcon_h); + ok(c.X == maxcon_w || c.X == maxcon_w - 1 /* Win10 */, "got %d, expected %ld\n", c.X, maxcon_w); + ok(c.Y == maxcon_h || c.Y == maxcon_h - 1 /* Win10 */, "got %d, expected %ld\n", c.Y, maxcon_h); ret = GetConsoleScreenBufferInfo(std_output, &sbi); - ok(ret, "GetConsoleScreenBufferInfo failed %u\n", GetLastError()); + ok(ret, "GetConsoleScreenBufferInfo failed %lu\n", GetLastError()); ok(sbi.dwMaximumWindowSize.X == min(c.X, sbi.dwSize.X), "got %d, expected %d\n", sbi.dwMaximumWindowSize.X, min(c.X, sbi.dwSize.X)); ok(sbi.dwMaximumWindowSize.Y == min(c.Y, sbi.dwSize.Y), "got %d, expected %d\n", @@ -2852,17 +3964,25 @@ static void test_GetConsoleFontInfo(HANDLE std_output) SetLastError(0xdeadbeef); ret = pGetConsoleFontInfo(NULL, FALSE, 0, cfi); ok(!ret, "got %d, expected zero\n", ret); - todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError()); + if (GetLastError() == LOWORD(E_NOTIMPL) /* win10 1709+ */ || + broken(GetLastError() == ERROR_GEN_FAILURE) /* win10 1607 */) + { + skip("GetConsoleFontInfo is not implemented\n"); + SetConsoleScreenBufferSize(std_output, orig_sb_size); + HeapFree(GetProcessHeap(), 0, cfi); + return; + } + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); SetLastError(0xdeadbeef); ret = pGetConsoleFontInfo(GetStdHandle(STD_INPUT_HANDLE), FALSE, 0, cfi); ok(!ret, "got %d, expected zero\n", ret); - todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); SetLastError(0xdeadbeef); ret = pGetConsoleFontInfo(std_output, FALSE, 0, cfi); ok(!ret, "got %d, expected zero\n", ret); - todo_wine ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError()); GetConsoleScreenBufferInfo(std_output, &csbi); win_width = csbi.srWindow.Right - csbi.srWindow.Left + 1; @@ -2874,55 +3994,53 @@ static void test_GetConsoleFontInfo(HANDLE std_output) memset(cfi, 0, memsize); ret = pGetConsoleFontInfo(std_output, FALSE, num_fonts, cfi); - todo_wine ok(ret, "got %d, expected non-zero\n", ret); - - todo_wine ok(cfi[index].dwFontSize.X == win_width, "got %d, expected %d\n", - cfi[index].dwFontSize.X, win_width); - todo_wine ok(cfi[index].dwFontSize.Y == win_height, "got %d, expected %d\n", - cfi[index].dwFontSize.Y, win_height); + ok(ret, "got %d, expected non-zero\n", ret); + ok(cfi[index].dwFontSize.X == win_width, "got %d, expected %d\n", + cfi[index].dwFontSize.X, win_width); + ok(cfi[index].dwFontSize.Y == win_height, "got %d, expected %d\n", + cfi[index].dwFontSize.Y, win_height); for (i = 0; i < num_fonts; i++) { - ok(cfi[i].nFont == i, "element out of order, got nFont %d, expected %d\n", cfi[i].nFont, i); + ok(cfi[i].nFont == i, "element out of order, got nFont %ld, expected %ld\n", cfi[i].nFont, i); tmp_font = GetConsoleFontSize(std_output, cfi[i].nFont); tmp_w = (double)orig_font.X / tmp_font.X * win_width; tmp_h = (double)orig_font.Y / tmp_font.Y * win_height; - todo_wine ok(cfi[i].dwFontSize.X == tmp_w, "got %d, expected %d\n", cfi[i].dwFontSize.X, tmp_w); - todo_wine ok(cfi[i].dwFontSize.Y == tmp_h, "got %d, expected %d\n", cfi[i].dwFontSize.Y, tmp_h); + ok(cfi[i].dwFontSize.X == tmp_w, "got %d, expected %d\n", cfi[i].dwFontSize.X, tmp_w); + ok(cfi[i].dwFontSize.Y == tmp_h, "got %d, expected %d\n", cfi[i].dwFontSize.Y, tmp_h); } SetLastError(0xdeadbeef); ret = pGetConsoleFontInfo(NULL, TRUE, 0, cfi); ok(!ret, "got %d, expected zero\n", ret); - todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); SetLastError(0xdeadbeef); ret = pGetConsoleFontInfo(GetStdHandle(STD_INPUT_HANDLE), TRUE, 0, cfi); ok(!ret, "got %d, expected zero\n", ret); - todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); SetLastError(0xdeadbeef); ret = pGetConsoleFontInfo(std_output, TRUE, 0, cfi); ok(!ret, "got %d, expected zero\n", ret); - todo_wine ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError()); memset(cfi, 0, memsize); ret = pGetConsoleFontInfo(std_output, TRUE, num_fonts, cfi); - todo_wine ok(ret, "got %d, expected non-zero\n", ret); - - todo_wine ok(cfi[index].dwFontSize.X == csbi.dwMaximumWindowSize.X, "got %d, expected %d\n", - cfi[index].dwFontSize.X, csbi.dwMaximumWindowSize.X); - todo_wine ok(cfi[index].dwFontSize.Y == csbi.dwMaximumWindowSize.Y, "got %d, expected %d\n", - cfi[index].dwFontSize.Y, csbi.dwMaximumWindowSize.Y); + ok(ret, "got %d, expected non-zero\n", ret); + ok(cfi[index].dwFontSize.X == csbi.dwMaximumWindowSize.X, "got %d, expected %d\n", + cfi[index].dwFontSize.X, csbi.dwMaximumWindowSize.X); + ok(cfi[index].dwFontSize.Y == csbi.dwMaximumWindowSize.Y, "got %d, expected %d\n", + cfi[index].dwFontSize.Y, csbi.dwMaximumWindowSize.Y); for (i = 0; i < num_fonts; i++) { - ok(cfi[i].nFont == i, "element out of order, got nFont %d, expected %d\n", cfi[i].nFont, i); + ok(cfi[i].nFont == i, "element out of order, got nFont %ld, expected %ld\n", cfi[i].nFont, i); tmp_font = GetConsoleFontSize(std_output, cfi[i].nFont); tmp_w = (double)orig_font.X / tmp_font.X * csbi.dwMaximumWindowSize.X; tmp_h = (double)orig_font.Y / tmp_font.Y * csbi.dwMaximumWindowSize.Y; - todo_wine ok(cfi[i].dwFontSize.X == tmp_w, "got %d, expected %d\n", cfi[i].dwFontSize.X, tmp_w); - todo_wine ok(cfi[i].dwFontSize.Y == tmp_h, "got %d, expected %d\n", cfi[i].dwFontSize.Y, tmp_h); + ok(cfi[i].dwFontSize.X == tmp_w, "got %d, expected %d\n", cfi[i].dwFontSize.X, tmp_w); + ok(cfi[i].dwFontSize.Y == tmp_h, "got %d, expected %d\n", cfi[i].dwFontSize.Y, tmp_h); } HeapFree(GetProcessHeap(), 0, cfi); @@ -2948,12 +4066,18 @@ static void test_SetConsoleFont(HANDLE std_output) SetLastError(0xdeadbeef); ret = pSetConsoleFont(NULL, 0); ok(!ret, "got %d, expected zero\n", ret); - todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError()); + if (GetLastError() == LOWORD(E_NOTIMPL) /* win10 1709+ */ || + broken(GetLastError() == ERROR_GEN_FAILURE) /* win10 1607 */) + { + skip("SetConsoleFont is not implemented\n"); + return; + } + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); SetLastError(0xdeadbeef); ret = pSetConsoleFont(GetStdHandle(STD_INPUT_HANDLE), 0); ok(!ret, "got %d, expected zero\n", ret); - todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); pGetNumberOfConsoleFonts = (void *)GetProcAddress(hmod, "GetNumberOfConsoleFonts"); if (!pGetNumberOfConsoleFonts) @@ -2967,7 +4091,7 @@ static void test_SetConsoleFont(HANDLE std_output) SetLastError(0xdeadbeef); ret = pSetConsoleFont(std_output, num_fonts); ok(!ret, "got %d, expected zero\n", ret); - todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError()); + todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError()); } static void test_GetConsoleScreenBufferInfoEx(HANDLE std_output) @@ -2975,6 +4099,7 @@ static void test_GetConsoleScreenBufferInfoEx(HANDLE std_output) HANDLE hmod; BOOL (WINAPI *pGetConsoleScreenBufferInfoEx)(HANDLE, CONSOLE_SCREEN_BUFFER_INFOEX *); CONSOLE_SCREEN_BUFFER_INFOEX csbix; + HANDLE pipe1, pipe2; BOOL ret; HANDLE std_input = GetStdHandle(STD_INPUT_HANDLE); @@ -2989,106 +4114,1525 @@ static void test_GetConsoleScreenBufferInfoEx(HANDLE std_output) SetLastError(0xdeadbeef); ret = pGetConsoleScreenBufferInfoEx(NULL, &csbix); ok(!ret, "got %d, expected zero\n", ret); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError()); SetLastError(0xdeadbeef); ret = pGetConsoleScreenBufferInfoEx(std_input, &csbix); ok(!ret, "got %d, expected zero\n", ret); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError()); SetLastError(0xdeadbeef); ret = pGetConsoleScreenBufferInfoEx(std_output, &csbix); ok(!ret, "got %d, expected zero\n", ret); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError()); csbix.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); SetLastError(0xdeadbeef); ret = pGetConsoleScreenBufferInfoEx(NULL, &csbix); ok(!ret, "got %d, expected zero\n", ret); - ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); SetLastError(0xdeadbeef); ret = pGetConsoleScreenBufferInfoEx(std_input, &csbix); ok(!ret, "got %d, expected zero\n", ret); - ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); + + CreatePipe(&pipe1, &pipe2, NULL, 0); + SetLastError(0xdeadbeef); + ret = pGetConsoleScreenBufferInfoEx(std_input, &csbix); + ok(!ret, "got %d, expected zero\n", ret); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); + CloseHandle(pipe1); + CloseHandle(pipe2); SetLastError(0xdeadbeef); ret = pGetConsoleScreenBufferInfoEx(std_output, &csbix); ok(ret, "got %d, expected non-zero\n", ret); - ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError()); +} + +static void test_FreeConsole(void) +{ + HANDLE handle, unbound_output = NULL, unbound_input = NULL; + DWORD size, mode, type; + WCHAR title[16]; + char buf[32]; + HWND hwnd; + UINT cp; + BOOL ret; + + ok(RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle != NULL, "ConsoleHandle is NULL\n"); + ok(!SetConsoleCtrlHandler(mydummych, FALSE), "dummy ctrl handler shouldn't be set\n"); + ret = SetConsoleCtrlHandler(mydummych, TRUE); + ok(ret, "SetConsoleCtrlHandler failed: %lu\n", GetLastError()); + if (!skip_nt) + { + unbound_input = create_unbound_handle(FALSE, TRUE); + unbound_output = create_unbound_handle(TRUE, TRUE); + } + + ret = FreeConsole(); + ok(ret, "FreeConsole failed: %lu\n", GetLastError()); + + ok(RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle == NULL, "ConsoleHandle = %p\n", + RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle); + + handle = CreateFileA("CONOUT$", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(handle == INVALID_HANDLE_VALUE && + (GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == ERROR_ACCESS_DENIED /* winxp */)), + "CreateFileA failed: %lu\n", GetLastError()); + + handle = CreateFileA("CONIN$", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); + ok(handle == INVALID_HANDLE_VALUE && + (GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == ERROR_ACCESS_DENIED /* winxp */)), + "CreateFileA failed: %lu\n", GetLastError()); + + handle = CreateFileA("CON", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); + ok(handle == INVALID_HANDLE_VALUE && + (GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == ERROR_ACCESS_DENIED /* winxp */)), + "CreateFileA failed: %lu\n", GetLastError()); + + handle = CreateFileA("CON", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(handle == INVALID_HANDLE_VALUE && + (GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == ERROR_FILE_NOT_FOUND /* winxp */)), + "CreateFileA failed: %lu\n", GetLastError()); + + handle = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + CONSOLE_TEXTMODE_BUFFER, NULL); + ok(handle == INVALID_HANDLE_VALUE && GetLastError() == ERROR_INVALID_HANDLE, + "CreateConsoleScreenBuffer returned: %p (%lu)\n", handle, GetLastError()); + + SetLastError(0xdeadbeef); + cp = GetConsoleCP(); + ok(!cp, "cp = %x\n", cp); + ok(GetLastError() == ERROR_INVALID_HANDLE, "last error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + cp = GetConsoleOutputCP(); + ok(!cp, "cp = %x\n", cp); + ok(GetLastError() == ERROR_INVALID_HANDLE, "last error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = SetConsoleCP(GetOEMCP()); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "SetConsoleCP returned %x(%lu)\n", ret, GetLastError()); + + SetLastError(0xdeadbeef); + ret = SetConsoleOutputCP(GetOEMCP()); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "SetConsoleCP returned %x(%lu)\n", ret, GetLastError()); + + if (skip_nt) return; + + SetLastError(0xdeadbeef); + memset( title, 0xc0, sizeof(title) ); + size = GetConsoleTitleW( title, ARRAY_SIZE(title) ); + ok(!size, "GetConsoleTitleW returned %lu\n", size); + ok(title[0] == 0xc0c0, "title byffer changed\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE, "last error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = SetConsoleTitleW( L"test" ); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "SetConsoleTitleW returned %x(%lu)\n", ret, GetLastError()); + + SetLastError(0xdeadbeef); + hwnd = GetConsoleWindow(); + ok(!hwnd, "hwnd = %p\n", hwnd); + ok(GetLastError() == ERROR_INVALID_HANDLE, "last error %lu\n", GetLastError()); + + ret = GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "GenerateConsoleCtrlEvent returned %x(%lu)\n", + ret, GetLastError()); + + SetStdHandle( STD_INPUT_HANDLE, (HANDLE)0xdeadbeef ); + handle = GetConsoleInputWaitHandle(); + ok(handle == (HANDLE)0xdeadbeef, "GetConsoleInputWaitHandle returned %p\n", handle); + SetStdHandle( STD_INPUT_HANDLE, NULL ); + handle = GetConsoleInputWaitHandle(); + ok(!handle, "GetConsoleInputWaitHandle returned %p\n", handle); + + ret = ReadFile(unbound_input, buf, sizeof(buf), &size, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, + "ReadFile returned %x %lu\n", ret, GetLastError()); + + ret = FlushFileBuffers(unbound_input); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, + "ReadFile returned %x %lu\n", ret, GetLastError()); + + ret = WriteFile(unbound_input, "test", 4, &size, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, + "ReadFile returned %x %lu\n", ret, GetLastError()); + + ret = GetConsoleMode(unbound_input, &mode); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, + "GetConsoleMode returned %x %lu\n", ret, GetLastError()); + ret = GetConsoleMode(unbound_output, &mode); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, + "GetConsoleMode returned %x %lu\n", ret, GetLastError()); + + type = GetFileType(unbound_input); + ok(type == FILE_TYPE_CHAR, "GetFileType returned %lu\n", type); + type = GetFileType(unbound_output); + ok(type == FILE_TYPE_CHAR, "GetFileType returned %lu\n", type); + + todo_wine + ok(!SetConsoleCtrlHandler(mydummych, FALSE), "FreeConsole() should have reset ctrl handlers' list\n"); + + CloseHandle(unbound_input); + CloseHandle(unbound_output); +} + +static void test_SetConsoleScreenBufferInfoEx(HANDLE std_output) +{ +#if defined(__REACTOS__) && DLL_EXPORT_VERSION < 0x600 + UNREFERENCED_PARAMETER(std_output); + skip("Cannot build test_SetConsoleScreenBufferInfoEx() unless DLL_EXPORT_VERSION >= 0x600.\n"); +#else + BOOL ret; + HANDLE hmod; + HANDLE std_input = CreateFileA("CONIN$", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); + BOOL (WINAPI *pSetConsoleScreenBufferInfoEx)(HANDLE, CONSOLE_SCREEN_BUFFER_INFOEX *); + BOOL (WINAPI *pGetConsoleScreenBufferInfoEx)(HANDLE, CONSOLE_SCREEN_BUFFER_INFOEX *); + CONSOLE_SCREEN_BUFFER_INFOEX info; + + hmod = GetModuleHandleA("kernel32.dll"); + pSetConsoleScreenBufferInfoEx = (void *)GetProcAddress(hmod, "SetConsoleScreenBufferInfoEx"); + pGetConsoleScreenBufferInfoEx = (void *)GetProcAddress(hmod, "GetConsoleScreenBufferInfoEx"); + if (!pSetConsoleScreenBufferInfoEx || !pGetConsoleScreenBufferInfoEx) + { + win_skip("SetConsoleScreenBufferInfoEx is not available\n"); + return; + } + + memset(&info, 0, sizeof(CONSOLE_SCREEN_BUFFER_INFOEX)); + info.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); + pGetConsoleScreenBufferInfoEx(std_output, &info); + + SetLastError(0xdeadbeef); + ret = pSetConsoleScreenBufferInfoEx(NULL, &info); + ok(!ret, "got %d, expected zero\n", ret); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = pSetConsoleScreenBufferInfoEx(std_output, &info); + ok(ret, "got %d, expected one\n", ret); + ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = pSetConsoleScreenBufferInfoEx(std_input, &info); + ok(!ret, "got %d, expected zero\n", ret); + ok(GetLastError() == ERROR_INVALID_HANDLE || GetLastError() == ERROR_ACCESS_DENIED, + "got %lu, expected 5 or 6\n", GetLastError()); + + info.cbSize = 0; + SetLastError(0xdeadbeef); + ret = pSetConsoleScreenBufferInfoEx(std_output, &info); + ok(!ret, "got %d, expected zero\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError()); + + CloseHandle(std_input); +#endif +} + +static void test_GetConsoleOriginalTitleA(void) +{ +#if defined(__REACTOS__) && DLL_EXPORT_VERSION < 0x600 + skip("Cannot build test_GetConsoleOriginalTitleA() unless DLL_EXPORT_VERSION >= 0x600.\n"); +#else + char title[] = "Original Console Title"; + char buf[64]; + DWORD ret, title_len = strlen(title); + + ret = GetConsoleOriginalTitleA(NULL, 0); + ok(!ret, "Unexpected string length; error %lu\n", GetLastError()); + + ret = GetConsoleOriginalTitleA(buf, 0); + ok(!ret, "Unexpected string length; error %lu\n", GetLastError()); + + ret = GetConsoleOriginalTitleA(buf, ARRAY_SIZE(buf)); + ok(ret, "GetConsoleOriginalTitleA failed: %lu\n", GetLastError()); + ok(!strcmp(buf, title), "got %s, expected %s\n", wine_dbgstr_a(buf), wine_dbgstr_a(title)); + ok(ret == title_len, "got %lu, expected %lu\n", ret, title_len); + + ret = SetConsoleTitleA("test"); + ok(ret, "SetConsoleTitleA failed: %lu\n", GetLastError()); + + ret = GetConsoleOriginalTitleA(buf, ARRAY_SIZE(buf)); + ok(ret, "GetConsoleOriginalTitleA failed: %lu\n", GetLastError()); + ok(!strcmp(buf, title), "got %s, expected %s\n", wine_dbgstr_a(buf), wine_dbgstr_a(title)); + ok(ret == title_len, "got %lu, expected %lu\n", ret, title_len); +#endif +} + +static void test_GetConsoleOriginalTitleW(void) +{ +#if defined(__REACTOS__) && DLL_EXPORT_VERSION < 0x600 + skip("Cannot build test_GetConsoleOriginalTitleW() unless DLL_EXPORT_VERSION >= 0x600.\n"); +#else + WCHAR title[] = L"Original Console Title"; + WCHAR buf[64]; + DWORD ret, title_len = lstrlenW(title); + + ret = GetConsoleOriginalTitleW(NULL, 0); + ok(!ret, "Unexpected string length; error %lu\n", GetLastError()); + + ret = GetConsoleOriginalTitleW(buf, 0); + ok(!ret, "Unexpected string length; error %lu\n", GetLastError()); + + ret = GetConsoleOriginalTitleW(buf, ARRAY_SIZE(buf)); + ok(ret, "GetConsoleOriginalTitleW failed: %lu\n", GetLastError()); + buf[ret] = 0; + ok(!wcscmp(buf, title), "got %s, expected %s\n", wine_dbgstr_w(buf), wine_dbgstr_w(title)); + ok(ret == title_len, "got %lu, expected %lu\n", ret, title_len); + + ret = SetConsoleTitleW(L"test"); + ok(ret, "SetConsoleTitleW failed: %lu\n", GetLastError()); + + ret = GetConsoleOriginalTitleW(buf, ARRAY_SIZE(buf)); + ok(ret, "GetConsoleOriginalTitleW failed: %lu\n", GetLastError()); + ok(!wcscmp(buf, title), "got %s, expected %s\n", wine_dbgstr_w(buf), wine_dbgstr_w(title)); + ok(ret == title_len, "got %lu, expected %lu\n", ret, title_len); + + ret = GetConsoleOriginalTitleW(buf, 5); + ok(ret, "GetConsoleOriginalTitleW failed: %lu\n", GetLastError()); + ok(!wcscmp(buf, L"Orig"), "got %s, expected 'Orig'\n", wine_dbgstr_w(buf)); + ok(ret == title_len, "got %lu, expected %lu\n", ret, title_len); +#endif +} + +static void test_GetConsoleOriginalTitleW_empty(void) +{ +#if defined(__REACTOS__) && DLL_EXPORT_VERSION < 0x600 + skip("Cannot build test_GetConsoleOriginalTitleW_empty() unless DLL_EXPORT_VERSION >= 0x600.\n"); +#else + WCHAR buf[64]; + DWORD ret; + + ret = GetConsoleOriginalTitleW(buf, ARRAY_SIZE(buf)); + ok(!ret, "GetConsoleOriginalTitleW failed: %lu\n", GetLastError()); +#endif +} + +static void test_GetConsoleOriginalTitle(void) +{ + STARTUPINFOA si = { sizeof(si) }; + PROCESS_INFORMATION info; + char **argv, buf[MAX_PATH]; + char title[] = "Original Console Title"; + BOOL ret; + +#ifdef __REACTOS__ + if (GetNTVersion() < _WIN32_WINNT_VISTA) { + skip("This test is incredibly broken on WS03\n"); + return; + } +#endif + winetest_get_mainargs(&argv); + sprintf(buf, "\"%s\" console title_test", argv[0]); + si.lpTitle = title; + ret = CreateProcessA(NULL, buf, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &info); + ok(ret, "CreateProcess failed: %lu\n", GetLastError()); + CloseHandle(info.hThread); + wait_child_process(info.hProcess); + CloseHandle(info.hProcess); + + strcat(buf, " empty"); + title[0] = 0; + ret = CreateProcessA(NULL, buf, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &info); + ok(ret, "CreateProcess failed: %lu\n", GetLastError()); + CloseHandle(info.hThread); + wait_child_process(info.hProcess); + CloseHandle(info.hProcess); +} + +static void test_GetConsoleTitleA(void) +{ + char buf[64], str[] = "test"; + DWORD ret; + + ret = SetConsoleTitleA(str); + ok(ret, "SetConsoleTitleA failed: %lu\n", GetLastError()); + + ret = GetConsoleTitleA(NULL, 0); + ok(!ret, "Unexpected string length; error %lu\n", GetLastError()); + + ret = GetConsoleTitleA(buf, 0); + ok(!ret, "Unexpected string length; error %lu\n", GetLastError()); + + ret = GetConsoleTitleA(buf, ARRAY_SIZE(buf)); + ok(ret, "GetConsoleTitleW failed: %lu\n", GetLastError()); + ok(ret == strlen(str), "Got string length %lu, expected %Iu\n", ret, strlen(str)); + ok(!strcmp(buf, str), "Title = %s\n", wine_dbgstr_a(buf)); + + ret = SetConsoleTitleA(""); + ok(ret, "SetConsoleTitleA failed: %lu\n", GetLastError()); + + ret = GetConsoleTitleA(buf, ARRAY_SIZE(buf)); + ok(!ret, "Unexpected string length; error %lu\n", GetLastError()); +} + +static void test_GetConsoleTitleW(void) +{ + WCHAR buf[64], str[] = L"test"; + DWORD ret; + + ret = SetConsoleTitleW(str); + ok(ret, "SetConsoleTitleW failed: %lu\n", GetLastError()); + + ret = GetConsoleTitleW(NULL, 0); + ok(!ret, "Unexpected string length; error %lu\n", GetLastError()); + + ret = GetConsoleTitleW(buf, 0); + ok(!ret, "Unexpected string length; error %lu\n", GetLastError()); + + ret = GetConsoleTitleW(buf, ARRAY_SIZE(buf)); + ok(ret, "GetConsoleTitleW failed: %lu\n", GetLastError()); + ok(ret == wcslen(str), "Got string length %lu, expected %Iu\n", ret, wcslen(str)); + ok(!wcscmp(buf, str), "Title = %s\n", wine_dbgstr_w(buf)); + + ret = GetConsoleTitleW(buf, 2); + ok(ret, "GetConsoleTitleW failed: %lu\n", GetLastError()); +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) +#endif + ok(ret == wcslen(str), "Got string length %lu, expected %Iu\n", ret, wcslen(str)); + if (!skip_nt) ok(!wcscmp(buf, L"t"), "Title = %s\n", wine_dbgstr_w(buf)); + + ret = GetConsoleTitleW(buf, 4); + ok(ret, "GetConsoleTitleW failed: %lu\n", GetLastError()); +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) +#endif + ok(ret == wcslen(str), "Got string length %lu, expected %Iu\n", ret, wcslen(str)); + if (!skip_nt) ok(!wcscmp(buf, L"tes"), "Title = %s\n", wine_dbgstr_w(buf)); + + ret = SetConsoleTitleW(L""); + ok(ret, "SetConsoleTitleW failed: %lu\n", GetLastError()); + + ret = GetConsoleTitleW(buf, ARRAY_SIZE(buf)); + ok(!ret, "Unexpected string length; error %lu\n", GetLastError()); +} + +static void test_file_info(HANDLE input, HANDLE output) +{ + FILE_STANDARD_INFORMATION std_info; + FILE_FS_DEVICE_INFORMATION fs_info; + LARGE_INTEGER size; + IO_STATUS_BLOCK io; + DWORD type; + NTSTATUS status; + BOOL ret; + + if (skip_nt) return; + + status = NtQueryInformationFile(input, &io, &std_info, sizeof(std_info), FileStandardInformation); + ok(status == STATUS_INVALID_DEVICE_REQUEST, "NtQueryInformationFile returned: %#lx\n", status); + + status = NtQueryInformationFile(output, &io, &std_info, sizeof(std_info), FileStandardInformation); + ok(status == STATUS_INVALID_DEVICE_REQUEST, "NtQueryInformationFile returned: %#lx\n", status); + + ret = GetFileSizeEx(input, &size); + ok(!ret && GetLastError() == ERROR_INVALID_FUNCTION, + "GetFileSizeEx returned %x(%lu)\n", ret, GetLastError()); + + ret = GetFileSizeEx(output, &size); + ok(!ret && GetLastError() == ERROR_INVALID_FUNCTION, + "GetFileSizeEx returned %x(%lu)\n", ret, GetLastError()); + + status = NtQueryVolumeInformationFile(input, &io, &fs_info, sizeof(fs_info), FileFsDeviceInformation); + ok(!status, "NtQueryVolumeInformationFile failed: %#lx\n", status); + ok(fs_info.DeviceType == FILE_DEVICE_CONSOLE, "DeviceType = %lu\n", fs_info.DeviceType); + ok(fs_info.Characteristics == FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL, + "Characteristics = %lx\n", fs_info.Characteristics); + + status = NtQueryVolumeInformationFile(output, &io, &fs_info, sizeof(fs_info), FileFsDeviceInformation); + ok(!status, "NtQueryVolumeInformationFile failed: %#lx\n", status); + ok(fs_info.DeviceType == FILE_DEVICE_CONSOLE, "DeviceType = %lu\n", fs_info.DeviceType); + ok(fs_info.Characteristics == FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL, + "Characteristics = %lx\n", fs_info.Characteristics); + + type = GetFileType(input); + ok(type == FILE_TYPE_CHAR, "GetFileType returned %lu\n", type); + type = GetFileType(output); + ok(type == FILE_TYPE_CHAR, "GetFileType returned %lu\n", type); +} + +static void test_console_as_root_directory(void) +{ + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK iosb; + UNICODE_STRING name; + HANDLE handle, h2; + NTSTATUS status; + + handle = CreateFileA( "CON", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileA error %lu\n", GetLastError() ); + + RtlInitUnicodeString( &name, L"" ); + InitializeObjectAttributes( &attr, &name, 0, handle, NULL ); + status = NtCreateFile( &h2, SYNCHRONIZE, &attr, &iosb, NULL, 0, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, 0, NULL, 0 ); +#ifdef __REACTOS__ + ok( status == STATUS_NOT_FOUND || broken( status == STATUS_OBJECT_TYPE_MISMATCH ) /* Win7 */ || broken( status == STATUS_INVALID_HANDLE ) /* WS03 */, +#else + ok( status == STATUS_NOT_FOUND || broken( status == STATUS_OBJECT_TYPE_MISMATCH ) /* Win7 */, +#endif + "NtCreateFile returned %#lx\n", status ); + + CloseHandle( handle ); +} + +static void test_condrv_server_as_root_directory(void) +{ + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK iosb; + UNICODE_STRING name; + HANDLE handle, h2; + NTSTATUS status; + + FreeConsole(); + + RtlInitUnicodeString( &name, L"\\Device\\ConDrv\\Server" ); + InitializeObjectAttributes( &attr, &name, 0, NULL, NULL ); + status = NtCreateFile( &handle, SYNCHRONIZE, &attr, &iosb, NULL, 0, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, 0, NULL, 0 ); + ok( !status || broken( status == STATUS_OBJECT_PATH_NOT_FOUND ) /* Win7 */, + "NtCreateFile returned %#lx\n", status ); + + if (status) + { + win_skip( "cannot open \\Device\\ConDrv\\Server, skipping RootDirectory test" ); + } + else + { + RtlInitUnicodeString( &name, L"" ); + InitializeObjectAttributes( &attr, &name, 0, handle, NULL ); + status = NtCreateFile( &h2, SYNCHRONIZE, &attr, &iosb, NULL, 0, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, 0, NULL, 0 ); + ok( status == STATUS_NOT_FOUND, "NtCreateFile returned %#lx\n", status ); + + CloseHandle( handle ); + } +} + +static void test_AttachConsole_child(DWORD console_pid) +{ + HANDLE pipe_in, pipe_out; + COORD c = {0,0}; + HANDLE console; + char buf[32]; + DWORD len; + BOOL res; + + res = CreatePipe(&pipe_in, &pipe_out, NULL, 0); + ok(res, "CreatePipe failed: %lu\n", GetLastError()); + + res = AttachConsole(console_pid); + ok(!res && GetLastError() == ERROR_ACCESS_DENIED, + "AttachConsole returned: %x(%lu)\n", res, GetLastError()); + + ok(RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle != NULL, "ConsoleHandle is NULL\n"); + res = FreeConsole(); + ok(res, "FreeConsole failed: %lu\n", GetLastError()); + ok(RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle == NULL, "ConsoleHandle = %p\n", + RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle); + + SetStdHandle(STD_ERROR_HANDLE, pipe_out); + + ok(!SetConsoleCtrlHandler(mydummych, FALSE), "dummy ctrl handler shouldn't be set\n"); + res = SetConsoleCtrlHandler(mydummych, TRUE); + ok(res, "SetConsoleCtrlHandler failed: %lu\n", GetLastError()); + + res = AttachConsole(console_pid); + ok(res, "AttachConsole failed: %lu\n", GetLastError()); + + ok(pipe_out != GetStdHandle(STD_ERROR_HANDLE), "std handle not set to console\n"); + ok(RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle != NULL, "ConsoleHandle is NULL\n"); + + console = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(console != INVALID_HANDLE_VALUE, "Could not open console\n"); + + res = ReadConsoleOutputCharacterA(console, buf, 6, c, &len); + ok(res, "ReadConsoleOutputCharacterA failed: %lu\n", GetLastError()); + ok(len == 6, "len = %lu\n", len); + ok(!memcmp(buf, "Parent", 6), "Unexpected console output\n"); + + todo_wine + ok(!SetConsoleCtrlHandler(mydummych, FALSE), "AttachConsole() should have reset ctrl handlers' list\n"); + + res = FreeConsole(); + ok(res, "FreeConsole failed: %lu\n", GetLastError()); + + SetStdHandle(STD_INPUT_HANDLE, pipe_in); + SetStdHandle(STD_OUTPUT_HANDLE, pipe_out); + + res = AttachConsole(ATTACH_PARENT_PROCESS); + ok(res, "AttachConsole failed: %lu\n", GetLastError()); + + if (pGetConsoleProcessList) + { + DWORD list[2] = { 0xbabebabe }; + DWORD pid = GetCurrentProcessId(); + + SetLastError(0xdeadbeef); + len = pGetConsoleProcessList(list, 1); + ok(len == 2, "Expected 2 processes, got %ld\n", len); + ok(list[0] == 0xbabebabe, "Unexpected value in list %lu\n", list[0]); + + len = pGetConsoleProcessList(list, 2); + ok(len == 2, "Expected 2 processes, got %ld\n", len); + ok(list[0] == console_pid || list[1] == console_pid, "Parent PID not in list\n"); + ok(list[0] == pid || list[1] == pid, "PID not in list\n"); + ok(GetLastError() == 0xdeadbeef, "Unexpected last error: %lu\n", GetLastError()); + } + + ok(pipe_in != GetStdHandle(STD_INPUT_HANDLE), "std handle not set to console\n"); + ok(pipe_out != GetStdHandle(STD_OUTPUT_HANDLE), "std handle not set to console\n"); + + console = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(console != INVALID_HANDLE_VALUE, "Could not open console\n"); + + res = ReadConsoleOutputCharacterA(console, buf, 6, c, &len); + ok(res, "ReadConsoleOutputCharacterA failed: %lu\n", GetLastError()); + ok(len == 6, "len = %lu\n", len); + ok(!memcmp(buf, "Parent", 6), "Unexpected console output\n"); + + simple_write_console(console, "Child"); + CloseHandle(console); + + res = FreeConsole(); + ok(res, "FreeConsole failed: %lu\n", GetLastError()); + + res = CloseHandle(pipe_in); + ok(res, "pipe_in is no longer valid\n"); + res = CloseHandle(pipe_out); + ok(res, "pipe_out is no longer valid\n"); +} + +static void test_AttachConsole(HANDLE console) +{ + STARTUPINFOA si = { sizeof(si) }; + PROCESS_INFORMATION info; + char **argv, buf[MAX_PATH]; + COORD c = {0,0}; + DWORD len; + BOOL res; + + simple_write_console(console, "Parent console"); + + winetest_get_mainargs(&argv); + sprintf(buf, "\"%s\" console attach_console %lx", argv[0], GetCurrentProcessId()); + res = CreateProcessA(NULL, buf, NULL, NULL, TRUE, 0, NULL, NULL, &si, &info); + ok(res, "CreateProcess failed: %lu\n", GetLastError()); + CloseHandle(info.hThread); + + wait_child_process(info.hProcess); + CloseHandle(info.hProcess); + + res = ReadConsoleOutputCharacterA(console, buf, 5, c, &len); + ok(res, "ReadConsoleOutputCharacterA failed: %lu\n", GetLastError()); + ok(len == 5, "len = %lu\n", len); + ok(!memcmp(buf, "Child", 5), "Unexpected console output\n"); +} + +static void test_AllocConsole_child(void) +{ + HANDLE unbound_output; + HANDLE prev_output, prev_error; + STARTUPINFOW si; + DWORD mode; + BOOL res; + + GetStartupInfoW(&si); + + prev_output = GetStdHandle(STD_OUTPUT_HANDLE); + res = DuplicateHandle(GetCurrentProcess(), prev_output, GetCurrentProcess(), &unbound_output, + 0, FALSE, DUPLICATE_SAME_ACCESS); + ok(res, "DuplicateHandle failed: %lu\n", GetLastError()); + + res = GetConsoleMode(unbound_output, &mode); + ok(res, "GetConsoleMode failed: %lu\n", GetLastError()); + + prev_error = GetStdHandle(STD_ERROR_HANDLE); + if (si.dwFlags & STARTF_USESTDHANDLES) + { + res = GetConsoleMode(prev_error, &mode); + ok(!res && GetLastError() == ERROR_INVALID_HANDLE, "GetConsoleMode failed: %lu\n", GetLastError()); + } + + FreeConsole(); + + ok(GetStdHandle(STD_OUTPUT_HANDLE) == prev_output, "GetStdHandle(STD_OUTPUT_HANDLE) = %p\n", GetStdHandle(STD_OUTPUT_HANDLE)); + ok(GetStdHandle(STD_ERROR_HANDLE) == prev_error, "GetStdHandle(STD_ERROR_HANDLE) = %p\n", GetStdHandle(STD_ERROR_HANDLE)); + res = GetConsoleMode(unbound_output, &mode); + ok(!res && GetLastError() == ERROR_INVALID_HANDLE, "GetConsoleMode failed: %lu\n", GetLastError()); + + ok(!SetConsoleCtrlHandler(mydummych, FALSE), "dummy ctrl handler shouldn't be set\n"); + res = SetConsoleCtrlHandler(mydummych, TRUE); + ok(res, "SetConsoleCtrlHandler failed: %lu\n", GetLastError()); + res = AllocConsole(); + ok(res, "AllocConsole failed: %lu\n", GetLastError()); + + if (si.dwFlags & STARTF_USESTDHANDLES) + { + ok(GetStdHandle(STD_OUTPUT_HANDLE) == prev_output, "GetStdHandle(STD_OUTPUT_HANDLE) = %p\n", GetStdHandle(STD_OUTPUT_HANDLE)); + ok(GetStdHandle(STD_ERROR_HANDLE) == prev_error, "GetStdHandle(STD_ERROR_HANDLE) = %p\n", GetStdHandle(STD_ERROR_HANDLE)); + } + + res = GetConsoleMode(unbound_output, &mode); + ok(res, "GetConsoleMode failed: %lu\n", GetLastError()); + + todo_wine + ok(!SetConsoleCtrlHandler(mydummych, FALSE), "AllocConsole() should have reset ctrl handlers' list\n"); + + FreeConsole(); + SetStdHandle(STD_OUTPUT_HANDLE, NULL); + SetStdHandle(STD_ERROR_HANDLE, NULL); + res = AllocConsole(); + ok(res, "AllocConsole failed: %lu\n", GetLastError()); + + ok(GetStdHandle(STD_OUTPUT_HANDLE) != NULL, "GetStdHandle(STD_OUTPUT_HANDLE) = %p\n", GetStdHandle(STD_OUTPUT_HANDLE)); + ok(GetStdHandle(STD_ERROR_HANDLE) != NULL, "GetStdHandle(STD_ERROR_HANDLE) = %p\n", GetStdHandle(STD_ERROR_HANDLE)); + + res = GetConsoleMode(unbound_output, &mode); + ok(res, "GetConsoleMode failed: %lu\n", GetLastError()); + res = GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &mode); + ok(res, "GetConsoleMode failed: %lu\n", GetLastError()); + res = GetConsoleMode(GetStdHandle(STD_ERROR_HANDLE), &mode); + ok(res, "GetConsoleMode failed: %lu\n", GetLastError()); + + res = CloseHandle(unbound_output); + ok(res, "CloseHandle failed: %lu\n", GetLastError()); +} + +static void test_AllocConsole(void) +{ + SECURITY_ATTRIBUTES inheritable_attr = { sizeof(inheritable_attr), NULL, TRUE }; + STARTUPINFOA si = { sizeof(si) }; + PROCESS_INFORMATION info; + char **argv, buf[MAX_PATH]; + HANDLE pipe_read, pipe_write; + BOOL res; + + if (skip_nt) return; + + winetest_get_mainargs(&argv); + sprintf(buf, "\"%s\" console alloc_console", argv[0]); + res = CreateProcessA(NULL, buf, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &info); + ok(res, "CreateProcess failed: %lu\n", GetLastError()); + CloseHandle(info.hThread); + wait_child_process(info.hProcess); + CloseHandle(info.hProcess); + + res = CreatePipe(&pipe_read, &pipe_write, &inheritable_attr, 0); + ok(res, "CreatePipe failed: %lu\n", GetLastError()); + + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdError = pipe_write; + res = CreateProcessA(NULL, buf, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &info); + ok(res, "CreateProcess failed: %lu\n", GetLastError()); + CloseHandle(info.hThread); + wait_child_process(info.hProcess); + CloseHandle(info.hProcess); + + CloseHandle(pipe_read); + CloseHandle(pipe_write); +} + +static void test_pseudo_console_child(HANDLE input, HANDLE output) +{ + CONSOLE_SCREEN_BUFFER_INFO sb_info; + CONSOLE_CURSOR_INFO cursor_info; + DWORD mode; + HWND hwnd; + BOOL ret; + + ret = GetConsoleMode(input, &mode); + ok(ret, "GetConsoleMode failed: %lu\n", GetLastError()); + ok(mode == (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT | + ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS | ENABLE_AUTO_POSITION), + "mode = %lx\n", mode); + + ret = SetConsoleMode(input, mode & ~ENABLE_AUTO_POSITION); + ok(ret, "SetConsoleMode failed: %lu\n", GetLastError()); + + ret = GetConsoleMode(input, &mode); + ok(ret, "GetConsoleMode failed: %lu\n", GetLastError()); + ok(mode == (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT | + ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS), "mode = %lx\n", mode); + + ret = SetConsoleMode(input, mode | ENABLE_AUTO_POSITION); + ok(ret, "SetConsoleMode failed: %lu\n", GetLastError()); + + ret = GetConsoleMode(output, &mode); + ok(ret, "GetConsoleMode failed: %lu\n", GetLastError()); + mode &= ~ENABLE_VIRTUAL_TERMINAL_PROCESSING; + ok(mode == (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT), "mode = %lx\n", mode); + + ret = SetConsoleMode(output, mode & ~ENABLE_WRAP_AT_EOL_OUTPUT); + ok(ret, "SetConsoleMode failed: %lu\n", GetLastError()); + + ret = GetConsoleMode(output, &mode); + ok(ret, "GetConsoleMode failed: %lu\n", GetLastError()); + ok(mode == ENABLE_PROCESSED_OUTPUT, "mode = %lx\n", mode); + + ret = SetConsoleMode(output, mode | ENABLE_WRAP_AT_EOL_OUTPUT); + ok(ret, "SetConsoleMode failed: %lu\n", GetLastError()); + + ret = GetConsoleScreenBufferInfo(output, &sb_info); + ok(ret, "GetConsoleScreenBufferInfo failed: %lu\n", GetLastError()); + ok(sb_info.dwSize.X == 40, "dwSize.X = %u\n", sb_info.dwSize.X); + ok(sb_info.dwSize.Y == 30, "dwSize.Y = %u\n", sb_info.dwSize.Y); + ok(sb_info.dwCursorPosition.X == 0, "dwCursorPosition.X = %u\n", sb_info.dwCursorPosition.X); + ok(sb_info.dwCursorPosition.Y == 0, "dwCursorPosition.Y = %u\n", sb_info.dwCursorPosition.Y); + ok(sb_info.wAttributes == 7, "wAttributes = %x\n", sb_info.wAttributes); + ok(sb_info.srWindow.Left == 0, "srWindow.Left = %u\n", sb_info.srWindow.Left); + ok(sb_info.srWindow.Top == 0, "srWindow.Top = %u\n", sb_info.srWindow.Top); + ok(sb_info.srWindow.Right == 39, "srWindow.Right = %u\n", sb_info.srWindow.Right); + ok(sb_info.srWindow.Bottom == 29, "srWindow.Bottom = %u\n", sb_info.srWindow.Bottom); + ok(sb_info.dwMaximumWindowSize.X == 40, "dwMaximumWindowSize.X = %u\n", sb_info.dwMaximumWindowSize.X); + ok(sb_info.dwMaximumWindowSize.Y == 30, "dwMaximumWindowSize.Y = %u\n", sb_info.dwMaximumWindowSize.Y); + + ret = GetConsoleCursorInfo(output, &cursor_info); + ok(ret, "GetConsoleCursorInfo failed: %lu\n", GetLastError()); + ok(cursor_info.dwSize == 25, "dwSize = %lu\n", cursor_info.dwSize); + ok(cursor_info.bVisible == TRUE, "bVisible = %x\n", cursor_info.bVisible); + + hwnd = GetConsoleWindow(); + ok(IsWindow(hwnd), "no console window\n"); + + test_GetConsoleTitleA(); + test_GetConsoleTitleW(); + test_WriteConsoleInputW(input); +} + +static DWORD WINAPI read_pipe_proc( void *handle ) +{ + char buf[64]; + DWORD size; + while (ReadFile(handle, buf, sizeof(buf), &size, NULL)); + ok(GetLastError() == ERROR_BROKEN_PIPE, "ReadFile returned %lu\n", GetLastError()); + CloseHandle(handle); + return 0; +} + +static void test_pseudo_console(void) +{ + STARTUPINFOEXA startup = {{ sizeof(startup) }}; + HANDLE console_pipe, console_pipe2, thread; + char **argv, cmdline[MAX_PATH]; + PROCESS_INFORMATION info; + HPCON pseudo_console; + SIZE_T attr_size; + COORD size; + BOOL ret; + HRESULT hres; + + if (!pCreatePseudoConsole) + { + win_skip("CreatePseudoConsole not available\n"); + return; + } + + console_pipe = CreateNamedPipeW(L"\\\\.\\pipe\\pseudoconsoleconn", PIPE_ACCESS_DUPLEX, + PIPE_WAIT | PIPE_TYPE_BYTE, 1, 4096, 4096, NMPWAIT_USE_DEFAULT_WAIT, NULL); + ok(console_pipe != INVALID_HANDLE_VALUE, "CreateNamedPipeW failed: %lu\n", GetLastError()); + + console_pipe2 = CreateFileW(L"\\\\.\\pipe\\pseudoconsoleconn", GENERIC_READ | GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + ok(console_pipe2 != INVALID_HANDLE_VALUE, "CreateFile failed: %lu\n", GetLastError()); + + thread = CreateThread( NULL, 0, read_pipe_proc, console_pipe, 0, NULL ); + CloseHandle(thread); + + size.X = 0; + size.Y = 30; + hres = pCreatePseudoConsole(size, console_pipe2, console_pipe2, 0, &pseudo_console); + ok(hres == E_INVALIDARG, "CreatePseudoConsole failed: %08lx\n", hres); + + size.X = 40; + size.Y = 0; + hres = pCreatePseudoConsole(size, console_pipe2, console_pipe2, 0, &pseudo_console); + ok(hres == E_INVALIDARG, "CreatePseudoConsole failed: %08lx\n", hres); + + size.X = 40; + size.Y = 30; + hres = pCreatePseudoConsole(size, console_pipe2, console_pipe2, 0, &pseudo_console); + ok(hres == S_OK, "CreatePseudoConsole failed: %08lx\n", hres); + CloseHandle(console_pipe2); + +#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600 + InitializeProcThreadAttributeList(NULL, 1, 0, &attr_size); + startup.lpAttributeList = HeapAlloc(GetProcessHeap(), 0, attr_size); + InitializeProcThreadAttributeList(startup.lpAttributeList, 1, 0, &attr_size); + UpdateProcThreadAttribute(startup.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, pseudo_console, + sizeof(pseudo_console), NULL, NULL); +#endif + + winetest_get_mainargs(&argv); + sprintf(cmdline, "\"%s\" %s --pseudo-console", argv[0], argv[1]); + ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, &startup.StartupInfo, &info); + ok(ret, "CreateProcessW failed: %lu\n", GetLastError()); + + CloseHandle(info.hThread); + HeapFree(GetProcessHeap(), 0, startup.lpAttributeList); + wait_child_process(info.hProcess); + CloseHandle(info.hProcess); + + pClosePseudoConsole(pseudo_console); +} + +/* copy an executable, but changing its subsystem */ +static void copy_change_subsystem(const char* in, const char* out, DWORD subsyst) +{ + BOOL ret; + HANDLE hFile, hMap; + void* mapping; + IMAGE_NT_HEADERS *nthdr; + + ret = CopyFileA(in, out, FALSE); + ok(ret, "Failed to copy executable %s in %s (%lu)\n", in, out, GetLastError()); + + hFile = CreateFileA(out, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + ok(hFile != INVALID_HANDLE_VALUE, "Couldn't open file %s (%lu)\n", out, GetLastError()); + hMap = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0, NULL); + ok(hMap != NULL, "Couldn't create map (%lu)\n", GetLastError()); + mapping = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0); + ok(mapping != NULL, "Couldn't map (%lu)\n", GetLastError()); + nthdr = RtlImageNtHeader(mapping); + ok(nthdr != NULL, "Cannot get NT headers out of %s\n", out); + if (nthdr) nthdr->OptionalHeader.Subsystem = subsyst; + ret = UnmapViewOfFile(mapping); + ok(ret, "Couldn't unmap (%lu)\n", GetLastError()); + CloseHandle(hMap); + CloseHandle(hFile); +} + +enum inheritance_model {NULL_STD, CONSOLE_STD, STARTUPINFO_STD}; + +static DWORD check_child_console_bits(const char* exec, DWORD flags, enum inheritance_model inherit) +{ + SECURITY_ATTRIBUTES sa = {0, NULL, TRUE}; + STARTUPINFOA si = { sizeof(si) }; + PROCESS_INFORMATION info; + char buf[MAX_PATH]; + HANDLE handle; + DWORD exit_code; + BOOL res; + DWORD ret; + BOOL inherit_handles = FALSE; + + sprintf(buf, "\"%s\" console check_console", exec); + switch (inherit) + { + case NULL_STD: + SetStdHandle(STD_INPUT_HANDLE, NULL); + SetStdHandle(STD_OUTPUT_HANDLE, NULL); + SetStdHandle(STD_ERROR_HANDLE, NULL); + break; + case CONSOLE_STD: + handle = CreateFileA("CONIN$", GENERIC_READ, 0, &sa, OPEN_EXISTING, 0, 0); + ok(handle != INVALID_HANDLE_VALUE, "Couldn't create input to console\n"); + SetStdHandle(STD_INPUT_HANDLE, handle); + handle = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0); + ok(handle != INVALID_HANDLE_VALUE, "Couldn't create input to console\n"); + SetStdHandle(STD_OUTPUT_HANDLE, handle); + SetStdHandle(STD_ERROR_HANDLE, handle); + break; + case STARTUPINFO_STD: + si.dwFlags |= STARTF_USESTDHANDLES; + si.hStdInput = CreateFileA("CONIN$", GENERIC_READ, 0, &sa, OPEN_EXISTING, 0, 0); + ok(si.hStdInput != INVALID_HANDLE_VALUE, "Couldn't create input to console\n"); + si.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0); + ok(si.hStdInput != INVALID_HANDLE_VALUE, "Couldn't create output to console\n"); + si.hStdError = INVALID_HANDLE_VALUE; + inherit_handles = TRUE; + break; + } + res = CreateProcessA(NULL, buf, NULL, NULL, inherit_handles, flags, NULL, NULL, &si, &info); + ok(res, "CreateProcess failed: %lu %s\n", GetLastError(), buf); + CloseHandle(info.hThread); + ret = WaitForSingleObject(info.hProcess, 30000); + ok(ret == WAIT_OBJECT_0, "Could not wait for the child process: %ld le=%lu\n", + ret, GetLastError()); + res = GetExitCodeProcess(info.hProcess, &exit_code); + ok(res && exit_code <= 255, "Couldn't get exit_code\n"); + CloseHandle(info.hProcess); + switch (inherit) + { + case NULL_STD: + break; + case CONSOLE_STD: + CloseHandle(GetStdHandle(STD_INPUT_HANDLE)); + CloseHandle(GetStdHandle(STD_OUTPUT_HANDLE)); + break; + case STARTUPINFO_STD: + CloseHandle(si.hStdInput); + CloseHandle(si.hStdOutput); + break; + } + return exit_code; +} + +#define CP_WITH_CONSOLE 0x01 /* attached to a console */ +#define CP_WITH_HANDLE 0x02 /* child has a console handle */ +#define CP_WITH_WINDOW 0x04 /* child has a console window */ +#define CP_ALONE 0x08 /* whether child is the single process attached to console */ +#define CP_GROUP_LEADER 0x10 /* whether the child is the process group leader */ +#define CP_INPUT_VALID 0x20 /* whether StdHandle(INPUT) is a valid console handle */ +#define CP_OUTPUT_VALID 0x40 /* whether StdHandle(OUTPUT) is a valid console handle */ +#define CP_ENABLED_CTRLC 0x80 /* whether the ctrl-c handling isn't blocked */ + +#define CP_OWN_CONSOLE (CP_WITH_CONSOLE | CP_WITH_HANDLE | CP_INPUT_VALID | CP_OUTPUT_VALID | CP_ALONE) +#define CP_INH_CONSOLE (CP_WITH_CONSOLE | CP_WITH_HANDLE | CP_INPUT_VALID | CP_OUTPUT_VALID) + +static void test_CreateProcessCUI(void) +{ + HANDLE hstd[3]; + static char guiexec[MAX_PATH]; + static char cuiexec[MAX_PATH]; + char **argv; + BOOL res; + int i; + BOOL saved_console_flags; + + static struct + { + BOOL use_cui; + DWORD cp_flags; + enum inheritance_model inherit; + DWORD expected; + DWORD is_broken; + } + no_console_tests[] = + { +/* 0*/ {FALSE, 0, NULL_STD, 0}, + {FALSE, DETACHED_PROCESS, NULL_STD, 0}, + {FALSE, CREATE_NEW_CONSOLE, NULL_STD, 0}, + {FALSE, CREATE_NO_WINDOW, NULL_STD, 0}, + {FALSE, DETACHED_PROCESS | CREATE_NO_WINDOW, NULL_STD, 0}, +/* 5*/ {FALSE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, NULL_STD, 0}, + + {TRUE, 0, NULL_STD, CP_OWN_CONSOLE | CP_WITH_WINDOW}, + {TRUE, DETACHED_PROCESS, NULL_STD, 0}, + {TRUE, CREATE_NEW_CONSOLE, NULL_STD, CP_OWN_CONSOLE | CP_WITH_WINDOW}, + {TRUE, CREATE_NO_WINDOW, NULL_STD, CP_OWN_CONSOLE}, +/*10*/ {TRUE, DETACHED_PROCESS | CREATE_NO_WINDOW, NULL_STD, 0}, + {TRUE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, NULL_STD, CP_OWN_CONSOLE | CP_WITH_WINDOW}, + }, + with_console_tests[] = + { +/* 0*/ {FALSE, 0, NULL_STD, 0}, + {FALSE, DETACHED_PROCESS, NULL_STD, 0}, + {FALSE, CREATE_NEW_CONSOLE, NULL_STD, 0}, + {FALSE, CREATE_NO_WINDOW, NULL_STD, 0}, + {FALSE, DETACHED_PROCESS | CREATE_NO_WINDOW, NULL_STD, 0}, +/* 5*/ {FALSE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, NULL_STD, 0}, + + {FALSE, 0, CONSOLE_STD, 0}, + {FALSE, DETACHED_PROCESS, CONSOLE_STD, 0}, + {FALSE, CREATE_NEW_CONSOLE, CONSOLE_STD, 0}, + {FALSE, CREATE_NO_WINDOW, CONSOLE_STD, 0}, +/*10*/ {FALSE, DETACHED_PROCESS | CREATE_NO_WINDOW, CONSOLE_STD, 0}, + {FALSE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, CONSOLE_STD, 0}, + + {FALSE, 0, STARTUPINFO_STD, 0}, + {FALSE, DETACHED_PROCESS, STARTUPINFO_STD, 0}, + {FALSE, CREATE_NEW_CONSOLE, STARTUPINFO_STD, 0}, +/*15*/ {FALSE, CREATE_NO_WINDOW, STARTUPINFO_STD, 0}, + {FALSE, DETACHED_PROCESS | CREATE_NO_WINDOW, STARTUPINFO_STD, 0}, + {FALSE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, STARTUPINFO_STD, 0}, + + {TRUE, 0, NULL_STD, CP_WITH_CONSOLE | CP_WITH_HANDLE | CP_WITH_WINDOW}, + {TRUE, DETACHED_PROCESS, NULL_STD, 0}, +/*20*/ {TRUE, CREATE_NEW_CONSOLE, NULL_STD, CP_OWN_CONSOLE | CP_WITH_WINDOW}, +#ifndef __REACTOS__ + {TRUE, CREATE_NO_WINDOW, NULL_STD, CP_OWN_CONSOLE}, +#endif + {TRUE, DETACHED_PROCESS | CREATE_NO_WINDOW, NULL_STD, 0}, + {TRUE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, NULL_STD, CP_OWN_CONSOLE | CP_WITH_WINDOW}, + + {TRUE, 0, CONSOLE_STD, CP_INH_CONSOLE | CP_WITH_WINDOW}, +/*25*/ {TRUE, DETACHED_PROCESS, CONSOLE_STD, 0}, + {TRUE, CREATE_NEW_CONSOLE, CONSOLE_STD, CP_OWN_CONSOLE | CP_WITH_WINDOW}, +#ifndef __REACTOS__ + {TRUE, CREATE_NO_WINDOW, CONSOLE_STD, CP_OWN_CONSOLE}, +#endif + {TRUE, DETACHED_PROCESS | CREATE_NO_WINDOW, CONSOLE_STD, 0}, + {TRUE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, CONSOLE_STD, CP_OWN_CONSOLE | CP_WITH_WINDOW}, + +/*30*/ {TRUE, 0, STARTUPINFO_STD, CP_INH_CONSOLE | CP_WITH_WINDOW}, + {TRUE, DETACHED_PROCESS, STARTUPINFO_STD, CP_INPUT_VALID | CP_OUTPUT_VALID, .is_broken = 0x100}, + {TRUE, CREATE_NEW_CONSOLE, STARTUPINFO_STD, CP_OWN_CONSOLE | CP_WITH_WINDOW, .is_broken = CP_WITH_CONSOLE | CP_WITH_HANDLE | CP_WITH_WINDOW | CP_ALONE}, +#ifndef __REACTOS__ + {TRUE, CREATE_NO_WINDOW, STARTUPINFO_STD, CP_OWN_CONSOLE, .is_broken = CP_WITH_CONSOLE | CP_WITH_HANDLE | CP_ALONE}, +#endif + {TRUE, DETACHED_PROCESS | CREATE_NO_WINDOW, STARTUPINFO_STD, CP_INPUT_VALID | CP_OUTPUT_VALID, .is_broken = 0x100}, +/*35*/ {TRUE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, STARTUPINFO_STD, CP_OWN_CONSOLE | CP_WITH_WINDOW, .is_broken = CP_WITH_CONSOLE | CP_WITH_HANDLE | CP_WITH_WINDOW | CP_ALONE}, + }; + static struct group_flags_tests + { + /* input */ + BOOL use_cui; + DWORD cp_flags; + enum inheritance_model inherit; + BOOL noctrl_flag; + /* output */ + DWORD expected; + } + group_flags_tests[] = + { +/* 0 */ {TRUE, 0, CONSOLE_STD, TRUE, CP_INH_CONSOLE | CP_WITH_WINDOW}, + {TRUE, CREATE_NEW_PROCESS_GROUP, CONSOLE_STD, TRUE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_GROUP_LEADER}, + {TRUE, 0, CONSOLE_STD, FALSE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_ENABLED_CTRLC}, + {TRUE, CREATE_NEW_PROCESS_GROUP, CONSOLE_STD, FALSE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_GROUP_LEADER}, + {TRUE, 0, STARTUPINFO_STD, TRUE, CP_INH_CONSOLE | CP_WITH_WINDOW}, +/* 5 */ {TRUE, CREATE_NEW_PROCESS_GROUP, STARTUPINFO_STD, TRUE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_GROUP_LEADER}, + {TRUE, 0, STARTUPINFO_STD, FALSE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_ENABLED_CTRLC}, + {TRUE, CREATE_NEW_PROCESS_GROUP, STARTUPINFO_STD, FALSE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_GROUP_LEADER}, + {FALSE, 0, CONSOLE_STD, TRUE, 0}, +#ifndef __REACTOS__ + {FALSE, CREATE_NEW_PROCESS_GROUP, CONSOLE_STD, TRUE, CP_GROUP_LEADER}, +#endif +/* 10 */ {FALSE, 0, CONSOLE_STD, FALSE, CP_ENABLED_CTRLC}, + {FALSE, CREATE_NEW_PROCESS_GROUP, CONSOLE_STD, FALSE, CP_GROUP_LEADER}, + {FALSE, 0, STARTUPINFO_STD, TRUE, 0}, + {FALSE, CREATE_NEW_PROCESS_GROUP, STARTUPINFO_STD, TRUE, CP_GROUP_LEADER}, + {FALSE, 0, STARTUPINFO_STD, FALSE, CP_ENABLED_CTRLC}, +/* 15 */ {FALSE, CREATE_NEW_PROCESS_GROUP, STARTUPINFO_STD, FALSE, CP_GROUP_LEADER}, + {TRUE, CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE, CONSOLE_STD, TRUE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_GROUP_LEADER | CP_ALONE}, + {FALSE, CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE, CONSOLE_STD, TRUE, CP_GROUP_LEADER}, + {TRUE, CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE, CONSOLE_STD, FALSE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_GROUP_LEADER | CP_ALONE | CP_ENABLED_CTRLC}, + {FALSE, CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE, CONSOLE_STD, FALSE, CP_GROUP_LEADER | CP_ENABLED_CTRLC}, +/* 20 */ {TRUE, CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS, CONSOLE_STD, TRUE, CP_GROUP_LEADER}, + {FALSE, CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS, CONSOLE_STD, TRUE, CP_GROUP_LEADER}, + {TRUE, CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS, CONSOLE_STD, FALSE, CP_GROUP_LEADER}, + {FALSE, CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS, CONSOLE_STD, FALSE, CP_GROUP_LEADER}, + }; + + hstd[0] = GetStdHandle(STD_INPUT_HANDLE); + hstd[1] = GetStdHandle(STD_OUTPUT_HANDLE); + hstd[2] = GetStdHandle(STD_ERROR_HANDLE); + + winetest_get_mainargs(&argv); + GetTempPathA(ARRAY_SIZE(guiexec), guiexec); + strcat(guiexec, "console_gui.exe"); + copy_change_subsystem(argv[0], guiexec, IMAGE_SUBSYSTEM_WINDOWS_GUI); + GetTempPathA(ARRAY_SIZE(cuiexec), cuiexec); + strcat(cuiexec, "console_cui.exe"); + copy_change_subsystem(argv[0], cuiexec, IMAGE_SUBSYSTEM_WINDOWS_CUI); + + FreeConsole(); + + for (i = 0; i < ARRAY_SIZE(no_console_tests); i++) + { +#ifdef __REACTOS__ + if (i == 9 && GetNTVersion() < _WIN32_WINNT_WIN7) + continue; +#endif + res = check_child_console_bits(no_console_tests[i].use_cui ? cuiexec : guiexec, + no_console_tests[i].cp_flags, + no_console_tests[i].inherit); + ok(res == no_console_tests[i].expected, "[%d] Unexpected result %x (%lx)\n", + i, res, no_console_tests[i].expected); + } + + AllocConsole(); + + for (i = 0; i < ARRAY_SIZE(with_console_tests); i++) + { + res = check_child_console_bits(with_console_tests[i].use_cui ? cuiexec : guiexec, + with_console_tests[i].cp_flags, + with_console_tests[i].inherit); + ok(res == with_console_tests[i].expected || + broken(with_console_tests[i].is_broken && res == (with_console_tests[i].is_broken & 0xff)), + "[%d] Unexpected result %x (%lx)\n", + i, res, with_console_tests[i].expected); + } + + saved_console_flags = RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags; + + for (i = 0; i < ARRAY_SIZE(group_flags_tests); i++) + { + res = SetConsoleCtrlHandler(NULL, group_flags_tests[i].noctrl_flag); + ok(res, "Couldn't set ctrl handler\n"); + res = check_child_console_bits(group_flags_tests[i].use_cui ? cuiexec : guiexec, + group_flags_tests[i].cp_flags, + group_flags_tests[i].inherit); + ok(res == group_flags_tests[i].expected || + /* Win7 doesn't report group id */ + broken(res == (group_flags_tests[i].expected & ~CP_GROUP_LEADER)), + "[%d] Unexpected result %x (%lx)\n", + i, res, group_flags_tests[i].expected); + } + + RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags = saved_console_flags; + + DeleteFileA(guiexec); + DeleteFileA(cuiexec); + + SetStdHandle(STD_INPUT_HANDLE, hstd[0]); + SetStdHandle(STD_OUTPUT_HANDLE, hstd[1]); + SetStdHandle(STD_ERROR_HANDLE, hstd[2]); +} + +#define NO_EVENT 0xfe + +static HANDLE mch_child_kill_event; +static DWORD mch_child_event = NO_EVENT; +static BOOL WINAPI mch_child(DWORD event) +{ + mch_child_event = event; + SetEvent(mch_child_kill_event); + return TRUE; +} + +static void test_CtrlHandlerSubsystem(void) +{ + static char guiexec[MAX_PATH]; + static char cuiexec[MAX_PATH]; + + static struct + { + /* input */ + BOOL use_cui; + DWORD cp_flags; + enum pgid {PGID_PARENT, PGID_ZERO, PGID_CHILD} pgid_kind; + /* output */ + unsigned child_event; + } + tests[] = + { +/* 0 */ {FALSE, 0, PGID_PARENT, NO_EVENT}, + {FALSE, 0, PGID_ZERO, NO_EVENT}, + {FALSE, CREATE_NEW_PROCESS_GROUP, PGID_CHILD, NO_EVENT}, + {FALSE, CREATE_NEW_PROCESS_GROUP, PGID_PARENT, NO_EVENT}, + {FALSE, CREATE_NEW_PROCESS_GROUP, PGID_ZERO, NO_EVENT}, +/* 5 */ {TRUE, 0, PGID_PARENT, CTRL_C_EVENT}, + {TRUE, 0, PGID_ZERO, CTRL_C_EVENT}, + {TRUE, CREATE_NEW_PROCESS_GROUP, PGID_CHILD, NO_EVENT}, + {TRUE, CREATE_NEW_PROCESS_GROUP, PGID_PARENT, NO_EVENT}, + {TRUE, CREATE_NEW_PROCESS_GROUP, PGID_ZERO, NO_EVENT}, +/* 10 */ {TRUE, CREATE_NEW_CONSOLE, PGID_PARENT, NO_EVENT}, + {TRUE, CREATE_NEW_CONSOLE, PGID_ZERO, NO_EVENT}, + {TRUE, DETACHED_PROCESS, PGID_PARENT, NO_EVENT}, + {TRUE, DETACHED_PROCESS, PGID_ZERO, NO_EVENT}, + }; + SECURITY_ATTRIBUTES inheritable_attr = { sizeof(inheritable_attr), NULL, TRUE }; + STARTUPINFOA si = { sizeof(si) }; + PROCESS_INFORMATION info; + char buf[MAX_PATH]; + DWORD exit_code; + HANDLE event_child; + char **argv; + DWORD saved_console_flags; + DWORD pgid; + BOOL ret; + DWORD res; + int i; + + winetest_get_mainargs(&argv); + GetTempPathA(ARRAY_SIZE(guiexec), guiexec); + strcat(guiexec, "console_gui.exe"); + copy_change_subsystem(argv[0], guiexec, IMAGE_SUBSYSTEM_WINDOWS_GUI); + GetTempPathA(ARRAY_SIZE(cuiexec), cuiexec); + strcat(cuiexec, "console_cui.exe"); + copy_change_subsystem(argv[0], cuiexec, IMAGE_SUBSYSTEM_WINDOWS_CUI); + + event_child = CreateEventA(&inheritable_attr, FALSE, FALSE, NULL); + ok(event_child != NULL, "Couldn't create event\n"); + + saved_console_flags = RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags; + + /* protect self against ctrl-c, but don't mask it on child */ + ret = SetConsoleCtrlHandler(NULL, FALSE); + ret = SetConsoleCtrlHandler(mydummych, TRUE); + ok(ret, "Couldn't set ctrl-c handler flag\n"); + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + winetest_push_context("test #%u", i); + + res = snprintf(buf, ARRAY_SIZE(buf), "\"%s\" console ctrl_handler %p", tests[i].use_cui ? cuiexec : guiexec, event_child); + ok((LONG)res >= 0 && res < ARRAY_SIZE(buf), "Truncated string %s (%lu)\n", buf, res); + + ret = CreateProcessA(NULL, buf, NULL, NULL, TRUE, tests[i].cp_flags, + NULL, NULL, &si, &info); + ok(ret, "CreateProcess failed: %lu %s\n", GetLastError(), tests[i].use_cui ? cuiexec : guiexec); + + res = WaitForSingleObject(event_child, 5000); + ok(res == WAIT_OBJECT_0, "Child didn't init %lu %p\n", res, event_child); + + switch (tests[i].pgid_kind) + { + case PGID_PARENT: + pgid = RtlGetCurrentPeb()->ProcessParameters->ProcessGroupId; + break; + case PGID_CHILD: + ok((tests[i].cp_flags & CREATE_NEW_PROCESS_GROUP) != 0, + "PGID should only be used with new process groupw\n"); + pgid = info.dwProcessId; + break; + case PGID_ZERO: + pgid = 0; + break; + default: + ok(0, "Unexpected pgid kind %u\n", tests[i].pgid_kind); + pgid = 0; + } + + ret = GenerateConsoleCtrlEvent(CTRL_C_EVENT, pgid); + ok(ret || broken(GetLastError() == ERROR_INVALID_PARAMETER) /* Win7 */, + "GenerateConsoleCtrlEvent failed: %lu\n", GetLastError()); + + res = WaitForSingleObject(info.hProcess, 2000); + ok(res == WAIT_OBJECT_0, "Expecting child to be terminated\n"); + + if (ret) + { + ret = GetExitCodeProcess(info.hProcess, &exit_code); + ok(ret, "Couldn't get exit code\n"); + + ok(tests[i].child_event == exit_code, "Unexpected exit code %#lx, instead of %#x\n", + exit_code, tests[i].child_event); + } + + CloseHandle(info.hProcess); + CloseHandle(info.hThread); + winetest_pop_context(); + } + + /* test default handlers return code */ + res = snprintf(buf, ARRAY_SIZE(buf), "\"%s\" console no_ctrl_handler %p", cuiexec, event_child); + ok((LONG)res >= 0 && res < ARRAY_SIZE(buf), "Truncated string %s (%lu)\n", buf, res); + + ret = CreateProcessA(NULL, buf, NULL, NULL, TRUE, 0, NULL, NULL, &si, &info); + ok(ret, "CreateProcess failed: %lu %s\n", GetLastError(), cuiexec); + + res = WaitForSingleObject(event_child, 5000); + ok(res == WAIT_OBJECT_0, "Child didn't init %lu\n", res); + + pgid = RtlGetCurrentPeb()->ProcessParameters->ProcessGroupId; + ret = GenerateConsoleCtrlEvent(CTRL_C_EVENT, pgid); + if (!ret && broken(GetLastError() == ERROR_INVALID_PARAMETER) /* Win7 */) + { + win_skip("Skip test on Win7\n"); + TerminateProcess(info.hProcess, 0); + } + else + { + ok(ret, "GenerateConsoleCtrlEvent failed: %lu\n", GetLastError()); + + res = WaitForSingleObject(info.hProcess, 2000); + ok(res == WAIT_OBJECT_0, "Expecting child to be terminated\n"); + + if (ret) + { + ret = GetExitCodeProcess(info.hProcess, &exit_code); + ok(ret, "Couldn't get exit code\n"); + + ok(exit_code == STATUS_CONTROL_C_EXIT, "Unexpected exit code %#lx, instead of %#lx\n", + exit_code, STATUS_CONTROL_C_EXIT); + } +#ifdef __REACTOS__ + /* If the test fails to close when it should, force close. + * This prevents an issue where the test hangs on ReactOS. */ + if (res != WAIT_OBJECT_0) + TerminateProcess(info.hProcess, 0); +#endif + } + + CloseHandle(info.hProcess); + CloseHandle(info.hThread); + + CloseHandle(event_child); + + RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags = saved_console_flags; + ret = SetConsoleCtrlHandler(mydummych, FALSE); + ok(ret, "Couldn't remove ctrl-c handler flag\n"); + + DeleteFileA(guiexec); + DeleteFileA(cuiexec); } START_TEST(console) { - static const char font_name[] = "Lucida Console"; - HANDLE hConIn, hConOut; - BOOL ret; + HANDLE hConIn, hConOut, revert_output = NULL, unbound_output; + BOOL ret, test_current; CONSOLE_SCREEN_BUFFER_INFO sbi; - LONG err; - HKEY console_key; - char old_font[LF_FACESIZE]; - BOOL delete = FALSE; + BOOL using_pseudo_console; DWORD size; + char **argv; + int argc; init_function_pointers(); - /* be sure we have a clean console (and that's our own) - * FIXME: this will make the test fail (currently) if we don't run - * under X11 - * Another solution would be to rerun the test under wineconsole with - * the curses backend - */ + argc = winetest_get_mainargs(&argv); - /* ReadConsoleOutputW doesn't retrieve characters from the output buffer - * correctly for characters that don't have a glyph in the console font. So, - * we first set the console font to Lucida Console (which has a wider - * selection of glyphs available than the default raster fonts). We want - * to be able to restore the original font afterwards, so don't change - * if we can't read the original font. - */ - err = RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0, - KEY_QUERY_VALUE | KEY_SET_VALUE, &console_key); - if (err == ERROR_SUCCESS) + if (argc > 3 && !strcmp(argv[2], "attach_console")) { - size = sizeof(old_font); - err = RegQueryValueExA(console_key, "FaceName", NULL, NULL, - (LPBYTE) old_font, &size); - if (err == ERROR_SUCCESS || err == ERROR_FILE_NOT_FOUND) + DWORD parent_pid; + sscanf(argv[3], "%lx", &parent_pid); + test_AttachConsole_child(parent_pid); + return; + } + + if (argc == 3 && !strcmp(argv[2], "alloc_console")) + { + test_AllocConsole_child(); + return; + } + + if (argc == 4 && !strcmp(argv[2], "ctrl_handler")) + { + HANDLE event; + + SetConsoleCtrlHandler(mch_child, TRUE); + mch_child_kill_event = CreateEventA(NULL, FALSE, FALSE, NULL); + ok(mch_child_kill_event != NULL, "Couldn't create event\n"); + sscanf(argv[3], "%p", &event); + ret = SetEvent(event); + ok(ret, "SetEvent failed\n"); + + WaitForSingleObject(mch_child_kill_event, 1000); /* enough for all events to be distributed? */ + ExitProcess(mch_child_event); + } + + if (argc == 4 && !strcmp(argv[2], "no_ctrl_handler")) + { + HANDLE event; + + SetConsoleCtrlHandler(NULL, FALSE); + sscanf(argv[3], "%p", &event); + ret = SetEvent(event); + ok(ret, "SetEvent failed\n"); + + event = CreateEventA(NULL, FALSE, FALSE, NULL); + ok(event != NULL, "Couldn't create event\n"); + + /* wait for parent to kill us */ + WaitForSingleObject(event, INFINITE); + ok(0, "Shouldn't happen\n"); + ExitProcess(0xff); + } + + if (argc == 3 && !strcmp(argv[2], "check_console")) + { + DWORD exit_code = 0, pcslist; + if (GetConsoleCP() != 0) exit_code |= CP_WITH_CONSOLE; + if (RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle) exit_code |= CP_WITH_HANDLE; + if (IsWindow(GetConsoleWindow())) exit_code |= CP_WITH_WINDOW; + if (pGetConsoleProcessList && GetConsoleProcessList(&pcslist, 1) == 1) + exit_code |= CP_ALONE; + if (RtlGetCurrentPeb()->ProcessParameters->Size >= + offsetof(RTL_USER_PROCESS_PARAMETERS, ProcessGroupId) + + sizeof(RtlGetCurrentPeb()->ProcessParameters->ProcessGroupId) && + RtlGetCurrentPeb()->ProcessParameters->ProcessGroupId == GetCurrentProcessId()) + exit_code |= CP_GROUP_LEADER; + if (GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_CHAR) + exit_code |= CP_INPUT_VALID; + if (GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)) == FILE_TYPE_CHAR) + exit_code |= CP_OUTPUT_VALID; + if (!(RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags & 1)) + exit_code |= CP_ENABLED_CTRLC; + ExitProcess(exit_code); + } + + if (argc >= 3 && !strcmp(argv[2], "title_test")) + { + if (argc == 3) { - delete = (err == ERROR_FILE_NOT_FOUND); - err = RegSetValueExA(console_key, "FaceName", 0, REG_SZ, - (const BYTE *) font_name, sizeof(font_name)); - if (err != ERROR_SUCCESS) - trace("Unable to change default console font, error %d\n", err); + test_GetConsoleOriginalTitleA(); + test_GetConsoleOriginalTitleW(); + } + else + test_GetConsoleOriginalTitleW_empty(); + return; + } + + test_current = argc >= 3 && !strcmp(argv[2], "--current"); + using_pseudo_console = argc >= 3 && !strcmp(argv[2], "--pseudo-console"); + + if (!test_current && !using_pseudo_console) + { + static const char font_name[] = "Lucida Console"; + HKEY console_key; + char old_font[LF_FACESIZE]; + BOOL delete = FALSE; + LONG err; + + /* ReadConsoleOutputW doesn't retrieve characters from the output buffer + * correctly for characters that don't have a glyph in the console font. So, + * we first set the console font to Lucida Console (which has a wider + * selection of glyphs available than the default raster fonts). We want + * to be able to restore the original font afterwards, so don't change + * if we can't read the original font. + */ + err = RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0, + KEY_QUERY_VALUE | KEY_SET_VALUE, &console_key); + if (err == ERROR_SUCCESS) + { + size = sizeof(old_font); + err = RegQueryValueExA(console_key, "FaceName", NULL, NULL, + (LPBYTE) old_font, &size); + if (err == ERROR_SUCCESS || err == ERROR_FILE_NOT_FOUND) + { + delete = (err == ERROR_FILE_NOT_FOUND); + err = RegSetValueExA(console_key, "FaceName", 0, REG_SZ, + (const BYTE *) font_name, sizeof(font_name)); + if (err != ERROR_SUCCESS) + trace("Unable to change default console font, error %ld\n", err); + } + else + { + trace("Unable to query default console font, error %ld\n", err); + RegCloseKey(console_key); + console_key = NULL; + } } else { - trace("Unable to query default console font, error %d\n", err); - RegCloseKey(console_key); + trace("Unable to open HKCU\\Console, error %ld\n", err); console_key = NULL; } - } - else - { - trace("Unable to open HKCU\\Console, error %d\n", err); - console_key = NULL; + + /* Now detach and open a fresh console to play with */ + FreeConsole(); + ok(AllocConsole(), "Couldn't alloc console\n"); + + /* Restore default console font if needed */ + if (console_key != NULL) + { + if (delete) + err = RegDeleteValueA(console_key, "FaceName"); + else + err = RegSetValueExA(console_key, "FaceName", 0, REG_SZ, + (const BYTE *) old_font, strlen(old_font) + 1); + ok(err == ERROR_SUCCESS, "Unable to restore default console font, error %ld\n", err); + } } - /* Now detach and open a fresh console to play with */ - FreeConsole(); - ok(AllocConsole(), "Couldn't alloc console\n"); - - /* Restore default console font if needed */ - if (console_key != NULL) + unbound_output = create_unbound_handle(TRUE, FALSE); + if (!unbound_output) { - if (delete) - err = RegDeleteValueA(console_key, "FaceName"); - else - err = RegSetValueExA(console_key, "FaceName", 0, REG_SZ, - (const BYTE *) old_font, strlen(old_font) + 1); - ok(err == ERROR_SUCCESS, "Unable to restore default console font, error %d\n", err); + win_skip("Skipping NT path tests, not supported on this Windows version\n"); + skip_nt = TRUE; } + + if (test_current) + { + HANDLE sb; + revert_output = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + sb = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + CONSOLE_TEXTMODE_BUFFER, NULL); + ok(sb != INVALID_HANDLE_VALUE, "Could not allocate screen buffer: %lu\n", GetLastError()); + SetConsoleActiveScreenBuffer(sb); + } + hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); @@ -3096,6 +5640,12 @@ START_TEST(console) ok(hConIn != INVALID_HANDLE_VALUE, "Opening ConIn\n"); ok(hConOut != INVALID_HANDLE_VALUE, "Opening ConOut\n"); + if (using_pseudo_console) + { + test_pseudo_console_child(hConIn, hConOut); + return; + } + ret = GetConsoleScreenBufferInfo(hConOut, &sbi); ok(ret, "Getting sb info\n"); if (!ret) return; @@ -3109,10 +5659,10 @@ START_TEST(console) ok(ret, "Setting sb info\n"); ret = GetConsoleScreenBufferInfo(hConOut, &sbi); ok(ret, "Getting sb info\n"); - ok(sbi.dwSize.Y == size, "Unexpected buffer size: %d instead of %d\n", sbi.dwSize.Y, size); + ok(sbi.dwSize.Y == size, "Unexpected buffer size: %d instead of %ld\n", sbi.dwSize.Y, size); if (!ret) return; - test_ReadConsole(); + test_ReadConsole(hConIn); /* Non interactive tests */ testCursor(hConOut, sbi.dwSize); /* test parameters (FIXME: test functionality) */ @@ -3124,19 +5674,25 @@ START_TEST(console) /* will test all the scrolling operations */ testScroll(hConOut, sbi.dwSize); /* will test sb creation / modification / codepage handling */ - testScreenBuffer(hConOut); + if (!test_current) testScreenBuffer(hConOut); + test_new_screen_buffer_properties(hConOut); + test_new_screen_buffer_color_attributes(hConOut); /* Test waiting for a console handle */ testWaitForConsoleInput(hConIn); + test_wait(hConIn, hConOut); - /* clear duplicated console font table */ - CloseHandle(hConIn); - CloseHandle(hConOut); - FreeConsole(); - ok(AllocConsole(), "Couldn't alloc console\n"); - hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); - hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); - ok(hConIn != INVALID_HANDLE_VALUE, "Opening ConIn\n"); - ok(hConOut != INVALID_HANDLE_VALUE, "Opening ConOut\n"); + if (!test_current) + { + /* clear duplicated console font table */ + CloseHandle(hConIn); + CloseHandle(hConOut); + FreeConsole(); + ok(AllocConsole(), "Couldn't alloc console\n"); + hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(hConIn != INVALID_HANDLE_VALUE, "Opening ConIn\n"); + ok(hConOut != INVALID_HANDLE_VALUE, "Opening ConOut\n"); + } testCtrlHandler(); /* still to be done: access rights & access on objects */ @@ -3146,28 +5702,56 @@ START_TEST(console) else test_GetSetConsoleInputExeName(); - test_GetConsoleProcessList(); + if (!test_current) test_GetConsoleProcessList(); test_OpenConsoleW(); test_CreateFileW(); test_OpenCON(); test_VerifyConsoleIoHandle(hConOut); test_GetSetStdHandle(); + test_DuplicateConsoleHandle(); test_GetNumberOfConsoleInputEvents(hConIn); test_WriteConsoleInputA(hConIn); test_WriteConsoleInputW(hConIn); + test_FlushConsoleInputBuffer(hConIn, hConOut); test_WriteConsoleOutputCharacterA(hConOut); test_WriteConsoleOutputCharacterW(hConOut); test_WriteConsoleOutputAttribute(hConOut); + test_WriteConsoleOutput(hConOut); test_FillConsoleOutputCharacterA(hConOut); test_FillConsoleOutputCharacterW(hConOut); test_FillConsoleOutputAttribute(hConOut); test_ReadConsoleOutputCharacterA(hConOut); test_ReadConsoleOutputCharacterW(hConOut); test_ReadConsoleOutputAttribute(hConOut); - test_GetCurrentConsoleFont(hConOut); - test_GetConsoleFontSize(hConOut); - test_GetLargestConsoleWindowSize(hConOut); - test_GetConsoleFontInfo(hConOut); - test_SetConsoleFont(hConOut); + test_ReadConsoleOutput(hConOut); + if (!test_current) + { + test_GetCurrentConsoleFont(hConOut); + test_GetCurrentConsoleFontEx(hConOut); + test_SetCurrentConsoleFontEx(hConOut); + test_GetConsoleFontSize(hConOut); + test_GetLargestConsoleWindowSize(hConOut); + test_GetConsoleFontInfo(hConOut); + test_SetConsoleFont(hConOut); + } test_GetConsoleScreenBufferInfoEx(hConOut); + test_SetConsoleScreenBufferInfoEx(hConOut); + test_file_info(hConIn, hConOut); + test_GetConsoleOriginalTitle(); + test_GetConsoleTitleA(); + test_GetConsoleTitleW(); + test_console_as_root_directory(); + if (!test_current) + { + test_pseudo_console(); + test_AttachConsole(hConOut); + test_AllocConsole(); + test_FreeConsole(); + test_condrv_server_as_root_directory(); + test_CreateProcessCUI(); + test_CtrlHandlerSubsystem(); + } + else if (revert_output) SetConsoleActiveScreenBuffer(revert_output); + + CloseHandle(unbound_output); } diff --git a/modules/rostests/winetests/kernel32/debugger.c b/modules/rostests/winetests/kernel32/debugger.c index 3de688d56a6..27b7ef8e697 100644 --- a/modules/rostests/winetests/kernel32/debugger.c +++ b/modules/rostests/winetests/kernel32/debugger.c @@ -21,10 +21,14 @@ #include #include +#include +#define WIN32_NO_STATUS #include #include #include #include "wine/test.h" +#include "wine/heap.h" +#include "wine/rbtree.h" #ifndef STATUS_DEBUGGER_INACTIVE #define STATUS_DEBUGGER_INACTIVE ((NTSTATUS) 0xC0000354) @@ -34,15 +38,27 @@ static int myARGC; static char** myARGV; +static BOOL is_wow64; static BOOL (WINAPI *pCheckRemoteDebuggerPresent)(HANDLE,PBOOL); -static BOOL (WINAPI *pDebugActiveProcessStop)(DWORD); -static BOOL (WINAPI *pDebugSetProcessKillOnExit)(BOOL); -static BOOL (WINAPI *pIsDebuggerPresent)(void); + +static void (WINAPI *pDbgBreakPoint)(void); + +static NTSTATUS (WINAPI *pNtSuspendProcess)(HANDLE process); +static NTSTATUS (WINAPI *pNtResumeProcess)(HANDLE process); +static NTSTATUS (WINAPI *pNtCreateDebugObject)(HANDLE *, ACCESS_MASK, OBJECT_ATTRIBUTES *, ULONG); +static NTSTATUS (WINAPI *pNtSetInformationDebugObject)(HANDLE,DEBUGOBJECTINFOCLASS,void *,ULONG,ULONG*); +static NTSTATUS (WINAPI *pDbgUiConnectToDbg)(void); +static HANDLE (WINAPI *pDbgUiGetThreadDebugObject)(void); +static void (WINAPI *pDbgUiSetThreadDebugObject)(HANDLE); +static DWORD (WINAPI *pGetMappedFileNameW)(HANDLE,void*,WCHAR*,DWORD); +static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL); static LONG child_failures; -static void __WINE_PRINTF_ATTR(2, 3) test_child_ok(int condition, const char *msg, ...) +static HMODULE ntdll; + +static void WINAPIV __WINE_PRINTF_ATTR(2, 3) test_child_ok(int condition, const char *msg, ...) { va_list valist; @@ -112,44 +128,74 @@ static void get_events(const char* name, HANDLE *start_event, HANDLE *done_event HeapFree(GetProcessHeap(), 0, event_name); } -static void save_blackbox(const char* logfile, void* blackbox, int size) +static void save_blackbox(const char* logfile, void* blackbox, int size, const char *dbgtrace) { HANDLE hFile; DWORD written; + BOOL ret; - hFile=CreateFileA(logfile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + hFile = CreateFileA(logfile, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0); + ok(hFile != INVALID_HANDLE_VALUE, "Couldn't create %s: %lu\n", logfile, GetLastError()); if (hFile == INVALID_HANDLE_VALUE) return; - WriteFile(hFile, blackbox, size, &written, NULL); + ret = WriteFile(hFile, blackbox, size, &written, NULL); + ok(ret && written == size, "Error writing\n"); + if (dbgtrace && dbgtrace[0]) + { + ret = WriteFile(hFile, dbgtrace, strlen(dbgtrace), &written, NULL); + ok(ret && written == strlen(dbgtrace), "Error writing\n"); + } CloseHandle(hFile); } -static int load_blackbox(const char* logfile, void* blackbox, int size) +#define load_blackbox(a, b, c) _load_blackbox(__LINE__, (a), (b), (c)) +static int _load_blackbox(unsigned int line, const char* logfile, void* blackbox, int size) { HANDLE hFile; DWORD read; BOOL ret; + char buf[4096]; - hFile=CreateFileA(logfile, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); + hFile = CreateFileA(logfile, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); if (hFile == INVALID_HANDLE_VALUE) { - ok(0, "unable to open '%s'\n", logfile); + ok_(__FILE__, line)(0, "unable to open '%s': %#lx\n", logfile, GetLastError()); return 0; } SetLastError(0xdeadbeef); - ret=ReadFile(hFile, blackbox, size, &read, NULL); - ok(ret, "ReadFile failed: %d\n", GetLastError()); - ok(read == size, "wrong size for '%s': read=%d\n", logfile, read); + ret = ReadFile(hFile, blackbox, size, &read, NULL); + ok(ret, "ReadFile failed: %ld\n", GetLastError()); +#ifdef __REACTOS__ + ok(read == size || broken(read == 0) /* WS03 */, "wrong size for '%s': read=%ld\n", logfile, read); +#else + ok(read == size, "wrong size for '%s': read=%ld\n", logfile, read); +#endif + ret = ReadFile(hFile, buf, sizeof(buf) - 1, &read, NULL); + if (ret && read) + { + buf[read] = 0; + trace("debugger traces:>>>\n%s\n<<< Done.\n", buf); + } CloseHandle(hFile); return 1; } -typedef struct +static DWORD WINAPI thread_proc(void *arg) { - DWORD pid; -} crash_blackbox_t; + Sleep(10000); + trace("exiting\n"); + ExitThread(1); +} -static void doCrash(int argc, char** argv) +static void run_background_thread(void) +{ + DWORD tid; + HANDLE thread = CreateThread(NULL, 0, thread_proc, NULL, 0, &tid); + ok(thread != NULL, "CreateThread failed\n"); + CloseHandle(thread); +} + +static void doCrash(void) { volatile char* p; @@ -157,12 +203,7 @@ static void doCrash(int argc, char** argv) SetErrorMode( 0 ); SetUnhandledExceptionFilter( NULL ); - if (argc >= 4) - { - crash_blackbox_t blackbox; - blackbox.pid=GetCurrentProcessId(); - save_blackbox(argv[3], &blackbox, sizeof(blackbox)); - } + run_background_thread(); /* Just crash */ trace("child: crashing...\n"); @@ -182,13 +223,308 @@ typedef struct DWORD nokill_err; BOOL detach_rc; DWORD detach_err; + DWORD failures; } debugger_blackbox_t; +struct debugger_context +{ + DWORD pid; + DEBUG_EVENT ev; + unsigned process_cnt; + unsigned dll_cnt; + void *image_base; + DWORD thread_tag; + unsigned thread_cnt; + struct wine_rb_tree threads; + struct debuggee_thread *current_thread; + struct debuggee_thread *main_thread; +}; + +struct debuggee_thread +{ + DWORD tid; + DWORD tag; + HANDLE handle; + CONTEXT ctx; + struct wine_rb_entry entry; +}; + +int debuggee_thread_compare(const void *key, const struct wine_rb_entry *entry) +{ + struct debuggee_thread *thread = WINE_RB_ENTRY_VALUE(entry, struct debuggee_thread, entry); + return memcmp(key, &thread->tid, sizeof(thread->tid)); +} + +static void add_thread(struct debugger_context *ctx, DWORD tid) +{ + struct debuggee_thread *thread; + if (!ctx->thread_cnt++) wine_rb_init(&ctx->threads, debuggee_thread_compare); + thread = heap_alloc(sizeof(*thread)); + thread->tid = tid; + thread->tag = ctx->thread_tag; + thread->handle = NULL; + wine_rb_put(&ctx->threads, &tid, &thread->entry); + if (!ctx->main_thread) ctx->main_thread = thread; +} + +static struct debuggee_thread *get_debuggee_thread(struct debugger_context *ctx, DWORD tid) +{ + struct wine_rb_entry *entry = wine_rb_get(&ctx->threads, &tid); + ok(entry != NULL, "unknown thread %lx\n", tid); + return WINE_RB_ENTRY_VALUE(entry, struct debuggee_thread, entry); +} + +static void remove_thread(struct debugger_context *ctx, DWORD tid) +{ + struct debuggee_thread *thread = get_debuggee_thread(ctx, tid); + + wine_rb_remove(&ctx->threads, &thread->entry); + if (thread->handle) CloseHandle(thread->handle); + heap_free(thread); +} + +static void *get_ip(const CONTEXT *ctx) +{ +#ifdef __i386__ + return (void *)ctx->Eip; +#elif defined(__x86_64__) + return (void *)ctx->Rip; +#else + return NULL; +#endif +} + +static void set_ip(CONTEXT *ctx, void *ip) +{ +#ifdef __i386__ + ctx->Eip = (DWORD_PTR)ip; +#elif defined(__x86_64__) + ctx->Rip = (DWORD_PTR)ip; +#endif +} + +#define fetch_thread_context(a) fetch_thread_context_(__LINE__,a) +static void fetch_thread_context_(unsigned line, struct debuggee_thread *thread) +{ + BOOL ret; + + if (!thread->handle) + { + thread->handle = OpenThread(THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_QUERY_INFORMATION, + FALSE, thread->tid); + ok_(__FILE__,line)(thread->handle != NULL, "OpenThread failed: %lu\n", GetLastError()); + } + + memset(&thread->ctx, 0xaa, sizeof(thread->ctx)); + thread->ctx.ContextFlags = CONTEXT_FULL; + ret = GetThreadContext(thread->handle, &thread->ctx); + ok_(__FILE__,line)(ret, "GetThreadContext failed: %lu\n", GetLastError()); +} + +#define set_thread_context(a,b) set_thread_context_(__LINE__,a,b) +static void set_thread_context_(unsigned line, struct debugger_context *ctx, struct debuggee_thread *thread) +{ + BOOL ret; + ret = SetThreadContext(thread->handle, &thread->ctx); + ok_(__FILE__,line)(ret, "SetThreadContext failed: %lu\n", GetLastError()); +} + +#define WAIT_EVENT_TIMEOUT 20000 +#define POLL_EVENT_TIMEOUT 200 + +#define next_event(a,b) next_event_(__LINE__,a,b) +static void next_event_(unsigned line, struct debugger_context *ctx, unsigned timeout) +{ + BOOL ret; + + ctx->current_thread = NULL; + + for (;;) + { + if (ctx->process_cnt && ctx->ev.dwDebugEventCode != -1) + { + ret = ContinueDebugEvent(ctx->ev.dwProcessId, ctx->ev.dwThreadId, DBG_CONTINUE); + ok_(__FILE__,line)(ret, "ContinueDebugEvent failed, last error %ld.\n", GetLastError()); + } + + ret = WaitForDebugEvent(&ctx->ev, timeout); + if (!ret) + { + ok_(__FILE__,line)(GetLastError() == ERROR_SEM_TIMEOUT, + "WaitForDebugEvent failed, last error %ld.\n", GetLastError()); + ctx->ev.dwDebugEventCode = -1; + return; + } + + if (ctx->ev.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) + { + if (!ctx->process_cnt) ctx->pid = ctx->ev.dwProcessId; + ctx->process_cnt++; + } + + if (ctx->ev.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) continue; /* ignore for now */ + if (ctx->ev.dwProcessId == ctx->pid) break; + + ok_(__FILE__,line)(ctx->process_cnt > 1, "unexpected event pid\n"); + } + + switch (ctx->ev.dwDebugEventCode) + { + case CREATE_PROCESS_DEBUG_EVENT: + add_thread(ctx, ctx->ev.dwThreadId); + ctx->image_base = ctx->ev.u.CreateProcessInfo.lpBaseOfImage; + break; + case EXIT_PROCESS_DEBUG_EVENT: + remove_thread(ctx, ctx->ev.dwThreadId); + return; + case CREATE_THREAD_DEBUG_EVENT: + add_thread(ctx, ctx->ev.dwThreadId); + break; + case EXIT_THREAD_DEBUG_EVENT: + remove_thread(ctx, ctx->ev.dwThreadId); + return; + case LOAD_DLL_DEBUG_EVENT: + ok(ctx->ev.u.LoadDll.lpBaseOfDll != ctx->image_base, "process image reported as DLL load event\n"); + ctx->dll_cnt++; + break; + case UNLOAD_DLL_DEBUG_EVENT: + ctx->dll_cnt--; + break; + } + + ctx->current_thread = get_debuggee_thread(ctx, ctx->ev.dwThreadId); +} + +static DWORD event_mask(DWORD ev) +{ + return (ev >= 1 && ev <= 7) ? (1LU << ev) : 0; +} + +#define next_event_filter(a, b,c) next_event_filter_(__LINE__, (a), (b), (c)) +static void next_event_filter_(unsigned line, struct debugger_context *ctx, DWORD timeout, DWORD mask) +{ + do + { + next_event_(line, ctx, timeout); + } while (event_mask(ctx->ev.dwDebugEventCode) & mask); +} + +#define wait_for_breakpoint(a) wait_for_breakpoint_(__LINE__,a) +static void wait_for_breakpoint_(unsigned line, struct debugger_context *ctx) +{ + next_event_filter_(line, ctx, WAIT_EVENT_TIMEOUT, + event_mask(LOAD_DLL_DEBUG_EVENT) | event_mask(UNLOAD_DLL_DEBUG_EVENT) | event_mask(CREATE_THREAD_DEBUG_EVENT)); + + ok_(__FILE__,line)(ctx->ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx->ev.dwDebugEventCode); + ok_(__FILE__,line)(ctx->ev.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "ExceptionCode = %lx\n", + ctx->ev.u.Exception.ExceptionRecord.ExceptionCode); +} + +#define check_thread_running(h) ok(_check_thread_suspend_count(h) == 0, "Expecting running thread\n") +#define check_thread_suspended(h) ok(_check_thread_suspend_count(h) > 0, "Expecting suspended thread\n") + +static LONG _check_thread_suspend_count(HANDLE h) +{ + DWORD suspend_count; + + suspend_count = SuspendThread(h); + if (suspend_count != (DWORD)-1 && ResumeThread(h) == (DWORD)-1) + return (DWORD)-2; + return suspend_count; +} + +static void process_attach_events(struct debugger_context *ctx, BOOL pass_exception) +{ + DEBUG_EVENT ev; + BOOL ret; + HANDLE prev_thread; + + ctx->ev.dwDebugEventCode = -1; + next_event(ctx, 0); + ok(ctx->ev.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx->ev.dwDebugEventCode); + + todo_wine + check_thread_suspended(ctx->ev.u.CreateProcessInfo.hThread); + prev_thread = ctx->ev.u.CreateProcessInfo.hThread; + next_event(ctx, 0); + + if (ctx->ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT) /* Vista+ reports ntdll.dll before reporting threads */ + { + ok(ctx->ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx->ev.dwDebugEventCode); + ok(ctx->ev.u.LoadDll.lpBaseOfDll == ntdll, "The first reported DLL is not ntdll.dll\n"); + next_event(ctx, 0); + } + + while (ctx->ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT) + { + todo_wine + check_thread_suspended(ctx->ev.u.CreateThread.hThread); + check_thread_running(prev_thread); + prev_thread = ctx->ev.u.CreateThread.hThread; + next_event(ctx, 0); + } + + do + { + /* even when there are more pending events, they are not reported until current event is continued */ + ret = WaitForDebugEvent(&ev, 10); + ok(GetLastError() == ERROR_SEM_TIMEOUT, "WaitForDebugEvent returned %x(%lu)\n", ret, GetLastError()); + + next_event(ctx, WAIT_EVENT_TIMEOUT); + if (ctx->ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT) + ok(ctx->ev.u.LoadDll.lpBaseOfDll != ntdll, "ntdll.dll reported out of order\n"); + } while (ctx->ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT || ctx->ev.dwDebugEventCode == UNLOAD_DLL_DEBUG_EVENT); + ok(ctx->dll_cnt > 2, "dll_cnt = %d\n", ctx->dll_cnt); + + /* a new thread is created and it executes DbgBreakPoint, which causes the exception */ + /* Win11 doesn't generate it at this point (Win <= 10 do) */ + if (ctx->ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT) + { + DWORD last_threads[5]; + unsigned thd_idx = 0, i; + + check_thread_running(prev_thread); + + /* sometimes (at least Win10) several thread creations are reported here */ + do + { + check_thread_running(ctx->ev.u.CreateThread.hThread); + if (thd_idx < ARRAY_SIZE(last_threads)) + last_threads[thd_idx++] = ctx->ev.dwThreadId; + next_event(ctx, WAIT_EVENT_TIMEOUT); + } while (ctx->ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT); + ok(thd_idx <= ARRAY_SIZE(last_threads), "too many threads created\n"); + for (i = 0; i < thd_idx; i++) + if (last_threads[i] == ctx->ev.dwThreadId) break; + ok(i < thd_idx, "unexpected thread\n"); + + ok(ctx->ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx->ev.dwDebugEventCode); + ok(ctx->ev.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "ExceptionCode = %lx\n", + ctx->ev.u.Exception.ExceptionRecord.ExceptionCode); + ok(ctx->ev.u.Exception.ExceptionRecord.ExceptionAddress == pDbgBreakPoint, "ExceptionAddress != DbgBreakPoint\n"); + + if (pass_exception) + { + ret = ContinueDebugEvent(ctx->ev.dwProcessId, ctx->ev.dwThreadId, DBG_EXCEPTION_NOT_HANDLED); + ok(ret, "ContinueDebugEvent failed, last error %ld.\n", GetLastError()); + ctx->ev.dwDebugEventCode = -1; + } + } + + /* flush debug events */ + do next_event(ctx, POLL_EVENT_TIMEOUT); + while (ctx->ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT || ctx->ev.dwDebugEventCode == UNLOAD_DLL_DEBUG_EVENT + || ctx->ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT || ctx->ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT); + ok(ctx->ev.dwDebugEventCode == -1, "dwDebugEventCode = %ld\n", ctx->ev.dwDebugEventCode); +} + static void doDebugger(int argc, char** argv) { const char* logfile; debugger_blackbox_t blackbox; HANDLE start_event = 0, done_event = 0, debug_event; + char buf[4096] = ""; + struct debugger_context ctx = { 0 }; blackbox.argc=argc; logfile=(argc >= 4 ? argv[3] : NULL); @@ -204,10 +540,17 @@ static void doDebugger(int argc, char** argv) else blackbox.attach_rc=TRUE; + if (strstr(myARGV[2], "process")) + { + strcat(buf, "processing debug messages\n"); + process_attach_events(&ctx, FALSE); + } + debug_event=(argc >= 6 ? (HANDLE)(INT_PTR)atol(argv[5]) : NULL); blackbox.debug_err=0; if (debug_event && strstr(myARGV[2], "event")) { + strcat(buf, "setting event\n"); blackbox.debug_rc=SetEvent(debug_event); if (!blackbox.debug_rc) blackbox.debug_err=GetLastError(); @@ -215,6 +558,14 @@ static void doDebugger(int argc, char** argv) else blackbox.debug_rc=TRUE; + if (strstr(myARGV[2], "process")) + { + next_event(&ctx, WAIT_EVENT_TIMEOUT); + ok(ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode); + ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionCode == STATUS_ACCESS_VIOLATION, "ExceptionCode = %lx\n", + ctx.ev.u.Exception.ExceptionRecord.ExceptionCode); + } + if (logfile) { get_events(logfile, &start_event, &done_event); @@ -222,14 +573,14 @@ static void doDebugger(int argc, char** argv) if (strstr(myARGV[2], "order")) { - trace("debugger: waiting for the start signal...\n"); + strcat(buf, "waiting for the start signal...\n"); WaitForSingleObject(start_event, INFINITE); } blackbox.nokill_err=0; if (strstr(myARGV[2], "nokill")) { - blackbox.nokill_rc=pDebugSetProcessKillOnExit(FALSE); + blackbox.nokill_rc = DebugSetProcessKillOnExit(FALSE); if (!blackbox.nokill_rc) blackbox.nokill_err=GetLastError(); } @@ -239,18 +590,28 @@ static void doDebugger(int argc, char** argv) blackbox.detach_err=0; if (strstr(myARGV[2], "detach")) { - blackbox.detach_rc=pDebugActiveProcessStop(blackbox.pid); + blackbox.detach_rc = DebugActiveProcessStop(blackbox.pid); if (!blackbox.detach_rc) blackbox.detach_err=GetLastError(); } else blackbox.detach_rc=TRUE; + if (debug_event && strstr(myARGV[2], "late")) + { + strcat(buf, "setting event\n"); + blackbox.debug_rc=SetEvent(debug_event); + if (!blackbox.debug_rc) + blackbox.debug_err=GetLastError(); + } + + strcat(buf, "done debugging...\n"); if (logfile) { - save_blackbox(logfile, &blackbox, sizeof(blackbox)); + blackbox.failures = winetest_get_failures(); + save_blackbox(logfile, &blackbox, sizeof(blackbox), buf); } - trace("debugger: done debugging...\n"); + SetEvent(done_event); /* Just exit with a known value */ @@ -265,11 +626,9 @@ static void crash_and_debug(HKEY hkey, const char* argv0, const char* dbgtasks) HANDLE start_event, done_event; char* cmd; char dbglog[MAX_PATH]; - char childlog[MAX_PATH]; PROCESS_INFORMATION info; STARTUPINFOA startup; DWORD exit_code; - crash_blackbox_t crash_blackbox; debugger_blackbox_t dbg_blackbox; DWORD wait_code; @@ -287,26 +646,26 @@ static void crash_and_debug(HKEY hkey, const char* argv0, const char* dbgtasks) return; } - ok(ret == ERROR_SUCCESS, "unable to set AeDebug/auto: ret=%d\n", ret); + ok(ret == ERROR_SUCCESS, "unable to set AeDebug/auto: ret=%ld\n", ret); get_file_name(dbglog); get_events(dbglog, &start_event, &done_event); cmd=HeapAlloc(GetProcessHeap(), 0, strlen(argv0)+10+strlen(dbgtasks)+1+strlen(dbglog)+2+34+1); sprintf(cmd, "%s debugger %s \"%s\" %%ld %%ld", argv0, dbgtasks, dbglog); ret=RegSetValueExA(hkey, "debugger", 0, REG_SZ, (BYTE*)cmd, strlen(cmd)+1); - ok(ret == ERROR_SUCCESS, "unable to set AeDebug/debugger: ret=%d\n", ret); + ok(ret == ERROR_SUCCESS, "unable to set AeDebug/debugger: ret=%ld\n", ret); HeapFree(GetProcessHeap(), 0, cmd); - get_file_name(childlog); - cmd=HeapAlloc(GetProcessHeap(), 0, strlen(argv0)+16+strlen(dbglog)+2+1); - sprintf(cmd, "%s debugger crash \"%s\"", argv0, childlog); + cmd = HeapAlloc(GetProcessHeap(), 0, strlen(argv0) + 16); + sprintf(cmd, "%s debugger crash", argv0); + trace("running %s...\n", dbgtasks); memset(&startup, 0, sizeof(startup)); startup.cb = sizeof(startup); startup.dwFlags = STARTF_USESHOWWINDOW; startup.wShowWindow = SW_SHOWNORMAL; ret=CreateProcessA(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info); - ok(ret, "CreateProcess: err=%d\n", GetLastError()); + ok(ret, "CreateProcess: err=%ld\n", GetLastError()); HeapFree(GetProcessHeap(), 0, cmd); CloseHandle(info.hThread); @@ -322,14 +681,13 @@ static void crash_and_debug(HKEY hkey, const char* argv0, const char* dbgtasks) WaitForSingleObject(info.hProcess, 5000); CloseHandle(info.hProcess); DeleteFileA(dbglog); - DeleteFileA(childlog); win_skip("Giving up on child process\n"); return; } #endif ok(wait_code == WAIT_OBJECT_0, "Timed out waiting for the child to crash\n"); bRet = GetExitCodeProcess(info.hProcess, &exit_code); - ok(bRet, "GetExitCodeProcess failed: err=%d\n", GetLastError()); + ok(bRet, "GetExitCodeProcess failed: err=%ld\n", GetLastError()); if (strstr(dbgtasks, "code2")) { /* If, after attaching to the debuggee, the debugger exits without @@ -338,12 +696,12 @@ static void crash_and_debug(HKEY hkey, const char* argv0, const char* dbgtasks) ok(exit_code == STATUS_DEBUGGER_INACTIVE || broken(exit_code == STATUS_ACCESS_VIOLATION) || /* Intermittent Vista+ */ broken(exit_code == WAIT_ABANDONED), /* NT4, W2K */ - "wrong exit code : %08x\n", exit_code); + "wrong exit code : %08lx\n", exit_code); } else ok(exit_code == STATUS_ACCESS_VIOLATION || broken(exit_code == WAIT_ABANDONED), /* NT4, W2K, W2K3 */ - "wrong exit code : %08x\n", exit_code); + "wrong exit code : %08lx\n", exit_code); CloseHandle(info.hProcess); /* ...before the debugger */ @@ -358,25 +716,23 @@ static void crash_and_debug(HKEY hkey, const char* argv0, const char* dbgtasks) if (skip_crash_and_debug) { DeleteFileA(dbglog); - DeleteFileA(childlog); win_skip("Giving up on debugger\n"); return; } #endif ok(wait_code == WAIT_OBJECT_0, "Timed out waiting for the debugger\n"); - ok(load_blackbox(childlog, &crash_blackbox, sizeof(crash_blackbox)), "failed to open: %s\n", childlog); ok(load_blackbox(dbglog, &dbg_blackbox, sizeof(dbg_blackbox)), "failed to open: %s\n", dbglog); ok(dbg_blackbox.argc == 6, "wrong debugger argument count: %d\n", dbg_blackbox.argc); - ok(dbg_blackbox.pid == crash_blackbox.pid, "the child and debugged pids don't match: %d != %d\n", crash_blackbox.pid, dbg_blackbox.pid); - ok(dbg_blackbox.debug_rc, "debugger: SetEvent(debug_event) failed err=%d\n", dbg_blackbox.debug_err); - ok(dbg_blackbox.attach_rc, "DebugActiveProcess(%d) failed err=%d\n", dbg_blackbox.pid, dbg_blackbox.attach_err); - ok(dbg_blackbox.nokill_rc, "DebugSetProcessKillOnExit(FALSE) failed err=%d\n", dbg_blackbox.nokill_err); - ok(dbg_blackbox.detach_rc, "DebugActiveProcessStop(%d) failed err=%d\n", dbg_blackbox.pid, dbg_blackbox.detach_err); + ok(dbg_blackbox.pid == info.dwProcessId, "the child and debugged pids don't match: %ld != %ld\n", info.dwProcessId, dbg_blackbox.pid); + ok(dbg_blackbox.debug_rc, "debugger: SetEvent(debug_event) failed err=%ld\n", dbg_blackbox.debug_err); + ok(dbg_blackbox.attach_rc, "DebugActiveProcess(%ld) failed err=%ld\n", dbg_blackbox.pid, dbg_blackbox.attach_err); + ok(dbg_blackbox.nokill_rc, "DebugSetProcessKillOnExit(FALSE) failed err=%ld\n", dbg_blackbox.nokill_err); + ok(dbg_blackbox.detach_rc, "DebugActiveProcessStop(%ld) failed err=%ld\n", dbg_blackbox.pid, dbg_blackbox.detach_err); + ok(!dbg_blackbox.failures, "debugger reported %lu failures\n", dbg_blackbox.failures); DeleteFileA(dbglog); - DeleteFileA(childlog); } static void crash_and_winedbg(HKEY hkey, const char* argv0) @@ -389,7 +745,7 @@ static void crash_and_winedbg(HKEY hkey, const char* argv0) DWORD exit_code; ret=RegSetValueExA(hkey, "auto", 0, REG_SZ, (BYTE*)"1", 2); - ok(ret == ERROR_SUCCESS, "unable to set AeDebug/auto: ret=%d\n", ret); + ok(ret == ERROR_SUCCESS, "unable to set AeDebug/auto: ret=%ld\n", ret); cmd=HeapAlloc(GetProcessHeap(), 0, strlen(argv0)+15+1); sprintf(cmd, "%s debugger crash", argv0); @@ -399,15 +755,15 @@ static void crash_and_winedbg(HKEY hkey, const char* argv0) startup.dwFlags = STARTF_USESHOWWINDOW; startup.wShowWindow = SW_SHOWNORMAL; ret=CreateProcessA(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info); - ok(ret, "CreateProcess: err=%d\n", GetLastError()); + ok(ret, "CreateProcess: err=%ld\n", GetLastError()); HeapFree(GetProcessHeap(), 0, cmd); CloseHandle(info.hThread); trace("waiting for child exit...\n"); ok(WaitForSingleObject(info.hProcess, 60000) == WAIT_OBJECT_0, "Timed out waiting for the child to crash\n"); bRet = GetExitCodeProcess(info.hProcess, &exit_code); - ok(bRet, "GetExitCodeProcess failed: err=%d\n", GetLastError()); - ok(exit_code == STATUS_ACCESS_VIOLATION, "exit code = %08x\n", exit_code); + ok(bRet, "GetExitCodeProcess failed: err=%ld\n", GetLastError()); + ok(exit_code == STATUS_ACCESS_VIOLATION, "exit code = %08lx\n", exit_code); CloseHandle(info.hProcess); } @@ -445,10 +801,14 @@ static void test_ExitCode(void) } else if (ret != ERROR_FILE_NOT_FOUND) { - ok(0, "could not open the AeDebug key: %d\n", ret); + ok(0, "could not open the AeDebug key: %ld\n", ret); return; } - else debugger_value.data = NULL; + else + { + auto_value.data = NULL; + debugger_value.data = NULL; + } if (debugger_value.data && debugger_value.type == REG_SZ && strstr((char*)debugger_value.data, "winedbg --auto")) @@ -461,12 +821,14 @@ static void test_ExitCode(void) reg_save_value crash_dlg_value; save_value(hkeyWinedbg, "ShowCrashDialog", &crash_dlg_value); RegSetValueExA(hkeyWinedbg, "ShowCrashDialog", 0, REG_DWORD, (BYTE *)&zero, sizeof(DWORD)); + ignore_exceptions(TRUE); crash_and_winedbg(hkey, test_exe); + ignore_exceptions(FALSE); restore_value(hkeyWinedbg, &crash_dlg_value); RegCloseKey(hkeyWinedbg); } else - ok(0, "Couldn't access WineDbg Key - error %u\n", ret); + ok(0, "Couldn't access WineDbg Key - error %lu\n", ret); } if (winetest_interactive) @@ -476,17 +838,13 @@ static void test_ExitCode(void) crash_and_debug(hkey, test_exe, "dbg,none"); else skip("\"none\" debugger test needs user interaction\n"); - ok(disposition == REG_OPENED_EXISTING_KEY, "expected REG_OPENED_EXISTING_KEY, got %d\n", disposition); + ok(disposition == REG_OPENED_EXISTING_KEY, "expected REG_OPENED_EXISTING_KEY, got %ld\n", disposition); crash_and_debug(hkey, test_exe, "dbg,event,order"); crash_and_debug(hkey, test_exe, "dbg,attach,event,code2"); - if (pDebugSetProcessKillOnExit) - crash_and_debug(hkey, test_exe, "dbg,attach,event,nokill"); - else - win_skip("DebugSetProcessKillOnExit is not available\n"); - if (pDebugActiveProcessStop) - crash_and_debug(hkey, test_exe, "dbg,attach,event,detach"); - else - win_skip("DebugActiveProcessStop is not available\n"); + crash_and_debug(hkey, test_exe, "dbg,attach,event,nokill"); + crash_and_debug(hkey, test_exe, "dbg,attach,event,detach"); + crash_and_debug(hkey, test_exe, "dbg,attach,detach,late"); + crash_and_debug(hkey, test_exe, "dbg,attach,process,event,detach"); if (disposition == REG_CREATED_NEW_KEY) { @@ -514,7 +872,7 @@ static void test_RemoteDebugger(void) bret = pCheckRemoteDebuggerPresent(GetCurrentProcess(),&present); ok(bret , "expected CheckRemoteDebuggerPresent to succeed\n"); ok(0xdeadbeef == GetLastError(), - "expected error to be unchanged, got %d/%x\n",GetLastError(), GetLastError()); + "expected error to be unchanged, got %ld/%lx\n",GetLastError(), GetLastError()); present = TRUE; SetLastError(0xdeadbeef); @@ -522,13 +880,13 @@ static void test_RemoteDebugger(void) ok(!bret , "expected CheckRemoteDebuggerPresent to fail\n"); ok(present, "expected parameter to be unchanged\n"); ok(ERROR_INVALID_PARAMETER == GetLastError(), - "expected error ERROR_INVALID_PARAMETER, got %d/%x\n",GetLastError(), GetLastError()); + "expected error ERROR_INVALID_PARAMETER, got %ld/%lx\n",GetLastError(), GetLastError()); SetLastError(0xdeadbeef); bret = pCheckRemoteDebuggerPresent(GetCurrentProcess(),NULL); ok(!bret , "expected CheckRemoteDebuggerPresent to fail\n"); ok(ERROR_INVALID_PARAMETER == GetLastError(), - "expected error ERROR_INVALID_PARAMETER, got %d/%x\n",GetLastError(), GetLastError()); + "expected error ERROR_INVALID_PARAMETER, got %ld/%lx\n",GetLastError(), GetLastError()); } struct child_blackbox @@ -540,56 +898,121 @@ static void doChild(int argc, char **argv) { struct child_blackbox blackbox; const char *blackbox_file; - HANDLE parent; + WCHAR path[MAX_PATH]; + HMODULE mod; + HANDLE parent, file, map; DWORD ppid; BOOL debug; BOOL ret; blackbox_file = argv[4]; - sscanf(argv[3], "%08x", &ppid); + sscanf(argv[3], "%08lx", &ppid); parent = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ppid); - child_ok(!!parent, "OpenProcess failed, last error %#x.\n", GetLastError()); + child_ok(!!parent, "OpenProcess failed, last error %#lx.\n", GetLastError()); ret = pCheckRemoteDebuggerPresent(parent, &debug); - child_ok(ret, "CheckRemoteDebuggerPresent failed, last error %#x.\n", GetLastError()); + child_ok(ret, "CheckRemoteDebuggerPresent failed, last error %#lx.\n", GetLastError()); child_ok(!debug, "Expected debug == 0, got %#x.\n", debug); ret = DebugActiveProcess(ppid); - child_ok(ret, "DebugActiveProcess failed, last error %#x.\n", GetLastError()); + child_ok(ret, "DebugActiveProcess failed, last error %#lx.\n", GetLastError()); ret = pCheckRemoteDebuggerPresent(parent, &debug); - child_ok(ret, "CheckRemoteDebuggerPresent failed, last error %#x.\n", GetLastError()); + child_ok(ret, "CheckRemoteDebuggerPresent failed, last error %#lx.\n", GetLastError()); child_ok(debug, "Expected debug != 0, got %#x.\n", debug); - ret = pDebugActiveProcessStop(ppid); - child_ok(ret, "DebugActiveProcessStop failed, last error %#x.\n", GetLastError()); + ret = DebugActiveProcessStop(ppid); + child_ok(ret, "DebugActiveProcessStop failed, last error %#lx.\n", GetLastError()); ret = pCheckRemoteDebuggerPresent(parent, &debug); - child_ok(ret, "CheckRemoteDebuggerPresent failed, last error %#x.\n", GetLastError()); + child_ok(ret, "CheckRemoteDebuggerPresent failed, last error %#lx.\n", GetLastError()); child_ok(!debug, "Expected debug == 0, got %#x.\n", debug); ret = CloseHandle(parent); - child_ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError()); + child_ok(ret, "CloseHandle failed, last error %#lx.\n", GetLastError()); - ret = pIsDebuggerPresent(); + ret = IsDebuggerPresent(); child_ok(ret, "Expected ret != 0, got %#x.\n", ret); ret = pCheckRemoteDebuggerPresent(GetCurrentProcess(), &debug); - child_ok(ret, "CheckRemoteDebuggerPresent failed, last error %#x.\n", GetLastError()); + child_ok(ret, "CheckRemoteDebuggerPresent failed, last error %#lx.\n", GetLastError()); child_ok(debug, "Expected debug != 0, got %#x.\n", debug); NtCurrentTeb()->Peb->BeingDebugged = FALSE; - ret = pIsDebuggerPresent(); + ret = IsDebuggerPresent(); child_ok(!ret, "Expected ret != 0, got %#x.\n", ret); ret = pCheckRemoteDebuggerPresent(GetCurrentProcess(), &debug); - child_ok(ret, "CheckRemoteDebuggerPresent failed, last error %#x.\n", GetLastError()); + child_ok(ret, "CheckRemoteDebuggerPresent failed, last error %#lx.\n", GetLastError()); child_ok(debug, "Expected debug != 0, got %#x.\n", debug); NtCurrentTeb()->Peb->BeingDebugged = TRUE; + mod = LoadLibraryW( L"ole32.dll" ); + FreeLibrary( mod ); + + GetSystemDirectoryW( path, MAX_PATH ); + wcscat( path, L"\\oleaut32.dll" ); + file = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); + child_ok( file != INVALID_HANDLE_VALUE, "failed to open %s: %lu\n", debugstr_w(path), GetLastError()); + map = CreateFileMappingW( file, NULL, SEC_IMAGE | PAGE_READONLY, 0, 0, NULL ); + child_ok( map != NULL, "failed to create mapping %s: %lu\n", debugstr_w(path), GetLastError() ); + mod = MapViewOfFile( map, FILE_MAP_READ, 0, 0, 0 ); + child_ok( mod != NULL, "failed to map %s: %lu\n", debugstr_w(path), GetLastError() ); + CloseHandle( file ); + CloseHandle( map ); + UnmapViewOfFile( mod ); + + if (sizeof(void *) > sizeof(int)) + { + GetSystemWow64DirectoryW( path, MAX_PATH ); + wcscat( path, L"\\oleacc.dll" ); + } + else if (is_wow64) + { + wcscpy( path, L"c:\\windows\\sysnative\\oleacc.dll" ); + } + else goto done; + + file = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); + child_ok( file != INVALID_HANDLE_VALUE, "failed to open %s: %lu\n", debugstr_w(path), GetLastError()); + map = CreateFileMappingW( file, NULL, SEC_IMAGE | PAGE_READONLY, 0, 0, NULL ); + child_ok( map != NULL, "failed to create mapping %s: %lu\n", debugstr_w(path), GetLastError() ); + mod = MapViewOfFile( map, FILE_MAP_READ, 0, 0, 0 ); + child_ok( mod != NULL, "failed to map %s: %lu\n", debugstr_w(path), GetLastError() ); + CloseHandle( file ); + CloseHandle( map ); + UnmapViewOfFile( mod ); + +done: blackbox.failures = child_failures; - save_blackbox(blackbox_file, &blackbox, sizeof(blackbox)); + save_blackbox(blackbox_file, &blackbox, sizeof(blackbox), NULL); +} + +static HMODULE ole32_mod, oleaut32_mod, oleacc_mod; + +static void check_dll_event( HANDLE process, DEBUG_EVENT *ev ) +{ + WCHAR *p, module[MAX_PATH]; + + switch (ev->dwDebugEventCode) + { + case CREATE_PROCESS_DEBUG_EVENT: + break; + case LOAD_DLL_DEBUG_EVENT: + if (!pGetMappedFileNameW( process, ev->u.LoadDll.lpBaseOfDll, module, MAX_PATH )) module[0] = 0; + if ((p = wcsrchr( module, '\\' ))) p++; + else p = module; + if (!wcsicmp( p, L"ole32.dll" )) ole32_mod = ev->u.LoadDll.lpBaseOfDll; + else if (!wcsicmp( p, L"oleaut32.dll" )) oleaut32_mod = ev->u.LoadDll.lpBaseOfDll; + else if (!wcsicmp( p, L"oleacc.dll" )) oleacc_mod = ev->u.LoadDll.lpBaseOfDll; + break; + case UNLOAD_DLL_DEBUG_EVENT: + if (ev->u.UnloadDll.lpBaseOfDll == ole32_mod) ole32_mod = (HMODULE)1; + if (ev->u.UnloadDll.lpBaseOfDll == oleaut32_mod) oleaut32_mod = (HMODULE)1; + if (ev->u.UnloadDll.lpBaseOfDll == oleacc_mod) oleacc_mod = (HMODULE)1; + break; + } } static void test_debug_loop(int argc, char **argv) @@ -604,11 +1027,30 @@ static void test_debug_loop(int argc, char **argv) char *cmd; BOOL ret; - if (!pDebugActiveProcessStop || !pCheckRemoteDebuggerPresent) + if (!pCheckRemoteDebuggerPresent) { - win_skip("DebugActiveProcessStop or CheckRemoteDebuggerPresent not available, skipping test.\n"); + win_skip("CheckRemoteDebuggerPresent not available, skipping test.\n"); return; } +#if defined(__REACTOS__) && defined(_WIN64) + if (is_reactos()) { + /* In theory this should be caught below and exit. In practice stack + * corruption occurs and the test crashes after exiting this function. */ + skip("FIXME: Skipping test on ReactOS x64 because it is 64bit only!\n"); + return; + } +#endif + if (sizeof(void *) > sizeof(int)) + { + WCHAR buffer[MAX_PATH]; + GetSystemWow64DirectoryW( buffer, MAX_PATH ); + wcscat( buffer, L"\\oleacc.dll" ); + if (GetFileAttributesW( buffer ) == INVALID_FILE_ATTRIBUTES) + { + skip("Skipping test on 64bit only configuration\n"); + return; + } + } pid = GetCurrentProcessId(); ret = DebugActiveProcess(pid); @@ -616,17 +1058,17 @@ static void test_debug_loop(int argc, char **argv) get_file_name(blackbox_file); cmd = HeapAlloc(GetProcessHeap(), 0, strlen(argv[0]) + strlen(arguments) + strlen(blackbox_file) + 2 + 10); - sprintf(cmd, "%s%s%08x \"%s\"", argv[0], arguments, pid, blackbox_file); + sprintf(cmd, "%s%s%08lx \"%s\"", argv[0], arguments, pid, blackbox_file); memset(&si, 0, sizeof(si)); si.cb = sizeof(si); ret = CreateProcessA(NULL, cmd, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi); - ok(ret, "CreateProcess failed, last error %#x.\n", GetLastError()); + ok(ret, "CreateProcess failed, last error %#lx.\n", GetLastError()); HeapFree(GetProcessHeap(), 0, cmd); ret = pCheckRemoteDebuggerPresent(pi.hProcess, &debug); - ok(ret, "CheckRemoteDebuggerPresent failed, last error %#x.\n", GetLastError()); + ok(ret, "CheckRemoteDebuggerPresent failed, last error %#lx.\n", GetLastError()); ok(debug, "Expected debug != 0, got %#x.\n", debug); for (;;) @@ -634,26 +1076,217 @@ static void test_debug_loop(int argc, char **argv) DEBUG_EVENT ev; ret = WaitForDebugEvent(&ev, INFINITE); - ok(ret, "WaitForDebugEvent failed, last error %#x.\n", GetLastError()); + ok(ret, "WaitForDebugEvent failed, last error %#lx.\n", GetLastError()); if (!ret) break; if (ev.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) break; - + check_dll_event( pi.hProcess, &ev ); +#if defined(__i386__) || defined(__x86_64__) + if (ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT && + ev.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT) + { + BYTE byte = 0; + NtReadVirtualMemory(pi.hProcess, ev.u.Exception.ExceptionRecord.ExceptionAddress, &byte, 1, NULL); + ok(byte == 0xcc, "got %02x\n", byte); + } +#endif ret = ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE); - ok(ret, "ContinueDebugEvent failed, last error %#x.\n", GetLastError()); + ok(ret, "ContinueDebugEvent failed, last error %#lx.\n", GetLastError()); if (!ret) break; } + /* sometimes not all unload events are sent on win7 */ + ok( ole32_mod == (HMODULE)1 || broken( ole32_mod != NULL ), "ole32.dll was not reported\n" ); + ok( oleaut32_mod == (HMODULE)1, "oleaut32.dll was not reported\n" ); +#ifdef _WIN64 + ok( oleacc_mod == (HMODULE)1, "oleacc.dll was not reported\n" ); +#else + ok( oleacc_mod == NULL, "oleacc.dll was reported\n" ); +#endif + ret = CloseHandle(pi.hThread); - ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError()); + ok(ret, "CloseHandle failed, last error %#lx.\n", GetLastError()); ret = CloseHandle(pi.hProcess); - ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError()); + ok(ret, "CloseHandle failed, last error %#lx.\n", GetLastError()); load_blackbox(blackbox_file, &blackbox, sizeof(blackbox)); - ok(!blackbox.failures, "Got %d failures from child process.\n", blackbox.failures); + ok(!blackbox.failures, "Got %ld failures from child process.\n", blackbox.failures); ret = DeleteFileA(blackbox_file); - ok(ret, "DeleteFileA failed, last error %#x.\n", GetLastError()); + ok(ret, "DeleteFileA failed, last error %#lx.\n", GetLastError()); +} + +struct find_main_window +{ + DWORD pid; + unsigned count; + HWND windows[5]; +}; + +static BOOL CALLBACK enum_windows_callback(HWND handle, LPARAM lParam) +{ + struct find_main_window* fmw = (struct find_main_window*)lParam; + DWORD pid = 0; + + if (GetWindowThreadProcessId(handle, &pid) && fmw->pid == pid && + !GetWindow(handle, GW_OWNER)) + { + ok(fmw->count < ARRAY_SIZE(fmw->windows), "Too many windows\n"); + if (fmw->count < ARRAY_SIZE(fmw->windows)) + fmw->windows[fmw->count++] = handle; + } + return TRUE; +} + +static void close_main_windows(DWORD pid) +{ + struct find_main_window fmw = {pid, 0}; + unsigned i; + + EnumWindows(enum_windows_callback, (LPARAM)&fmw); + ok(fmw.count, "no window found\n"); + for (i = 0; i < fmw.count; i++) + PostMessageA(fmw.windows[i], WM_CLOSE, 0, 0); +} + +static void test_debug_loop_wow64(void) +{ + WCHAR buffer[MAX_PATH], *p; + PROCESS_INFORMATION pi; + STARTUPINFOW si; + BOOL ret; + unsigned order = 0, bp_order = 0, bpwx_order = 0, num_ntdll = 0, num_wow64 = 0; + + /* checking conditions for running this test */ +#if defined(__REACTOS__) && defined(_WIN64) + if (is_reactos()) { + skip("FIXME: ReactOS x64 does not have WoW64 yet!\n"); + return; + } +#endif + if (GetSystemWow64DirectoryW( buffer, ARRAY_SIZE(buffer) ) && sizeof(void*) > sizeof(int) && pGetMappedFileNameW) + { + wcscat( buffer, L"\\msinfo32.exe" ); + ret = GetFileAttributesW( buffer ) != INVALID_FILE_ATTRIBUTES; + } + else ret = FALSE; + if (!ret) + { + skip("Skipping test on incompatible config\n"); + return; + } + memset( &si, 0, sizeof(si) ); + si.cb = sizeof(si); + ret = CreateProcessW( NULL, buffer, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi ); + ok(ret, "CreateProcess failed, last error %#lx.\n", GetLastError()); + + for (;;) + { + DEBUG_EVENT ev; + + ++order; + ret = WaitForDebugEvent( &ev, 2000 ); + if (!ret) break; + + switch (ev.dwDebugEventCode) + { + case CREATE_PROCESS_DEBUG_EVENT: + break; + case LOAD_DLL_DEBUG_EVENT: + if (!pGetMappedFileNameW( pi.hProcess, ev.u.LoadDll.lpBaseOfDll, buffer, ARRAY_SIZE(buffer) )) buffer[0] = L'\0'; + if ((p = wcsrchr( buffer, '\\' ))) p++; + else p = buffer; + if (!wcsnicmp( p, L"wow64", 5 ) || !wcsicmp( p, L"xtajit.dll" )) + { + /* on Win10, wow64cpu's load dll event is received after first exception */ + ok(bpwx_order == 0, "loaddll for wow64 DLLs should appear before exception\n"); + num_wow64++; + } + else if (!wcsicmp( p, L"ntdll.dll" )) + { + ok(bp_order == 0 && bpwx_order == 0, "loaddll on ntdll should appear before exception\n"); + num_ntdll++; + } + break; + case EXCEPTION_DEBUG_EVENT: + if (ev.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT) + bp_order = order; + else if (ev.u.Exception.ExceptionRecord.ExceptionCode == STATUS_WX86_BREAKPOINT) + bpwx_order = order; + } + ret = ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE); + ok(ret, "ContinueDebugEvent failed, last error %#lx.\n", GetLastError()); + if (!ret) break; + } + + /* gracefully terminates msinfo32 */ + close_main_windows( pi.dwProcessId ); + + /* eat up the remaining events... not generating unload dll events in case of process termination */ + for (;;) + { + DEBUG_EVENT ev; + + ret = WaitForDebugEvent( &ev, 2000 ); + if (!ret || ev.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) break; + switch (ev.dwDebugEventCode) + { + default: + ok(0, "Unexpected event: %lu\n", ev.dwDebugEventCode); + /* fall through */ + case EXIT_THREAD_DEBUG_EVENT: + ret = ContinueDebugEvent( ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE ); + ok(ret, "ContinueDebugEvent failed, last error %#lx.\n", GetLastError()); + break; + } + } + + ret = WaitForSingleObject( pi.hProcess, 2000 ); + if (ret != WAIT_OBJECT_0) + { + DWORD ec; + ret = GetExitCodeProcess( pi.hProcess, &ec ); + ok(ret, "GetExitCodeProcess failed: %lu\n", GetLastError()); + ok(ec != STILL_ACTIVE, "GetExitCodeProcess still active\n"); + } + for (;;) + { + DEBUG_EVENT ev; + + ret = WaitForDebugEvent( &ev, 2000 ); + if (!ret || ev.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) break; + switch (ev.dwDebugEventCode) + { + default: + ok(0, "Unexpected event: %lu\n", ev.dwDebugEventCode); + /* fall through */ + case EXIT_THREAD_DEBUG_EVENT: + ret = ContinueDebugEvent( ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE ); + ok(ret, "ContinueDebugEvent failed, last error %#lx.\n", GetLastError()); + break; + } + } + ret = CloseHandle( pi.hThread ); + ok(ret, "CloseHandle failed, last error %#lx.\n", GetLastError()); + ret = CloseHandle( pi.hProcess ); + ok(ret, "CloseHandle failed, last error %#lx.\n", GetLastError()); + + if (strcmp( winetest_platform, "wine" ) || num_wow64) /* windows or new wine wow */ + { + ok(num_ntdll == 2, "Expecting two ntdll instances\n"); + ok(num_wow64 >= 3, "Expecting more than 3 wow64*.dll\n"); + } + else /* Wine's old wow, or 32/64 bit only configurations */ + { + ok(num_ntdll == 1, "Expecting one ntdll instances\n"); + ok(num_wow64 == 0, "Expecting more no wow64*.dll\n"); + } + ok(bp_order, "Expecting 1 bp exceptions\n"); + todo_wine + { + ok(bpwx_order, "Expecting 1 bpwx exceptions\n"); + ok(bp_order < bpwx_order, "Out of order bp exceptions\n"); + } } static void doChildren(int argc, char **argv) @@ -672,12 +1305,14 @@ static void doChildren(int argc, char **argv) blackbox_file = argv[3]; + run_background_thread(); + p = strrchr(blackbox_file, '\\'); p = p ? p+1 : blackbox_file; strcpy(event_name, p); strcat(event_name, "_init"); event = OpenEventA(EVENT_ALL_ACCESS, FALSE, event_name); - child_ok(event != NULL, "OpenEvent failed, last error %d.\n", GetLastError()); + child_ok(event != NULL, "OpenEvent failed, last error %ld.\n", GetLastError()); SetEvent(event); CloseHandle(event); @@ -686,7 +1321,7 @@ static void doChildren(int argc, char **argv) strcpy(event_name, p); strcat(event_name, "_attach"); event = OpenEventA(EVENT_ALL_ACCESS, FALSE, event_name); - child_ok(event != NULL, "OpenEvent failed, last error %d.\n", GetLastError()); + child_ok(event != NULL, "OpenEvent failed, last error %ld.\n", GetLastError()); WaitForSingleObject(event, INFINITE); CloseHandle(event); @@ -696,26 +1331,30 @@ static void doChildren(int argc, char **argv) memset(&si, 0, sizeof(si)); si.cb = sizeof(si); ret = CreateProcessA(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); - child_ok(ret, "CreateProcess failed, last error %d.\n", GetLastError()); + child_ok(ret, "CreateProcess failed, last error %ld.\n", GetLastError()); child_ok(WaitForSingleObject(pi.hProcess, 10000) == WAIT_OBJECT_0, "Timed out waiting for the child to exit\n"); ret = CloseHandle(pi.hThread); - child_ok(ret, "CloseHandle failed, last error %d.\n", GetLastError()); + child_ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError()); ret = CloseHandle(pi.hProcess); - child_ok(ret, "CloseHandle failed, last error %d.\n", GetLastError()); + child_ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError()); blackbox.failures = child_failures; - save_blackbox(blackbox_file, &blackbox, sizeof(blackbox)); + save_blackbox(blackbox_file, &blackbox, sizeof(blackbox), NULL); HeapFree(GetProcessHeap(), 0, cmd); } -static void test_debug_children(char *name, DWORD flag, BOOL debug_child) +static void test_debug_children(const char *name, DWORD flag, BOOL debug_child, BOOL pass_exception) { const char *arguments = "debugger children"; +#ifdef __REACTOS__ + struct child_blackbox blackbox = {0}; +#else struct child_blackbox blackbox; +#endif char blackbox_file[MAX_PATH], *p; char event_name[MAX_PATH]; PROCESS_INFORMATION pi; @@ -723,11 +1362,11 @@ static void test_debug_children(char *name, DWORD flag, BOOL debug_child) HANDLE event_init, event_attach; char *cmd; BOOL debug, ret; - BOOL got_child_event = FALSE; + struct debugger_context ctx = { 0 }; - if (!pDebugActiveProcessStop || !pCheckRemoteDebuggerPresent) + if (!pCheckRemoteDebuggerPresent) { - win_skip("DebugActiveProcessStop or CheckRemoteDebuggerPresent not available, skipping test.\n"); + win_skip("CheckRemoteDebuggerPresent not available, skipping test.\n"); return; } @@ -740,66 +1379,1114 @@ static void test_debug_children(char *name, DWORD flag, BOOL debug_child) strcpy(event_name, p); strcat(event_name, "_init"); event_init = CreateEventA(NULL, FALSE, FALSE, event_name); - ok(event_init != NULL, "OpenEvent failed, last error %d.\n", GetLastError()); + ok(event_init != NULL, "OpenEvent failed, last error %ld.\n", GetLastError()); p = strrchr(blackbox_file, '\\'); p = p ? p+1 : blackbox_file; strcpy(event_name, p); strcat(event_name, "_attach"); event_attach = CreateEventA(NULL, FALSE, flag!=0, event_name); - ok(event_attach != NULL, "CreateEvent failed, last error %d.\n", GetLastError()); + ok(event_attach != NULL, "CreateEvent failed, last error %ld.\n", GetLastError()); memset(&si, 0, sizeof(si)); si.cb = sizeof(si); ret = CreateProcessA(NULL, cmd, NULL, NULL, FALSE, flag, NULL, NULL, &si, &pi); - ok(ret, "CreateProcess failed, last error %d.\n", GetLastError()); + ok(ret, "CreateProcess failed, last error %ld.\n", GetLastError()); HeapFree(GetProcessHeap(), 0, cmd); if (!flag) { WaitForSingleObject(event_init, INFINITE); + Sleep(100); ret = DebugActiveProcess(pi.dwProcessId); - ok(ret, "DebugActiveProcess failed, last error %d.\n", GetLastError()); - ret = SetEvent(event_attach); - ok(ret, "SetEvent failed, last error %d.\n", GetLastError()); + ok(ret, "DebugActiveProcess failed, last error %ld.\n", GetLastError()); } ret = pCheckRemoteDebuggerPresent(pi.hProcess, &debug); - ok(ret, "CheckRemoteDebuggerPresent failed, last error %d.\n", GetLastError()); + ok(ret, "CheckRemoteDebuggerPresent failed, last error %ld.\n", GetLastError()); ok(debug, "Expected debug != 0, got %x.\n", debug); - for (;;) + trace("starting debugger loop\n"); + + if (flag) { - DEBUG_EVENT ev; + DWORD last_thread; - ret = WaitForDebugEvent(&ev, INFINITE); - ok(ret, "WaitForDebugEvent failed, last error %d.\n", GetLastError()); - if (!ret) break; + next_event(&ctx, WAIT_EVENT_TIMEOUT); + ok(ctx.ev.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode); + ok(ctx.pid == pi.dwProcessId, "unexpected dwProcessId %x\n", ctx.ev.dwProcessId == ctx.pid); - if (ev.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT && ev.dwProcessId==pi.dwProcessId) break; - else if (ev.dwProcessId != pi.dwProcessId) got_child_event = TRUE; + next_event(&ctx, WAIT_EVENT_TIMEOUT); + ok(ctx.ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode); + last_thread = ctx.ev.dwThreadId; - ret = ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE); - ok(ret, "ContinueDebugEvent failed, last error %d.\n", GetLastError()); - if (!ret) break; + wait_for_breakpoint(&ctx); + ok(ctx.dll_cnt > 2, "dll_cnt = %d\n", ctx.dll_cnt); + + ok(ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode); + ok(ctx.ev.dwThreadId == last_thread, "unexpected thread\n"); + ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "ExceptionCode = %lx\n", + ctx.ev.u.Exception.ExceptionRecord.ExceptionCode); + + /* Except for wxppro and w2008, the initial breakpoint is now somewhere else, possibly within LdrInitShimEngineDynamic, + * It's also catching exceptions and ContinueDebugEvent(DBG_EXCEPTION_NOT_HANDLED) should not crash the child now */ +#ifdef __REACTOS__ + ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress != pDbgBreakPoint || broken(GetNTVersion() <= _WIN32_WINNT_VISTA), "ExceptionAddress == pDbgBreakPoint\n"); +#else + ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress != pDbgBreakPoint, "ExceptionAddress == pDbgBreakPoint\n"); +#endif + + if (pass_exception) + { + ret = ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, DBG_EXCEPTION_NOT_HANDLED); + ok(ret, "ContinueDebugEvent failed, last error %ld.\n", GetLastError()); + ctx.ev.dwDebugEventCode = -1; + + next_event(&ctx, WAIT_EVENT_TIMEOUT); +#ifdef __REACTOS__ + ok(ctx.ev.dwDebugEventCode != EXCEPTION_DEBUG_EVENT || broken(GetNTVersion() <= _WIN32_WINNT_WS03), "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode); +#else + ok(ctx.ev.dwDebugEventCode != EXCEPTION_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode); +#endif + } } - if(debug_child) - ok(got_child_event, "didn't get any child events (flag: %x).\n", flag); else - ok(!got_child_event, "got child event (flag: %x).\n", flag); + { + DWORD last_thread; + + process_attach_events(&ctx, pass_exception); + ok(ctx.pid == pi.dwProcessId, "unexpected dwProcessId %lx\n", ctx.pid); + + ret = DebugBreakProcess(pi.hProcess); + ok(ret, "BreakProcess failed: %lu\n", GetLastError()); + + /* a new thread, which executes DbgBreakPoint, is created */ + next_event(&ctx, WAIT_EVENT_TIMEOUT); + ok(ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode); + last_thread = ctx.ev.dwThreadId; + + if (ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT) + next_event(&ctx, WAIT_EVENT_TIMEOUT); + + ok(ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode); + ok(ctx.ev.dwThreadId == last_thread, "unexpected thread\n"); + ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "ExceptionCode = %lx\n", + ctx.ev.u.Exception.ExceptionRecord.ExceptionCode); + ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress == pDbgBreakPoint, "ExceptionAddress != DbgBreakPoint\n"); + + ret = SetEvent(event_attach); + ok(ret, "SetEvent failed, last error %ld.\n", GetLastError()); + + if (pass_exception) + { + ret = ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, DBG_EXCEPTION_NOT_HANDLED); + ok(ret, "ContinueDebugEvent failed, last error %ld.\n", GetLastError()); + ctx.ev.dwDebugEventCode = -1; + } + } + + do next_event(&ctx, WAIT_EVENT_TIMEOUT); + while (ctx.ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT || ctx.ev.dwDebugEventCode == UNLOAD_DLL_DEBUG_EVENT + || ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT || ctx.ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT); + +#ifdef __REACTOS__ + ok(ctx.ev.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT || broken(ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) /* WS03 */, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode); +#else + ok(ctx.ev.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode); +#endif + ret = ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, DBG_CONTINUE); + ok(ret, "ContinueDebugEvent failed, last error %ld.\n", GetLastError()); + + if(debug_child) + ok(ctx.process_cnt == 2, "didn't get any child events (flag: %lx).\n", flag); + else + ok(ctx.process_cnt == 1, "got child event (flag: %lx).\n", flag); CloseHandle(event_init); CloseHandle(event_attach); ret = CloseHandle(pi.hThread); - ok(ret, "CloseHandle failed, last error %d.\n", GetLastError()); + ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError()); ret = CloseHandle(pi.hProcess); - ok(ret, "CloseHandle failed, last error %d.\n", GetLastError()); + ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError()); load_blackbox(blackbox_file, &blackbox, sizeof(blackbox)); - ok(!blackbox.failures, "Got %d failures from child process.\n", blackbox.failures); + ok(!blackbox.failures, "Got %ld failures from child process.\n", blackbox.failures); ret = DeleteFileA(blackbox_file); - ok(ret, "DeleteFileA failed, last error %d.\n", GetLastError()); + ok(ret, "DeleteFileA failed, last error %ld.\n", GetLastError()); +} + +static void wait_debugger(HANDLE event, unsigned int cnt) +{ + while (cnt--) WaitForSingleObject(event, INFINITE); + ExitProcess(0); +} + +#define expect_event(a,b) expect_event_(__LINE__,a,b) +static void expect_event_(unsigned line, struct debugger_context *ctx, DWORD event_code) +{ + next_event(ctx, WAIT_EVENT_TIMEOUT); + ok_(__FILE__,line)(ctx->ev.dwDebugEventCode == event_code, "dwDebugEventCode = %ld expected %ld\n", + ctx->ev.dwDebugEventCode, event_code); +} + +#define expect_exception(a,b) expect_exception_(__LINE__,a,b) +static void expect_exception_(unsigned line, struct debugger_context *ctx, DWORD exception_code) +{ + expect_event_(line, ctx, EXCEPTION_DEBUG_EVENT); + ok_(__FILE__,line)(ctx->ev.u.Exception.ExceptionRecord.ExceptionCode == exception_code, "ExceptionCode = %lx expected %lx\n", + ctx->ev.u.Exception.ExceptionRecord.ExceptionCode, exception_code); +} + +#define check_breakpoint_exception(a,b) expect_breakpoint_exception_(__LINE__,a,b) +static void check_breakpoint_exception_(unsigned line, struct debugger_context *ctx, const void *expect_addr) +{ + struct debuggee_thread *thread; + if (!expect_addr) return; + ok_(__FILE__,line)(ctx->ev.u.Exception.ExceptionRecord.ExceptionAddress == expect_addr, + "ExceptionAddress = %p expected %p\n", ctx->ev.u.Exception.ExceptionRecord.ExceptionAddress, expect_addr); + thread = get_debuggee_thread(ctx, ctx->ev.dwThreadId); + fetch_thread_context(thread); + ok_(__FILE__,line)(get_ip(&thread->ctx) == (char*)expect_addr + 1, "unexpected instruction pointer %p expected %p\n", + get_ip(&thread->ctx), expect_addr); +} + +#define expect_breakpoint_exception(a,b) expect_breakpoint_exception_(__LINE__,a,b) +static void expect_breakpoint_exception_(unsigned line, struct debugger_context *ctx, const void *expect_addr) +{ + expect_exception_(line, ctx, EXCEPTION_BREAKPOINT); + check_breakpoint_exception_(line, ctx, expect_addr); +} + +#define single_step(a,b,c) single_step_(__LINE__,a,b,c) +static void single_step_(unsigned line, struct debugger_context *ctx, struct debuggee_thread *thread, void *expect_addr) +{ +#if defined(__i386__) || defined(__x86_64__) + fetch_thread_context(thread); + thread->ctx.EFlags |= 0x100; + set_thread_context(ctx, thread); + expect_exception_(line, ctx, EXCEPTION_SINGLE_STEP); + ok_(__FILE__,line)(ctx->ev.u.Exception.ExceptionRecord.ExceptionAddress == expect_addr, + "ExceptionAddress = %p expected %p\n", ctx->ev.u.Exception.ExceptionRecord.ExceptionAddress, expect_addr); + fetch_thread_context(thread); + ok_(__FILE__,line)(get_ip(&thread->ctx) == expect_addr, "unexpected instruction pointer %p expected %p\n", + get_ip(&thread->ctx), expect_addr); + ok_(__FILE__,line)(!(thread->ctx.EFlags & 0x100), "EFlags = %lx\n", thread->ctx.EFlags); +#endif +} + +static const BYTE loop_code[] = { +#if defined(__i386__) || defined(__x86_64__) + 0x90, /* nop */ + 0x90, /* nop */ + 0x90, /* nop */ + 0xe9, 0xf8, 0xff, 0xff, 0xff /* jmp $-8 */ +#endif +}; + +static const BYTE call_debug_service_code[] = { +#ifdef __i386__ + 0x53, /* pushl %ebx */ + 0x57, /* pushl %edi */ + 0x8b, 0x44, 0x24, 0x0c, /* movl 12(%esp),%eax */ + 0xb9, 0x11, 0x11, 0x11, 0x11, /* movl $0x11111111,%ecx */ + 0xba, 0x22, 0x22, 0x22, 0x22, /* movl $0x22222222,%edx */ + 0xbb, 0x33, 0x33, 0x33, 0x33, /* movl $0x33333333,%ebx */ + 0xbf, 0x44, 0x44, 0x44, 0x44, /* movl $0x44444444,%edi */ + 0xcd, 0x2d, /* int $0x2d */ + 0xeb, /* jmp $+17 */ + 0x0f, 0x1f, 0x00, /* nop */ + 0x31, 0xc0, /* xorl %eax,%eax */ + 0xeb, 0x0c, /* jmp $+14 */ + 0x90, 0x90, 0x90, 0x90, /* nop */ + 0x90, 0x90, 0x90, 0x90, + 0x90, + 0x31, 0xc0, /* xorl %eax,%eax */ + 0x40, /* incl %eax */ + 0x5f, /* popl %edi */ + 0x5b, /* popl %ebx */ + 0xc3, /* ret */ +#elif defined(__x86_64__) + 0x53, /* push %rbx */ + 0x57, /* push %rdi */ + 0x48, 0x89, 0xc8, /* movl %rcx,%rax */ + 0x48, 0xb9, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, /* movabs $0x1111111111111111,%rcx */ + 0x48, 0xba, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* movabs $0x2222222222222222,%rdx */ + 0x48, 0xbb, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, /* movabs $0x3333333333333333,%rbx */ + 0x48, 0xbf, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, /* movabs $0x4444444444444444,%rdi */ + 0xcd, 0x2d, /* int $0x2d */ + 0xeb, /* jmp $+17 */ + 0x0f, 0x1f, 0x00, /* nop */ + 0x48, 0x31, 0xc0, /* xor %rax,%rax */ + 0xeb, 0x0e, /* jmp $+16 */ + 0x90, 0x90, 0x90, 0x90, /* nop */ + 0x90, 0x90, 0x90, 0x90, + 0x48, 0x31, 0xc0, /* xor %rax,%rax */ + 0x48, 0xff, 0xc0, /* inc %rax */ + 0x5f, /* pop %rdi */ + 0x5b, /* pop %rbx */ + 0xc3, /* ret */ +#endif +}; + +#if defined(__i386__) || defined(__x86_64__) +#define OP_BP 0xcc +#else +#define OP_BP 0 +#endif + +static void test_debugger(const char *argv0) +{ + static const char arguments[] = " debugger wait "; + SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, TRUE }; + struct debugger_context ctx = { 0 }; + PROCESS_INFORMATION pi; + STARTUPINFOA si; + NTSTATUS status; + HANDLE event, thread; + BYTE *mem, buf[4096], *proc_code, *thread_proc, byte; + unsigned int i, worker_cnt, exception_cnt, skip_reply_later; + struct debuggee_thread *debuggee_thread; + char *cmd; + BOOL ret; + + event = CreateEventW(&sa, FALSE, FALSE, NULL); + ok(event != NULL, "CreateEvent failed: %lu\n", GetLastError()); + + cmd = heap_alloc(strlen(argv0) + strlen(arguments) + 16); + sprintf(cmd, "%s%s%lx %u\n", argv0, arguments, (DWORD)(DWORD_PTR)event, OP_BP ? 3 : 1); + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + ret = CreateProcessA(NULL, cmd, NULL, NULL, TRUE, DEBUG_PROCESS, NULL, NULL, &si, &pi); + ok(ret, "CreateProcess failed, last error %#lx.\n", GetLastError()); + heap_free(cmd); + + next_event(&ctx, WAIT_EVENT_TIMEOUT); + ok(ctx.ev.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode); + + if ((skip_reply_later = !ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, DBG_REPLY_LATER))) + win_skip("Skipping unsupported DBG_REPLY_LATER tests\n"); + else + { + DEBUG_EVENT de; + + de = ctx.ev; + ctx.ev.dwDebugEventCode = -1; + next_event(&ctx, WAIT_EVENT_TIMEOUT); + ok(de.dwDebugEventCode == ctx.ev.dwDebugEventCode, + "dwDebugEventCode differs: %lx (was %lx)\n", ctx.ev.dwDebugEventCode, de.dwDebugEventCode); + ok(de.dwProcessId == ctx.ev.dwProcessId, + "dwProcessId differs: %lx (was %lx)\n", ctx.ev.dwProcessId, de.dwProcessId); + ok(de.dwThreadId == ctx.ev.dwThreadId, + "dwThreadId differs: %lx (was %lx)\n", ctx.ev.dwThreadId, de.dwThreadId); + + /* Suspending the thread should prevent other attach debug events + * to be received until it's resumed */ + thread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, ctx.ev.dwThreadId); + ok(thread != INVALID_HANDLE_VALUE, "OpenThread failed, last error:%lu\n", GetLastError()); + + status = NtSuspendThread(thread, NULL); + ok(!status, "NtSuspendThread failed, last error:%lu\n", GetLastError()); + + ret = ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, DBG_REPLY_LATER); + ok(ret, "ContinueDebugEvent failed, last error:%lu\n", GetLastError()); + ok(!WaitForDebugEvent(&ctx.ev, POLL_EVENT_TIMEOUT), "WaitForDebugEvent succeeded.\n"); + + status = NtResumeThread(thread, NULL); + ok(!status, "NtResumeThread failed, last error:%lu\n", GetLastError()); + + ret = CloseHandle(thread); + ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError()); + + ok(WaitForDebugEvent(&ctx.ev, POLL_EVENT_TIMEOUT), "WaitForDebugEvent failed.\n"); + ok(de.dwDebugEventCode == ctx.ev.dwDebugEventCode, + "dwDebugEventCode differs: %lx (was %lx)\n", ctx.ev.dwDebugEventCode, de.dwDebugEventCode); + + next_event(&ctx, WAIT_EVENT_TIMEOUT); + ok(ctx.ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode); + de = ctx.ev; + + ret = ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, DBG_REPLY_LATER); + ok(ret, "ContinueDebugEvent failed, last error:%lu\n", GetLastError()); + + ctx.ev.dwDebugEventCode = -1; + next_event(&ctx, WAIT_EVENT_TIMEOUT); + ok(de.dwDebugEventCode == ctx.ev.dwDebugEventCode, + "dwDebugEventCode differs: %lx (was %lx)\n", ctx.ev.dwDebugEventCode, de.dwDebugEventCode); + ok(de.dwProcessId == ctx.ev.dwProcessId, + "dwProcessId differs: %lx (was %lx)\n", ctx.ev.dwProcessId, de.dwProcessId); + ok(de.dwThreadId == ctx.ev.dwThreadId, + "dwThreadId differs: %lx (was %lx)\n", ctx.ev.dwThreadId, de.dwThreadId); + } + + wait_for_breakpoint(&ctx); + do next_event(&ctx, POLL_EVENT_TIMEOUT); + while(ctx.ev.dwDebugEventCode != -1); + + mem = VirtualAllocEx(pi.hProcess, NULL, sizeof(buf), MEM_COMMIT, PAGE_EXECUTE_READWRITE); + ok(mem != NULL, "VirtualAllocEx failed: %lu\n", GetLastError()); + proc_code = buf + 1024; + thread_proc = mem + 1024; + + if (sizeof(loop_code) > 1) + { + /* test single-step exceptions */ + memset(buf, OP_BP, sizeof(buf)); + memcpy(proc_code, &loop_code, sizeof(loop_code)); + proc_code[0] = OP_BP; /* set a breakpoint */ + ret = WriteProcessMemory(pi.hProcess, mem, buf, sizeof(buf), NULL); + ok(ret, "WriteProcessMemory failed: %lu\n", GetLastError()); + + thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void*)thread_proc, NULL, 0, NULL); + ok(thread != NULL, "CreateRemoteThread failed: %lu\n", GetLastError()); + + expect_event(&ctx, CREATE_THREAD_DEBUG_EVENT); + debuggee_thread = get_debuggee_thread(&ctx, ctx.ev.dwThreadId); + + wait_for_breakpoint(&ctx); + fetch_thread_context(debuggee_thread); + ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress == thread_proc, + "ExceptionAddress = %p\n", ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress); + ok(get_ip(&debuggee_thread->ctx) == thread_proc + 1, "unexpected instruction pointer %p\n", + get_ip(&debuggee_thread->ctx)); + + single_step(&ctx, debuggee_thread, thread_proc + 2); + single_step(&ctx, debuggee_thread, thread_proc + 3); + single_step(&ctx, debuggee_thread, thread_proc); + + byte = 0xc3; /* ret */ + ret = WriteProcessMemory(pi.hProcess, thread_proc, &byte, 1, NULL); + ok(ret, "WriteProcessMemory failed: %lu\n", GetLastError()); + + expect_event(&ctx, EXIT_THREAD_DEBUG_EVENT); + } + else todo_wine win_skip("loop_code not supported on this architecture\n"); + + if (sizeof(call_debug_service_code) > 1) + { + /* test debug service exceptions */ + memset(buf, OP_BP, sizeof(buf)); + memcpy(proc_code, call_debug_service_code, sizeof(call_debug_service_code)); + ret = WriteProcessMemory(pi.hProcess, mem, buf, sizeof(buf), NULL); + ok(ret, "WriteProcessMemory failed: %lu\n", GetLastError()); + + /* BREAKPOINT_PRINT */ +#ifndef __REACTOS__ // These tests don't pass on WS03-Win10 1607 + thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void*)thread_proc, (void*)2, 0, NULL); + ok(thread != NULL, "CreateRemoteThread failed: %lu\n", GetLastError()); + expect_event(&ctx, CREATE_THREAD_DEBUG_EVENT); + expect_breakpoint_exception(&ctx, NULL); + expect_event(&ctx, EXIT_THREAD_DEBUG_EVENT); +#endif + + /* BREAKPOINT_PROMPT */ + thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void*)thread_proc, (void*)1, 0, NULL); + ok(thread != NULL, "CreateRemoteThread failed: %lu\n", GetLastError()); + expect_event(&ctx, CREATE_THREAD_DEBUG_EVENT); + next_event(&ctx, WAIT_EVENT_TIMEOUT); + /* some 32-bit Windows versions report exception to the debugger */ + if (sizeof(void *) == 4 && ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) next_event(&ctx, WAIT_EVENT_TIMEOUT); +#if defined(__REACTOS__) && defined(_WIN64) + ok(ctx.ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT || broken(ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) /* Win8+ x64 */, "unexpected debug event %lu\n", ctx.ev.dwDebugEventCode); +#else + ok(ctx.ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT, "unexpected debug event %lu\n", ctx.ev.dwDebugEventCode); +#endif + } + else todo_wine win_skip("call_debug_service_code not supported on this architecture\n"); + + if (skip_reply_later) + win_skip("Skipping unsupported DBG_REPLY_LATER tests\n"); + else if (sizeof(loop_code) > 1) + { + HANDLE thread_a, thread_b; + DEBUG_EVENT de_a, de_b; + + memset(buf, OP_BP, sizeof(buf)); + memcpy(proc_code, &loop_code, sizeof(loop_code)); + ret = WriteProcessMemory(pi.hProcess, mem, buf, sizeof(buf), NULL); + ok(ret, "WriteProcessMemory failed: %lu\n", GetLastError()); + + byte = OP_BP; + ret = WriteProcessMemory(pi.hProcess, thread_proc + 1, &byte, 1, NULL); + ok(ret, "WriteProcessMemory failed: %lu\n", GetLastError()); + + thread_a = CreateRemoteThread(pi.hProcess, NULL, 0, (void*)thread_proc, NULL, 0, NULL); + ok(thread_a != NULL, "CreateRemoteThread failed: %lu\n", GetLastError()); + next_event(&ctx, WAIT_EVENT_TIMEOUT); + ok(ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode); + de_a = ctx.ev; + + thread_b = CreateRemoteThread(pi.hProcess, NULL, 0, (void*)thread_proc, NULL, 0, NULL); + ok(thread_b != NULL, "CreateRemoteThread failed: %lu\n", GetLastError()); + do next_event(&ctx, POLL_EVENT_TIMEOUT); + while(ctx.ev.dwDebugEventCode != CREATE_THREAD_DEBUG_EVENT); + de_b = ctx.ev; + + status = NtSuspendThread(thread_b, NULL); + ok(!status, "NtSuspendThread failed, last error:%lu\n", GetLastError()); + ret = ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, DBG_REPLY_LATER); + ok(ret, "ContinueDebugEvent failed, last error:%lu\n", GetLastError()); + + ctx.ev.dwDebugEventCode = -1; + next_event(&ctx, WAIT_EVENT_TIMEOUT); + ok(ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT, + "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode); + ok(de_a.dwProcessId == ctx.ev.dwProcessId, + "dwProcessId differs: %lx (was %lx)\n", ctx.ev.dwProcessId, de_a.dwProcessId); + ok(de_a.dwThreadId == ctx.ev.dwThreadId, + "dwThreadId differs: %lx (was %lx)\n", ctx.ev.dwThreadId, de_a.dwThreadId); + de_a = ctx.ev; + + byte = 0xc3; /* ret */ + ret = WriteProcessMemory(pi.hProcess, thread_proc + 1, &byte, 1, NULL); + ok(ret, "WriteProcessMemory failed: %lu\n", GetLastError()); + + ok(pNtSuspendProcess != NULL, "NtSuspendProcess not found\n"); + ok(pNtResumeProcess != NULL, "pNtResumeProcess not found\n"); + if (pNtSuspendProcess && pNtResumeProcess) + { + DWORD action = DBG_REPLY_LATER; + status = pNtSuspendProcess(pi.hProcess); + ok(!status, "NtSuspendProcess failed, last error:%lu\n", GetLastError()); + do + { + ret = ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, action); + ok(ret, "ContinueDebugEvent failed, last error:%lu\n", GetLastError()); + ret = WaitForDebugEvent(&ctx.ev, POLL_EVENT_TIMEOUT); + ok(!ret || ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT, "WaitForDebugEvent succeeded.\n"); + if (ret) add_thread(&ctx, ctx.ev.dwThreadId); + action = DBG_CONTINUE; + } while (ret); + + status = NtResumeThread(thread_b, NULL); + ok(!status, "NtResumeThread failed, last error:%lu\n", GetLastError()); + while (WaitForDebugEvent(&ctx.ev, POLL_EVENT_TIMEOUT)) + { + ok(ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT, "Unexpected debug event %lx\n", ctx.ev.dwDebugEventCode); + if (ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT) + { + add_thread(&ctx, ctx.ev.dwThreadId); + ret = ContinueDebugEvent(ctx.ev.dwProcessId, ctx.ev.dwThreadId, DBG_CONTINUE); + ok(ret, "ContinueDebugEvent failed, last error:%lu\n", GetLastError()); + } + } + + status = pNtResumeProcess(pi.hProcess); + ok(!status, "pNtResumeProcess failed, last error:%lu\n", GetLastError()); + } + else + { + status = NtResumeThread(thread_b, NULL); + ok(!status, "NtResumeThread failed, last error:%lu\n", GetLastError()); + ok(!WaitForDebugEvent(&ctx.ev, POLL_EVENT_TIMEOUT), "WaitForDebugEvent succeeded.\n"); + } + + /* Testing shows that on windows the debug event order between threads + * is not guaranteed. + * + * Now we expect thread_a to report: + * - its delayed EXCEPTION_DEBUG_EVENT + * - EXIT_THREAD_DEBUG_EVENT + * + * and thread_b to report: + * - its delayed CREATE_THREAD_DEBUG_EVENT + * - EXIT_THREAD_DEBUG_EVENT + * + * We should not get EXCEPTION_DEBUG_EVENT from thread_b as we updated + * its instructions before continuing CREATE_THREAD_DEBUG_EVENT. + */ + ctx.ev.dwDebugEventCode = -1; + next_event(&ctx, POLL_EVENT_TIMEOUT); + + if (ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) + { + ok(de_a.dwDebugEventCode == ctx.ev.dwDebugEventCode, + "dwDebugEventCode differs: %lx (was %lx)\n", ctx.ev.dwDebugEventCode, de_a.dwDebugEventCode); + ok(de_a.dwProcessId == ctx.ev.dwProcessId, + "dwProcessId differs: %lx (was %lx)\n", ctx.ev.dwProcessId, de_a.dwProcessId); + ok(de_a.dwThreadId == ctx.ev.dwThreadId, + "dwThreadId differs: %lx (was %lx)\n", ctx.ev.dwThreadId, de_a.dwThreadId); + + next_event(&ctx, POLL_EVENT_TIMEOUT); + if (ctx.ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT) + { + ok(de_a.dwProcessId == ctx.ev.dwProcessId, + "dwProcessId differs: %lx (was %lx)\n", ctx.ev.dwProcessId, de_a.dwProcessId); + ok(de_a.dwThreadId == ctx.ev.dwThreadId, + "dwThreadId differs: %lx (was %lx)\n", ctx.ev.dwThreadId, de_a.dwThreadId); + + ret = CloseHandle(thread_a); + ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError()); + thread_a = NULL; + + next_event(&ctx, POLL_EVENT_TIMEOUT); + } + + ok(de_b.dwDebugEventCode == ctx.ev.dwDebugEventCode, + "dwDebugEventCode differs: %lx (was %lx)\n", ctx.ev.dwDebugEventCode, de_b.dwDebugEventCode); + ok(de_b.dwProcessId == ctx.ev.dwProcessId, + "dwProcessId differs: %lx (was %lx)\n", ctx.ev.dwProcessId, de_b.dwProcessId); + ok(de_b.dwThreadId == ctx.ev.dwThreadId, + "dwThreadId differs: %lx (was %lx)\n", ctx.ev.dwThreadId, de_b.dwThreadId); + } + else + { + ok(de_b.dwDebugEventCode == ctx.ev.dwDebugEventCode, + "dwDebugEventCode differs: %lx (was %lx)\n", ctx.ev.dwDebugEventCode, de_b.dwDebugEventCode); + ok(de_b.dwProcessId == ctx.ev.dwProcessId, + "dwProcessId differs: %lx (was %lx)\n", ctx.ev.dwProcessId, de_b.dwProcessId); + ok(de_b.dwThreadId == ctx.ev.dwThreadId, + "dwThreadId differs: %lx (was %lx)\n", ctx.ev.dwThreadId, de_b.dwThreadId); + + next_event(&ctx, POLL_EVENT_TIMEOUT); + if (ctx.ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT) + { + ok(de_b.dwProcessId == ctx.ev.dwProcessId, + "dwProcessId differs: %lx (was %lx)\n", ctx.ev.dwProcessId, de_b.dwProcessId); + ok(de_b.dwThreadId == ctx.ev.dwThreadId, + "dwThreadId differs: %lx (was %lx)\n", ctx.ev.dwThreadId, de_b.dwThreadId); + + ret = CloseHandle(thread_b); + ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError()); + thread_b = NULL; + + next_event(&ctx, POLL_EVENT_TIMEOUT); + } + + ok(de_a.dwDebugEventCode == ctx.ev.dwDebugEventCode, + "dwDebugEventCode differs: %lx (was %lx)\n", ctx.ev.dwDebugEventCode, de_a.dwDebugEventCode); + ok(de_a.dwProcessId == ctx.ev.dwProcessId, + "dwProcessId differs: %lx (was %lx)\n", ctx.ev.dwProcessId, de_a.dwProcessId); + ok(de_a.dwThreadId == ctx.ev.dwThreadId, + "dwThreadId differs: %lx (was %lx)\n", ctx.ev.dwThreadId, de_a.dwThreadId); + } + + if (thread_a) + { + next_event(&ctx, POLL_EVENT_TIMEOUT); + ok(ctx.ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT, + "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode); + + ret = CloseHandle(thread_a); + ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError()); + } + + + if (thread_b) + { + next_event(&ctx, POLL_EVENT_TIMEOUT); + ok(ctx.ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT, + "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode); + + ret = CloseHandle(thread_b); + ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError()); + } + } + + if (sizeof(loop_code) > 1) + { + unsigned event_order = 0; + + memset(buf, OP_BP, sizeof(buf)); + memcpy(proc_code, &loop_code, sizeof(loop_code)); + ret = WriteProcessMemory(pi.hProcess, mem, buf, sizeof(buf), NULL); + ok(ret, "WriteProcessMemory failed: %lu\n", GetLastError()); + + ctx.thread_tag = 1; + + worker_cnt = 20; + for (i = 0; i < worker_cnt; i++) + { + DWORD tid; + thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void*)thread_proc, NULL, 0, &tid); + ok(thread != NULL, "CreateRemoteThread failed: %lu\n", GetLastError()); + + do + { + next_event(&ctx, WAIT_EVENT_TIMEOUT); +#if defined(__REACTOS__) && defined(_WIN64) + ok(ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT || broken(GetNTVersion() >= EXCEPTION_DEBUG_EVENT) /* Win8+ x64 */, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode); +#else + ok(ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode); +#endif + } while (ctx.ev.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT && ctx.ev.dwThreadId != tid); +#if defined(__REACTOS__) && defined(_WIN64) + ok(ctx.ev.u.CreateThread.lpStartAddress == (void*)thread_proc || broken(GetNTVersion() != _WIN32_WINNT_WIN7), "Unexpected thread's start address\n"); +#elif defined(__REACTOS__) + ok(ctx.ev.u.CreateThread.lpStartAddress == (void*)thread_proc || broken(GetNTVersion() <= _WIN32_WINNT_VISTA), "Unexpected thread's start address\n"); +#else + ok(ctx.ev.u.CreateThread.lpStartAddress == (void*)thread_proc, "Unexpected thread's start address\n"); +#endif + + ret = CloseHandle(thread); + ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError()); + } + + byte = OP_BP; + ret = WriteProcessMemory(pi.hProcess, thread_proc + 1, &byte, 1, NULL); + ok(ret, "WriteProcessMemory failed: %lu\n", GetLastError()); + + wait_for_breakpoint(&ctx); +#if defined(__REACTOS__) && defined(_WIN64) + if (GetNTVersion() < _WIN32_WINNT_WIN8) +#endif + check_breakpoint_exception(&ctx, thread_proc + 1); + exception_cnt = 1; + + byte = 0xc3; /* ret */ + ret = WriteProcessMemory(pi.hProcess, thread_proc + 1, &byte, 1, NULL); + ok(ret, "WriteProcessMemory failed: %lu\n", GetLastError()); + + /* One would expect that we get all exception debug events (for the worker threads + * that hit the BP instruction), then the exit thread events for all created threads. + * It happens that on Windows, the exception & exit thread events can be intertwined. + * So detect this situation. + */ +#if defined(__REACTOS__) && defined(_WIN64) + if (GetNTVersion() >= _WIN32_WINNT_WIN8 || is_reactos()) { + skip("These tests run far too long on Windows 8+ x64 and ReactOS x64.\n"); + } else { +#endif + for (;;) + { + DEBUG_EVENT ev; + + fetch_thread_context(ctx.current_thread); + ok(get_ip(&ctx.current_thread->ctx) == thread_proc + 2 + || broken(get_ip(&ctx.current_thread->ctx) == thread_proc), /* sometimes observed on win10 */ + "unexpected instruction pointer2 %p (%p)\n", get_ip(&ctx.current_thread->ctx), thread_proc); + /* even when there are more pending events, they are not reported until current event is continued */ + ret = WaitForDebugEvent(&ev, 10); + ok(GetLastError() == ERROR_SEM_TIMEOUT, "WaitForDebugEvent returned %x(%lu)\n", ret, GetLastError()); + + for (;;) + { + next_event_filter(&ctx, POLL_EVENT_TIMEOUT, event_mask(CREATE_THREAD_DEBUG_EVENT)); + if (ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) break; + if (ctx.ev.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT) + { + if (event_order == 0) event_order = 1; /* first exit thread event */ + if (!--worker_cnt) break; + } + } + if (!worker_cnt) break; + + ok(ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode); + trace("exception at %p in thread %04lx\n", ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress, ctx.ev.dwThreadId); + ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "ExceptionCode = %lx\n", + ctx.ev.u.Exception.ExceptionRecord.ExceptionCode); + ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress == thread_proc + 1, + "ExceptionAddress = %p\n", ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress); + exception_cnt++; + if (event_order == 1) event_order = 2; /* exception debug event after exit thread event */ + } + + trace("received %u exceptions\n", exception_cnt); + ok(!worker_cnt, "Missing %u exit thread events\n", worker_cnt); + ok(event_order == 1 || broken(event_order == 2), "Intertwined exit thread & exception debug events\n"); + } +#if defined(__REACTOS__) && defined(_WIN64) + } +#endif + + if (OP_BP) + { + CONTEXT orig_context; + char instr, *ip; + + /* main thread sleeps inside ntdll waiting for the event. set breakpoint there and make sure + * ntdll can handle that. */ + SuspendThread(ctx.main_thread->handle); + + fetch_thread_context(ctx.main_thread); + ret = ReadProcessMemory(pi.hProcess, get_ip(&ctx.main_thread->ctx), &instr, 1, NULL); + ok(ret, "ReadProcessMemory failed: %lu\n", GetLastError()); + + orig_context = ctx.main_thread->ctx; + ip = get_ip(&ctx.main_thread->ctx); + +#if defined(__i386__) + ctx.main_thread->ctx.Eax = 101; + ctx.main_thread->ctx.Ebx = 102; + ctx.main_thread->ctx.Ecx = 103; + ctx.main_thread->ctx.Edx = 104; + ctx.main_thread->ctx.Esi = 105; + ctx.main_thread->ctx.Edi = 106; +#elif defined(__x86_64__) + ctx.main_thread->ctx.Rax = 101; + ctx.main_thread->ctx.Rbx = 102; + ctx.main_thread->ctx.Rcx = 103; + ctx.main_thread->ctx.Rdx = 104; + ctx.main_thread->ctx.Rsi = 105; + ctx.main_thread->ctx.Rdi = 106; + ctx.main_thread->ctx.R8 = 107; + ctx.main_thread->ctx.R9 = 108; + ctx.main_thread->ctx.R10 = 109; + ctx.main_thread->ctx.R11 = 110; + ctx.main_thread->ctx.R12 = 111; + ctx.main_thread->ctx.R13 = 112; + ctx.main_thread->ctx.R14 = 113; + ctx.main_thread->ctx.R15 = 114; +#endif + set_thread_context(&ctx, ctx.main_thread); + + fetch_thread_context(ctx.main_thread); +#if defined(__i386__) + /* win2k8 do not preserve eax, rcx and edx; newer versions do */ + ok(ctx.main_thread->ctx.Ebx == 102, "Ebx = %lx\n", ctx.main_thread->ctx.Ebx); + ok(ctx.main_thread->ctx.Esi == 105, "Esi = %lx\n", ctx.main_thread->ctx.Esi); + ok(ctx.main_thread->ctx.Edi == 106, "Edi = %lx\n", ctx.main_thread->ctx.Edi); +#elif defined(__x86_64__) + ok(ctx.main_thread->ctx.Rax == 101, "Rax = %I64x\n", ctx.main_thread->ctx.Rax); + ok(ctx.main_thread->ctx.Rbx == 102, "Rbx = %I64x\n", ctx.main_thread->ctx.Rbx); + ok(ctx.main_thread->ctx.Rcx == 103, "Rcx = %I64x\n", ctx.main_thread->ctx.Rcx); + ok(ctx.main_thread->ctx.Rdx == 104, "Rdx = %I64x\n", ctx.main_thread->ctx.Rdx); + ok(ctx.main_thread->ctx.Rsi == 105, "Rsi = %I64x\n", ctx.main_thread->ctx.Rsi); + ok(ctx.main_thread->ctx.Rdi == 106, "Rdi = %I64x\n", ctx.main_thread->ctx.Rdi); + ok(ctx.main_thread->ctx.R8 == 107, "R8 = %I64x\n", ctx.main_thread->ctx.R8); + ok(ctx.main_thread->ctx.R9 == 108, "R9 = %I64x\n", ctx.main_thread->ctx.R9); + ok(ctx.main_thread->ctx.R10 == 109, "R10 = %I64x\n", ctx.main_thread->ctx.R10); + ok(ctx.main_thread->ctx.R11 == 110, "R11 = %I64x\n", ctx.main_thread->ctx.R11); + ok(ctx.main_thread->ctx.R12 == 111, "R12 = %I64x\n", ctx.main_thread->ctx.R12); + ok(ctx.main_thread->ctx.R13 == 112, "R13 = %I64x\n", ctx.main_thread->ctx.R13); + ok(ctx.main_thread->ctx.R14 == 113, "R14 = %I64x\n", ctx.main_thread->ctx.R14); + ok(ctx.main_thread->ctx.R15 == 114, "R15 = %I64x\n", ctx.main_thread->ctx.R15); +#endif + + byte = OP_BP; + ret = WriteProcessMemory(pi.hProcess, ip, &byte, 1, NULL); + ok(ret, "WriteProcessMemory failed: %lu\n", GetLastError()); + + SetEvent(event); + ResumeThread(ctx.main_thread->handle); + + next_event_filter(&ctx, 2000, event_mask(CREATE_THREAD_DEBUG_EVENT)); + ok(ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode); + ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "ExceptionCode = %lx\n", + ctx.ev.u.Exception.ExceptionRecord.ExceptionCode); + ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress == ip, + "ExceptionAddress = %p\n", ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress); + + fetch_thread_context(ctx.main_thread); + ok(get_ip(&ctx.main_thread->ctx) == ip + 1, "unexpected instruction pointer %p\n", get_ip(&ctx.main_thread->ctx)); + +#if defined(__i386__) + ok(ctx.main_thread->ctx.Eax == 0, "Eax = %lx\n", ctx.main_thread->ctx.Eax); + ok(ctx.main_thread->ctx.Ebx == 102, "Ebx = %lx\n", ctx.main_thread->ctx.Ebx); + ok(ctx.main_thread->ctx.Ecx != 103, "Ecx = %lx\n", ctx.main_thread->ctx.Ecx); + ok(ctx.main_thread->ctx.Edx != 104, "Edx = %lx\n", ctx.main_thread->ctx.Edx); + ok(ctx.main_thread->ctx.Esi == 105, "Esi = %lx\n", ctx.main_thread->ctx.Esi); + ok(ctx.main_thread->ctx.Edi == 106, "Edi = %lx\n", ctx.main_thread->ctx.Edi); +#elif defined(__x86_64__) + ok(ctx.main_thread->ctx.Rax == 0, "Rax = %I64x\n", ctx.main_thread->ctx.Rax); + ok(ctx.main_thread->ctx.Rbx == 102, "Rbx = %I64x\n", ctx.main_thread->ctx.Rbx); + ok(ctx.main_thread->ctx.Rcx != 103, "Rcx = %I64x\n", ctx.main_thread->ctx.Rcx); + ok(ctx.main_thread->ctx.Rdx != 104, "Rdx = %I64x\n", ctx.main_thread->ctx.Rdx); + ok(ctx.main_thread->ctx.Rsi == 105, "Rsi = %I64x\n", ctx.main_thread->ctx.Rsi); + ok(ctx.main_thread->ctx.Rdi == 106, "Rdi = %I64x\n", ctx.main_thread->ctx.Rdi); + ok(ctx.main_thread->ctx.R8 != 107, "R8 = %I64x\n", ctx.main_thread->ctx.R8); + ok(ctx.main_thread->ctx.R9 != 108, "R9 = %I64x\n", ctx.main_thread->ctx.R9); + ok(ctx.main_thread->ctx.R10 != 109, "R10 = %I64x\n", ctx.main_thread->ctx.R10); + ok(ctx.main_thread->ctx.R11 != 110, "R11 = %I64x\n", ctx.main_thread->ctx.R11); + ok(ctx.main_thread->ctx.R12 == 111, "R12 = %I64x\n", ctx.main_thread->ctx.R12); + ok(ctx.main_thread->ctx.R13 == 112, "R13 = %I64x\n", ctx.main_thread->ctx.R13); + ok(ctx.main_thread->ctx.R14 == 113, "R14 = %I64x\n", ctx.main_thread->ctx.R14); + ok(ctx.main_thread->ctx.R15 == 114, "R15 = %I64x\n", ctx.main_thread->ctx.R15); +#endif + + ctx.main_thread->ctx = orig_context; + set_ip(&ctx.main_thread->ctx, ip); + set_thread_context(&ctx, ctx.main_thread); + + ret = WriteProcessMemory(pi.hProcess, ip, &instr, 1, NULL); + ok(ret, "WriteProcessMemory failed: %lu\n", GetLastError()); + + memset(buf + 10, 0x90, 10); /* nop */ + ret = WriteProcessMemory(pi.hProcess, mem + 10, buf + 10, 10, NULL); + ok(ret, "WriteProcessMemory failed: %lu\n", GetLastError()); + + next_event(&ctx, POLL_EVENT_TIMEOUT); + + /* try single step while debuggee is in a syscall */ + fetch_thread_context(ctx.main_thread); + orig_context = ctx.main_thread->ctx; + ip = get_ip(&ctx.main_thread->ctx); + +#if defined(__i386__) + ctx.main_thread->ctx.EFlags |= 0x100; + ctx.main_thread->ctx.Eip = (ULONG_PTR)mem + 10; +#elif defined(__x86_64__) + ctx.main_thread->ctx.EFlags |= 0x100; + ctx.main_thread->ctx.Rip = (ULONG64)mem + 10; +#endif + set_thread_context(&ctx, ctx.main_thread); + + SetEvent(event); + + next_event(&ctx, WAIT_EVENT_TIMEOUT); + if (sizeof(void*) != 4 || ctx.ev.u.Exception.ExceptionRecord.ExceptionCode != EXCEPTION_BREAKPOINT) + { + ok(ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT, "dwDebugEventCode = %ld\n", ctx.ev.dwDebugEventCode); + ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP, "ExceptionCode = %lx\n", + ctx.ev.u.Exception.ExceptionRecord.ExceptionCode); + ok(ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress == mem + 10 || + ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress == mem + 11, + "ExceptionAddress = %p expected %p\n", ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress, mem + 10); + + fetch_thread_context(ctx.main_thread); + ok(get_ip(&ctx.main_thread->ctx) == ctx.ev.u.Exception.ExceptionRecord.ExceptionAddress, + "ip = %p\n", get_ip(&ctx.main_thread->ctx)); + + } + else win_skip("got breakpoint instead of single step exception\n"); + + ctx.main_thread->ctx = orig_context; + set_thread_context(&ctx, ctx.main_thread); + } + + SetEvent(event); + +#if defined(__REACTOS__) && defined(_MSC_VER) + if (is_reactos()) { + skip("This test doesn't work correctly on MSVC ReactOS.\n"); + } else { +#endif + do + { + next_event(&ctx, WAIT_EVENT_TIMEOUT); + ok (ctx.ev.dwDebugEventCode != EXCEPTION_DEBUG_EVENT, "got exception\n"); + if (ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) break; + } + while (ctx.ev.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT); + if (ctx.ev.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT) TerminateProcess(pi.hProcess, 0); +#if defined(__REACTOS__) && defined(_MSC_VER) + } +#endif + + ret = CloseHandle(event); + ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError()); + ret = CloseHandle(pi.hThread); + ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError()); + ret = CloseHandle(pi.hProcess); + ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError()); +} + +static DWORD run_child_wait( char *cmd, HANDLE event ) +{ + PROCESS_INFORMATION pi; + STARTUPINFOA si = { sizeof(si) }; + BOOL ret; + DWORD exit_code; + + ret = CreateProcessA(NULL, cmd, NULL, NULL, TRUE, DEBUG_PROCESS, NULL, NULL, &si, &pi); + ok(ret, "CreateProcess failed, last error %#lx.\n", GetLastError()); + Sleep(200); + CloseHandle( pDbgUiGetThreadDebugObject() ); + pDbgUiSetThreadDebugObject( 0 ); + SetEvent( event ); + WaitForSingleObject( pi.hProcess, 1000 ); + ret = GetExitCodeProcess( pi.hProcess, &exit_code ); + ok( ret, "GetExitCodeProcess failed err=%ld\n", GetLastError()); + CloseHandle( pi.hProcess ); + CloseHandle( pi.hThread ); + return exit_code; +} + +static PROCESS_INFORMATION pi; +static char *cmd; + +static DWORD WINAPI debug_and_exit(void *arg) +{ + STARTUPINFOA si = { sizeof(si) }; + HANDLE debug; + ULONG val = 0; + NTSTATUS status; + BOOL ret; + + ret = CreateProcessA(NULL, cmd, NULL, NULL, TRUE, DEBUG_PROCESS, NULL, NULL, &si, &pi); + ok(ret, "CreateProcess failed, last error %#lx.\n", GetLastError()); + debug = pDbgUiGetThreadDebugObject(); + status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation, + &val, sizeof(val), NULL ); + ok( !status, "NtSetInformationDebugObject failed %lx\n", status ); + *(HANDLE *)arg = debug; + Sleep(200); + ExitThread(0); +} + +static DWORD WINAPI debug_and_wait(void *arg) +{ + STARTUPINFOA si = { sizeof(si) }; + HANDLE debug = *(HANDLE *)arg; + ULONG val = 0; + NTSTATUS status; + BOOL ret; + + pDbgUiSetThreadDebugObject( debug ); + ret = CreateProcessA(NULL, cmd, NULL, NULL, TRUE, DEBUG_PROCESS, NULL, NULL, &si, &pi); + ok(ret, "CreateProcess failed, last error %#lx.\n", GetLastError()); + debug = pDbgUiGetThreadDebugObject(); + status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation, + &val, sizeof(val), NULL ); + ok( !status, "NtSetInformationDebugObject failed %lx\n", status ); + Sleep(INFINITE); + ExitThread(0); +} + +static DWORD WINAPI create_debug_port(void *arg) +{ + STARTUPINFOA si = { sizeof(si) }; + NTSTATUS status = pDbgUiConnectToDbg(); + + ok( !status, "DbgUiConnectToDbg failed %lx\n", status ); + *(HANDLE *)arg = pDbgUiGetThreadDebugObject(); + Sleep( INFINITE ); + ExitThread(0); +} + +static void test_kill_on_exit(const char *argv0) +{ + static const char arguments[] = " debugger wait "; + SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, TRUE }; + OBJECT_ATTRIBUTES attr = { sizeof(attr) }; + NTSTATUS status; + HANDLE event, debug, thread; + DWORD exit_code, tid; + ULONG val; + BOOL ret; + + event = CreateEventW(&sa, FALSE, FALSE, NULL); + ok(event != NULL, "CreateEvent failed: %lu\n", GetLastError()); + + cmd = heap_alloc(strlen(argv0) + strlen(arguments) + 16); + sprintf(cmd, "%s%s%lx\n", argv0, arguments, (DWORD)(DWORD_PTR)event); + + status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, 0 ); + ok( !status, "NtCreateDebugObject failed %lx\n", status ); + pDbgUiSetThreadDebugObject( debug ); + exit_code = run_child_wait( cmd, event ); + ok( exit_code == 0, "exit code = %08lx\n", exit_code); + + status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, DEBUG_KILL_ON_CLOSE ); + ok( !status, "NtCreateDebugObject failed %lx\n", status ); + pDbgUiSetThreadDebugObject( debug ); + exit_code = run_child_wait( cmd, event ); + ok( exit_code == STATUS_DEBUGGER_INACTIVE, "exit code = %08lx\n", exit_code); + + status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, 0xfffe ); + ok( status == STATUS_INVALID_PARAMETER, "NtCreateDebugObject failed %lx\n", status ); + + status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, 0 ); + ok( !status, "NtCreateDebugObject failed %lx\n", status ); + pDbgUiSetThreadDebugObject( debug ); + val = DEBUG_KILL_ON_CLOSE; + status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation, + &val, sizeof(val), NULL ); + ok( !status, "NtSetInformationDebugObject failed %lx\n", status ); + exit_code = run_child_wait( cmd, event ); + ok( exit_code == STATUS_DEBUGGER_INACTIVE, "exit code = %08lx\n", exit_code); + + status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, DEBUG_KILL_ON_CLOSE ); + ok( !status, "NtCreateDebugObject failed %lx\n", status ); + pDbgUiSetThreadDebugObject( debug ); + val = 0; + status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation, + &val, sizeof(val), NULL ); + ok( !status, "NtSetInformationDebugObject failed %lx\n", status ); + exit_code = run_child_wait( cmd, event ); + ok( exit_code == 0, "exit code = %08lx\n", exit_code); + + status = pDbgUiConnectToDbg(); + ok( !status, "DbgUiConnectToDbg failed %lx\n", status ); + exit_code = run_child_wait( cmd, event ); + ok( exit_code == STATUS_DEBUGGER_INACTIVE, "exit code = %08lx\n", exit_code); + + /* test that threads close the debug port on exit */ + thread = CreateThread(NULL, 0, debug_and_exit, &debug, 0, &tid); + WaitForSingleObject( thread, 1000 ); + ok( debug != 0, "no debug port\n" ); + val = 0; + status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation, + &val, sizeof(val), NULL ); + ok( status == STATUS_INVALID_HANDLE || broken(status == STATUS_SUCCESS), /* wow64 */ + "NtSetInformationDebugObject failed %lx\n", status ); + SetEvent( event ); + if (!status) + { + WaitForSingleObject( pi.hProcess, 100 ); + GetExitCodeProcess( pi.hProcess, &exit_code ); + ok( exit_code == STILL_ACTIVE, "exit code = %08lx\n", exit_code); + CloseHandle( debug ); + } + WaitForSingleObject( pi.hProcess, 1000 ); + GetExitCodeProcess( pi.hProcess, &exit_code ); + ok( exit_code == 0, "exit code = %08lx\n", exit_code); + CloseHandle( pi.hProcess ); + CloseHandle( pi.hThread ); + CloseHandle( thread ); + + /* checking on forced exit */ + status = pNtCreateDebugObject( &debug, DEBUG_ALL_ACCESS, &attr, DEBUG_KILL_ON_CLOSE ); + ok( !status, "NtCreateDebugObject failed %lx\n", status ); + thread = CreateThread(NULL, 0, debug_and_wait, &debug, 0, &tid); + Sleep( 100 ); + ok( debug != 0, "no debug port\n" ); + val = DEBUG_KILL_ON_CLOSE; + status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation, + &val, sizeof(val), NULL ); + ok( status == STATUS_SUCCESS, "NtSetInformationDebugObject failed %lx\n", status ); + TerminateThread( thread, 0 ); + + status = WaitForSingleObject( pi.hProcess, 1500 ); + if (status != WAIT_OBJECT_0) + { + todo_wine /* Wine doesn't handle debug port of TerminateThread */ + ok(broken(sizeof(void*) == sizeof(int)), /* happens consistently on 32bit on Win7, 10 & 11 */ + "Terminating thread should terminate debuggee\n"); + + ret = TerminateProcess( pi.hProcess, 0 ); + ok(ret, "TerminateProcess failed: %lu\n", GetLastError()); + CloseHandle( debug ); + } + else + { + ok(status == WAIT_OBJECT_0, "debuggee didn't terminate %lx\n", status); + ret = GetExitCodeProcess( pi.hProcess, &exit_code ); + ok(ret, "No exit code: %lu\n", GetLastError()); + todo_wine + ok( exit_code == STATUS_DEBUGGER_INACTIVE || broken(exit_code == STILL_ACTIVE), /* wow64 */ + "exit code = %08lx\n", exit_code); + status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation, + &val, sizeof(val), NULL ); + todo_wine + ok( status == STATUS_INVALID_HANDLE, "NtSetInformationDebugObject failed %lx\n", status ); + } + + CloseHandle( pi.hProcess ); + CloseHandle( pi.hThread ); + CloseHandle( thread ); + + debug = 0; + thread = CreateThread(NULL, 0, create_debug_port, &debug, 0, &tid); + Sleep(100); + ok( debug != 0, "no debug port\n" ); + val = 0; + status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation, + &val, sizeof(val), NULL ); + ok( status == STATUS_SUCCESS, "NtSetInformationDebugObject failed %lx\n", status ); + TerminateThread( thread, 0 ); + Sleep( 200 ); + status = pNtSetInformationDebugObject( debug, DebugObjectKillProcessOnExitInformation, + &val, sizeof(val), NULL ); + todo_wine + ok( status == STATUS_INVALID_HANDLE || broken( status == STATUS_SUCCESS ), + "NtSetInformationDebugObject failed %lx\n", status ); + if (status != STATUS_INVALID_HANDLE) CloseHandle( debug ); + CloseHandle( thread ); + + CloseHandle( event ); + heap_free(cmd); } START_TEST(debugger) @@ -808,14 +2495,31 @@ START_TEST(debugger) hdll=GetModuleHandleA("kernel32.dll"); pCheckRemoteDebuggerPresent=(void*)GetProcAddress(hdll, "CheckRemoteDebuggerPresent"); - pDebugActiveProcessStop=(void*)GetProcAddress(hdll, "DebugActiveProcessStop"); - pDebugSetProcessKillOnExit=(void*)GetProcAddress(hdll, "DebugSetProcessKillOnExit"); - pIsDebuggerPresent=(void*)GetProcAddress(hdll, "IsDebuggerPresent"); + pIsWow64Process=(void*)GetProcAddress(hdll, "IsWow64Process"); + pGetMappedFileNameW = (void*)GetProcAddress(hdll, "GetMappedFileNameW"); + if (!pGetMappedFileNameW) pGetMappedFileNameW = (void*)GetProcAddress(LoadLibraryA("psapi.dll"), + "GetMappedFileNameW"); + ntdll = GetModuleHandleA("ntdll.dll"); + pDbgBreakPoint = (void*)GetProcAddress(ntdll, "DbgBreakPoint"); + pNtSuspendProcess = (void*)GetProcAddress(ntdll, "NtSuspendProcess"); + pNtResumeProcess = (void*)GetProcAddress(ntdll, "NtResumeProcess"); + pNtCreateDebugObject = (void*)GetProcAddress(ntdll, "NtCreateDebugObject"); + pNtSetInformationDebugObject = (void*)GetProcAddress(ntdll, "NtSetInformationDebugObject"); + pDbgUiConnectToDbg = (void*)GetProcAddress(ntdll, "DbgUiConnectToDbg"); + pDbgUiGetThreadDebugObject = (void*)GetProcAddress(ntdll, "DbgUiGetThreadDebugObject"); + pDbgUiSetThreadDebugObject = (void*)GetProcAddress(ntdll, "DbgUiSetThreadDebugObject"); + +#ifdef __arm__ + /* mask thumb bit for address comparisons */ + pDbgBreakPoint = (void *)((ULONG_PTR)pDbgBreakPoint & ~1); +#endif + + if (pIsWow64Process) pIsWow64Process( GetCurrentProcess(), &is_wow64 ); myARGC=winetest_get_mainargs(&myARGV); if (myARGC >= 3 && strcmp(myARGV[2], "crash") == 0) { - doCrash(myARGC, myARGV); + doCrash(); } else if (myARGC >= 3 && strncmp(myARGV[2], "dbg,", 4) == 0) { @@ -829,14 +2533,26 @@ START_TEST(debugger) { doChildren(myARGC, myARGV); } + else if (myARGC >= 4 && !strcmp(myARGV[2], "wait")) + { + DWORD event, cnt = 1; + sscanf(myARGV[3], "%lx", &event); + if (myARGC >= 5) cnt = atoi(myARGV[4]); + wait_debugger((HANDLE)(DWORD_PTR)event, cnt); + } else { test_ExitCode(); test_RemoteDebugger(); test_debug_loop(myARGC, myARGV); - test_debug_children(myARGV[0], DEBUG_PROCESS, TRUE); - test_debug_children(myARGV[0], DEBUG_ONLY_THIS_PROCESS, FALSE); - test_debug_children(myARGV[0], DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS, FALSE); - test_debug_children(myARGV[0], 0, FALSE); + test_debug_loop_wow64(); + test_debug_children(myARGV[0], DEBUG_PROCESS, TRUE, FALSE); + test_debug_children(myARGV[0], DEBUG_ONLY_THIS_PROCESS, FALSE, FALSE); + test_debug_children(myARGV[0], DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS, FALSE, FALSE); + test_debug_children(myARGV[0], 0, FALSE, FALSE); + test_debug_children(myARGV[0], 0, FALSE, TRUE); + test_debug_children(myARGV[0], DEBUG_ONLY_THIS_PROCESS, FALSE, TRUE); + test_debugger(myARGV[0]); + test_kill_on_exit(myARGV[0]); } } diff --git a/modules/rostests/winetests/kernel32/directory.c b/modules/rostests/winetests/kernel32/directory.c index 512dc6d22ad..d9f6ee4c9a5 100644 --- a/modules/rostests/winetests/kernel32/directory.c +++ b/modules/rostests/winetests/kernel32/directory.c @@ -42,9 +42,9 @@ static void test_granted_access(HANDLE handle, ACCESS_MASK access, int line) status = pNtQueryObject(handle, ObjectBasicInformation, &obj_info, sizeof(obj_info), NULL); - ok_(__FILE__, line)(!status, "NtQueryObject with err: %08x\n", status); + ok_(__FILE__, line)(!status, "NtQueryObject with err: %08lx\n", status); ok_(__FILE__, line)(obj_info.GrantedAccess == access, "Granted access should " - "be 0x%08x, instead of 0x%08x\n", access, obj_info.GrantedAccess); + "be 0x%08lx, instead of 0x%08lx\n", access, obj_info.GrantedAccess); } /* If you change something in these tests, please do the same @@ -185,12 +185,12 @@ static void test_CreateDirectoryA(void) ret = CreateDirectoryA(NULL, NULL); ok(ret == FALSE && (GetLastError() == ERROR_PATH_NOT_FOUND || GetLastError() == ERROR_INVALID_PARAMETER), - "CreateDirectoryA(NULL): ret=%d err=%d\n", ret, GetLastError()); + "CreateDirectoryA(NULL): ret=%d err=%ld\n", ret, GetLastError()); ret = CreateDirectoryA("", NULL); ok(ret == FALSE && (GetLastError() == ERROR_BAD_PATHNAME || GetLastError() == ERROR_PATH_NOT_FOUND), - "CreateDirectoryA(%s): ret=%d err=%d\n", tmpdir, ret, GetLastError()); + "CreateDirectoryA(%s): ret=%d err=%ld\n", tmpdir, ret, GetLastError()); ret = GetSystemDirectoryA(tmpdir, MAX_PATH); ok(ret < MAX_PATH, "System directory should fit into MAX_PATH\n"); @@ -201,53 +201,53 @@ static void test_CreateDirectoryA(void) ret = CreateDirectoryA(".", NULL); ok(ret == FALSE && GetLastError() == ERROR_ALREADY_EXISTS, - "CreateDirectoryA(%s): ret=%d err=%d\n", tmpdir, ret, GetLastError()); + "CreateDirectoryA(%s): ret=%d err=%ld\n", tmpdir, ret, GetLastError()); ret = CreateDirectoryA("..", NULL); ok(ret == FALSE && GetLastError() == ERROR_ALREADY_EXISTS, - "CreateDirectoryA(%s): ret=%d err=%d\n", tmpdir, ret, GetLastError()); + "CreateDirectoryA(%s): ret=%d err=%ld\n", tmpdir, ret, GetLastError()); GetTempPathA(MAX_PATH, tmpdir); tmpdir[3] = 0; /* truncate the path */ ret = CreateDirectoryA(tmpdir, NULL); ok(ret == FALSE && (GetLastError() == ERROR_ALREADY_EXISTS || GetLastError() == ERROR_ACCESS_DENIED), - "CreateDirectoryA(%s): ret=%d err=%d\n", tmpdir, ret, GetLastError()); + "CreateDirectoryA(%s): ret=%d err=%ld\n", tmpdir, ret, GetLastError()); GetTempPathA(MAX_PATH, tmpdir); lstrcatA(tmpdir, "Please Remove Me"); ret = CreateDirectoryA(tmpdir, NULL); - ok(ret == TRUE, "CreateDirectoryA(%s) failed err=%d\n", tmpdir, GetLastError()); + ok(ret == TRUE, "CreateDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError()); ret = CreateDirectoryA(tmpdir, NULL); ok(ret == FALSE && GetLastError() == ERROR_ALREADY_EXISTS, - "CreateDirectoryA(%s): ret=%d err=%d\n", tmpdir, ret, GetLastError()); + "CreateDirectoryA(%s): ret=%d err=%ld\n", tmpdir, ret, GetLastError()); ret = RemoveDirectoryA(tmpdir); ok(ret == TRUE, - "RemoveDirectoryA(%s) failed err=%d\n", tmpdir, GetLastError()); + "RemoveDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError()); lstrcatA(tmpdir, "?"); ret = CreateDirectoryA(tmpdir, NULL); ok(ret == FALSE && (GetLastError() == ERROR_INVALID_NAME || GetLastError() == ERROR_PATH_NOT_FOUND), - "CreateDirectoryA(%s): ret=%d err=%d\n", tmpdir, ret, GetLastError()); + "CreateDirectoryA(%s): ret=%d err=%ld\n", tmpdir, ret, GetLastError()); RemoveDirectoryA(tmpdir); tmpdir[lstrlenA(tmpdir) - 1] = '*'; ret = CreateDirectoryA(tmpdir, NULL); ok(ret == FALSE && (GetLastError() == ERROR_INVALID_NAME || GetLastError() == ERROR_PATH_NOT_FOUND), - "CreateDirectoryA(%s): ret=%d err=%d\n", tmpdir, ret, GetLastError()); + "CreateDirectoryA(%s): ret=%d err=%ld\n", tmpdir, ret, GetLastError()); RemoveDirectoryA(tmpdir); GetTempPathA(MAX_PATH, tmpdir); lstrcatA(tmpdir, "Please Remove Me/Please Remove Me"); ret = CreateDirectoryA(tmpdir, NULL); ok(ret == FALSE && GetLastError() == ERROR_PATH_NOT_FOUND, - "CreateDirectoryA(%s): ret=%d err=%d\n", tmpdir, ret, GetLastError()); + "CreateDirectoryA(%s): ret=%d err=%ld\n", tmpdir, ret, GetLastError()); RemoveDirectoryA(tmpdir); /* Test behavior with a trailing dot. @@ -257,21 +257,21 @@ static void test_CreateDirectoryA(void) lstrcatA(tmpdir, "Please Remove Me."); ret = CreateDirectoryA(tmpdir, NULL); ok(ret == TRUE, - "CreateDirectoryA(%s) failed err=%d\n", tmpdir, GetLastError()); + "CreateDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError()); lstrcatA(tmpdir, "/Please Remove Me"); ret = CreateDirectoryA(tmpdir, NULL); ok(ret == TRUE, - "CreateDirectoryA(%s) failed err=%d\n", tmpdir, GetLastError()); + "CreateDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError()); ret = RemoveDirectoryA(tmpdir); ok(ret == TRUE, - "RemoveDirectoryA(%s) failed err=%d\n", tmpdir, GetLastError()); + "RemoveDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError()); GetTempPathA(MAX_PATH, tmpdir); lstrcatA(tmpdir, "Please Remove Me"); ret = RemoveDirectoryA(tmpdir); ok(ret == TRUE, - "RemoveDirectoryA(%s) failed err=%d\n", tmpdir, GetLastError()); + "RemoveDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError()); /* Test behavior with two trailing dots. * The directory should be created without the trailing dots. @@ -280,25 +280,25 @@ static void test_CreateDirectoryA(void) lstrcatA(tmpdir, "Please Remove Me.."); ret = CreateDirectoryA(tmpdir, NULL); ok(ret == TRUE, - "CreateDirectoryA(%s) failed err=%d\n", tmpdir, GetLastError()); + "CreateDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError()); lstrcatA(tmpdir, "/Please Remove Me"); ret = CreateDirectoryA(tmpdir, NULL); ok(ret == TRUE || /* On Win98 */ (ret == FALSE && GetLastError() == ERROR_PATH_NOT_FOUND), /* On NT! */ - "CreateDirectoryA(%s): ret=%d err=%d\n", tmpdir, ret, GetLastError()); + "CreateDirectoryA(%s): ret=%d err=%ld\n", tmpdir, ret, GetLastError()); if (ret == TRUE) { ret = RemoveDirectoryA(tmpdir); ok(ret == TRUE, - "RemoveDirectoryA(%s) failed err=%d\n", tmpdir, GetLastError()); + "RemoveDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError()); } GetTempPathA(MAX_PATH, tmpdir); lstrcatA(tmpdir, "Please Remove Me"); ret = RemoveDirectoryA(tmpdir); ok(ret == TRUE, - "RemoveDirectoryA(%s) failed err=%d\n", tmpdir, GetLastError()); + "RemoveDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError()); /* Test behavior with a trailing space. * The directory should be created without the trailing space. @@ -307,25 +307,25 @@ static void test_CreateDirectoryA(void) lstrcatA(tmpdir, "Please Remove Me "); ret = CreateDirectoryA(tmpdir, NULL); ok(ret == TRUE, - "CreateDirectoryA(%s) failed err=%d\n", tmpdir, GetLastError()); + "CreateDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError()); lstrcatA(tmpdir, "/Please Remove Me"); ret = CreateDirectoryA(tmpdir, NULL); ok(ret == TRUE || /* On Win98 */ (ret == FALSE && GetLastError() == ERROR_PATH_NOT_FOUND), /* On NT! */ - "CreateDirectoryA(%s): ret=%d err=%d\n", tmpdir, ret, GetLastError()); + "CreateDirectoryA(%s): ret=%d err=%ld\n", tmpdir, ret, GetLastError()); if (ret == TRUE) { ret = RemoveDirectoryA(tmpdir); ok(ret == TRUE, - "RemoveDirectoryA(%s) failed err=%d\n", tmpdir, GetLastError()); + "RemoveDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError()); } GetTempPathA(MAX_PATH, tmpdir); lstrcatA(tmpdir, "Please Remove Me"); ret = RemoveDirectoryA(tmpdir); ok(ret == TRUE, - "RemoveDirectoryA(%s) failed err=%d\n", tmpdir, GetLastError()); + "RemoveDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError()); /* Test behavior with a trailing space. * The directory should be created without the trailing spaces. @@ -334,25 +334,25 @@ static void test_CreateDirectoryA(void) lstrcatA(tmpdir, "Please Remove Me "); ret = CreateDirectoryA(tmpdir, NULL); ok(ret == TRUE, - "CreateDirectoryA(%s) failed err=%d\n", tmpdir, GetLastError()); + "CreateDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError()); lstrcatA(tmpdir, "/Please Remove Me"); ret = CreateDirectoryA(tmpdir, NULL); ok(ret == TRUE || /* On Win98 */ (ret == FALSE && GetLastError() == ERROR_PATH_NOT_FOUND), /* On NT! */ - "CreateDirectoryA(%s): ret=%d err=%d\n", tmpdir, ret, GetLastError()); + "CreateDirectoryA(%s): ret=%d err=%ld\n", tmpdir, ret, GetLastError()); if (ret == TRUE) { ret = RemoveDirectoryA(tmpdir); ok(ret == TRUE, - "RemoveDirectoryA(%s) failed err=%d\n", tmpdir, GetLastError()); + "RemoveDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError()); } GetTempPathA(MAX_PATH, tmpdir); lstrcatA(tmpdir, "Please Remove Me"); ret = RemoveDirectoryA(tmpdir); ok(ret == TRUE, - "RemoveDirectoryA(%s) failed err=%d\n", tmpdir, GetLastError()); + "RemoveDirectoryA(%s) failed err=%ld\n", tmpdir, GetLastError()); SetCurrentDirectoryW(curdir); } @@ -375,32 +375,32 @@ static void test_CreateDirectoryW(void) return; } ok(ret == FALSE && GetLastError() == ERROR_PATH_NOT_FOUND, - "should not create NULL path ret %u err %u\n", ret, GetLastError()); + "should not create NULL path ret %u err %lu\n", ret, GetLastError()); ret = CreateDirectoryW(empty_strW, NULL); ok(ret == FALSE && GetLastError() == ERROR_PATH_NOT_FOUND, - "should not create empty path ret %u err %u\n", ret, GetLastError()); + "should not create empty path ret %u err %lu\n", ret, GetLastError()); ret = GetSystemDirectoryW(tmpdir, MAX_PATH); ok(ret < MAX_PATH, "System directory should fit into MAX_PATH\n"); GetCurrentDirectoryW(MAX_PATH, curdir); ret = SetCurrentDirectoryW(tmpdir); - ok(ret == TRUE, "could not chdir to the System directory ret %u err %u\n", ret, GetLastError()); + ok(ret == TRUE, "could not chdir to the System directory ret %u err %lu\n", ret, GetLastError()); ret = CreateDirectoryW(dotW, NULL); ok(ret == FALSE && GetLastError() == ERROR_ALREADY_EXISTS, - "should not create existing path ret %u err %u\n", ret, GetLastError()); + "should not create existing path ret %u err %lu\n", ret, GetLastError()); ret = CreateDirectoryW(dotdotW, NULL); ok(ret == FALSE && GetLastError() == ERROR_ALREADY_EXISTS, - "should not create existing path ret %u err %u\n", ret, GetLastError()); + "should not create existing path ret %u err %lu\n", ret, GetLastError()); GetTempPathW(MAX_PATH, tmpdir); tmpdir[3] = 0; /* truncate the path */ ret = CreateDirectoryW(tmpdir, NULL); ok(ret == FALSE && (GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == ERROR_ALREADY_EXISTS), - "should deny access to the drive root ret %u err %u\n", ret, GetLastError()); + "should deny access to the drive root ret %u err %lu\n", ret, GetLastError()); GetTempPathW(MAX_PATH, tmpdir); lstrcatW(tmpdir, tmp_dir_name); @@ -409,7 +409,7 @@ static void test_CreateDirectoryW(void) ret = CreateDirectoryW(tmpdir, NULL); ok(ret == FALSE && GetLastError() == ERROR_ALREADY_EXISTS, - "should not create existing path ret %u err %u\n", ret, GetLastError()); + "should not create existing path ret %u err %lu\n", ret, GetLastError()); ret = RemoveDirectoryW(tmpdir); ok(ret == TRUE, "RemoveDirectoryW should always succeed\n"); @@ -417,7 +417,7 @@ static void test_CreateDirectoryW(void) lstrcatW(tmpdir, questionW); ret = CreateDirectoryW(tmpdir, NULL); ok(ret == FALSE && GetLastError() == ERROR_INVALID_NAME, - "CreateDirectoryW with ? wildcard name should fail with error 183, ret=%s error=%d\n", + "CreateDirectoryW with ? wildcard name should fail with error 183, ret=%s error=%ld\n", ret ? " True" : "False", GetLastError()); ret = RemoveDirectoryW(tmpdir); ok(ret == FALSE, "RemoveDirectoryW should have failed\n"); @@ -425,7 +425,7 @@ static void test_CreateDirectoryW(void) tmpdir[lstrlenW(tmpdir) - 1] = '*'; ret = CreateDirectoryW(tmpdir, NULL); ok(ret == FALSE && GetLastError() == ERROR_INVALID_NAME, - "CreateDirectoryW with * wildcard name should fail with error 183, ret=%s error=%d\n", + "CreateDirectoryW with * wildcard name should fail with error 183, ret=%s error=%ld\n", ret ? " True" : "False", GetLastError()); ret = RemoveDirectoryW(tmpdir); ok(ret == FALSE, "RemoveDirectoryW should have failed\n"); @@ -436,7 +436,7 @@ static void test_CreateDirectoryW(void) lstrcatW(tmpdir, tmp_dir_name); ret = CreateDirectoryW(tmpdir, NULL); ok(ret == FALSE && GetLastError() == ERROR_PATH_NOT_FOUND, - "CreateDirectoryW with multiple nonexistent directories in path should fail ret %u err %u\n", + "CreateDirectoryW with multiple nonexistent directories in path should fail ret %u err %lu\n", ret, GetLastError()); ret = RemoveDirectoryW(tmpdir); ok(ret == FALSE, "RemoveDirectoryW should have failed\n"); @@ -461,7 +461,7 @@ static void test_RemoveDirectoryA(void) SetLastError(0xdeadbeef); ok(!RemoveDirectoryA(tmpdir), "RemoveDirectoryA succeeded\n"); ok(GetLastError() == ERROR_SHARING_VIOLATION, - "Expected ERROR_SHARING_VIOLATION, got %u\n", GetLastError()); + "Expected ERROR_SHARING_VIOLATION, got %lu\n", GetLastError()); TEST_GRANTED_ACCESS(NtCurrentTeb()->Peb->ProcessParameters->CurrentDirectory.Handle, FILE_TRAVERSE | SYNCHRONIZE); @@ -474,14 +474,14 @@ static void test_RemoveDirectoryA(void) ret = RemoveDirectoryA(tmpdir); ok(ret == FALSE && (GetLastError() == ERROR_INVALID_NAME || GetLastError() == ERROR_PATH_NOT_FOUND), - "RemoveDirectoryA with ? wildcard name should fail, ret=%s error=%d\n", + "RemoveDirectoryA with ? wildcard name should fail, ret=%s error=%ld\n", ret ? " True" : "False", GetLastError()); tmpdir[lstrlenA(tmpdir) - 1] = '*'; ret = RemoveDirectoryA(tmpdir); ok(ret == FALSE && (GetLastError() == ERROR_INVALID_NAME || GetLastError() == ERROR_PATH_NOT_FOUND), - "RemoveDirectoryA with * wildcard name should fail, ret=%s error=%d\n", + "RemoveDirectoryA with * wildcard name should fail, ret=%s error=%ld\n", ret ? " True" : "False", GetLastError()); } @@ -510,7 +510,7 @@ static void test_RemoveDirectoryW(void) SetLastError(0xdeadbeef); ok(!RemoveDirectoryW(tmpdir), "RemoveDirectoryW succeeded\n"); ok(GetLastError() == ERROR_SHARING_VIOLATION, - "Expected ERROR_SHARING_VIOLATION, got %u\n", GetLastError()); + "Expected ERROR_SHARING_VIOLATION, got %lu\n", GetLastError()); TEST_GRANTED_ACCESS(NtCurrentTeb()->Peb->ProcessParameters->CurrentDirectory.Handle, FILE_TRAVERSE | SYNCHRONIZE); @@ -522,13 +522,13 @@ static void test_RemoveDirectoryW(void) lstrcatW(tmpdir, questionW); ret = RemoveDirectoryW(tmpdir); ok(ret == FALSE && GetLastError() == ERROR_INVALID_NAME, - "RemoveDirectoryW with wildcard should fail with error 183, ret=%s error=%d\n", + "RemoveDirectoryW with wildcard should fail with error 183, ret=%s error=%ld\n", ret ? " True" : "False", GetLastError()); tmpdir[lstrlenW(tmpdir) - 1] = '*'; ret = RemoveDirectoryW(tmpdir); ok(ret == FALSE && GetLastError() == ERROR_INVALID_NAME, - "RemoveDirectoryW with * wildcard name should fail with error 183, ret=%s error=%d\n", + "RemoveDirectoryW with * wildcard name should fail with error 183, ret=%s error=%ld\n", ret ? " True" : "False", GetLastError()); } @@ -536,15 +536,58 @@ static void test_SetCurrentDirectoryA(void) { SetLastError(0); ok( !SetCurrentDirectoryA( "\\some_dummy_dir" ), "SetCurrentDirectoryA succeeded\n" ); - ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %d\n", GetLastError() ); + ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %ld\n", GetLastError() ); ok( !SetCurrentDirectoryA( "\\some_dummy\\subdir" ), "SetCurrentDirectoryA succeeded\n" ); - ok( GetLastError() == ERROR_PATH_NOT_FOUND, "wrong error %d\n", GetLastError() ); + ok( GetLastError() == ERROR_PATH_NOT_FOUND, "wrong error %ld\n", GetLastError() ); +} + +static void test_CreateDirectory_root(void) +{ + static const WCHAR drive_c_root[] = { 'C',':','\\',0 }; + static const WCHAR drive_c[] = { 'C',':',0 }; + char curdir[MAX_PATH]; + BOOL ret; + + GetCurrentDirectoryA(sizeof(curdir), curdir); + + ret = SetCurrentDirectoryA("C:\\"); + ok(ret, "SetCurrentDirectory error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = CreateDirectoryA("C:\\", NULL); + ok(!ret, "CreateDirectory should fail\n"); + if (GetLastError() == ERROR_ACCESS_DENIED) + { + win_skip("not an administrator\n"); + SetCurrentDirectoryA(curdir); + return; + } + ok(GetLastError() == ERROR_ALREADY_EXISTS, "got %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = CreateDirectoryA("C:", NULL); + ok(!ret, "CreateDirectory should fail\n"); + ok(GetLastError() == ERROR_ALREADY_EXISTS, "got %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = CreateDirectoryW(drive_c_root, NULL); + ok(!ret, "CreateDirectory should fail\n"); + ok(GetLastError() == ERROR_ALREADY_EXISTS, "got %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = CreateDirectoryW(drive_c, NULL); + ok(!ret, "CreateDirectory should fail\n"); + ok(GetLastError() == ERROR_ALREADY_EXISTS, "got %lu\n", GetLastError()); + + SetCurrentDirectoryA(curdir); } START_TEST(directory) { init(); + test_CreateDirectory_root(); + test_GetWindowsDirectoryA(); test_GetWindowsDirectoryW(); diff --git a/modules/rostests/winetests/kernel32/drive.c b/modules/rostests/winetests/kernel32/drive.c index 98dc454f340..ca7dc14a1cb 100644 --- a/modules/rostests/winetests/kernel32/drive.c +++ b/modules/rostests/winetests/kernel32/drive.c @@ -35,7 +35,7 @@ static void test_GetDriveTypeA(void) UINT type; logical_drives = GetLogicalDrives(); - ok(logical_drives != 0, "GetLogicalDrives error %d\n", GetLastError()); + ok(logical_drives != 0, "GetLogicalDrives error %ld\n", GetLastError()); for (drive[0] = 'A'; drive[0] <= 'Z'; drive[0]++) { @@ -88,7 +88,7 @@ static void test_GetDriveTypeW(void) UINT type; logical_drives = GetLogicalDrives(); - ok(logical_drives != 0, "GetLogicalDrives error %d\n", GetLastError()); + ok(logical_drives != 0, "GetLogicalDrives error %ld\n", GetLastError()); for (drive[0] = 'A'; drive[0] <= 'Z'; drive[0]++) { @@ -138,25 +138,41 @@ static void test_GetDiskFreeSpaceA(void) { BOOL ret; DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters; + char volume_guid_path[50]; char drive[] = "?:\\"; DWORD logical_drives; ret = GetDiskFreeSpaceA(NULL, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters); - ok(ret, "GetDiskFreeSpaceA error %d\n", GetLastError()); + ok(ret, "GetDiskFreeSpaceA error %ld\n", GetLastError()); ret = GetDiskFreeSpaceA("", §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters); ok(!ret && (GetLastError() == ERROR_PATH_NOT_FOUND || GetLastError() == ERROR_INVALID_NAME), - "GetDiskFreeSpaceA(\"\"): ret=%d GetLastError=%d\n", + "GetDiskFreeSpaceA(\"\"): ret=%d GetLastError=%ld\n", ret, GetLastError()); ret = GetDiskFreeSpaceA("\\", §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters); - ok(ret, "GetDiskFreeSpaceA error %d\n", GetLastError()); + ok(ret, "GetDiskFreeSpaceA error %ld\n", GetLastError()); ret = GetDiskFreeSpaceA("/", §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters); - ok(ret, "GetDiskFreeSpaceA error %d\n", GetLastError()); + ok(ret, "GetDiskFreeSpaceA error %ld\n", GetLastError()); + + ret = GetDiskFreeSpaceA("C:\\", §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters); + ok(ret, "GetDiskFreeSpaceA error %ld\n", GetLastError()); + +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) { +#endif + ret = GetVolumeNameForVolumeMountPointA("C:\\", volume_guid_path, ARRAY_SIZE(volume_guid_path)); + ok(ret, "GetVolumeNameForVolumeMountPointA error %ld\n", GetLastError()); + + ret = GetDiskFreeSpaceA(volume_guid_path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters); + ok(ret, "GetDiskFreeSpaceA error %ld\n", GetLastError()); +#ifdef __REACTOS__ + } +#endif logical_drives = GetLogicalDrives(); - ok(logical_drives != 0, "GetLogicalDrives error %d\n", GetLastError()); + ok(logical_drives != 0, "GetLogicalDrives error %ld\n", GetLastError()); for (drive[0] = 'A'; drive[0] <= 'Z'; drive[0]++) { @@ -169,7 +185,7 @@ static void test_GetDiskFreeSpaceA(void) ret = GetDiskFreeSpaceA(drive, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters); if (!(logical_drives & 1)) ok(!ret && (GetLastError() == ERROR_PATH_NOT_FOUND || GetLastError() == ERROR_INVALID_DRIVE), - "GetDiskFreeSpaceA(%s): ret=%d GetLastError=%d\n", + "GetDiskFreeSpaceA(%s): ret=%d GetLastError=%ld\n", drive, ret, GetLastError()); else { @@ -177,12 +193,12 @@ static void test_GetDiskFreeSpaceA(void) if (!ret) /* GetDiskFreeSpaceA() should succeed, but it can fail with too many different GetLastError() results to be usable for an ok() */ - trace("GetDiskFreeSpaceA(%s) failed with %d\n", drive, GetLastError()); + trace("GetDiskFreeSpaceA(%s) failed with %ld\n", drive, GetLastError()); if( GetVersion() & 0x80000000) /* win3.0 through winME */ ok( total_clusters <= 65535, - "total clusters is %d > 65535\n", total_clusters); + "total clusters is %ld > 65535\n", total_clusters); else if (pGetDiskFreeSpaceExA) { /* NT, 2k, XP : GetDiskFreeSpace should be accurate */ ULARGE_INTEGER totEx, tot, d; @@ -194,7 +210,7 @@ static void test_GetDiskFreeSpaceA(void) if (!ret) /* GetDiskFreeSpaceExA() should succeed, but it can fail with too many different GetLastError() results to be usable for an ok() */ - trace("GetDiskFreeSpaceExA(%s) failed with %d\n", drive, GetLastError()); + trace("GetDiskFreeSpaceExA(%s) failed with %ld\n", drive, GetLastError()); ok( bytes_per_sector == 0 || /* empty cd rom drive */ totEx.QuadPart <= tot.QuadPart, @@ -210,11 +226,13 @@ static void test_GetDiskFreeSpaceW(void) { BOOL ret; DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters; + WCHAR volume_guid_path[50]; WCHAR drive[] = {'?',':','\\',0}; DWORD logical_drives; static const WCHAR empty_pathW[] = { 0 }; static const WCHAR root_pathW[] = { '\\', 0 }; static const WCHAR unix_style_root_pathW[] = { '/', 0 }; + static const WCHAR c_drive_pathW[] = { 'C', ':', '\\', 0 }; ret = GetDiskFreeSpaceW(NULL, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters); if (ret == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) @@ -222,21 +240,30 @@ static void test_GetDiskFreeSpaceW(void) win_skip("GetDiskFreeSpaceW is not available\n"); return; } - ok(ret, "GetDiskFreeSpaceW error %d\n", GetLastError()); + ok(ret, "GetDiskFreeSpaceW error %ld\n", GetLastError()); ret = GetDiskFreeSpaceW(empty_pathW, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters); ok(!ret && GetLastError() == ERROR_PATH_NOT_FOUND, - "GetDiskFreeSpaceW(\"\"): ret=%d GetLastError=%d\n", + "GetDiskFreeSpaceW(\"\"): ret=%d GetLastError=%ld\n", ret, GetLastError()); ret = GetDiskFreeSpaceW(root_pathW, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters); - ok(ret, "GetDiskFreeSpaceW(\"\") error %d\n", GetLastError()); + ok(ret, "GetDiskFreeSpaceW(\"\") error %ld\n", GetLastError()); ret = GetDiskFreeSpaceW(unix_style_root_pathW, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters); - ok(ret, "GetDiskFreeSpaceW error %d\n", GetLastError()); + ok(ret, "GetDiskFreeSpaceW error %ld\n", GetLastError()); + + ret = GetDiskFreeSpaceW(c_drive_pathW, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters); + ok(ret, "GetDiskFreeSpaceW error %ld\n", GetLastError()); + + ret = GetVolumeNameForVolumeMountPointW(c_drive_pathW, volume_guid_path, ARRAY_SIZE(volume_guid_path)); + ok(ret, "GetVolumeNameForVolumeMountPointW error %ld\n", GetLastError()); + + ret = GetDiskFreeSpaceW(volume_guid_path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters); + ok(ret, "GetDiskFreeSpaceW error %ld\n", GetLastError()); logical_drives = GetLogicalDrives(); - ok(logical_drives != 0, "GetLogicalDrives error %d\n", GetLastError()); + ok(logical_drives != 0, "GetLogicalDrives error %ld\n", GetLastError()); for (drive[0] = 'A'; drive[0] <= 'Z'; drive[0]++) { @@ -247,12 +274,12 @@ static void test_GetDiskFreeSpaceW(void) ret = GetDiskFreeSpaceW(drive, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters); if (!(logical_drives & 1)) ok(!ret && GetLastError() == ERROR_PATH_NOT_FOUND, - "GetDiskFreeSpaceW(%c): ret=%d GetLastError=%d\n", + "GetDiskFreeSpaceW(%c): ret=%d GetLastError=%ld\n", drive[0], ret, GetLastError()); else if (!ret) /* GetDiskFreeSpaceW() should succeed, but it can fail with too many different GetLastError() results to be usable for an ok() */ - trace("GetDiskFreeSpaceW(%c) failed with %d\n", drive[0], GetLastError()); + trace("GetDiskFreeSpaceW(%c) failed with %ld\n", drive[0], GetLastError()); } logical_drives >>= 1; } diff --git a/modules/rostests/winetests/kernel32/dummy.c b/modules/rostests/winetests/kernel32/dummy.c new file mode 100644 index 00000000000..4837a3736ba --- /dev/null +++ b/modules/rostests/winetests/kernel32/dummy.c @@ -0,0 +1,42 @@ +/* + * Copyright 2019 Fabian Maurer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep testdll +#endif + +#include + +static HINSTANCE instance; + +BOOL WINAPI DllMain(HINSTANCE instance_new, DWORD reason, LPVOID reserved) +{ + switch (reason) + { + case DLL_PROCESS_ATTACH: + instance = instance_new; + break; + } + + return TRUE; +} + +void WINAPI get_path(char *buffer, int buffer_size) +{ + GetModuleFileNameA(instance, buffer, buffer_size); +} diff --git a/modules/rostests/winetests/kernel32/dummy.spec b/modules/rostests/winetests/kernel32/dummy.spec new file mode 100644 index 00000000000..d227c478953 --- /dev/null +++ b/modules/rostests/winetests/kernel32/dummy.spec @@ -0,0 +1 @@ +@ stdcall get_path(ptr long) diff --git a/modules/rostests/winetests/kernel32/environ.c b/modules/rostests/winetests/kernel32/environ.c index f8452be2ee6..1aae02db692 100644 --- a/modules/rostests/winetests/kernel32/environ.c +++ b/modules/rostests/winetests/kernel32/environ.c @@ -34,18 +34,17 @@ static CHAR string[MAX_PATH]; static BOOL (WINAPI *pGetComputerNameExA)(COMPUTER_NAME_FORMAT,LPSTR,LPDWORD); static BOOL (WINAPI *pGetComputerNameExW)(COMPUTER_NAME_FORMAT,LPWSTR,LPDWORD); -static BOOL (WINAPI *pOpenProcessToken)(HANDLE,DWORD,PHANDLE); static BOOL (WINAPI *pGetUserProfileDirectoryA)(HANDLE,LPSTR,LPDWORD); +static BOOL (WINAPI *pSetEnvironmentStringsW)(WCHAR *); static void init_functionpointers(void) { HMODULE hkernel32 = GetModuleHandleA("kernel32.dll"); - HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll"); HMODULE huserenv = LoadLibraryA("userenv.dll"); pGetComputerNameExA = (void *)GetProcAddress(hkernel32, "GetComputerNameExA"); pGetComputerNameExW = (void *)GetProcAddress(hkernel32, "GetComputerNameExW"); - pOpenProcessToken = (void *)GetProcAddress(hadvapi32, "OpenProcessToken"); + pSetEnvironmentStringsW = (void *)GetProcAddress(hkernel32, "SetEnvironmentStringsW"); pGetUserProfileDirectoryA = (void *)GetProcAddress(huserenv, "GetUserProfileDirectoryA"); } @@ -63,21 +62,21 @@ static void test_Predefined(void) * Check value of %USERPROFILE%, should be same as GetUserProfileDirectory() * If this fails, your test environment is probably not set up */ - if (pOpenProcessToken == NULL || pGetUserProfileDirectoryA == NULL) + if (pGetUserProfileDirectoryA == NULL) { skip("Skipping USERPROFILE check\n"); return; } - NoErr = pOpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &Token); - ok(NoErr, "Failed to open token, error %u\n", GetLastError()); + NoErr = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &Token); + ok(NoErr, "Failed to open token, error %lu\n", GetLastError()); DataSize = sizeof(Data); NoErr = pGetUserProfileDirectoryA(Token, Data, &DataSize); - ok(NoErr, "Failed to get user profile dir, error %u\n", GetLastError()); + ok(NoErr, "Failed to get user profile dir, error %lu\n", GetLastError()); if (NoErr) { EnvSize = GetEnvironmentVariableA("USERPROFILE", Env, sizeof(Env)); ok(EnvSize != 0 && EnvSize <= sizeof(Env), - "Failed to retrieve environment variable USERPROFILE, error %u\n", + "Failed to retrieve environment variable USERPROFILE, error %lu\n", GetLastError()); ok(strcmp(Data, Env) == 0, "USERPROFILE env var %s doesn't match GetUserProfileDirectory %s\n", @@ -86,7 +85,7 @@ static void test_Predefined(void) else skip("Skipping USERPROFILE check, can't get user profile dir\n"); NoErr = CloseHandle(Token); - ok(NoErr, "Failed to close token, error %u\n", GetLastError()); + ok(NoErr, "Failed to close token, error %lu\n", GetLastError()); } static void test_GetSetEnvironmentVariableA(void) @@ -100,82 +99,99 @@ static void test_GetSetEnvironmentVariableA(void) ret = SetEnvironmentVariableA(name, value); ok(ret == TRUE, - "unexpected error in SetEnvironmentVariableA, GetLastError=%d\n", + "unexpected error in SetEnvironmentVariableA, GetLastError=%ld\n", GetLastError()); /* Try to retrieve the environment variable we just set */ + SetLastError(0xdeadbeef); ret_size = GetEnvironmentVariableA(name, NULL, 0); ok(ret_size == strlen(value) + 1, - "should return length with terminating 0 ret_size=%d\n", ret_size); + "should return length with terminating 0 ret_size=%ld\n", ret_size); + ok(GetLastError() == 0xdeadbeef, + "should not fail with zero size but GetLastError=%ld\n", GetLastError()); lstrcpyA(buf, "foo"); ret_size = GetEnvironmentVariableA(name, buf, lstrlenA(value)); ok(lstrcmpA(buf, "foo") == 0, "should not touch the buffer\n"); ok(ret_size == strlen(value) + 1, - "should return length with terminating 0 ret_size=%d\n", ret_size); + "should return length with terminating 0 ret_size=%ld\n", ret_size); lstrcpyA(buf, "foo"); ret_size = GetEnvironmentVariableA(name, buf, lstrlenA(value) + 1); ok(lstrcmpA(buf, value) == 0, "should touch the buffer\n"); ok(ret_size == strlen(value), - "should return length without terminating 0 ret_size=%d\n", ret_size); + "should return length without terminating 0 ret_size=%ld\n", ret_size); lstrcpyA(buf, "foo"); ret_size = GetEnvironmentVariableA(name_cased, buf, lstrlenA(value) + 1); ok(lstrcmpA(buf, value) == 0, "should touch the buffer\n"); ok(ret_size == strlen(value), - "should return length without terminating 0 ret_size=%d\n", ret_size); + "should return length without terminating 0 ret_size=%ld\n", ret_size); /* Remove that environment variable */ ret = SetEnvironmentVariableA(name_cased, NULL); ok(ret == TRUE, "should erase existing variable\n"); lstrcpyA(buf, "foo"); + SetLastError(0xdeadbeef); ret_size = GetEnvironmentVariableA(name, buf, lstrlenA(value) + 1); ok(lstrcmpA(buf, "foo") == 0, "should not touch the buffer\n"); ok(ret_size == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND, - "should not find variable but ret_size=%d GetLastError=%d\n", + "should not find variable but ret_size=%ld GetLastError=%ld\n", ret_size, GetLastError()); /* Check behavior of SetEnvironmentVariableA(name, "") */ ret = SetEnvironmentVariableA(name, value); ok(ret == TRUE, - "unexpected error in SetEnvironmentVariableA, GetLastError=%d\n", + "unexpected error in SetEnvironmentVariableA, GetLastError=%ld\n", GetLastError()); lstrcpyA(buf, "foo"); ret_size = GetEnvironmentVariableA(name_cased, buf, lstrlenA(value) + 1); ok(lstrcmpA(buf, value) == 0, "should touch the buffer\n"); ok(ret_size == strlen(value), - "should return length without terminating 0 ret_size=%d\n", ret_size); + "should return length without terminating 0 ret_size=%ld\n", ret_size); ret = SetEnvironmentVariableA(name_cased, ""); ok(ret == TRUE, - "should not fail with empty value but GetLastError=%d\n", GetLastError()); + "should not fail with empty value but GetLastError=%ld\n", GetLastError()); lstrcpyA(buf, "foo"); - SetLastError(0); + SetLastError(0xdeadbeef); ret_size = GetEnvironmentVariableA(name, buf, lstrlenA(value) + 1); ok(ret_size == 0 && - ((GetLastError() == 0 && lstrcmpA(buf, "") == 0) || + ((GetLastError() == 0xdeadbeef && lstrcmpA(buf, "") == 0) || (GetLastError() == ERROR_ENVVAR_NOT_FOUND)), - "%s should be set to \"\" (NT) or removed (Win9x) but ret_size=%d GetLastError=%d and buf=%s\n", + "%s should be set to \"\" (NT) or removed (Win9x) but ret_size=%ld GetLastError=%ld and buf=%s\n", name, ret_size, GetLastError(), buf); + SetLastError(0xdeadbeef); + ret_size = GetEnvironmentVariableA(name, NULL, 0); + ok(ret_size == 1 || + broken(ret_size == 0), /* XP */ + "should return 1 for empty string but ret_size=%ld GetLastError=%ld\n", + ret_size, GetLastError()); + ok(GetLastError() == 0xdeadbeef || + broken(GetLastError() == ERROR_MORE_DATA), /* XP */ + "should not fail with zero size but GetLastError=%ld\n", GetLastError()); + /* Test the limits */ + SetLastError(0xdeadbeef); ret_size = GetEnvironmentVariableA(NULL, NULL, 0); ok(ret_size == 0 && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_ENVVAR_NOT_FOUND), - "should not find variable but ret_size=%d GetLastError=%d\n", + "should not find variable but ret_size=%ld GetLastError=%ld\n", ret_size, GetLastError()); + SetLastError(0xdeadbeef); ret_size = GetEnvironmentVariableA(NULL, buf, lstrlenA(value) + 1); ok(ret_size == 0 && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_ENVVAR_NOT_FOUND), - "should not find variable but ret_size=%d GetLastError=%d\n", + "should not find variable but ret_size=%ld GetLastError=%ld\n", ret_size, GetLastError()); + SetLastError(0xdeadbeef); ret_size = GetEnvironmentVariableA("", buf, lstrlenA(value) + 1); ok(ret_size == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND, - "should not find variable but ret_size=%d GetLastError=%d\n", + "should not find variable but ret_size=%ld GetLastError=%ld\n", ret_size, GetLastError()); } @@ -198,14 +214,17 @@ static void test_GetSetEnvironmentVariableW(void) return; } ok(ret == TRUE, - "unexpected error in SetEnvironmentVariableW, GetLastError=%d\n", + "unexpected error in SetEnvironmentVariableW, GetLastError=%ld\n", GetLastError()); /* Try to retrieve the environment variable we just set */ + SetLastError(0xdeadbeef); ret_size = GetEnvironmentVariableW(name, NULL, 0); ok(ret_size == lstrlenW(value) + 1, - "should return length with terminating 0 ret_size=%d\n", + "should return length with terminating 0 ret_size=%ld\n", ret_size); + ok(GetLastError() == 0xdeadbeef, + "should not fail with zero size but GetLastError=%ld\n", GetLastError()); lstrcpyW(buf, fooW); ret_size = GetEnvironmentVariableW(name, buf, lstrlenW(value)); @@ -214,85 +233,322 @@ static void test_GetSetEnvironmentVariableW(void) "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); + "should return length with terminating 0 ret_size=%ld\n", ret_size); lstrcpyW(buf, fooW); ret_size = GetEnvironmentVariableW(name, buf, lstrlenW(value) + 1); ok(lstrcmpW(buf, value) == 0, "should touch the buffer\n"); ok(ret_size == lstrlenW(value), - "should return length without terminating 0 ret_size=%d\n", ret_size); + "should return length without terminating 0 ret_size=%ld\n", ret_size); lstrcpyW(buf, fooW); ret_size = GetEnvironmentVariableW(name_cased, buf, lstrlenW(value) + 1); ok(lstrcmpW(buf, value) == 0, "should touch the buffer\n"); ok(ret_size == lstrlenW(value), - "should return length without terminating 0 ret_size=%d\n", ret_size); + "should return length without terminating 0 ret_size=%ld\n", ret_size); /* Remove that environment variable */ ret = SetEnvironmentVariableW(name_cased, NULL); ok(ret == TRUE, "should erase existing variable\n"); lstrcpyW(buf, fooW); + SetLastError(0xdeadbeef); ret_size = GetEnvironmentVariableW(name, buf, lstrlenW(value) + 1); ok(lstrcmpW(buf, fooW) == 0, "should not touch the buffer\n"); ok(ret_size == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND, - "should not find variable but ret_size=%d GetLastError=%d\n", + "should not find variable but ret_size=%ld GetLastError=%ld\n", ret_size, GetLastError()); /* Check behavior of SetEnvironmentVariableW(name, "") */ ret = SetEnvironmentVariableW(name, value); ok(ret == TRUE, - "unexpected error in SetEnvironmentVariableW, GetLastError=%d\n", + "unexpected error in SetEnvironmentVariableW, GetLastError=%ld\n", GetLastError()); lstrcpyW(buf, fooW); ret_size = GetEnvironmentVariableW(name, buf, lstrlenW(value) + 1); ok(lstrcmpW(buf, value) == 0, "should touch the buffer\n"); ok(ret_size == lstrlenW(value), - "should return length without terminating 0 ret_size=%d\n", ret_size); + "should return length without terminating 0 ret_size=%ld\n", ret_size); ret = SetEnvironmentVariableW(name_cased, empty_strW); - ok(ret == TRUE, "should not fail with empty value but GetLastError=%d\n", GetLastError()); + ok(ret == TRUE, "should not fail with empty value but GetLastError=%ld\n", GetLastError()); lstrcpyW(buf, fooW); + SetLastError(0xdeadbeef); ret_size = GetEnvironmentVariableW(name, buf, lstrlenW(value) + 1); - ok(ret_size == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND, - "should not find variable but ret_size=%d GetLastError=%d\n", + ok(ret_size == 0 && + ((GetLastError() == 0xdeadbeef && lstrcmpW(buf, empty_strW) == 0) || + (GetLastError() == ERROR_ENVVAR_NOT_FOUND)), + "should be set to \"\" (NT) or removed (Win9x) but ret_size=%ld GetLastError=%ld\n", ret_size, GetLastError()); ok(lstrcmpW(buf, empty_strW) == 0, "should copy an empty string\n"); + SetLastError(0xdeadbeef); + ret_size = GetEnvironmentVariableW(name, NULL, 0); + ok(ret_size == 1 || + broken(ret_size == 0), /* XP */ + "should return 1 for empty string but ret_size=%ld GetLastError=%ld\n", + ret_size, GetLastError()); + ok(GetLastError() == 0xdeadbeef || + broken(GetLastError() == ERROR_MORE_DATA), /* XP */ + "should not fail with zero size but GetLastError=%ld\n", GetLastError()); + /* Test the limits */ + SetLastError(0xdeadbeef); ret_size = GetEnvironmentVariableW(NULL, NULL, 0); - ok(ret_size == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND, - "should not find variable but ret_size=%d GetLastError=%d\n", + ok(ret_size == 0 && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_ENVVAR_NOT_FOUND), + "should not find variable but ret_size=%ld GetLastError=%ld\n", ret_size, GetLastError()); if (0) /* Both tests crash on Vista */ { + SetLastError(0xdeadbeef); ret_size = GetEnvironmentVariableW(NULL, buf, lstrlenW(value) + 1); ok(ret_size == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND, - "should not find variable but ret_size=%d GetLastError=%d\n", + "should not find variable but ret_size=%ld GetLastError=%ld\n", ret_size, GetLastError()); + SetLastError(0xdeadbeef); ret = SetEnvironmentVariableW(NULL, NULL); ok(ret == FALSE && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_ENVVAR_NOT_FOUND), - "should fail with NULL, NULL but ret=%d and GetLastError=%d\n", + "should fail with NULL, NULL but ret=%d and GetLastError=%ld\n", ret, GetLastError()); } } +static void test_GetSetEnvironmentVariableAW(void) +{ + static const WCHAR nameW[] = {0x540D, 0x524D, 0}; + static const char name[] = "\x96\xBC\x91\x4F"; + static const WCHAR valueW[] = {0x5024, 0}; + static const char value[] = "\x92\x6C"; + WCHAR bufW[256]; + char buf[256]; + DWORD ret_size; + BOOL ret; + + if (GetACP() != 932) + { + skip("GetACP() == %d, need 932 for A/W tests\n", GetACP()); + return; + } + + /* Write W, read A */ + ret = SetEnvironmentVariableW(nameW, valueW); + ok(ret == TRUE, "SetEnvironmentVariableW failed, last error %ld\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret_size = GetEnvironmentVariableA(name, NULL, 0); + todo_wine ok(ret_size == lstrlenA(value) + 1, "expected ret_size %d, got %ld\n", lstrlenA(value) + 1, ret_size); + ok(GetLastError() == 0xdeadbeef, "expected last error 0xdeadbeef, got %ld\n", GetLastError()); + + lstrcpyA(buf, "foo"); + SetLastError(0xdeadbeef); + ret_size = GetEnvironmentVariableA(name, buf, lstrlenA(value) + 1); + todo_wine ok(lstrcmpA(buf, value) == 0, "expected %s, got %s\n", debugstr_a(value), debugstr_a(buf)); + todo_wine ok(ret_size == lstrlenA(value), "expected ret_size %d, got %ld\n", lstrlenA(value), ret_size); + ok(GetLastError() == 0xdeadbeef, "expected last error 0xdeadbeef, got %ld\n", GetLastError()); + + /* Write A, read A/W */ + ret = SetEnvironmentVariableA(name, value); + ok(ret == TRUE, "SetEnvironmentVariableW failed, last error %ld\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret_size = GetEnvironmentVariableA(name, NULL, 0); + todo_wine ok(ret_size == lstrlenA(value) + 1, "expected ret_size %d, got %ld\n", lstrlenA(value) + 1, ret_size); + ok(GetLastError() == 0xdeadbeef, "expected last error 0xdeadbeef, got %ld\n", GetLastError()); + + lstrcpyA(buf, "foo"); + SetLastError(0xdeadbeef); + ret_size = GetEnvironmentVariableA(name, buf, lstrlenA(value) + 1); + todo_wine ok(lstrcmpA(buf, value) == 0, "expected %s, got %s\n", debugstr_a(value), debugstr_a(buf)); + todo_wine ok(ret_size == lstrlenA(value), "expected ret_size %d, got %ld\n", lstrlenA(value), ret_size); + ok(GetLastError() == 0xdeadbeef, "expected last error 0xdeadbeef, got %ld\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret_size = GetEnvironmentVariableW(nameW, NULL, 0); + ok(ret_size == lstrlenW(valueW) + 1, "expected ret_size %d, got %ld\n", lstrlenW(valueW) + 1, ret_size); + ok(GetLastError() == 0xdeadbeef, "expected last error 0xdeadbeef, got %ld\n", GetLastError()); + + lstrcpyW(bufW, L"foo"); + SetLastError(0xdeadbeef); + ret_size = GetEnvironmentVariableW(nameW, bufW, lstrlenW(valueW) + 1); + ok(ret_size == lstrlenW(valueW), "expected ret_size %d, got %ld\n", lstrlenW(valueW), ret_size); + ok(GetLastError() == 0xdeadbeef, "expected last error 0xdeadbeef, got %ld\n", GetLastError()); + ok(lstrcmpW(bufW, valueW) == 0, "expected %s, got %s\n", debugstr_w(valueW), debugstr_w(bufW)); +} + +static void test_ExpandEnvironmentStringsW(void) +{ + int i; + WCHAR buf[256]; + DWORD ret; + BOOL success; + static const struct test_info + { + const WCHAR *input; + const WCHAR *expected_str; + int count_in; + int expected_count_out; + } tests[] = + { + /* 0 */ { L"Long long value", L"abcdefghijklmnopqrstuv", 0, 16 }, + /* 1 */ { L"Long long value", L"abcdefghijklmnopqrstuv", 1, 16 }, + /* 2 */ { L"Long long value", L"Lbcdefghijklmnopqrstuv", 2, 16 }, + /* 3 */ { L"Long long value", L"Locdefghijklmnopqrstuv", 3, 16 }, + /* 4 */ { L"Long long value", L"Long long valuopqrstuv", 15, 16 }, + /* 5 */ { L"Long long value", L"Long long value", 16, 16 }, + /* 6 */ { L"Long long value", L"Long long value", 17, 16 }, + /* 7 */ { L"%TVAR% long long", L"abcdefghijklmnopqrstuv", 0, 15 }, +#ifndef __REACTOS__ + /* 8 */ { L"%TVAR% long long", L"", 1, 15 }, + /* 9 */ { L"%TVAR% long long", L"", 2, 15 }, + /* 10 */ { L"%TVAR% long long", L"", 4, 15 }, +#endif + /* 11 */ { L"%TVAR% long long", L"WINE", 5, 15 }, + /* 12 */ { L"%TVAR% long long", L"WINE fghijklmnopqrstuv", 6, 15 }, + /* 13 */ { L"%TVAR% long long", L"WINE lghijklmnopqrstuv", 7, 15 }, + /* 14 */ { L"%TVAR% long long", L"WINE long long", 15, 15 }, + /* 15 */ { L"%TVAR% long long", L"WINE long long", 16, 15 }, +#ifndef __REACTOS__ + /* 16 */ { L"%TVAR%%TVAR% long", L"", 4, 14 }, +#endif + /* 17 */ { L"%TVAR%%TVAR% long", L"WINE", 5, 14 }, + /* 18 */ { L"%TVAR%%TVAR% long", L"WINE", 6, 14 }, +#ifndef __REACTOS__ + /* 19 */ { L"%TVAR%%TVAR% long", L"WINE", 8, 14 }, +#endif + /* 20 */ { L"%TVAR%%TVAR% long", L"WINEWINE", 9, 14 }, + /* 21 */ { L"%TVAR%%TVAR% long", L"WINEWINE jklmnopqrstuv", 10, 14 }, + /* 22 */ { L"%TVAR%%TVAR% long", L"WINEWINE long", 14, 14 }, + /* 23 */ { L"%TVAR%%TVAR% long", L"WINEWINE long", 15, 14 }, + /* 24 */ { L"%TVAR% %TVAR% long", L"WINE", 5, 15 }, +#ifndef __REACTOS__ + /* 25 */ { L"%TVAR% %TVAR% long", L"WINE ", 6, 15 }, + /* 26 */ { L"%TVAR% %TVAR% long", L"WINE ", 8, 15 }, + /* 27 */ { L"%TVAR% %TVAR% long", L"WINE ", 9, 15 }, +#endif + /* 28 */ { L"%TVAR% %TVAR% long", L"WINE WINE", 10, 15 }, + /* 29 */ { L"%TVAR% %TVAR% long", L"WINE WINE klmnopqrstuv", 11, 15 }, + /* 30 */ { L"%TVAR% %TVAR% long", L"WINE WINE llmnopqrstuv", 12, 15 }, + /* 31 */ { L"%TVAR% %TVAR% long", L"WINE WINE lonnopqrstuv", 14, 15 }, + /* 32 */ { L"%TVAR% %TVAR% long", L"WINE WINE long", 15, 15 }, + /* 33 */ { L"%TVAR% %TVAR% long", L"WINE WINE long", 16, 15 }, + /* 34 */ { L"%TVAR2% long long", L"abcdefghijklmnopqrstuv", 1, 18 }, + /* 35 */ { L"%TVAR2% long long", L"%bcdefghijklmnopqrstuv", 2, 18 }, + /* 36 */ { L"%TVAR2% long long", L"%TVdefghijklmnopqrstuv", 4, 18 }, + /* 37 */ { L"%TVAR2% long long", L"%TVAR2ghijklmnopqrstuv", 7, 18 }, + /* 38 */ { L"%TVAR2% long long", L"%TVAR2%hijklmnopqrstuv", 8, 18 }, + /* 39 */ { L"%TVAR2% long long", L"%TVAR2% ijklmnopqrstuv", 9, 18 }, + /* 40 */ { L"%TVAR2% long long", L"%TVAR2% ljklmnopqrstuv", 10, 18 }, + /* 41 */ { L"%TVAR2% long long", L"%TVAR2% long long", 18, 18 }, + /* 42 */ { L"%TVAR2% long long", L"%TVAR2% long long", 19, 18 }, + /* 43 */ { L"%TVAR long long", L"abcdefghijklmnopqrstuv", 1, 16 }, + /* 44 */ { L"%TVAR long long", L"%bcdefghijklmnopqrstuv", 2, 16 }, + /* 45 */ { L"%TVAR long long", L"%Tcdefghijklmnopqrstuv", 3, 16 }, + /* 46 */ { L"%TVAR long long", L"%TVAR long lonopqrstuv", 15, 16 }, + /* 47 */ { L"%TVAR long long", L"%TVAR long long", 16, 16 }, + /* 48 */ { L"%TVAR long long", L"%TVAR long long", 17, 16 }, + }; + + success = SetEnvironmentVariableW(L"TVAR", L"WINE"); + ok(success, "SetEnvironmentVariableW failed with %ld\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = ExpandEnvironmentStringsW(L"Long long value", NULL, 0); + ok(ret == 16, "got %lu\n", ret); + ok(GetLastError() == 0xdeadbeef, "got last error %ld\n", GetLastError()); + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + const struct test_info *test = &tests[i]; + + SetLastError(0xdeadbeef); + wcscpy(buf, L"abcdefghijklmnopqrstuv"); + ret = ExpandEnvironmentStringsW(test->input, buf, test->count_in); + ok(ret == test->expected_count_out, "Test %d: got %lu\n", i, ret); + ok(GetLastError() == 0xdeadbeef, "Test %d: got last error %ld\n", i, GetLastError()); + ok(!wcscmp(buf, test->expected_str), "Test %d: got %s\n", i, debugstr_w(buf)); + } + + success = SetEnvironmentVariableW(L"TVAR", NULL); + ok(success, "SetEnvironmentVariableW failed with %ld\n", GetLastError()); +} + static void test_ExpandEnvironmentStringsA(void) { const char* value="Long long value"; const char* not_an_env_var="%NotAnEnvVar%"; char buf[256], buf1[256], buf2[0x8000]; DWORD ret_size, ret_size1; + int i; + DWORD ret; + BOOL success; + static const struct test_info + { + const char *input; + const char *expected_str; + int count_in; + int expected_count_out; + } tests[] = + { + /* 0 */ { "Long long value", "", 0, 17 }, + /* 1 */ { "Long long value", "", 1, 17 }, + /* 2 */ { "Long long value", "", 2, 17 }, + /* 3 */ { "Long long value", "", 3, 17 }, + /* 4 */ { "Long long value", "", 15, 17 }, + /* 5 */ { "Long long value", "", 16, 17 }, + /* 6 */ { "Long long value", "Long long value", 17, 16 }, + /* 7 */ { "%TVAR% long long", "", 0, 16 }, + /* 8 */ { "%TVAR% long long", "", 1, 16 }, + /* 9 */ { "%TVAR% long long", "", 2, 16 }, + /* 10 */ { "%TVAR% long long", "", 4, 16 }, + /* 11 */ { "%TVAR% long long", "", 5, 16 }, + /* 12 */ { "%TVAR% long long", "", 6, 16 }, + /* 13 */ { "%TVAR% long long", "", 7, 16 }, + /* 14 */ { "%TVAR% long long", "", 15, 16 }, + /* 15 */ { "%TVAR% long long", "WINE long long", 16, 15 }, + /* 16 */ { "%TVAR%%TVAR% long", "", 4, 15 }, + /* 17 */ { "%TVAR%%TVAR% long", "", 5, 15 }, + /* 18 */ { "%TVAR%%TVAR% long", "", 6, 15 }, + /* 19 */ { "%TVAR%%TVAR% long", "", 8, 15 }, + /* 20 */ { "%TVAR%%TVAR% long", "", 9, 15 }, + /* 21 */ { "%TVAR%%TVAR% long", "", 10, 15 }, + /* 22 */ { "%TVAR%%TVAR% long", "", 14, 15 }, + /* 23 */ { "%TVAR%%TVAR% long", "WINEWINE long", 15, 14 }, + /* 24 */ { "%TVAR% %TVAR% long", "", 5, 16 }, + /* 25 */ { "%TVAR% %TVAR% long", "", 6, 16 }, + /* 26 */ { "%TVAR% %TVAR% long", "", 8, 16 }, + /* 27 */ { "%TVAR% %TVAR% long", "", 9, 16 }, + /* 28 */ { "%TVAR% %TVAR% long", "", 10, 16 }, + /* 29 */ { "%TVAR% %TVAR% long", "", 11, 16 }, + /* 30 */ { "%TVAR% %TVAR% long", "", 12, 16 }, + /* 31 */ { "%TVAR% %TVAR% long", "", 14, 16 }, + /* 32 */ { "%TVAR% %TVAR% long", "", 15, 16 }, + /* 33 */ { "%TVAR% %TVAR% long", "WINE WINE long", 16, 15 }, + /* 34 */ { "%TVAR2% long long", "", 1, 19 }, + /* 35 */ { "%TVAR2% long long", "", 2, 19 }, + /* 36 */ { "%TVAR2% long long", "", 4, 19 }, + /* 37 */ { "%TVAR2% long long", "", 7, 19 }, + /* 38 */ { "%TVAR2% long long", "", 8, 19 }, + /* 39 */ { "%TVAR2% long long", "", 9, 19 }, + /* 40 */ { "%TVAR2% long long", "", 10, 19 }, + /* 41 */ { "%TVAR2% long long", "", 18, 19 }, + /* 42 */ { "%TVAR2% long long", "%TVAR2% long long", 19, 18 }, + /* 43 */ { "%TVAR long long", "", 1, 17 }, + /* 44 */ { "%TVAR long long", "", 2, 17 }, + /* 45 */ { "%TVAR long long", "", 3, 17 }, + /* 46 */ { "%TVAR long long", "", 15, 17 }, + /* 47 */ { "%TVAR long long", "", 16, 17 }, + /* 48 */ { "%TVAR long long", "%TVAR long long", 17, 16 }, + }; SetEnvironmentVariableA("EnvVar", value); ret_size = ExpandEnvironmentStringsA(NULL, buf1, sizeof(buf1)); ok(ret_size == 1 || ret_size == 0 /* Win9x */ || ret_size == 2 /* NT4 */, - "ExpandEnvironmentStrings returned %d\n", ret_size); + "ExpandEnvironmentStrings returned %ld\n", ret_size); /* Try to get the required buffer size 'the natural way' */ strcpy(buf, "%EnvVar%"); @@ -301,7 +557,7 @@ static void test_ExpandEnvironmentStringsA(void) ret_size == (strlen(value)+1)*2 || /* NT4 */ ret_size == strlen(value)+2 || /* win2k, XP, win2k3 */ ret_size == 0 /* Win95 */, - "ExpandEnvironmentStrings returned %d instead of %d, %d or %d\n", + "ExpandEnvironmentStrings returned %ld instead of %d, %d or %d\n", ret_size, lstrlenA(value)+1, lstrlenA(value)+2, 0); /* Again, side-stepping the Win95 bug */ @@ -309,7 +565,7 @@ static void test_ExpandEnvironmentStringsA(void) /* v5.1.2600.2945 (XP SP2) returns len + 2 here! */ ok(ret_size == strlen(value)+1 || ret_size == strlen(value)+2 || ret_size == (strlen(value)+1)*2 /* NT4 */, - "ExpandEnvironmentStrings returned %d instead of %d\n", + "ExpandEnvironmentStrings returned %ld instead of %d\n", ret_size, lstrlenA(value)+1); /* Try with a buffer that's too small */ @@ -317,7 +573,7 @@ static void test_ExpandEnvironmentStringsA(void) /* v5.1.2600.2945 (XP SP2) returns len + 2 here! */ ok(ret_size == strlen(value)+1 || ret_size == strlen(value)+2 || ret_size == (strlen(value)+1)*2 /* NT4 */, - "ExpandEnvironmentStrings returned %d instead of %d\n", + "ExpandEnvironmentStrings returned %ld instead of %d\n", ret_size, lstrlenA(value)+1); /* Try with a buffer of just the right size */ @@ -325,7 +581,7 @@ static void test_ExpandEnvironmentStringsA(void) ret_size = ExpandEnvironmentStringsA(buf, buf1, ret_size); ok(ret_size == strlen(value)+1 || ret_size == strlen(value)+2 || ret_size == (strlen(value)+1)*2 /* NT4 */, - "ExpandEnvironmentStrings returned %d instead of %d\n", + "ExpandEnvironmentStrings returned %ld instead of %d\n", ret_size, lstrlenA(value)+1); ok(!strcmp(buf1, value), "ExpandEnvironmentStrings returned [%s]\n", buf1); @@ -334,20 +590,21 @@ static void test_ExpandEnvironmentStringsA(void) ret_size = ExpandEnvironmentStringsA(buf, buf1, sizeof(buf1)); ok(ret_size == strlen(not_an_env_var)+1 || ret_size == (strlen(not_an_env_var)+1)*2 /* NT4 */, - "ExpandEnvironmentStrings returned %d instead of %d\n", ret_size, lstrlenA(not_an_env_var)+1); + "ExpandEnvironmentStrings returned %ld instead of %d\n", ret_size, lstrlenA(not_an_env_var)+1); ok(!strcmp(buf1, not_an_env_var), "ExpandEnvironmentStrings returned [%s]\n", buf1); /* test a large destination size */ strcpy(buf, "12345"); ret_size = ExpandEnvironmentStringsA(buf, buf2, sizeof(buf2)); - ok(!strcmp(buf, buf2), "ExpandEnvironmentStrings failed %s vs %s. ret_size = %d\n", buf, buf2, ret_size); + ok(!strcmp(buf, buf2), "ExpandEnvironmentStrings failed %s vs %s. ret_size = %ld\n", buf, buf2, ret_size); + SetLastError(0xdeadbeef); ret_size1 = GetWindowsDirectoryA(buf1,256); ok ((ret_size1 >0) && (ret_size1<256), "GetWindowsDirectory Failed\n"); ret_size = ExpandEnvironmentStringsA("%SystemRoot%",buf,sizeof(buf)); if (ERROR_ENVVAR_NOT_FOUND != GetLastError()) { - ok(!strcmp(buf, buf1), "ExpandEnvironmentStrings failed %s vs %s. ret_size = %d\n", buf, buf1, ret_size); + ok(!strcmp(buf, buf1), "ExpandEnvironmentStrings failed %s vs %s. ret_size = %ld\n", buf, buf1, ret_size); } /* Try with a variable that references another */ @@ -357,11 +614,60 @@ static void test_ExpandEnvironmentStringsA(void) ret_size = ExpandEnvironmentStringsA(buf, buf1, sizeof(buf1)); ok(ret_size == strlen(buf2)+1 || ret_size == (strlen(buf2)+1)*2 /* NT4 */, - "ExpandEnvironmentStrings returned %d instead of %d\n", ret_size, lstrlenA(buf2)+1); + "ExpandEnvironmentStrings returned %ld instead of %d\n", ret_size, lstrlenA(buf2)+1); ok(!strcmp(buf1, buf2), "ExpandEnvironmentStrings returned [%s]\n", buf1); SetEnvironmentVariableA("IndirectVar", NULL); SetEnvironmentVariableA("EnvVar", NULL); + + success = SetEnvironmentVariableA("TVAR", "WINE"); + ok(success, "SetEnvironmentVariableA failed with %ld\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = ExpandEnvironmentStringsW(L"Long long value", NULL, 0); + ok(ret == 16, "got %lu\n", ret); + ok(GetLastError() == 0xdeadbeef, "got last error %ld\n", GetLastError()); + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + const struct test_info *test = &tests[i]; + + SetLastError(0xdeadbeef); + strcpy(buf, "abcdefghijklmnopqrstuv"); + ret = ExpandEnvironmentStringsA(test->input, buf, test->count_in); + ok(ret == test->expected_count_out, "Test %d: got %lu\n", i, ret); + ok(GetLastError() == 0xdeadbeef, "Test %d: got last error %ld\n", i, GetLastError()); + ok(!strcmp(buf, test->expected_str), "Test %d: got %s\n", i, debugstr_a(buf)); + } + + success = SetEnvironmentVariableA("TVAR", NULL); + ok(success, "SetEnvironmentVariableA failed with %ld\n", GetLastError()); + + if (GetACP() == 932) /* shift-jis */ + { + const char *japanese_test = "\x88\xEA\x93\xF1\x8E\x4F\x8E\x6C\x8C\xDC\x98\x5A\x8E\xB5\x94\xAA\x8B\xE3"; /* Japanese Kanji for "one" to "nine", in shift-jis */ + int japanese_len = strlen(japanese_test); + + SetLastError(0xdeadbeef); + ret_size = ExpandEnvironmentStringsA(japanese_test, NULL, 0); + ok(GetLastError() == 0xdeadbeef, "got last error %ld\n", GetLastError()); + ok(ret_size >= japanese_len, "Needed at least %d, got %lu\n", japanese_len, ret_size); + + SetLastError(0xdeadbeef); + ret_size = ExpandEnvironmentStringsA(japanese_test, buf, ret_size); + ok(GetLastError() == 0xdeadbeef, "got last error %ld\n", GetLastError()); + ok(ret_size >= japanese_len, "Needed at least %d, got %lu\n", japanese_len, ret_size); + ok(!strcmp(buf, japanese_test), "Got %s\n", debugstr_a(buf)); + + SetLastError(0xdeadbeef); + ret_size = ExpandEnvironmentStringsA(japanese_test, buf, japanese_len / 2); /* Buffer too small */ + ok(GetLastError() == 0xdeadbeef, "got last error %ld\n", GetLastError()); + ok(ret_size >= japanese_len, "Needed at least %d, got %lu\n", japanese_len, ret_size); + } + else + { + skip("Skipping japanese language tests\n"); + } } static void test_GetComputerName(void) @@ -374,29 +680,30 @@ static void test_GetComputerName(void) int name_len; size = 0; + SetLastError(0xdeadbeef); ret = GetComputerNameA((LPSTR)0xdeadbeef, &size); error = GetLastError(); - ok(!ret && error == ERROR_BUFFER_OVERFLOW, "GetComputerNameA should have failed with ERROR_BUFFER_OVERFLOW instead of %d\n", error); + ok(!ret && error == ERROR_BUFFER_OVERFLOW, "GetComputerNameA should have failed with ERROR_BUFFER_OVERFLOW instead of %ld\n", error); /* Only Vista returns the computer name length as documented in the MSDN */ if (size != 0) { size++; /* nul terminating character */ name = HeapAlloc(GetProcessHeap(), 0, size * sizeof(name[0])); - ok(name != NULL, "HeapAlloc failed with error %d\n", GetLastError()); + ok(name != NULL, "HeapAlloc failed with error %ld\n", GetLastError()); ret = GetComputerNameA(name, &size); - ok(ret, "GetComputerNameA failed with error %d\n", GetLastError()); + ok(ret, "GetComputerNameA failed with error %ld\n", GetLastError()); HeapFree(GetProcessHeap(), 0, name); } size = MAX_COMPUTERNAME_LENGTH + 1; name = HeapAlloc(GetProcessHeap(), 0, size * sizeof(name[0])); - ok(name != NULL, "HeapAlloc failed with error %d\n", GetLastError()); + ok(name != NULL, "HeapAlloc failed with error %ld\n", GetLastError()); ret = GetComputerNameA(name, &size); - ok(ret, "GetComputerNameA failed with error %d\n", GetLastError()); + ok(ret, "GetComputerNameA failed with error %ld\n", GetLastError()); trace("computer name is \"%s\"\n", name); name_len = strlen(name); - ok(size == name_len, "size should be same as length, name_len=%d, size=%d\n", name_len, size); + ok(size == name_len, "size should be same as length, name_len=%d, size=%ld\n", name_len, size); HeapFree(GetProcessHeap(), 0, name); size = 0; @@ -407,12 +714,12 @@ static void test_GetComputerName(void) win_skip("GetComputerNameW is not implemented\n"); else { - ok(!ret && error == ERROR_BUFFER_OVERFLOW, "GetComputerNameW should have failed with ERROR_BUFFER_OVERFLOW instead of %d\n", error); + ok(!ret && error == ERROR_BUFFER_OVERFLOW, "GetComputerNameW should have failed with ERROR_BUFFER_OVERFLOW instead of %ld\n", error); size++; /* nul terminating character */ nameW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(nameW[0])); - ok(nameW != NULL, "HeapAlloc failed with error %d\n", GetLastError()); + ok(nameW != NULL, "HeapAlloc failed with error %ld\n", GetLastError()); ret = GetComputerNameW(nameW, &size); - ok(ret, "GetComputerNameW failed with error %d\n", GetLastError()); + ok(ret, "GetComputerNameW failed with error %ld\n", GetLastError()); HeapFree(GetProcessHeap(), 0, nameW); } } @@ -433,10 +740,11 @@ static void test_GetComputerNameExA(void) } size = 0; + SetLastError(0xdeadbeef); ret = pGetComputerNameExA(ComputerNameDnsDomain, (LPSTR)0xdeadbeef, &size); error = GetLastError(); ok(ret == 0, "Expected 0, got %d\n", ret); - ok(error == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", error); + ok(error == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %ld\n", error); /* size is not set in win2k */ if (size == 0) @@ -445,57 +753,67 @@ static void test_GetComputerNameExA(void) size = MAX_COMP_NAME; } name = HeapAlloc(GetProcessHeap(), 0, size * sizeof(name[0])); - ok(name != NULL, "HeapAlloc failed with error %d\n", GetLastError()); + ok(name != NULL, "HeapAlloc failed with error %ld\n", GetLastError()); ret = pGetComputerNameExA(ComputerNameDnsDomain, name, &size); - ok(ret, "GetComputerNameExA(ComputerNameDnsDomain) failed with error %d\n", GetLastError()); + ok(ret, "GetComputerNameExA(ComputerNameDnsDomain) failed with error %ld\n", GetLastError()); trace("domain name is \"%s\"\n", name); HeapFree(GetProcessHeap(), 0, name); size = 0; + SetLastError(0xdeadbeef); ret = pGetComputerNameExA(ComputerNameDnsFullyQualified, (LPSTR)0xdeadbeef, &size); error = GetLastError(); ok(ret == 0, "Expected 0, got %d\n", ret); - ok(error == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", error); + ok(error == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %ld\n", error); /* size is not set in win2k */ if (size == 0) size = MAX_COMP_NAME; name = HeapAlloc(GetProcessHeap(), 0, size * sizeof(name[0])); - ok(name != NULL, "HeapAlloc failed with error %d\n", GetLastError()); + ok(name != NULL, "HeapAlloc failed with error %ld\n", GetLastError()); ret = pGetComputerNameExA(ComputerNameDnsFullyQualified, name, &size); - ok(ret, "GetComputerNameExA(ComputerNameDnsFullyQualified) failed with error %d\n", GetLastError()); + ok(ret, "GetComputerNameExA(ComputerNameDnsFullyQualified) failed with error %ld\n", GetLastError()); trace("fully qualified hostname is \"%s\"\n", name); HeapFree(GetProcessHeap(), 0, name); size = 0; + SetLastError(0xdeadbeef); ret = pGetComputerNameExA(ComputerNameDnsHostname, (LPSTR)0xdeadbeef, &size); error = GetLastError(); ok(ret == 0, "Expected 0, got %d\n", ret); - ok(error == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", error); + ok(error == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %ld\n", error); /* size is not set in win2k */ if (size == 0) size = MAX_COMP_NAME; name = HeapAlloc(GetProcessHeap(), 0, size * sizeof(name[0])); - ok(name != NULL, "HeapAlloc failed with error %d\n", GetLastError()); + ok(name != NULL, "HeapAlloc failed with error %ld\n", GetLastError()); ret = pGetComputerNameExA(ComputerNameDnsHostname, name, &size); - ok(ret, "GetComputerNameExA(ComputerNameDnsHostname) failed with error %d\n", GetLastError()); + ok(ret, "GetComputerNameExA(ComputerNameDnsHostname) failed with error %ld\n", GetLastError()); trace("hostname is \"%s\"\n", name); HeapFree(GetProcessHeap(), 0, name); size = 0; + SetLastError(0xdeadbeef); ret = pGetComputerNameExA(ComputerNameNetBIOS, (LPSTR)0xdeadbeef, &size); error = GetLastError(); ok(ret == 0, "Expected 0, got %d\n", ret); - ok(error == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", error); + ok(error == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %ld\n", error); + + size = 0; + SetLastError(0xdeadbeef); + ret = pGetComputerNameExA(ComputerNameNetBIOS, NULL, &size); + error = GetLastError(); + ok(ret == 0, "Expected 0, got %d\n", ret); + ok(error == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %ld\n", error); /* size is not set in win2k */ if (size == 0) size = MAX_COMP_NAME; name = HeapAlloc(GetProcessHeap(), 0, size * sizeof(name[0])); - ok(name != NULL, "HeapAlloc failed with error %d\n", GetLastError()); + ok(name != NULL, "HeapAlloc failed with error %ld\n", GetLastError()); ret = pGetComputerNameExA(ComputerNameNetBIOS, name, &size); - ok(ret, "GetComputerNameExA(ComputerNameNetBIOS) failed with error %d\n", GetLastError()); + ok(ret, "GetComputerNameExA(ComputerNameNetBIOS) failed with error %ld\n", GetLastError()); trace("NetBIOS name is \"%s\"\n", name); HeapFree(GetProcessHeap(), 0, name); } @@ -514,44 +832,151 @@ static void test_GetComputerNameExW(void) } size = 0; + SetLastError(0xdeadbeef); ret = pGetComputerNameExW(ComputerNameDnsDomain, (LPWSTR)0xdeadbeef, &size); error = GetLastError(); - ok(!ret && error == ERROR_MORE_DATA, "GetComputerNameExW should have failed with ERROR_MORE_DATA instead of %d\n", error); + ok(!ret && error == ERROR_MORE_DATA, "GetComputerNameExW should have failed with ERROR_MORE_DATA instead of %ld\n", error); nameW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(nameW[0])); - ok(nameW != NULL, "HeapAlloc failed with error %d\n", GetLastError()); + ok(nameW != NULL, "HeapAlloc failed with error %ld\n", GetLastError()); ret = pGetComputerNameExW(ComputerNameDnsDomain, nameW, &size); - ok(ret, "GetComputerNameExW(ComputerNameDnsDomain) failed with error %d\n", GetLastError()); + ok(ret, "GetComputerNameExW(ComputerNameDnsDomain) failed with error %ld\n", GetLastError()); HeapFree(GetProcessHeap(), 0, nameW); size = 0; + SetLastError(0xdeadbeef); ret = pGetComputerNameExW(ComputerNameDnsFullyQualified, (LPWSTR)0xdeadbeef, &size); error = GetLastError(); - ok(!ret && error == ERROR_MORE_DATA, "GetComputerNameExW should have failed with ERROR_MORE_DATA instead of %d\n", error); + ok(!ret && error == ERROR_MORE_DATA, "GetComputerNameExW should have failed with ERROR_MORE_DATA instead of %ld\n", error); nameW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(nameW[0])); - ok(nameW != NULL, "HeapAlloc failed with error %d\n", GetLastError()); + ok(nameW != NULL, "HeapAlloc failed with error %ld\n", GetLastError()); ret = pGetComputerNameExW(ComputerNameDnsFullyQualified, nameW, &size); - ok(ret, "GetComputerNameExW(ComputerNameDnsFullyQualified) failed with error %d\n", GetLastError()); + ok(ret, "GetComputerNameExW(ComputerNameDnsFullyQualified) failed with error %ld\n", GetLastError()); HeapFree(GetProcessHeap(), 0, nameW); size = 0; + SetLastError(0xdeadbeef); ret = pGetComputerNameExW(ComputerNameDnsHostname, (LPWSTR)0xdeadbeef, &size); error = GetLastError(); - ok(!ret && error == ERROR_MORE_DATA, "GetComputerNameExW should have failed with ERROR_MORE_DATA instead of %d\n", error); + ok(!ret && error == ERROR_MORE_DATA, "GetComputerNameExW should have failed with ERROR_MORE_DATA instead of %ld\n", error); nameW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(nameW[0])); - ok(nameW != NULL, "HeapAlloc failed with error %d\n", GetLastError()); + ok(nameW != NULL, "HeapAlloc failed with error %ld\n", GetLastError()); ret = pGetComputerNameExW(ComputerNameDnsHostname, nameW, &size); - ok(ret, "GetComputerNameExW(ComputerNameDnsHostname) failed with error %d\n", GetLastError()); + ok(ret, "GetComputerNameExW(ComputerNameDnsHostname) failed with error %ld\n", GetLastError()); HeapFree(GetProcessHeap(), 0, nameW); size = 0; + SetLastError(0xdeadbeef); ret = pGetComputerNameExW(ComputerNameNetBIOS, (LPWSTR)0xdeadbeef, &size); error = GetLastError(); - ok(!ret && error == ERROR_MORE_DATA, "GetComputerNameExW should have failed with ERROR_MORE_DATA instead of %d\n", error); + ok(!ret && error == ERROR_MORE_DATA, "GetComputerNameExW should have failed with ERROR_MORE_DATA instead of %ld\n", error); nameW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(nameW[0])); - ok(nameW != NULL, "HeapAlloc failed with error %d\n", GetLastError()); + ok(nameW != NULL, "HeapAlloc failed with error %ld\n", GetLastError()); ret = pGetComputerNameExW(ComputerNameNetBIOS, nameW, &size); - ok(ret, "GetComputerNameExW(ComputerNameNetBIOS) failed with error %d\n", GetLastError()); + ok(ret, "GetComputerNameExW(ComputerNameNetBIOS) failed with error %ld\n", GetLastError()); HeapFree(GetProcessHeap(), 0, nameW); + + size = 0; + SetLastError(0xdeadbeef); + ret = pGetComputerNameExW(ComputerNameNetBIOS, NULL, &size); + error = GetLastError(); + ok(!ret && error == ERROR_MORE_DATA, "GetComputerNameExW should have failed with ERROR_MORE_DATA instead of %ld\n", error); +} + +static void test_GetEnvironmentStringsW(void) +{ + PWCHAR env1; + PWCHAR env2; + + env1 = GetEnvironmentStringsW(); + env2 = GetEnvironmentStringsW(); + ok(env1 != env2 || + broken(env1 == env2), /* NT <= 5.1 */ + "should return different copies\n"); + FreeEnvironmentStringsW(env1); + FreeEnvironmentStringsW(env2); +} + +#define copy_string(dst, src) memcpy(dst, src, sizeof(src)) + +static void check_env_var_(int line, const char *var, const char *value) +{ + char buffer[20]; + DWORD size = GetEnvironmentVariableA(var, buffer, sizeof(buffer)); + if (value) + { + ok_(__FILE__, line)(size == strlen(value), "wrong size %lu\n", size); + ok_(__FILE__, line)(!strcmp(buffer, value), "wrong value %s\n", debugstr_a(buffer)); + } + else + { + ok_(__FILE__, line)(!size, "wrong size %lu\n", size); + ok_(__FILE__, line)(GetLastError() == ERROR_ENVVAR_NOT_FOUND, "got error %lu\n", GetLastError()); + } +} +#define check_env_var(a, b) check_env_var_(__LINE__, a, b) + +static void test_SetEnvironmentStrings(void) +{ + static const WCHAR testenv[] = L"testenv1=unus\0testenv3=tres\0"; + WCHAR env[200]; + WCHAR *old_env; + BOOL ret; + + if (!pSetEnvironmentStringsW) + { + win_skip("SetEnvironmentStringsW() is not available\n"); + return; + } + + ret = SetEnvironmentVariableA("testenv1", "heis"); + ok(ret, "got error %lu\n", GetLastError()); + ret = SetEnvironmentVariableA("testenv2", "dyo"); + ok(ret, "got error %lu\n", GetLastError()); + + old_env = GetEnvironmentStringsW(); + + memcpy(env, testenv, sizeof(testenv)); + ret = pSetEnvironmentStringsW(env); + ok(ret, "got error %lu\n", GetLastError()); + ok(!memcmp(env, testenv, sizeof(testenv)), "input parameter should not be changed\n"); + + check_env_var("testenv1", "unus"); + check_env_var("testenv2", NULL); + check_env_var("testenv3", "tres"); + check_env_var("PATH", NULL); + + ret = pSetEnvironmentStringsW(old_env); + ok(ret, "got error %lu\n", GetLastError()); + + check_env_var("testenv1", "heis"); + check_env_var("testenv2", "dyo"); + check_env_var("testenv3", NULL); + + SetEnvironmentVariableA("testenv1", NULL); + SetEnvironmentVariableA("testenv2", NULL); + + copy_string(env, L"testenv\0"); + SetLastError(0xdeadbeef); + ret = pSetEnvironmentStringsW(env); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError()); + + copy_string(env, L"=unus\0"); + SetLastError(0xdeadbeef); + ret = pSetEnvironmentStringsW(env); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError()); + + copy_string(env, L"one=two=three four=five\0"); + ret = pSetEnvironmentStringsW(env); + ok(ret, "got error %lu\n", GetLastError()); + + check_env_var("one", "two=three four=five"); + + ret = pSetEnvironmentStringsW(old_env); + ok(ret, "got error %lu\n", GetLastError()); + ret = FreeEnvironmentStringsW(old_env); + ok(ret, "got error %lu\n", GetLastError()); } START_TEST(environ) @@ -561,8 +986,12 @@ START_TEST(environ) test_Predefined(); test_GetSetEnvironmentVariableA(); test_GetSetEnvironmentVariableW(); + test_GetSetEnvironmentVariableAW(); + test_ExpandEnvironmentStringsW(); test_ExpandEnvironmentStringsA(); test_GetComputerName(); test_GetComputerNameExA(); test_GetComputerNameExW(); + test_GetEnvironmentStringsW(); + test_SetEnvironmentStrings(); } diff --git a/modules/rostests/winetests/kernel32/fiber.c b/modules/rostests/winetests/kernel32/fiber.c index 7501165dc87..6686e9c855d 100644 --- a/modules/rostests/winetests/kernel32/fiber.c +++ b/modules/rostests/winetests/kernel32/fiber.c @@ -18,7 +18,13 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include + +#include +#define WIN32_NO_STATUS +#include #include "wine/test.h" +#include static LPVOID (WINAPI *pCreateFiber)(SIZE_T,LPFIBER_START_ROUTINE,LPVOID); static LPVOID (WINAPI *pConvertThreadToFiber)(LPVOID); @@ -32,7 +38,13 @@ static DWORD (WINAPI *pFlsAlloc)(PFLS_CALLBACK_FUNCTION); static BOOL (WINAPI *pFlsFree)(DWORD); static PVOID (WINAPI *pFlsGetValue)(DWORD); static BOOL (WINAPI *pFlsSetValue)(DWORD,PVOID); - +static void (WINAPI *pRtlAcquirePebLock)(void); +static void (WINAPI *pRtlReleasePebLock)(void); +static NTSTATUS (WINAPI *pRtlFlsAlloc)(PFLS_CALLBACK_FUNCTION,DWORD*); +static NTSTATUS (WINAPI *pRtlFlsFree)(ULONG); +static NTSTATUS (WINAPI *pRtlFlsSetValue)(ULONG,void *); +static NTSTATUS (WINAPI *pRtlFlsGetValue)(ULONG,void **); +static void (WINAPI *pRtlProcessFlsData)(void *fls_data, ULONG flags); static void *fibers[3]; static BYTE testparam = 185; static DWORD fls_index_to_set = FLS_OUT_OF_INDEXES; @@ -44,6 +56,7 @@ static int cbCount = 0; static VOID init_funcs(void) { HMODULE hKernel32 = GetModuleHandleA("kernel32.dll"); + HMODULE hntdll = GetModuleHandleA("ntdll.dll"); #define X(f) p##f = (void*)GetProcAddress(hKernel32, #f); X(CreateFiber); @@ -59,6 +72,17 @@ static VOID init_funcs(void) X(FlsGetValue); X(FlsSetValue); #undef X + +#define X(f) p##f = (void*)GetProcAddress(hntdll, #f); + X(RtlFlsAlloc); + X(RtlFlsFree); + X(RtlFlsSetValue); + X(RtlFlsGetValue); + X(RtlProcessFlsData); + X(RtlAcquirePebLock); + X(RtlReleasePebLock); +#undef X + } static VOID WINAPI FiberLocalStorageProc(PVOID lpFlsData) @@ -72,6 +96,10 @@ static VOID WINAPI FiberLocalStorageProc(PVOID lpFlsData) static VOID WINAPI FiberMainProc(LPVOID lpFiberParameter) { BYTE *tparam = (BYTE *)lpFiberParameter; + TEB *teb = NtCurrentTeb(); + + ok(!teb->FlsSlots, "Got unexpected FlsSlots %p.\n", teb->FlsSlots); + fiberCount++; ok(*tparam == 185, "Parameterdata expected not to be changed\n"); if (fls_index_to_set != FLS_OUT_OF_INDEXES) @@ -79,28 +107,39 @@ static VOID WINAPI FiberMainProc(LPVOID lpFiberParameter) void* ret; BOOL bret; + SetLastError( 0xdeadbeef ); ret = pFlsGetValue(fls_index_to_set); ok(ret == NULL, "FlsGetValue returned %p, expected NULL\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got unexpected error %lu.\n", GetLastError()); /* Set the FLS value */ bret = pFlsSetValue(fls_index_to_set, fls_value_to_set); - ok(bret, "FlsSetValue failed with error %u\n", GetLastError()); + ok(bret, "FlsSetValue failed with error %lu\n", GetLastError()); + + ok(!!teb->FlsSlots, "Got unexpected FlsSlots %p.\n", teb->FlsSlots); /* Verify that FlsGetValue retrieves the value set by FlsSetValue */ SetLastError( 0xdeadbeef ); ret = pFlsGetValue(fls_index_to_set); ok(ret == fls_value_to_set, "FlsGetValue returned %p, expected %p\n", ret, fls_value_to_set); - ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue error %u\n", GetLastError()); + ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue error %lu\n", GetLastError()); } pSwitchToFiber(fibers[0]); } static void test_ConvertThreadToFiber(void) { + void *ret; + if (pConvertThreadToFiber) { fibers[0] = pConvertThreadToFiber(&testparam); - ok(fibers[0] != NULL, "ConvertThreadToFiber failed with error %u\n", GetLastError()); + ok(fibers[0] != NULL, "ConvertThreadToFiber failed with error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = pConvertThreadToFiber(&testparam); + ok(!ret, "Got non NULL ret.\n"); + ok(GetLastError() == ERROR_ALREADY_FIBER, "Got unexpected error %lu.\n", GetLastError()); } else { @@ -110,10 +149,17 @@ static void test_ConvertThreadToFiber(void) static void test_ConvertThreadToFiberEx(void) { + void *ret; + if (pConvertThreadToFiberEx) { fibers[0] = pConvertThreadToFiberEx(&testparam, 0); - ok(fibers[0] != NULL, "ConvertThreadToFiberEx failed with error %u\n", GetLastError()); + ok(fibers[0] != NULL, "ConvertThreadToFiberEx failed with error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = pConvertThreadToFiberEx(&testparam, 0); + ok(!ret, "Got non NULL ret.\n"); + ok(GetLastError() == ERROR_ALREADY_FIBER, "Got unexpected error %lu.\n", GetLastError()); } else { @@ -126,7 +172,7 @@ static void test_ConvertFiberToThread(void) if (pConvertFiberToThread) { BOOL ret = pConvertFiberToThread(); - ok(ret, "ConvertFiberToThread failed with error %u\n", GetLastError()); + ok(ret, "ConvertFiberToThread failed with error %lu\n", GetLastError()); } else { @@ -138,7 +184,7 @@ static void test_FiberHandling(void) { fiberCount = 0; fibers[0] = pCreateFiber(0,FiberMainProc,&testparam); - ok(fibers[0] != NULL, "CreateFiber failed with error %u\n", GetLastError()); + ok(fibers[0] != NULL, "CreateFiber failed with error %lu\n", GetLastError()); pDeleteFiber(fibers[0]); test_ConvertThreadToFiber(); @@ -149,7 +195,7 @@ static void test_FiberHandling(void) test_ConvertThreadToFiber(); fibers[1] = pCreateFiber(0,FiberMainProc,&testparam); - ok(fibers[1] != NULL, "CreateFiber failed with error %u\n", GetLastError()); + ok(fibers[1] != NULL, "CreateFiber failed with error %lu\n", GetLastError()); pSwitchToFiber(fibers[1]); ok(fiberCount == 1, "Wrong fiber count: %d\n", fiberCount); @@ -158,7 +204,7 @@ static void test_FiberHandling(void) if (pCreateFiberEx) { fibers[1] = pCreateFiberEx(0,0,0,FiberMainProc,&testparam); - ok(fibers[1] != NULL, "CreateFiberEx failed with error %u\n", GetLastError()); + ok(fibers[1] != NULL, "CreateFiberEx failed with error %lu\n", GetLastError()); pSwitchToFiber(fibers[1]); ok(fiberCount == 2, "Wrong fiber count: %d\n", fiberCount); @@ -171,11 +217,79 @@ static void test_FiberHandling(void) if (pIsThreadAFiber) ok(!pIsThreadAFiber(), "IsThreadAFiber reported TRUE\n"); } +#define FLS_TEST_INDEX_COUNT 4096 + +static unsigned int check_linked_list(const LIST_ENTRY *le, const LIST_ENTRY *search_entry, unsigned int *index_found) +{ + unsigned int count = 0; + LIST_ENTRY *entry; + + *index_found = ~0; + + for (entry = le->Flink; entry != le; entry = entry->Flink) + { + if (entry == search_entry) + { + ok(*index_found == ~0, "Duplicate list entry.\n"); + *index_found = count; + } + ++count; + } + return count; +} + +static unsigned int test_fls_callback_call_count; + +static void WINAPI test_fls_callback(void *data) +{ + ++test_fls_callback_call_count; +} + +static unsigned int test_fls_chunk_size(unsigned int chunk_index) +{ + return 0x10 << chunk_index; +} + +static unsigned int test_fls_chunk_index_from_index(unsigned int index, unsigned int *index_in_chunk) +{ + unsigned int chunk_index = 0; + + while (index >= test_fls_chunk_size(chunk_index)) + index -= test_fls_chunk_size(chunk_index++); + + *index_in_chunk = index; + return chunk_index; +} + +static HANDLE test_fiberlocalstorage_peb_locked_event; +static HANDLE test_fiberlocalstorage_done_event; + + +static DWORD WINAPI test_FiberLocalStorage_thread(void *arg) +{ + pRtlAcquirePebLock(); + SetEvent(test_fiberlocalstorage_peb_locked_event); + WaitForSingleObject(test_fiberlocalstorage_done_event, INFINITE); + pRtlReleasePebLock(); + return 0; +} + static void test_FiberLocalStorage(void) { - DWORD fls, fls_2; - BOOL ret; + static DWORD fls_indices[FLS_TEST_INDEX_COUNT]; + unsigned int i, j, count, entry_count, index; + LIST_ENTRY *fls_list_head, saved_entry; + TEB_FLS_DATA *fls_data, *new_fls_data; + GLOBAL_FLS_DATA *g_fls_data; + DWORD fls, fls_2, result; + TEB *teb = NtCurrentTeb(); + PEB *peb = teb->Peb; + NTSTATUS status; + HANDLE hthread; + ULONG index2; + SIZE_T size; void* val; + BOOL ret; if (!pFlsAlloc || !pFlsSetValue || !pFlsGetValue || !pFlsFree) { @@ -183,6 +297,271 @@ static void test_FiberLocalStorage(void) return; } + if (pRtlFlsAlloc) + { + if (pRtlFlsGetValue) + { + status = pRtlFlsGetValue(0, NULL); + ok(status == STATUS_INVALID_PARAMETER, "Got unexpected status %#lx.\n", status); + } + else + { + win_skip("RtlFlsGetValue is not available.\n"); + } + + for (i = 0; i < FLS_TEST_INDEX_COUNT; ++i) + { + fls_indices[i] = 0xdeadbeef; + status = pRtlFlsAlloc(test_fls_callback, &fls_indices[i]); + ok(!status || status == STATUS_NO_MEMORY, "Got unexpected status %#lx.\n", status); + if (status) + { + ok(fls_indices[i] == 0xdeadbeef, "Got unexpected index %#lx.\n", fls_indices[i]); + break; + } + if (pRtlFlsSetValue) + { + status = pRtlFlsSetValue(fls_indices[i], (void *)(ULONG_PTR)(i + 1)); + ok(!status, "Got unexpected status %#lx.\n", status); + } + } + count = i; + + fls_data = teb->FlsSlots; + + /* FLS limits are increased since Win10 18312. */ + ok(count && (count <= 127 || (count > 4000 && count < 4096)), "Got unexpected count %u.\n", count); + +#if defined(__REACTOS__) && defined(_WIN64) + /* peb layout is different on ReactOS x64 */ + if (!is_reactos() && !peb->FlsCallback) +#else + if (!peb->FlsCallback) +#endif + { + ok(pRtlFlsSetValue && pRtlFlsGetValue, "Missing RtlFlsGetValue / RtlFlsSetValue.\n"); + ok(!peb->FlsBitmap, "Got unexpected FlsBitmap %p.\n", peb->FlsBitmap); + ok(!peb->FlsListHead.Flink && !peb->FlsListHead.Blink, "Got nonzero FlsListHead.\n"); + ok(!peb->FlsHighIndex, "Got unexpected FlsHighIndex %lu.\n", peb->FlsHighIndex); + + fls_list_head = fls_data->fls_list_entry.Flink; + + entry_count = check_linked_list(fls_list_head, &fls_data->fls_list_entry, &index); + ok(entry_count == 1, "Got unexpected count %u.\n", entry_count); + ok(!index, "Got unexpected index %u.\n", index); + + g_fls_data = CONTAINING_RECORD(fls_list_head, GLOBAL_FLS_DATA, fls_list_head); + + ok(g_fls_data->fls_high_index == 0xfef, "Got unexpected fls_high_index %#lx.\n", g_fls_data->fls_high_index); + + for (i = 0; i < 8; ++i) + { + ok(!!g_fls_data->fls_callback_chunks[i], "Got zero fls_callback_chunks[%u].\n", i); + ok(g_fls_data->fls_callback_chunks[i]->count == test_fls_chunk_size(i), + "Got unexpected g_fls_data->fls_callback_chunks[%u]->count %lu.\n", + i, g_fls_data->fls_callback_chunks[i]->count); + + size = HeapSize(GetProcessHeap(), 0, g_fls_data->fls_callback_chunks[i]); + ok(size == sizeof(ULONG_PTR) + sizeof(FLS_CALLBACK) * test_fls_chunk_size(i), + "Got unexpected size %p.\n", (void *)size); + + ok(!!fls_data->fls_data_chunks[i], "Got zero fls_data->fls_data_chunks[%u].\n", i); + ok(!fls_data->fls_data_chunks[i][0], "Got unexpected fls_data->fls_data_chunks[%u][0] %p.\n", + i, fls_data->fls_data_chunks[i][0]); + size = HeapSize(GetProcessHeap(), 0, fls_data->fls_data_chunks[i]); + ok(size == sizeof(void *) * (test_fls_chunk_size(i) + 1), "Got unexpected size %p.\n", (void *)size); + + if (!i) + { + ok(g_fls_data->fls_callback_chunks[0]->callbacks[0].callback == (void *)~(ULONG_PTR)0, + "Got unexpected callback %p.\n", + g_fls_data->fls_callback_chunks[0]->callbacks[0].callback); + } + + for (j = i ? 0 : fls_indices[0]; j < test_fls_chunk_size(i); ++j) + { + ok(!g_fls_data->fls_callback_chunks[i]->callbacks[j].unknown, + "Got unexpected unknown %p, i %u, j %u.\n", + g_fls_data->fls_callback_chunks[i]->callbacks[j].unknown, i, j); + ok(g_fls_data->fls_callback_chunks[i]->callbacks[j].callback == test_fls_callback, + "Got unexpected callback %p, i %u, j %u.\n", + g_fls_data->fls_callback_chunks[i]->callbacks[j].callback, i, j); + } + } + for (i = 0; i < count; ++i) + { + j = test_fls_chunk_index_from_index(fls_indices[i], &index); + ok(fls_data->fls_data_chunks[j][index + 1] == (void *)(ULONG_PTR)(i + 1), + "Got unexpected FLS value %p, i %u, j %u, index %u.\n", + fls_data->fls_data_chunks[j][index + 1], i, j, index); + } + j = test_fls_chunk_index_from_index(fls_indices[0x10], &index); + g_fls_data->fls_callback_chunks[j]->callbacks[index].callback = NULL; + status = pRtlFlsFree(fls_indices[0x10]); + ok(status == STATUS_INVALID_PARAMETER, "Got unexpected status %#lx.\n", status); + + g_fls_data->fls_callback_chunks[j]->callbacks[index].callback = test_fls_callback; + test_fls_callback_call_count = 0; + status = pRtlFlsFree(fls_indices[0x10]); + ok(!status, "Got unexpected status %#lx.\n", status); + ok(test_fls_callback_call_count == 1, "Got unexpected callback call count %u.\n", + test_fls_callback_call_count); + + ok(!fls_data->fls_data_chunks[j][0], "Got unexpected fls_data->fls_data_chunks[%u][0] %p.\n", + j, fls_data->fls_data_chunks[j][0]); + ok(!g_fls_data->fls_callback_chunks[j]->callbacks[index].callback, + "Got unexpected callback %p.\n", + g_fls_data->fls_callback_chunks[j]->callbacks[index].callback); + + fls_data->fls_data_chunks[j][index + 1] = (void *)(ULONG_PTR)0x28; + status = pRtlFlsAlloc(test_fls_callback, &index2); + ok(!status, "Got unexpected status %#lx.\n", status); + ok(index2 == fls_indices[0x10], "Got unexpected index %lu.\n", index2); + ok(fls_data->fls_data_chunks[j][index + 1] == (void *)(ULONG_PTR)0x28, "Got unexpected data %p.\n", + fls_data->fls_data_chunks[j][index + 1]); + + status = pRtlFlsSetValue(index2, (void *)(ULONG_PTR)0x11); + ok(!status, "Got unexpected status %#lx.\n", status); + + teb->FlsSlots = NULL; + + val = (void *)0xdeadbeef; + status = pRtlFlsGetValue(fls_indices[1], &val); + new_fls_data = teb->FlsSlots; + ok(status == STATUS_INVALID_PARAMETER, "Got unexpected status %#lx.\n", status); + ok(val == (void *)0xdeadbeef, "Got unexpected val %p.\n", val); + ok(!new_fls_data, "Got unexpected teb->FlsSlots %p.\n", new_fls_data); + + status = pRtlFlsSetValue(fls_indices[1], (void *)(ULONG_PTR)0x28); + new_fls_data = teb->FlsSlots; + ok(!status, "Got unexpected status %#lx.\n", status); + ok(!!new_fls_data, "Got unexpected teb->FlsSlots %p.\n", new_fls_data); + + entry_count = check_linked_list(fls_list_head, &fls_data->fls_list_entry, &index); + ok(entry_count == 2, "Got unexpected count %u.\n", entry_count); + ok(!index, "Got unexpected index %u.\n", index); + check_linked_list(fls_list_head, &new_fls_data->fls_list_entry, &index); + ok(index == 1, "Got unexpected index %u.\n", index); + + val = (void *)0xdeadbeef; + status = pRtlFlsGetValue(fls_indices[2], &val); + ok(!status, "Got unexpected status %#lx.\n", status); + ok(!val, "Got unexpected val %p.\n", val); + + + /* With bit 0 of flags set RtlProcessFlsData is removing FLS data from the linked list + * and calls FLS callbacks. With bit 1 set the memory is freed. The remaining bits do not seem + * to have any obvious effect. */ + for (i = 2; i < 32; ++i) + { + pRtlProcessFlsData(new_fls_data, 1 << i); + size = HeapSize(GetProcessHeap(), 0, new_fls_data); + ok(size == sizeof(*new_fls_data), "Got unexpected size %p.\n", (void *)size); + } + + if (0) + { + pRtlProcessFlsData(new_fls_data, 2); + entry_count = check_linked_list(fls_list_head, &fls_data->fls_list_entry, &index); + ok(entry_count == 2, "Got unexpected count %u.\n", entry_count); + + /* Crashes on Windows. */ + HeapSize(GetProcessHeap(), 0, new_fls_data); + } + + test_fiberlocalstorage_peb_locked_event = CreateEventA(NULL, FALSE, FALSE, NULL); + test_fiberlocalstorage_done_event = CreateEventA(NULL, FALSE, FALSE, NULL); + hthread = CreateThread(NULL, 0, test_FiberLocalStorage_thread, NULL, 0, NULL); + ok(!!hthread, "CreateThread failed.\n"); + result = WaitForSingleObject(test_fiberlocalstorage_peb_locked_event, INFINITE); + ok(result == WAIT_OBJECT_0, "Got unexpected result %lu.\n", result); + teb->FlsSlots = NULL; + + test_fls_callback_call_count = 0; + saved_entry = new_fls_data->fls_list_entry; + pRtlProcessFlsData(new_fls_data, 1); + ok(!teb->FlsSlots, "Got unexpected teb->FlsSlots %p.\n", teb->FlsSlots); + + teb->FlsSlots = fls_data; + ok(test_fls_callback_call_count == 1, "Got unexpected callback call count %u.\n", + test_fls_callback_call_count); + + SetEvent(test_fiberlocalstorage_done_event); + WaitForSingleObject(hthread, INFINITE); + CloseHandle(hthread); + CloseHandle(test_fiberlocalstorage_peb_locked_event); + CloseHandle(test_fiberlocalstorage_done_event); + + ok(new_fls_data->fls_list_entry.Flink == saved_entry.Flink, "Got unexpected Flink %p.\n", + saved_entry.Flink); + ok(new_fls_data->fls_list_entry.Blink == saved_entry.Blink, "Got unexpected Flink %p.\n", + saved_entry.Blink); + size = HeapSize(GetProcessHeap(), 0, new_fls_data); + ok(size == sizeof(*new_fls_data), "Got unexpected size %p.\n", (void *)size); + test_fls_callback_call_count = 0; + i = test_fls_chunk_index_from_index(fls_indices[1], &index); + new_fls_data->fls_data_chunks[i][index + 1] = (void *)(ULONG_PTR)0x28; + pRtlProcessFlsData(new_fls_data, 2); + ok(!test_fls_callback_call_count, "Got unexpected callback call count %u.\n", + test_fls_callback_call_count); + + if (0) + { + /* crashes on Windows. */ + HeapSize(GetProcessHeap(), 0, new_fls_data); + } + + entry_count = check_linked_list(fls_list_head, &fls_data->fls_list_entry, &index); + ok(entry_count == 1, "Got unexpected count %u.\n", entry_count); + ok(!index, "Got unexpected index %u.\n", index); + } + else + { + win_skip("Old FLS data storage layout, skipping test.\n"); + g_fls_data = NULL; + } + + if (0) + { + /* crashes on Windows. */ + pRtlFlsGetValue(fls_indices[0], NULL); + } + + for (i = 0; i < count; ++i) + { + if (pRtlFlsGetValue) + { + status = pRtlFlsGetValue(fls_indices[i], &val); + ok(!status, "Got unexpected status %#lx.\n", status); + ok(val == (void *)(ULONG_PTR)(i + 1), "Got unexpected val %p, i %u.\n", val, i); + } + + status = pRtlFlsFree(fls_indices[i]); + ok(!status, "Got unexpected status %#lx, i %u.\n", status, i); + } + +#if defined(__REACTOS__) && defined(_WIN64) + /* peb layout is different on ReactOS x64 */ + if (!is_reactos() && !peb->FlsCallback) +#else + if (!peb->FlsCallback) +#endif + { + ok(g_fls_data->fls_high_index == 0xfef, "Got unexpected fls_high_index %#lx.\n", + g_fls_data->fls_high_index); + + for (i = 0; i < 8; ++i) + { + ok(!!g_fls_data->fls_callback_chunks[i], "Got zero fls_callback_chunks[%u].\n", i); + ok(!!fls_data->fls_data_chunks[i], "Got zero fls_data->fls_data_chunks[%u].\n", i); + } + } + } + else + { + win_skip("RtlFlsAlloc is not available.\n"); + } + /* Test an unallocated index * FlsFree should fail * FlsGetValue and FlsSetValue should succeed @@ -191,20 +570,36 @@ static void test_FiberLocalStorage(void) ret = pFlsFree( 127 ); ok( !ret, "freeing fls index 127 (unallocated) succeeded\n" ); ok( GetLastError() == ERROR_INVALID_PARAMETER, - "freeing fls index 127 (unallocated) wrong error %u\n", GetLastError() ); + "freeing fls index 127 (unallocated) wrong error %lu\n", GetLastError() ); val = pFlsGetValue( 127 ); ok( val == NULL, - "getting fls index 127 (unallocated) failed with error %u\n", GetLastError() ); + "getting fls index 127 (unallocated) failed with error %lu\n", GetLastError() ); + + if (pRtlFlsGetValue) + { + val = (void *)0xdeadbeef; + status = pRtlFlsGetValue(127, &val); + ok( !status, "Got unexpected status %#lx.\n", status ); + ok( !val, "Got unexpected val %p.\n", val ); + } ret = pFlsSetValue( 127, (void*) 0x217 ); - ok( ret, "setting fls index 127 (unallocated) failed with error %u\n", GetLastError() ); + ok( ret, "setting fls index 127 (unallocated) failed with error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); val = pFlsGetValue( 127 ); ok( val == (void*) 0x217, "fls index 127 (unallocated) wrong value %p\n", val ); ok( GetLastError() == ERROR_SUCCESS, - "getting fls index 127 (unallocated) failed with error %u\n", GetLastError() ); + "getting fls index 127 (unallocated) failed with error %lu\n", GetLastError() ); + + if (pRtlFlsGetValue) + { + val = (void *)0xdeadbeef; + status = pRtlFlsGetValue(127, &val); + ok( !status, "Got unexpected status %#lx.\n", status ); + ok( val == (void*)0x217, "Got unexpected val %p.\n", val ); + } /* FlsFree, FlsGetValue, and FlsSetValue out of bounds should return * ERROR_INVALID_PARAMETER @@ -213,72 +608,86 @@ static void test_FiberLocalStorage(void) ret = pFlsFree( 128 ); ok( !ret, "freeing fls index 128 (out of bounds) succeeded\n" ); ok( GetLastError() == ERROR_INVALID_PARAMETER, - "freeing fls index 128 (out of bounds) wrong error %u\n", GetLastError() ); + "freeing fls index 128 (out of bounds) wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); ret = pFlsSetValue( 128, (void*) 0x217 ); - ok( !ret, "setting fls index 128 (out of bounds) succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, - "setting fls index 128 (out of bounds) wrong error %u\n", GetLastError() ); + ok( ret || GetLastError() == ERROR_INVALID_PARAMETER, + "setting fls index 128 (out of bounds) wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); val = pFlsGetValue( 128 ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, - "getting fls index 128 (out of bounds) wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER || val == (void *)0x217, + "getting fls index 128 (out of bounds) wrong error %lu\n", GetLastError() ); /* Test index 0 */ SetLastError( 0xdeadbeef ); val = pFlsGetValue( 0 ); ok( !val, "fls index 0 set to %p\n", val ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "setting fls index wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "setting fls index wrong error %lu\n", GetLastError() ); + if (pRtlFlsGetValue) + { + val = (void *)0xdeadbeef; + status = pRtlFlsGetValue(0, &val); + ok( status == STATUS_INVALID_PARAMETER, "Got unexpected status %#lx.\n", status ); + ok( val == (void*)0xdeadbeef, "Got unexpected val %p.\n", val ); + } + SetLastError( 0xdeadbeef ); ret = pFlsSetValue( 0, (void *)0xdeadbeef ); ok( !ret, "setting fls index 0 succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "setting fls index wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "setting fls index wrong error %lu\n", GetLastError() ); + if (pRtlFlsSetValue) + { + status = pRtlFlsSetValue( 0, (void *)0xdeadbeef ); + ok( status == STATUS_INVALID_PARAMETER, "Got unexpected status %#lx.\n", status ); + } SetLastError( 0xdeadbeef ); val = pFlsGetValue( 0 ); ok( !val, "fls index 0 wrong value %p\n", val ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "setting fls index wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "setting fls index wrong error %lu\n", GetLastError() ); /* Test creating an FLS index */ fls = pFlsAlloc( NULL ); ok( fls != FLS_OUT_OF_INDEXES, "FlsAlloc failed\n" ); ok( fls != 0, "fls index 0 allocated\n" ); val = pFlsGetValue( fls ); - ok( !val, "fls index %u wrong value %p\n", fls, val ); + ok( !val, "fls index %lu wrong value %p\n", fls, val ); + SetLastError( 0xdeadbeef ); ret = pFlsSetValue( fls, (void *)0xdeadbeef ); - ok( ret, "setting fls index %u failed\n", fls ); + ok( ret, "setting fls index %lu failed\n", fls ); + ok( GetLastError() == 0xdeadbeef, "setting fls index wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); val = pFlsGetValue( fls ); - ok( val == (void *)0xdeadbeef, "fls index %u wrong value %p\n", fls, val ); + ok( val == (void *)0xdeadbeef, "fls index %lu wrong value %p\n", fls, val ); ok( GetLastError() == ERROR_SUCCESS, - "getting fls index %u failed with error %u\n", fls, GetLastError() ); + "getting fls index %lu failed with error %lu\n", fls, GetLastError() ); pFlsFree( fls ); /* Undefined behavior: verify the value is NULL after it the slot is freed */ SetLastError( 0xdeadbeef ); val = pFlsGetValue( fls ); - ok( val == NULL, "fls index %u wrong value %p\n", fls, val ); + ok( val == NULL, "fls index %lu wrong value %p\n", fls, val ); ok( GetLastError() == ERROR_SUCCESS, - "getting fls index %u failed with error %u\n", fls, GetLastError() ); + "getting fls index %lu failed with error %lu\n", fls, GetLastError() ); /* Undefined behavior: verify the value is settable after the slot is freed */ ret = pFlsSetValue( fls, (void *)0xdeadbabe ); - ok( ret, "setting fls index %u failed\n", fls ); + ok( ret, "setting fls index %lu failed\n", fls ); val = pFlsGetValue( fls ); - ok( val == (void *)0xdeadbabe, "fls index %u wrong value %p\n", fls, val ); + ok( val == (void *)0xdeadbabe, "fls index %lu wrong value %p\n", fls, val ); /* Try to create the same FLS index again, and verify that is initialized to NULL */ fls_2 = pFlsAlloc( NULL ); - ok( fls != FLS_OUT_OF_INDEXES, "FlsAlloc failed with error %u\n", GetLastError() ); + ok( fls != FLS_OUT_OF_INDEXES, "FlsAlloc failed with error %lu\n", GetLastError() ); /* If this fails it is not an API error, but the test will be inconclusive */ - ok( fls_2 == fls, "different FLS index allocated, was %u, now %u\n", fls, fls_2 ); + ok( fls_2 == fls, "different FLS index allocated, was %lu, now %lu\n", fls, fls_2 ); SetLastError( 0xdeadbeef ); val = pFlsGetValue( fls_2 ); - ok( val == NULL, "fls index %u wrong value %p\n", fls, val ); + ok( val == NULL || val == (void *)0xdeadbabe, "fls index %lu wrong value %p\n", fls, val ); ok( GetLastError() == ERROR_SUCCESS, - "getting fls index %u failed with error %u\n", fls_2, GetLastError() ); + "getting fls index %lu failed with error %lu\n", fls_2, GetLastError() ); pFlsFree( fls_2 ); } @@ -297,30 +706,30 @@ static void test_FiberLocalStorageCallback(PFLS_CALLBACK_FUNCTION cbfunc) /* Test that the callback is executed */ cbCount = 0; fls = pFlsAlloc( cbfunc ); - ok( fls != FLS_OUT_OF_INDEXES, "FlsAlloc failed with error %u\n", GetLastError() ); + ok( fls != FLS_OUT_OF_INDEXES, "FlsAlloc failed with error %lu\n", GetLastError() ); val = (void*) 0x1587; fls_value_to_set = val; ret = pFlsSetValue( fls, val ); - ok(ret, "FlsSetValue failed with error %u\n", GetLastError() ); + ok(ret, "FlsSetValue failed with error %lu\n", GetLastError() ); val2 = pFlsGetValue( fls ); ok(val == val2, "FlsGetValue returned %p, expected %p\n", val2, val); ret = pFlsFree( fls ); - ok(ret, "FlsFree failed with error %u\n", GetLastError() ); - todo_wine ok( cbCount == 1, "Wrong callback count: %d\n", cbCount ); + ok(ret, "FlsFree failed with error %lu\n", GetLastError() ); + ok( cbCount == 1, "Wrong callback count: %d\n", cbCount ); /* Test that callback is not executed if value is NULL */ cbCount = 0; fls = pFlsAlloc( cbfunc ); - ok( fls != FLS_OUT_OF_INDEXES, "FlsAlloc failed with error %u\n", GetLastError() ); + ok( fls != FLS_OUT_OF_INDEXES, "FlsAlloc failed with error %lu\n", GetLastError() ); ret = pFlsSetValue( fls, NULL ); - ok( ret, "FlsSetValue failed with error %u\n", GetLastError() ); + ok( ret, "FlsSetValue failed with error %lu\n", GetLastError() ); pFlsFree( fls ); - ok( ret, "FlsFree failed with error %u\n", GetLastError() ); + ok( ret, "FlsFree failed with error %lu\n", GetLastError() ); ok( cbCount == 0, "Wrong callback count: %d\n", cbCount ); } @@ -337,7 +746,7 @@ static void test_FiberLocalStorageWithFibers(PFLS_CALLBACK_FUNCTION cbfunc) } fls_index_to_set = pFlsAlloc(cbfunc); - ok(fls_index_to_set != FLS_OUT_OF_INDEXES, "FlsAlloc failed with error %u\n", GetLastError()); + ok(fls_index_to_set != FLS_OUT_OF_INDEXES, "FlsAlloc failed with error %lu\n", GetLastError()); test_ConvertThreadToFiber(); @@ -345,8 +754,8 @@ static void test_FiberLocalStorageWithFibers(PFLS_CALLBACK_FUNCTION cbfunc) cbCount = 0; fibers[1] = pCreateFiber(0,FiberMainProc,&testparam); fibers[2] = pCreateFiber(0,FiberMainProc,&testparam); - ok(fibers[1] != NULL, "CreateFiber failed with error %u\n", GetLastError()); - ok(fibers[2] != NULL, "CreateFiber failed with error %u\n", GetLastError()); + ok(fibers[1] != NULL, "CreateFiber failed with error %lu\n", GetLastError()); + ok(fibers[2] != NULL, "CreateFiber failed with error %lu\n", GetLastError()); ok(fiberCount == 0, "Wrong fiber count: %d\n", fiberCount); ok(cbCount == 0, "Wrong callback count: %d\n", cbCount); @@ -374,14 +783,14 @@ static void test_FiberLocalStorageWithFibers(PFLS_CALLBACK_FUNCTION cbfunc) fls_value_to_set = val1; pDeleteFiber(fibers[1]); ok(fiberCount == 0, "Wrong fiber count: %d\n", fiberCount); - todo_wine ok(cbCount == 1, "Wrong callback count: %d\n", cbCount); + ok(cbCount == 1, "Wrong callback count: %d\n", cbCount); fiberCount = 0; cbCount = 0; fls_value_to_set = val2; pFlsFree(fls_index_to_set); ok(fiberCount == 0, "Wrong fiber count: %d\n", fiberCount); - todo_wine ok(cbCount == 2, "Wrong callback count: %d\n", cbCount); + ok(cbCount == 2, "Wrong callback count: %d\n", cbCount); fiberCount = 0; cbCount = 0; @@ -393,8 +802,305 @@ static void test_FiberLocalStorageWithFibers(PFLS_CALLBACK_FUNCTION cbfunc) test_ConvertFiberToThread(); } +#define check_current_actctx_is(e,t) check_current_actctx_is_(__LINE__, e, t) +static void check_current_actctx_is_(int line, HANDLE expected_actctx, BOOL todo) +{ + HANDLE cur_actctx; + BOOL ret; + + cur_actctx = (void*)0xdeadbeef; + ret = GetCurrentActCtx(&cur_actctx); + ok_(__FILE__, line)(ret, "thread GetCurrentActCtx failed, %lu\n", GetLastError()); + + todo_wine_if(todo) + ok_(__FILE__, line)(cur_actctx == expected_actctx, "got %p, expected %p\n", cur_actctx, expected_actctx); + + ReleaseActCtx(cur_actctx); +} + +static DWORD WINAPI subthread_actctx_func(void *actctx) +{ + HANDLE fiber; + BOOL ret; + + check_current_actctx_is(actctx, FALSE); + + fiber = pConvertThreadToFiber(NULL); + ok(fiber != NULL, "ConvertThreadToFiber returned error %lu\n", GetLastError()); + check_current_actctx_is(actctx, FALSE); + fibers[2] = fiber; + + SwitchToFiber(fibers[0]); + check_current_actctx_is(actctx, FALSE); + + ok(fibers[2] == fiber, "fibers[2]: expected %p, got %p\n", fiber, fibers[2]); + fibers[2] = NULL; + ret = pConvertFiberToThread(); + ok(ret, "ConvertFiberToThread returned error %lu\n", GetLastError()); + check_current_actctx_is(actctx, FALSE); + + return 0; +} + +static void WINAPI fiber_actctx_func(void *actctx) +{ + ULONG_PTR cookie; + DWORD tid, wait; + HANDLE thread; + BOOL ret; + + check_current_actctx_is(NULL, FALSE); + + ret = ActivateActCtx(actctx, &cookie); + ok(ret, "ActivateActCtx returned error %lu\n", GetLastError()); + check_current_actctx_is(actctx, FALSE); + + SwitchToFiber(fibers[0]); + check_current_actctx_is(actctx, FALSE); + + thread = CreateThread(NULL, 0, subthread_actctx_func, actctx, 0, &tid); + ok(thread != NULL, "CreateThread returned error %lu\n", GetLastError()); + + wait = WaitForSingleObject(thread, INFINITE); + ok(wait == WAIT_OBJECT_0, "WaitForSingleObject returned %lu (last error: %lu)\n", + wait, GetLastError()); + CloseHandle(thread); + + ret = DeactivateActCtx(0, cookie); + ok(ret, "DeactivateActCtx returned error %lu\n", GetLastError()); + check_current_actctx_is(NULL, FALSE); + + SwitchToFiber(fibers[0]); + ok(0, "unreachable\n"); +} + +/* Test that activation context is switched on SwitchToFiber() call */ +static void subtest_fiber_actctx_switch(HANDLE current_actctx, HANDLE child_actctx) +{ + fibers[1] = pCreateFiber(0, fiber_actctx_func, child_actctx); + ok(fibers[1] != NULL, "CreateFiber returned error %lu\n", GetLastError()); + check_current_actctx_is(current_actctx, FALSE); + + SwitchToFiber(fibers[1]); + check_current_actctx_is(current_actctx, FALSE); + + SwitchToFiber(fibers[1]); + check_current_actctx_is(current_actctx, FALSE); + + SwitchToFiber(fibers[2]); + check_current_actctx_is(current_actctx, FALSE); + ok(fibers[2] == NULL, "expected fiber to be deleted (got %p)\n", fibers[2]); + + DeleteFiber(fibers[1]); + fibers[1] = NULL; +} + +static void WINAPI exit_thread_fiber_func(void *unused) +{ + BOOL ret; + + ret = pConvertFiberToThread(); + ok(ret, "ConvertFiberToThread returned error %lu\n", GetLastError()); + + ExitThread(16); +} + +static DWORD WINAPI thread_actctx_func_early_exit(void *actctx) +{ + HANDLE exit_thread_fiber; + + check_current_actctx_is(actctx, FALSE); + + fibers[1] = pConvertThreadToFiber(NULL); + ok(fibers[1] != NULL, "ConvertThreadToFiber returned error %lu\n", GetLastError()); + check_current_actctx_is(actctx, FALSE); + + exit_thread_fiber = pCreateFiber(0, exit_thread_fiber_func, NULL); + ok(exit_thread_fiber != NULL, "CreateFiber returned error %lu\n", GetLastError()); + + /* exit thread, but keep current fiber */ + SwitchToFiber(exit_thread_fiber); + check_current_actctx_is(actctx, FALSE); + + SwitchToFiber(fibers[0]); + ok(0, "unreachable\n"); + return 17; +} + +/* Test that fiber activation context stack is preserved regardless of creator thread's lifetime */ +static void subtest_fiber_actctx_preservation(HANDLE current_actctx, HANDLE child_actctx) +{ + ULONG_PTR cookie; + DWORD tid, wait; + HANDLE thread; + BOOL ret; + + ret = ActivateActCtx(child_actctx, &cookie); + ok(ret, "ActivateActCtx returned error %lu\n", GetLastError()); + check_current_actctx_is(child_actctx, FALSE); + + thread = CreateThread(NULL, 0, thread_actctx_func_early_exit, child_actctx, 0, &tid); + ok(thread != NULL, "CreateThread returned error %lu\n", GetLastError()); + + ret = DeactivateActCtx(0, cookie); + ok(ret, "DeactivateActCtx returned error %lu\n", GetLastError()); + check_current_actctx_is(current_actctx, FALSE); + + wait = WaitForSingleObject(thread, INFINITE); + ok(wait == WAIT_OBJECT_0, "WaitForSingleObject returned %lu (last error: %lu)\n", + wait, GetLastError()); + CloseHandle(thread); + + /* The exited thread has been converted to a fiber */ +#if defined(__REACTOS__) && defined(_M_AMD64) + skip("FIXME: SwitchToFiber() is unimplemented on AMD64 ReactOS\n"); +#else + SwitchToFiber(fibers[1]); + check_current_actctx_is(current_actctx, FALSE); + + DeleteFiber(fibers[1]); + fibers[1] = NULL; +#endif +} + +static HANDLE create_actctx_from_module_manifest(void) +{ + ACTCTXW actctx; + + memset(&actctx, 0, sizeof(ACTCTXW)); + actctx.cbSize = sizeof(actctx); + actctx.dwFlags = ACTCTX_FLAG_HMODULE_VALID | ACTCTX_FLAG_RESOURCE_NAME_VALID; + actctx.lpResourceName = MAKEINTRESOURCEW(124); + actctx.hModule = GetModuleHandleW(NULL); + + return CreateActCtxW(&actctx); +} + +static void test_fiber_actctx(void) +{ + ULONG_PTR cookies[3]; + HANDLE actctxs[3]; + size_t i, j; + BOOL ret; + +#ifdef __REACTOS__ + if (GetNTVersion() < _WIN32_WINNT_VISTA && !is_reactos()) { + skip("test_fiber_actctx() crashes and isn't valid on WS03.\n"); + return; + } +#endif + for (i = 0; i < ARRAY_SIZE(actctxs); i++) + { + actctxs[i] = create_actctx_from_module_manifest(); + ok(actctxs[i] != INVALID_HANDLE_VALUE, "failed to create context, error %lu\n", GetLastError()); + for (j = 0; j < i; j++) + { + ok(actctxs[i] != actctxs[j], + "actctxs[%Iu] (%p) and actctxs[%Iu] (%p) should not alias\n", + i, actctxs[i], j, actctxs[j]); + } + } + + ret = ActivateActCtx(actctxs[0], &cookies[0]); + ok(ret, "ActivateActCtx returned error %lu\n", GetLastError()); + check_current_actctx_is(actctxs[0], FALSE); + + test_ConvertThreadToFiber(); + check_current_actctx_is(actctxs[0], FALSE); + + ret = ActivateActCtx(actctxs[1], &cookies[1]); + ok(ret, "ActivateActCtx returned error %lu\n", GetLastError()); + check_current_actctx_is(actctxs[1], FALSE); + + subtest_fiber_actctx_switch(actctxs[1], actctxs[2]); + subtest_fiber_actctx_preservation(actctxs[1], actctxs[2]); + + ret = DeactivateActCtx(0, cookies[1]); + ok(ret, "DeactivateActCtx returned error %lu\n", GetLastError()); + check_current_actctx_is(actctxs[0], FALSE); + + test_ConvertFiberToThread(); + check_current_actctx_is(actctxs[0], FALSE); + + ret = DeactivateActCtx(0, cookies[0]); + ok(ret, "DeactivateActCtx returned error %lu\n", GetLastError()); + check_current_actctx_is(NULL, FALSE); + + for (i = ARRAY_SIZE(actctxs); i > 0; ) + ReleaseActCtx(actctxs[--i]); +} + + +static void WINAPI fls_exit_deadlock_callback(void *arg) +{ + if (arg == (void *)1) + Sleep(INFINITE); + if (arg == (void *)2) + /* Unfortunately this test won't affect the exit code if it fails, but + * at least it will print a failure message. */ + ok(RtlDllShutdownInProgress(), "expected DLL shutdown\n"); +} + +static DWORD CALLBACK fls_exit_deadlock_thread(void *arg) +{ + FlsSetValue((DWORD_PTR)arg, (void *)1); + return 0; +} + +static void fls_exit_deadlock_child(void) +{ + DWORD index = FlsAlloc(fls_exit_deadlock_callback); + FlsSetValue(index, (void *)2); + CreateThread(NULL, 0, fls_exit_deadlock_thread, (void *)(DWORD_PTR)index, 0, NULL); + Sleep(100); + ExitProcess(0); +} + +static void test_fls_exit_deadlock(void) +{ + char **argv, cmdline[MAX_PATH]; + PROCESS_INFORMATION pi; + STARTUPINFOA si = {0}; + BOOL ret; + + /* Regression test for the following deadlock: + * + * Thread A Thread B + * ----------------------------- + * ExitThread + * acquire FLS lock + * call FLS callback + * ExitProcess + * terminate thread A + * acquire FLS lock + * + * Thread B deadlocks on acquiring the FLS lock (in order to itself call its + * FLS callbacks.) + */ + + winetest_get_mainargs(&argv); + sprintf(cmdline, "%s %s fls_exit_deadlock", argv[0], argv[1]); + ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + ok(ret, "failed to create child, error %lu\n", GetLastError()); + ret = WaitForSingleObject(pi.hProcess, 1000); + ok(!ret, "wait failed\n"); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); +} + START_TEST(fiber) { + char **argv; + int argc; + + argc = winetest_get_mainargs(&argv); + + if (argc == 3 && !strcmp(argv[2], "fls_exit_deadlock")) + { + fls_exit_deadlock_child(); + return; + } + init_funcs(); if (!pCreateFiber) @@ -407,4 +1113,6 @@ START_TEST(fiber) test_FiberLocalStorage(); test_FiberLocalStorageCallback(FiberLocalStorageProc); test_FiberLocalStorageWithFibers(FiberLocalStorageProc); + test_fiber_actctx(); + test_fls_exit_deadlock(); } diff --git a/modules/rostests/winetests/kernel32/file.c b/modules/rostests/winetests/kernel32/file.c index ee91e62e419..0f092c3c09b 100644 --- a/modules/rostests/winetests/kernel32/file.c +++ b/modules/rostests/winetests/kernel32/file.c @@ -20,19 +20,27 @@ * */ -#include "precomp.h" - +#include +#include #include -#include +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "wine/test.h" +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winternl.h" +#include "winnls.h" +#include "fileapi.h" #undef DeleteFile /* needed for FILE_DISPOSITION_INFO */ static HANDLE (WINAPI *pFindFirstFileExA)(LPCSTR,FINDEX_INFO_LEVELS,LPVOID,FINDEX_SEARCH_OPS,LPVOID,DWORD); -static BOOL (WINAPI *pReplaceFileA)(LPCSTR, LPCSTR, LPCSTR, DWORD, LPVOID, LPVOID); static BOOL (WINAPI *pReplaceFileW)(LPCWSTR, LPCWSTR, LPCWSTR, DWORD, LPVOID, LPVOID); static UINT (WINAPI *pGetSystemWindowsDirectoryA)(LPSTR, UINT); static BOOL (WINAPI *pGetVolumeNameForVolumeMountPointA)(LPCSTR, LPSTR, DWORD); -static DWORD (WINAPI *pQueueUserAPC)(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData); static BOOL (WINAPI *pGetFileInformationByHandleEx)(HANDLE, FILE_INFO_BY_HANDLE_CLASS, LPVOID, DWORD); static HANDLE (WINAPI *pOpenFileById)(HANDLE, LPFILE_ID_DESCRIPTOR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD); static BOOL (WINAPI *pSetFileValidData)(HANDLE, LONGLONG); @@ -45,8 +53,12 @@ static NTSTATUS (WINAPI *pNtCreateFile)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES static BOOL (WINAPI *pRtlDosPathNameToNtPathName_U)(LPCWSTR, PUNICODE_STRING, PWSTR*, CURDIR*); static NTSTATUS (WINAPI *pRtlAnsiStringToUnicodeString)(PUNICODE_STRING, PCANSI_STRING, BOOLEAN); static BOOL (WINAPI *pSetFileInformationByHandle)(HANDLE, FILE_INFO_BY_HANDLE_CLASS, void*, DWORD); +static BOOL (WINAPI *pGetQueuedCompletionStatusEx)(HANDLE, OVERLAPPED_ENTRY*, ULONG, ULONG*, DWORD, BOOL); +static HANDLE (WINAPI *pReOpenFile)(HANDLE, DWORD, DWORD, DWORD); static void (WINAPI *pRtlInitAnsiString)(PANSI_STRING,PCSZ); static void (WINAPI *pRtlFreeUnicodeString)(PUNICODE_STRING); +static BOOL (WINAPI *pSetFileCompletionNotificationModes)(HANDLE, UCHAR); +static HANDLE (WINAPI *pFindFirstStreamW)(LPCWSTR filename, STREAM_INFO_LEVELS infolevel, void *data, DWORD flags); static char filename[MAX_PATH]; static const char sillytext[] = @@ -81,11 +93,9 @@ static void InitFunctionPointers(void) pRtlFreeUnicodeString = (void *)GetProcAddress(hntdll, "RtlFreeUnicodeString"); pFindFirstFileExA=(void*)GetProcAddress(hkernel32, "FindFirstFileExA"); - pReplaceFileA=(void*)GetProcAddress(hkernel32, "ReplaceFileA"); pReplaceFileW=(void*)GetProcAddress(hkernel32, "ReplaceFileW"); pGetSystemWindowsDirectoryA=(void*)GetProcAddress(hkernel32, "GetSystemWindowsDirectoryA"); pGetVolumeNameForVolumeMountPointA = (void *) GetProcAddress(hkernel32, "GetVolumeNameForVolumeMountPointA"); - pQueueUserAPC = (void *) GetProcAddress(hkernel32, "QueueUserAPC"); pGetFileInformationByHandleEx = (void *) GetProcAddress(hkernel32, "GetFileInformationByHandleEx"); pOpenFileById = (void *) GetProcAddress(hkernel32, "OpenFileById"); pSetFileValidData = (void *) GetProcAddress(hkernel32, "SetFileValidData"); @@ -94,6 +104,17 @@ static void InitFunctionPointers(void) pGetFinalPathNameByHandleA = (void *) GetProcAddress(hkernel32, "GetFinalPathNameByHandleA"); pGetFinalPathNameByHandleW = (void *) GetProcAddress(hkernel32, "GetFinalPathNameByHandleW"); pSetFileInformationByHandle = (void *) GetProcAddress(hkernel32, "SetFileInformationByHandle"); + pGetQueuedCompletionStatusEx = (void *) GetProcAddress(hkernel32, "GetQueuedCompletionStatusEx"); + pReOpenFile = (void *) GetProcAddress(hkernel32, "ReOpenFile"); + pSetFileCompletionNotificationModes = (void *)GetProcAddress(hkernel32, "SetFileCompletionNotificationModes"); + pFindFirstStreamW = (void *)GetProcAddress(hkernel32, "FindFirstStreamW"); +} + +static void create_file( const char *path ) +{ + FILE *f = fopen( path, "wb" ); + fputs( path, f ); + fclose( f ); } static void test__hread( void ) @@ -110,7 +131,7 @@ static void test__hread( void ) filehandle = _lcreat( filename, 0 ); if (filehandle == HFILE_ERROR) { - ok(0,"couldn't create file \"%s\" (err=%d)\n",filename,GetLastError()); + ok(0,"couldn't create file \"%s\" (err=%ld)\n",filename,GetLastError()); return; } @@ -120,7 +141,7 @@ static void test__hread( void ) filehandle = _lopen( filename, OF_READ ); - ok( HFILE_ERROR != filehandle, "couldn't open file \"%s\" again (err=%d)\n", filename, GetLastError( ) ); + ok( HFILE_ERROR != filehandle, "couldn't open file \"%s\" again (err=%ld)\n", filename, GetLastError( ) ); bytes_read = _hread( filehandle, buffer, 2 * strlen( sillytext ) ); @@ -139,7 +160,7 @@ static void test__hread( void ) ok( HFILE_ERROR != _lclose( filehandle ), "_lclose complains\n" ); ret = DeleteFileA( filename ); - ok( ret != 0, "DeleteFile failed (%d)\n", GetLastError( ) ); + ok( ret != 0, "DeleteFile failed (%ld)\n", GetLastError( ) ); } @@ -159,7 +180,7 @@ static void test__hwrite( void ) filehandle = _lcreat( filename, 0 ); if (filehandle == HFILE_ERROR) { - ok(0,"couldn't create file \"%s\" (err=%d)\n",filename,GetLastError()); + ok(0,"couldn't create file \"%s\" (err=%ld)\n",filename,GetLastError()); return; } @@ -224,7 +245,7 @@ static void test__hwrite( void ) ok( HFILE_ERROR != _lclose( filehandle ), "_lclose complains\n" ); ret = DeleteFileA( filename ); - ok( ret != 0, "DeleteFile failed (%d)\n", GetLastError( ) ); + ok( ret != 0, "DeleteFile failed (%ld)\n", GetLastError( ) ); LocalFree( contents ); } @@ -238,7 +259,7 @@ static void test__lclose( void ) filehandle = _lcreat( filename, 0 ); if (filehandle == HFILE_ERROR) { - ok(0,"couldn't create file \"%s\" (err=%d)\n",filename,GetLastError()); + ok(0,"couldn't create file \"%s\" (err=%ld)\n",filename,GetLastError()); return; } @@ -247,7 +268,7 @@ static void test__lclose( void ) ok( HFILE_ERROR != _lclose(filehandle), "_lclose complains\n" ); ret = DeleteFileA( filename ); - ok( ret != 0, "DeleteFile failed (%d)\n", GetLastError( ) ); + ok( ret != 0, "DeleteFile failed (%ld)\n", GetLastError( ) ); } /* helper function for test__lcreat */ @@ -261,7 +282,7 @@ static void get_nt_pathW( const char *name, UNICODE_STRING *nameW ) pRtlInitAnsiString( &str, name ); status = pRtlAnsiStringToUnicodeString( &strW, &str, TRUE ); - ok( !status, "RtlAnsiStringToUnicodeString failed with %08x\n", status ); + ok( !status, "RtlAnsiStringToUnicodeString failed with %08lx\n", status ); ret = pRtlDosPathNameToNtPathName_U( strW.Buffer, nameW, NULL, NULL ); ok( ret, "RtlDosPathNameToNtPathName_U failed\n" ); @@ -286,7 +307,7 @@ static void test__lcreat( void ) filehandle = _lcreat( filename, 0 ); if (filehandle == HFILE_ERROR) { - ok(0,"couldn't create file \"%s\" (err=%d)\n",filename,GetLastError()); + ok(0,"couldn't create file \"%s\" (err=%ld)\n",filename,GetLastError()); return; } @@ -303,10 +324,10 @@ static void test__lcreat( void ) FindClose( find ); ret = DeleteFileA(filename); - ok( ret != 0, "DeleteFile failed (%d)\n", GetLastError()); + ok( ret != 0, "DeleteFile failed (%ld)\n", GetLastError()); filehandle = _lcreat( filename, 1 ); /* readonly */ - ok( HFILE_ERROR != filehandle, "couldn't create file \"%s\" (err=%d)\n", filename, GetLastError( ) ); + ok( HFILE_ERROR != filehandle, "couldn't create file \"%s\" (err=%ld)\n", filename, GetLastError( ) ); ok( HFILE_ERROR != _hwrite( filehandle, sillytext, strlen( sillytext ) ), "_hwrite shouldn't be able to write never the less\n" ); @@ -318,14 +339,14 @@ static void test__lcreat( void ) SetLastError( 0xdeadbeef ); ok( 0 == DeleteFileA( filename ), "shouldn't be able to delete a readonly file\n" ); - ok( GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError() ); + ok( GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError() ); ok( SetFileAttributesA(filename, FILE_ATTRIBUTE_NORMAL ) != 0, "couldn't change attributes on file\n" ); ok( DeleteFileA( filename ) != 0, "now it should be possible to delete the file!\n" ); filehandle = _lcreat( filename, 1 ); /* readonly */ - ok( HFILE_ERROR != filehandle, "couldn't create file \"%s\" (err=%d)\n", filename, GetLastError() ); + ok( HFILE_ERROR != filehandle, "couldn't create file \"%s\" (err=%ld)\n", filename, GetLastError() ); ok( HFILE_ERROR != _hwrite( filehandle, sillytext, strlen(sillytext) ), "_hwrite shouldn't be able to write never the less\n" ); ok( HFILE_ERROR != _lclose(filehandle), "_lclose complains\n" ); @@ -345,24 +366,24 @@ static void test__lcreat( void ) status = pNtCreateFile( &file, GENERIC_READ | GENERIC_WRITE | DELETE, &attr, &io, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DELETE_ON_CLOSE | FILE_NON_DIRECTORY_FILE, NULL, 0 ); - ok( status == STATUS_ACCESS_DENIED, "expected STATUS_ACCESS_DENIED, got %08x\n", status ); + ok( status == STATUS_ACCESS_DENIED, "expected STATUS_ACCESS_DENIED, got %08lx\n", status ); ok( GetFileAttributesA( filename ) != INVALID_FILE_ATTRIBUTES, "file was deleted\n" ); status = pNtCreateFile( &file, DELETE, &attr, &io, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DELETE_ON_CLOSE | FILE_NON_DIRECTORY_FILE, NULL, 0 ); - ok( status == STATUS_CANNOT_DELETE, "expected STATUS_CANNOT_DELETE, got %08x\n", status ); + ok( status == STATUS_CANNOT_DELETE, "expected STATUS_CANNOT_DELETE, got %08lx\n", status ); status = pNtCreateFile( &file, DELETE, &attr, &io, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DELETE_ON_CLOSE | FILE_DIRECTORY_FILE, NULL, 0 ); - ok( status == STATUS_NOT_A_DIRECTORY, "expected STATUS_NOT_A_DIRECTORY, got %08x\n", status ); + ok( status == STATUS_NOT_A_DIRECTORY, "expected STATUS_NOT_A_DIRECTORY, got %08lx\n", status ); status = pNtCreateFile( &file, DELETE, &attr, &io, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_DELETE_ON_CLOSE | FILE_NON_DIRECTORY_FILE, NULL, 0 ); todo_wine - ok( status == STATUS_CANNOT_DELETE, "expected STATUS_CANNOT_DELETE, got %08x\n", status ); + ok( status == STATUS_CANNOT_DELETE, "expected STATUS_CANNOT_DELETE, got %08lx\n", status ); if (!status) CloseHandle( file ); pRtlFreeUnicodeString( &filenameW ); @@ -375,7 +396,7 @@ static void test__lcreat( void ) ok( DeleteFileA( filename ) != 0, "now it should be possible to delete the file\n" ); filehandle = _lcreat( filename, 2 ); - ok( HFILE_ERROR != filehandle, "couldn't create file \"%s\" (err=%d)\n", filename, GetLastError( ) ); + ok( HFILE_ERROR != filehandle, "couldn't create file \"%s\" (err=%ld)\n", filename, GetLastError( ) ); ok( HFILE_ERROR != _hwrite( filehandle, sillytext, strlen( sillytext ) ), "_hwrite complains\n" ); @@ -390,10 +411,10 @@ static void test__lcreat( void ) FindClose( find ); ret = DeleteFileA( filename ); - ok( ret, "DeleteFile failed (%d)\n", GetLastError( ) ); + ok( ret, "DeleteFile failed (%ld)\n", GetLastError( ) ); filehandle = _lcreat( filename, 4 ); /* SYSTEM file */ - ok( HFILE_ERROR != filehandle, "couldn't create file \"%s\" (err=%d)\n", filename, GetLastError( ) ); + ok( HFILE_ERROR != filehandle, "couldn't create file \"%s\" (err=%ld)\n", filename, GetLastError( ) ); ok( HFILE_ERROR != _hwrite( filehandle, sillytext, strlen( sillytext ) ), "_hwrite complains\n" ); @@ -408,30 +429,13 @@ static void test__lcreat( void ) FindClose( find ); ret = DeleteFileA( filename ); - ok( ret, "DeleteFile failed (%d)\n", GetLastError( ) ); + ok( ret, "DeleteFile failed (%ld)\n", GetLastError( ) ); filehandle=_lcreat (slashname, 0); /* illegal name */ - if (HFILE_ERROR==filehandle) { - err=GetLastError (); - ok (err==ERROR_INVALID_NAME || err==ERROR_PATH_NOT_FOUND, - "creating file \"%s\" failed with error %d\n", slashname, err); - } else { /* only NT succeeds */ - _lclose(filehandle); - find=FindFirstFileA (slashname, &search_results); - if (INVALID_HANDLE_VALUE!=find) - { - ret = FindClose (find); - ok (0 != ret, "FindClose complains (%d)\n", GetLastError ()); - slashname[strlen(slashname)-1]=0; - ok (!strcmp (slashname, search_results.cFileName), - "found unexpected name \"%s\"\n", search_results.cFileName); - ok (FILE_ATTRIBUTE_ARCHIVE==search_results.dwFileAttributes, - "attributes of file \"%s\" are 0x%04x\n", search_results.cFileName, - search_results.dwFileAttributes); - } - ret = DeleteFileA( slashname ); - ok( ret, "DeleteFile failed (%d)\n", GetLastError( ) ); - } + ok( filehandle == HFILE_ERROR, "succeeded\n" ); + err=GetLastError (); + ok (err==ERROR_INVALID_NAME || err==ERROR_PATH_NOT_FOUND, + "creating file \"%s\" failed with error %d\n", slashname, err); filehandle=_lcreat (filename, 8); /* illegal attribute */ if (HFILE_ERROR==filehandle) @@ -448,17 +452,17 @@ static void test__lcreat( void ) else name = filename; ret = FindClose(find); - ok ( 0 != ret, "FindClose complains (%d)\n", GetLastError ()); + ok ( 0 != ret, "FindClose complains (%ld)\n", GetLastError ()); ok (!strcmp (name, search_results.cFileName), "expected \"%s\", got \"%s\"\n", name, search_results.cFileName); search_results.dwFileAttributes &= ~FILE_ATTRIBUTE_NOT_CONTENT_INDEXED; search_results.dwFileAttributes &= ~FILE_ATTRIBUTE_COMPRESSED; ok (FILE_ATTRIBUTE_ARCHIVE==search_results.dwFileAttributes, - "attributes of file \"%s\" are 0x%04x\n", search_results.cFileName, + "attributes of file \"%s\" are 0x%04lx\n", search_results.cFileName, search_results.dwFileAttributes); } ret = DeleteFileA( filename ); - ok( ret, "DeleteFile failed (%d)\n", GetLastError( ) ); + ok( ret, "DeleteFile failed (%ld)\n", GetLastError( ) ); } } @@ -474,7 +478,7 @@ static void test__llseek( void ) filehandle = _lcreat( filename, 0 ); if (filehandle == HFILE_ERROR) { - ok(0,"couldn't create file \"%s\" (err=%d)\n",filename,GetLastError()); + ok(0,"couldn't create file \"%s\" (err=%ld)\n",filename,GetLastError()); return; } @@ -497,7 +501,7 @@ static void test__llseek( void ) ok( HFILE_ERROR != _lclose(filehandle), "_lclose complains\n" ); ret = DeleteFileA( filename ); - ok( ret, "DeleteFile failed (%d)\n", GetLastError( ) ); + ok( ret, "DeleteFile failed (%ld)\n", GetLastError( ) ); } @@ -511,7 +515,7 @@ static void test__llopen( void ) filehandle = _lcreat( filename, 0 ); if (filehandle == HFILE_ERROR) { - ok(0,"couldn't create file \"%s\" (err=%d)\n",filename,GetLastError()); + ok(0,"couldn't create file \"%s\" (err=%ld)\n",filename,GetLastError()); return; } @@ -536,7 +540,7 @@ static void test__llopen( void ) ok( HFILE_ERROR != _lclose(filehandle), "_lclose complains\n" ); ret = DeleteFileA( filename ); - ok( ret, "DeleteFile failed (%d)\n", GetLastError( ) ); + ok( ret, "DeleteFile failed (%ld)\n", GetLastError( ) ); /* TODO - add tests for the SHARE modes - use two processes to pull this one off */ } @@ -553,7 +557,7 @@ static void test__lread( void ) filehandle = _lcreat( filename, 0 ); if (filehandle == HFILE_ERROR) { - ok(0,"couldn't create file \"%s\" (err=%d)\n",filename,GetLastError()); + ok(0,"couldn't create file \"%s\" (err=%ld)\n",filename,GetLastError()); return; } @@ -563,7 +567,7 @@ static void test__lread( void ) filehandle = _lopen( filename, OF_READ ); - ok( HFILE_ERROR != filehandle, "couldn't open file \"%s\" again (err=%d)\n", filename, GetLastError()); + ok( HFILE_ERROR != filehandle, "couldn't open file \"%s\" again (err=%ld)\n", filename, GetLastError()); bytes_read = _lread( filehandle, buffer, 2 * strlen( sillytext ) ); @@ -582,7 +586,7 @@ static void test__lread( void ) ok( HFILE_ERROR != _lclose(filehandle), "_lclose complains\n" ); ret = DeleteFileA( filename ); - ok( ret, "DeleteFile failed (%d)\n", GetLastError( ) ); + ok( ret, "DeleteFile failed (%ld)\n", GetLastError( ) ); } @@ -602,7 +606,7 @@ static void test__lwrite( void ) filehandle = _lcreat( filename, 0 ); if (filehandle == HFILE_ERROR) { - ok(0,"couldn't create file \"%s\" (err=%d)\n",filename,GetLastError()); + ok(0,"couldn't create file \"%s\" (err=%ld)\n",filename,GetLastError()); return; } @@ -667,7 +671,7 @@ static void test__lwrite( void ) ok( HFILE_ERROR != _lclose( filehandle ), "_lclose complains\n" ); ret = DeleteFileA( filename ); - ok( ret, "DeleteFile failed (%d)\n", GetLastError( ) ); + ok( ret, "DeleteFile failed (%ld)\n", GetLastError( ) ); LocalFree( contents ); } @@ -685,139 +689,147 @@ static void test_CopyFileA(void) BOOL retok; ret = GetTempPathA(MAX_PATH, temp_path); - ok(ret != 0, "GetTempPathA error %d\n", GetLastError()); + ok(ret != 0, "GetTempPathA error %ld\n", GetLastError()); ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n"); ret = GetTempFileNameA(temp_path, prefix, 0, source); - ok(ret != 0, "GetTempFileNameA error %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameA error %ld\n", GetLastError()); /* copying a file to itself must fail */ retok = CopyFileA(source, source, FALSE); ok( !retok && (GetLastError() == ERROR_SHARING_VIOLATION || broken(GetLastError() == ERROR_FILE_EXISTS) /* Win 9x */), - "copying a file to itself didn't fail (ret=%d, err=%d)\n", retok, GetLastError()); + "copying a file to itself didn't fail (ret=%d, err=%ld)\n", retok, GetLastError()); /* make the source have not zero size */ hfile = CreateFileA(source, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0 ); ok(hfile != INVALID_HANDLE_VALUE, "failed to open source file\n"); retok = WriteFile(hfile, prefix, sizeof(prefix), &ret, NULL ); ok( retok && ret == sizeof(prefix), - "WriteFile error %d\n", GetLastError()); + "WriteFile error %ld\n", GetLastError()); ok(GetFileSize(hfile, NULL) == sizeof(prefix), "source file has wrong size\n"); /* get the file time and change it to prove the difference */ ret = GetFileTime(hfile, NULL, NULL, &ft1); - ok( ret, "GetFileTime error %d\n", GetLastError()); + ok( ret, "GetFileTime error %ld\n", GetLastError()); ft1.dwLowDateTime -= 600000000; /* 60 second */ ret = SetFileTime(hfile, NULL, NULL, &ft1); - ok( ret, "SetFileTime error %d\n", GetLastError()); + ok( ret, "SetFileTime error %ld\n", GetLastError()); GetFileTime(hfile, NULL, NULL, &ft1); /* get the actual time back */ CloseHandle(hfile); ret = GetTempFileNameA(temp_path, prefix, 0, dest); - ok(ret != 0, "GetTempFileNameA error %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameA error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = CopyFileA(source, dest, TRUE); ok(!ret && GetLastError() == ERROR_FILE_EXISTS, - "CopyFileA: unexpected error %d\n", GetLastError()); + "CopyFileA: unexpected error %ld\n", GetLastError()); ret = CopyFileA(source, dest, FALSE); - ok(ret, "CopyFileA: error %d\n", GetLastError()); + ok(ret, "CopyFileA: error %ld\n", GetLastError()); + + /* NULL checks */ + retok = CopyFileA(NULL, dest, TRUE); + ok(!retok && GetLastError() == ERROR_PATH_NOT_FOUND, + "CopyFileA: ret = %d, unexpected error %ld\n", retok, GetLastError()); + retok = CopyFileA(source, NULL, TRUE); + ok(!retok && GetLastError() == ERROR_PATH_NOT_FOUND, + "CopyFileA: ret = %d, unexpected error %ld\n", retok, GetLastError()); /* copying from a read-locked source fails */ hfile = CreateFileA(source, GENERIC_READ, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); - ok(hfile != INVALID_HANDLE_VALUE, "failed to open source file, error %d\n", GetLastError()); + ok(hfile != INVALID_HANDLE_VALUE, "failed to open source file, error %ld\n", GetLastError()); retok = CopyFileA(source, dest, FALSE); ok(!retok && GetLastError() == ERROR_SHARING_VIOLATION, "copying from a read-locked file succeeded when it shouldn't have\n"); /* in addition, the source is opened before the destination */ retok = CopyFileA("25f99d3b-4ba4-4f66-88f5-2906886993cc", dest, FALSE); ok(!retok && GetLastError() == ERROR_FILE_NOT_FOUND, - "copying from a file that doesn't exist failed in an unexpected way (ret=%d, err=%d)\n", retok, GetLastError()); + "copying from a file that doesn't exist failed in an unexpected way (ret=%d, err=%ld)\n", retok, GetLastError()); CloseHandle(hfile); /* copying from a r+w opened, r shared source succeeds */ hfile = CreateFileA(source, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); - ok(hfile != INVALID_HANDLE_VALUE, "failed to open source file, error %d\n", GetLastError()); + ok(hfile != INVALID_HANDLE_VALUE, "failed to open source file, error %ld\n", GetLastError()); retok = CopyFileA(source, dest, FALSE); ok(retok, - "copying from an r+w opened and r shared file failed (ret=%d, err=%d)\n", retok, GetLastError()); + "copying from an r+w opened and r shared file failed (ret=%d, err=%ld)\n", retok, GetLastError()); CloseHandle(hfile); /* copying from a delete-locked source mostly succeeds */ hfile = CreateFileA(source, DELETE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); - ok(hfile != INVALID_HANDLE_VALUE, "failed to open source file, error %d\n", GetLastError()); + ok(hfile != INVALID_HANDLE_VALUE, "failed to open source file, error %ld\n", GetLastError()); retok = CopyFileA(source, dest, FALSE); ok(retok || broken(!retok && GetLastError() == ERROR_SHARING_VIOLATION) /* NT, 2000, XP */, - "copying from a delete-locked file failed (ret=%d, err=%d)\n", retok, GetLastError()); + "copying from a delete-locked file failed (ret=%d, err=%ld)\n", retok, GetLastError()); CloseHandle(hfile); /* copying to a write-locked destination fails */ hfile = CreateFileA(dest, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); - ok(hfile != INVALID_HANDLE_VALUE, "failed to open destination file, error %d\n", GetLastError()); + ok(hfile != INVALID_HANDLE_VALUE, "failed to open destination file, error %ld\n", GetLastError()); retok = CopyFileA(source, dest, FALSE); ok(!retok && GetLastError() == ERROR_SHARING_VIOLATION, - "copying to a write-locked file didn't fail (ret=%d, err=%d)\n", retok, GetLastError()); + "copying to a write-locked file didn't fail (ret=%d, err=%ld)\n", retok, GetLastError()); CloseHandle(hfile); /* copying to a r+w opened, w shared destination mostly succeeds */ hfile = CreateFileA(dest, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); - ok(hfile != INVALID_HANDLE_VALUE, "failed to open destination file, error %d\n", GetLastError()); + ok(hfile != INVALID_HANDLE_VALUE, "failed to open destination file, error %ld\n", GetLastError()); retok = CopyFileA(source, dest, FALSE); ok(retok || broken(!retok && GetLastError() == ERROR_SHARING_VIOLATION) /* Win 9x */, - "copying to a r+w opened and w shared file failed (ret=%d, err=%d)\n", retok, GetLastError()); + "copying to a r+w opened and w shared file failed (ret=%d, err=%ld)\n", retok, GetLastError()); CloseHandle(hfile); /* copying to a delete-locked destination fails, even when the destination is delete-shared */ hfile = CreateFileA(dest, DELETE, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, 0); ok(hfile != INVALID_HANDLE_VALUE || broken(GetLastError() == ERROR_INVALID_PARAMETER) /* Win 9x */, - "failed to open destination file, error %d\n", GetLastError()); + "failed to open destination file, error %ld\n", GetLastError()); if (hfile != INVALID_HANDLE_VALUE) { retok = CopyFileA(source, dest, FALSE); ok(!retok && GetLastError() == ERROR_SHARING_VIOLATION, - "copying to a delete-locked shared file didn't fail (ret=%d, err=%d)\n", retok, GetLastError()); + "copying to a delete-locked shared file didn't fail (ret=%d, err=%ld)\n", retok, GetLastError()); CloseHandle(hfile); } /* copy to a file that's opened the way Wine opens the source */ hfile = CreateFileA(dest, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); - ok(hfile != INVALID_HANDLE_VALUE, "failed to open destination file, error %d\n", GetLastError()); + ok(hfile != INVALID_HANDLE_VALUE, "failed to open destination file, error %ld\n", GetLastError()); retok = CopyFileA(source, dest, FALSE); ok(retok || broken(GetLastError() == ERROR_SHARING_VIOLATION) /* Win 9x */, - "copying to a file opened the way Wine opens the source failed (ret=%d, err=%d)\n", retok, GetLastError()); + "copying to a file opened the way Wine opens the source failed (ret=%d, err=%ld)\n", retok, GetLastError()); CloseHandle(hfile); /* make sure that destination has correct size */ hfile = CreateFileA(dest, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); ok(hfile != INVALID_HANDLE_VALUE, "failed to open destination file\n"); ret = GetFileSize(hfile, NULL); - ok(ret == sizeof(prefix), "destination file has wrong size %d\n", ret); + ok(ret == sizeof(prefix), "destination file has wrong size %ld\n", ret); /* make sure that destination has the same filetime */ ret = GetFileTime(hfile, NULL, NULL, &ft2); - ok( ret, "GetFileTime error %d\n", GetLastError()); + ok( ret, "GetFileTime error %ld\n", GetLastError()); ok(CompareFileTime(&ft1, &ft2) == 0, "destination file has wrong filetime\n"); SetLastError(0xdeadbeef); ret = CopyFileA(source, dest, FALSE); ok(!ret && GetLastError() == ERROR_SHARING_VIOLATION, - "CopyFileA: ret = %d, unexpected error %d\n", ret, GetLastError()); + "CopyFileA: ret = %ld, unexpected error %ld\n", ret, GetLastError()); /* make sure that destination still has correct size */ ret = GetFileSize(hfile, NULL); - ok(ret == sizeof(prefix), "destination file has wrong size %d\n", ret); + ok(ret == sizeof(prefix), "destination file has wrong size %ld\n", ret); retok = ReadFile(hfile, buf, sizeof(buf), &ret, NULL); ok( retok && ret == sizeof(prefix), - "ReadFile: error %d\n", GetLastError()); + "ReadFile: error %ld\n", GetLastError()); ok(!memcmp(prefix, buf, sizeof(prefix)), "buffer contents mismatch\n"); /* check error on copying over a mapped file that was opened with FILE_SHARE_READ */ hmapfile = CreateFileMappingW(hfile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL); - ok(hmapfile != NULL, "CreateFileMapping: error %d\n", GetLastError()); + ok(hmapfile != NULL, "CreateFileMapping: error %ld\n", GetLastError()); ret = CopyFileA(source, dest, FALSE); ok(!ret && GetLastError() == ERROR_SHARING_VIOLATION, - "CopyFileA with mapped dest file: expected ERROR_SHARING_VIOLATION, got %d\n", GetLastError()); + "CopyFileA with mapped dest file: expected ERROR_SHARING_VIOLATION, got %ld\n", GetLastError()); CloseHandle(hmapfile); CloseHandle(hfile); @@ -827,21 +839,71 @@ static void test_CopyFileA(void) /* check error on copying over a mapped file that was opened with FILE_SHARE_WRITE */ hmapfile = CreateFileMappingW(hfile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL); - ok(hmapfile != NULL, "CreateFileMapping: error %d\n", GetLastError()); + ok(hmapfile != NULL, "CreateFileMapping: error %ld\n", GetLastError()); ret = CopyFileA(source, dest, FALSE); ok(!ret, "CopyFileA: expected failure\n"); ok(GetLastError() == ERROR_USER_MAPPED_FILE || broken(GetLastError() == ERROR_SHARING_VIOLATION), /* Win9x */ - "CopyFileA with mapped dest file: expected ERROR_USER_MAPPED_FILE, got %d\n", GetLastError()); + "CopyFileA with mapped dest file: expected ERROR_USER_MAPPED_FILE, got %ld\n", GetLastError()); CloseHandle(hmapfile); CloseHandle(hfile); - ret = DeleteFileA(source); - ok(ret, "DeleteFileA: error %d\n", GetLastError()); + /* check read-only attribute */ + ret = GetFileAttributesA(source); + ok(ret != INVALID_FILE_ATTRIBUTES, "GetFileAttributesA: error %ld\n", GetLastError()); + ok(!(ret & FILE_ATTRIBUTE_READONLY), "source is read-only\n"); + ret = GetFileAttributesA(dest); + ok(ret != INVALID_FILE_ATTRIBUTES, "GetFileAttributesA: error %ld\n", GetLastError()); + ok(!(ret & FILE_ATTRIBUTE_READONLY), "dest is read-only\n"); + + /* make source read-only */ + ret = SetFileAttributesA(source, FILE_ATTRIBUTE_READONLY); + ok(ret, "SetFileAttributesA: error %ld\n", GetLastError()); + ret = GetFileAttributesA(source); + ok(ret != INVALID_FILE_ATTRIBUTES, "GetFileAttributesA: error %ld\n", GetLastError()); + ok(ret & FILE_ATTRIBUTE_READONLY, "source is not read-only\n"); + ret = GetFileAttributesA(dest); + ok(ret != INVALID_FILE_ATTRIBUTES, "GetFileAttributesA: error %ld\n", GetLastError()); + ok(!(ret & FILE_ATTRIBUTE_READONLY), "dest is read-only\n"); + + /* dest becomes read-only after copied from read-only source */ + ret = SetFileAttributesA(source, FILE_ATTRIBUTE_READONLY); + ok(ret, "SetFileAttributesA: error %ld\n", GetLastError()); + ret = GetFileAttributesA(source); + ok(ret != INVALID_FILE_ATTRIBUTES, "GetFileAttributesA: error %ld\n", GetLastError()); + ok(ret & FILE_ATTRIBUTE_READONLY, "source is not read-only\n"); + ret = GetFileAttributesA(dest); + ok(ret != INVALID_FILE_ATTRIBUTES, "GetFileAttributesA: error %ld\n", GetLastError()); + ok(!(ret & FILE_ATTRIBUTE_READONLY), "dest is read-only\n"); + + ret = CopyFileA(source, dest, FALSE); + ok(ret, "CopyFileA: error %ld\n", GetLastError()); + ret = GetFileAttributesA(dest); + ok(ret != INVALID_FILE_ATTRIBUTES, "GetFileAttributesA: error %ld\n", GetLastError()); + ok(ret & FILE_ATTRIBUTE_READONLY, "dest is not read-only\n"); + + /* same when dest does not exist */ + ret = SetFileAttributesA(dest, FILE_ATTRIBUTE_NORMAL); + ok(ret, "SetFileAttributesA: error %ld\n", GetLastError()); ret = DeleteFileA(dest); - ok(ret, "DeleteFileA: error %d\n", GetLastError()); + ok(ret, "DeleteFileA: error %ld\n", GetLastError()); + ret = CopyFileA(source, dest, TRUE); + ok(ret, "CopyFileA: error %ld\n", GetLastError()); + ret = GetFileAttributesA(dest); + ok(ret != INVALID_FILE_ATTRIBUTES, "GetFileAttributesA: error %ld\n", GetLastError()); + ok(ret & FILE_ATTRIBUTE_READONLY, "dest is not read-only\n"); + + ret = SetFileAttributesA(source, FILE_ATTRIBUTE_NORMAL); + ok(ret, "SetFileAttributesA: error %ld\n", GetLastError()); + ret = SetFileAttributesA(dest, FILE_ATTRIBUTE_NORMAL); + ok(ret, "SetFileAttributesA: error %ld\n", GetLastError()); + + ret = DeleteFileA(source); + ok(ret, "DeleteFileA: error %ld\n", GetLastError()); + ret = DeleteFileA(dest); + ok(ret, "DeleteFileA: error %ld\n", GetLastError()); } static void test_CopyFileW(void) @@ -857,26 +919,35 @@ static void test_CopyFileW(void) win_skip("GetTempPathW is not available\n"); return; } - ok(ret != 0, "GetTempPathW error %d\n", GetLastError()); + ok(ret != 0, "GetTempPathW error %ld\n", GetLastError()); ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n"); ret = GetTempFileNameW(temp_path, prefix, 0, source); - ok(ret != 0, "GetTempFileNameW error %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameW error %ld\n", GetLastError()); ret = GetTempFileNameW(temp_path, prefix, 0, dest); - ok(ret != 0, "GetTempFileNameW error %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameW error %ld\n", GetLastError()); ret = CopyFileW(source, dest, TRUE); ok(!ret && GetLastError() == ERROR_FILE_EXISTS, - "CopyFileW: unexpected error %d\n", GetLastError()); + "CopyFileW: unexpected error %ld\n", GetLastError()); + SetLastError(0xdeadbeef); ret = CopyFileW(source, dest, FALSE); - ok(ret, "CopyFileW: error %d\n", GetLastError()); + ok(ret, "CopyFileW: error %ld\n", GetLastError()); + ok(GetLastError() == ERROR_SUCCESS || broken(GetLastError() == ERROR_INVALID_PARAMETER) /* some win8 machines */, + "Unexpected error %lu.\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = CopyFileExW(source, dest, NULL, NULL, NULL, 0 ); + ok(ret, "CopyFileExW: error %ld\n", GetLastError()); + ok(GetLastError() == ERROR_SUCCESS || broken(GetLastError() == ERROR_INVALID_PARAMETER) /* some win8 machines */, + "Unexpected error %lu.\n", GetLastError()); ret = DeleteFileW(source); - ok(ret, "DeleteFileW: error %d\n", GetLastError()); + ok(ret, "DeleteFileW: error %ld\n", GetLastError()); ret = DeleteFileW(dest); - ok(ret, "DeleteFileW: error %d\n", GetLastError()); + ok(ret, "DeleteFileW: error %ld\n", GetLastError()); } static void test_CopyFile2(void) @@ -893,19 +964,19 @@ static void test_CopyFile2(void) if (!pCopyFile2) { - skip("CopyFile2 is not available\n"); + todo_wine win_skip("CopyFile2 is not available\n"); return; } ret = GetTempPathW(MAX_PATH, temp_path); - ok(ret != 0, "GetTempPathW error %d\n", GetLastError()); + ok(ret != 0, "GetTempPathW error %ld\n", GetLastError()); ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n"); ret = GetTempFileNameW(temp_path, prefix, 0, source); - ok(ret != 0, "GetTempFileNameW error %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameW error %ld\n", GetLastError()); ret = GetTempFileNameW(temp_path, prefix, 0, dest); - ok(ret != 0, "GetTempFileNameW error %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameW error %ld\n", GetLastError()); /* fail if exists */ memset(¶ms, 0, sizeof(params)); @@ -914,15 +985,15 @@ static void test_CopyFile2(void) SetLastError(0xdeadbeef); hr = pCopyFile2(source, dest, ¶ms); - ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_EXISTS), "CopyFile2: unexpected error 0x%08x\n", hr); - ok(GetLastError() == ERROR_FILE_EXISTS, "CopyFile2: last error %d\n", GetLastError()); + ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_EXISTS), "CopyFile2: unexpected error 0x%08lx\n", hr); + ok(GetLastError() == ERROR_FILE_EXISTS, "CopyFile2: last error %ld\n", GetLastError()); /* don't fail if exists */ params.dwSize = sizeof(params); params.dwCopyFlags = 0; hr = pCopyFile2(source, dest, ¶ms); - ok(hr == S_OK, "CopyFile2: error 0x%08x\n", hr); + ok(hr == S_OK, "CopyFile2: error 0x%08lx\n", hr); /* copying a file to itself must fail */ params.dwSize = sizeof(params); @@ -930,160 +1001,160 @@ static void test_CopyFile2(void) SetLastError(0xdeadbeef); hr = pCopyFile2(source, source, ¶ms); - ok(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), "CopyFile2: copying a file to itself didn't fail, 0x%08x\n", hr); - ok(GetLastError() == ERROR_SHARING_VIOLATION, "CopyFile2: last error %d\n", GetLastError()); + ok(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), "CopyFile2: copying a file to itself didn't fail, 0x%08lx\n", hr); + ok(GetLastError() == ERROR_SHARING_VIOLATION, "CopyFile2: last error %ld\n", GetLastError()); /* make the source have not zero size */ hfile = CreateFileW(source, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0 ); ok(hfile != INVALID_HANDLE_VALUE, "failed to open source file\n"); ret = WriteFile(hfile, prefix, sizeof(prefix), &len, NULL ); - ok(ret && len == sizeof(prefix), "WriteFile error %d\n", GetLastError()); + ok(ret && len == sizeof(prefix), "WriteFile error %ld\n", GetLastError()); ok(GetFileSize(hfile, NULL) == sizeof(prefix), "source file has wrong size\n"); /* get the file time and change it to prove the difference */ ret = GetFileTime(hfile, NULL, NULL, &ft1); - ok(ret, "GetFileTime error %d\n", GetLastError()); + ok(ret, "GetFileTime error %ld\n", GetLastError()); ft1.dwLowDateTime -= 600000000; /* 60 second */ ret = SetFileTime(hfile, NULL, NULL, &ft1); - ok(ret, "SetFileTime error %d\n", GetLastError()); + ok(ret, "SetFileTime error %ld\n", GetLastError()); GetFileTime(hfile, NULL, NULL, &ft1); /* get the actual time back */ CloseHandle(hfile); ret = GetTempFileNameW(temp_path, prefix, 0, dest); - ok(ret != 0, "GetTempFileNameA error %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameA error %ld\n", GetLastError()); params.dwSize = sizeof(params); params.dwCopyFlags = COPY_FILE_FAIL_IF_EXISTS; SetLastError(0xdeadbeef); hr = pCopyFile2(source, dest, ¶ms); - ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_EXISTS), "CopyFile2: unexpected error 0x%08x\n", hr); - ok(GetLastError() == ERROR_FILE_EXISTS, "CopyFile2: last error %d\n", GetLastError()); + ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_EXISTS), "CopyFile2: unexpected error 0x%08lx\n", hr); + ok(GetLastError() == ERROR_FILE_EXISTS, "CopyFile2: last error %ld\n", GetLastError()); params.dwSize = sizeof(params); params.dwCopyFlags = 0; hr = pCopyFile2(source, dest, ¶ms); - ok(ret, "CopyFile2: error 0x%08x\n", hr); + ok(ret, "CopyFile2: error 0x%08lx\n", hr); /* copying from a read-locked source fails */ hfile = CreateFileW(source, GENERIC_READ, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); - ok(hfile != INVALID_HANDLE_VALUE, "failed to open source file, error %d\n", GetLastError()); + ok(hfile != INVALID_HANDLE_VALUE, "failed to open source file, error %ld\n", GetLastError()); params.dwSize = sizeof(params); params.dwCopyFlags = 0; SetLastError(0xdeadbeef); hr = pCopyFile2(source, dest, ¶ms); - ok(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), "CopyFile2: unexpected error 0x%08x\n", hr); - ok(GetLastError() == ERROR_SHARING_VIOLATION, "CopyFile2: last error %d\n", GetLastError()); + ok(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), "CopyFile2: unexpected error 0x%08lx\n", hr); + ok(GetLastError() == ERROR_SHARING_VIOLATION, "CopyFile2: last error %ld\n", GetLastError()); /* in addition, the source is opened before the destination */ params.dwSize = sizeof(params); params.dwCopyFlags = 0; SetLastError(0xdeadbeef); hr = pCopyFile2(doesntexistW, dest, ¶ms); - ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "got 0x%08x\n", hr); - ok(GetLastError() == ERROR_FILE_NOT_FOUND, "CopyFile2: last error %d\n", GetLastError()); + ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "got 0x%08lx\n", hr); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "CopyFile2: last error %ld\n", GetLastError()); CloseHandle(hfile); /* copying from a r+w opened, r shared source succeeds */ hfile = CreateFileW(source, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); - ok(hfile != INVALID_HANDLE_VALUE, "failed to open source file, error %d\n", GetLastError()); + ok(hfile != INVALID_HANDLE_VALUE, "failed to open source file, error %ld\n", GetLastError()); params.dwSize = sizeof(params); params.dwCopyFlags = 0; hr = pCopyFile2(source, dest, ¶ms); - ok(hr == S_OK, "failed 0x%08x\n", hr); + ok(hr == S_OK, "failed 0x%08lx\n", hr); CloseHandle(hfile); /* copying from a delete-locked source mostly succeeds */ hfile = CreateFileW(source, DELETE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); - ok(hfile != INVALID_HANDLE_VALUE, "failed to open source file, error %d\n", GetLastError()); + ok(hfile != INVALID_HANDLE_VALUE, "failed to open source file, error %ld\n", GetLastError()); params.dwSize = sizeof(params); params.dwCopyFlags = 0; hr = pCopyFile2(source, dest, ¶ms); - ok(hr == S_OK, "failed 0x%08x\n", hr); + ok(hr == S_OK, "failed 0x%08lx\n", hr); CloseHandle(hfile); /* copying to a write-locked destination fails */ hfile = CreateFileW(dest, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); - ok(hfile != INVALID_HANDLE_VALUE, "failed to open destination file, error %d\n", GetLastError()); + ok(hfile != INVALID_HANDLE_VALUE, "failed to open destination file, error %ld\n", GetLastError()); params.dwSize = sizeof(params); params.dwCopyFlags = 0; SetLastError(0xdeadbeef); hr = pCopyFile2(source, dest, FALSE); - ok(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), "CopyFile2: unexpected error 0x%08x\n", hr); - ok(GetLastError() == ERROR_SHARING_VIOLATION, "CopyFile2: last error %d\n", GetLastError()); + ok(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), "CopyFile2: unexpected error 0x%08lx\n", hr); + ok(GetLastError() == ERROR_SHARING_VIOLATION, "CopyFile2: last error %ld\n", GetLastError()); CloseHandle(hfile); /* copying to a r+w opened, w shared destination mostly succeeds */ hfile = CreateFileW(dest, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); - ok(hfile != INVALID_HANDLE_VALUE, "failed to open destination file, error %d\n", GetLastError()); + ok(hfile != INVALID_HANDLE_VALUE, "failed to open destination file, error %ld\n", GetLastError()); params.dwSize = sizeof(params); params.dwCopyFlags = 0; hr = pCopyFile2(source, dest, FALSE); - ok(hr == S_OK, "got 0x%08x\n", hr); + ok(hr == S_OK, "got 0x%08lx\n", hr); CloseHandle(hfile); /* copying to a delete-locked destination fails, even when the destination is delete-shared */ hfile = CreateFileW(dest, DELETE, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, 0); - ok(hfile != INVALID_HANDLE_VALUE, "failed to open destination file, error %d\n", GetLastError()); + ok(hfile != INVALID_HANDLE_VALUE, "failed to open destination file, error %ld\n", GetLastError()); params.dwSize = sizeof(params); params.dwCopyFlags = 0; SetLastError(0xdeadbeef); hr = pCopyFile2(source, dest, ¶ms); - ok(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), "CopyFile2: unexpected error 0x%08x\n", hr); - ok(GetLastError() == ERROR_SHARING_VIOLATION, "CopyFile2: last error %d\n", GetLastError()); + ok(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), "CopyFile2: unexpected error 0x%08lx\n", hr); + ok(GetLastError() == ERROR_SHARING_VIOLATION, "CopyFile2: last error %ld\n", GetLastError()); CloseHandle(hfile); /* copy to a file that's opened the way Wine opens the source */ hfile = CreateFileW(dest, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); - ok(hfile != INVALID_HANDLE_VALUE, "failed to open destination file, error %d\n", GetLastError()); + ok(hfile != INVALID_HANDLE_VALUE, "failed to open destination file, error %ld\n", GetLastError()); params.dwSize = sizeof(params); params.dwCopyFlags = 0; hr = pCopyFile2(source, dest, ¶ms); - ok(hr == S_OK, "got 0x%08x\n", hr); + ok(hr == S_OK, "got 0x%08lx\n", hr); CloseHandle(hfile); /* make sure that destination has correct size */ hfile = CreateFileW(dest, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); ok(hfile != INVALID_HANDLE_VALUE, "failed to open destination file\n"); ret = GetFileSize(hfile, NULL); - ok(ret == sizeof(prefix), "destination file has wrong size %d\n", ret); + ok(ret == sizeof(prefix), "destination file has wrong size %ld\n", ret); /* make sure that destination has the same filetime */ ret = GetFileTime(hfile, NULL, NULL, &ft2); - ok(ret, "GetFileTime error %d\n", GetLastError()); + ok(ret, "GetFileTime error %ld\n", GetLastError()); ok(CompareFileTime(&ft1, &ft2) == 0, "destination file has wrong filetime\n"); params.dwSize = sizeof(params); params.dwCopyFlags = 0; SetLastError(0xdeadbeef); hr = pCopyFile2(source, dest, ¶ms); - ok(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), "CopyFile2: unexpected error 0x%08x\n", hr); - ok(GetLastError() == ERROR_SHARING_VIOLATION, "CopyFile2: last error %d\n", GetLastError()); + ok(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), "CopyFile2: unexpected error 0x%08lx\n", hr); + ok(GetLastError() == ERROR_SHARING_VIOLATION, "CopyFile2: last error %ld\n", GetLastError()); /* make sure that destination still has correct size */ ret = GetFileSize(hfile, NULL); - ok(ret == sizeof(prefix), "destination file has wrong size %d\n", ret); + ok(ret == sizeof(prefix), "destination file has wrong size %ld\n", ret); ret = ReadFile(hfile, buf, sizeof(buf), &len, NULL); - ok(ret && len == sizeof(prefix), "ReadFile: error %d\n", GetLastError()); + ok(ret && len == sizeof(prefix), "ReadFile: error %ld\n", GetLastError()); ok(!memcmp(prefix, buf, sizeof(prefix)), "buffer contents mismatch\n"); /* check error on copying over a mapped file that was opened with FILE_SHARE_READ */ hmapfile = CreateFileMappingW(hfile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL); - ok(hmapfile != NULL, "CreateFileMapping: error %d\n", GetLastError()); + ok(hmapfile != NULL, "CreateFileMapping: error %ld\n", GetLastError()); params.dwSize = sizeof(params); params.dwCopyFlags = 0; SetLastError(0xdeadbeef); hr = pCopyFile2(source, dest, ¶ms); - ok(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), "CopyFile2: unexpected error 0x%08x\n", hr); - ok(GetLastError() == ERROR_SHARING_VIOLATION, "CopyFile2: last error %d\n", GetLastError()); + ok(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), "CopyFile2: unexpected error 0x%08lx\n", hr); + ok(GetLastError() == ERROR_SHARING_VIOLATION, "CopyFile2: last error %ld\n", GetLastError()); CloseHandle(hmapfile); CloseHandle(hfile); @@ -1093,13 +1164,13 @@ static void test_CopyFile2(void) /* check error on copying over a mapped file that was opened with FILE_SHARE_WRITE */ hmapfile = CreateFileMappingW(hfile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL); - ok(hmapfile != NULL, "CreateFileMapping: error %d\n", GetLastError()); + ok(hmapfile != NULL, "CreateFileMapping: error %ld\n", GetLastError()); params.dwSize = sizeof(params); params.dwCopyFlags = 0; hr = pCopyFile2(source, dest, ¶ms); - ok(hr == HRESULT_FROM_WIN32(ERROR_USER_MAPPED_FILE), "CopyFile2: unexpected error 0x%08x\n", hr); - ok(GetLastError() == ERROR_USER_MAPPED_FILE, "CopyFile2: last error %d\n", GetLastError()); + ok(hr == HRESULT_FROM_WIN32(ERROR_USER_MAPPED_FILE), "CopyFile2: unexpected error 0x%08lx\n", hr); + ok(GetLastError() == ERROR_USER_MAPPED_FILE, "CopyFile2: last error %ld\n", GetLastError()); CloseHandle(hmapfile); CloseHandle(hfile); @@ -1112,7 +1183,7 @@ static DWORD WINAPI copy_progress_cb(LARGE_INTEGER total_size, LARGE_INTEGER tot LARGE_INTEGER stream_size, LARGE_INTEGER stream_transferred, DWORD stream, DWORD reason, HANDLE source, HANDLE dest, LPVOID userdata) { - ok(reason == CALLBACK_STREAM_SWITCH, "expected CALLBACK_STREAM_SWITCH, got %u\n", reason); + ok(reason == CALLBACK_STREAM_SWITCH, "expected CALLBACK_STREAM_SWITCH, got %lu\n", reason); CloseHandle(userdata); return PROGRESS_CANCEL; } @@ -1127,34 +1198,47 @@ static void test_CopyFileEx(void) BOOL retok; ret = GetTempPathA(MAX_PATH, temp_path); - ok(ret != 0, "GetTempPathA error %d\n", GetLastError()); + ok(ret != 0, "GetTempPathA error %ld\n", GetLastError()); ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n"); ret = GetTempFileNameA(temp_path, prefix, 0, source); - ok(ret != 0, "GetTempFileNameA error %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameA error %ld\n", GetLastError()); ret = GetTempFileNameA(temp_path, prefix, 0, dest); - ok(ret != 0, "GetTempFileNameA error %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameA error %ld\n", GetLastError()); hfile = CreateFileA(dest, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); - ok(hfile != INVALID_HANDLE_VALUE, "failed to open destination file, error %d\n", GetLastError()); + ok(hfile != INVALID_HANDLE_VALUE, "failed to open destination file, error %ld\n", GetLastError()); SetLastError(0xdeadbeef); retok = CopyFileExA(source, dest, copy_progress_cb, hfile, NULL, 0); + todo_wine ok(!retok, "CopyFileExA unexpectedly succeeded\n"); - ok(GetLastError() == ERROR_REQUEST_ABORTED, "expected ERROR_REQUEST_ABORTED, got %d\n", GetLastError()); + todo_wine + ok(GetLastError() == ERROR_REQUEST_ABORTED, "expected ERROR_REQUEST_ABORTED, got %ld\n", GetLastError()); ok(GetFileAttributesA(dest) != INVALID_FILE_ATTRIBUTES, "file was deleted\n"); hfile = CreateFileA(dest, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, 0); - ok(hfile != INVALID_HANDLE_VALUE, "failed to open destination file, error %d\n", GetLastError()); + todo_wine + ok(hfile != INVALID_HANDLE_VALUE, "failed to open destination file, error %ld\n", GetLastError()); SetLastError(0xdeadbeef); retok = CopyFileExA(source, dest, copy_progress_cb, hfile, NULL, 0); + todo_wine ok(!retok, "CopyFileExA unexpectedly succeeded\n"); - ok(GetLastError() == ERROR_REQUEST_ABORTED, "expected ERROR_REQUEST_ABORTED, got %d\n", GetLastError()); + todo_wine + ok(GetLastError() == ERROR_REQUEST_ABORTED, "expected ERROR_REQUEST_ABORTED, got %ld\n", GetLastError()); + todo_wine ok(GetFileAttributesA(dest) == INVALID_FILE_ATTRIBUTES, "file was not deleted\n"); + retok = CopyFileExA(source, NULL, copy_progress_cb, hfile, NULL, 0); + ok(!retok, "CopyFileExA unexpectedly succeeded\n"); + ok(GetLastError() == ERROR_PATH_NOT_FOUND, "expected ERROR_PATH_NOT_FOUND, got %ld\n", GetLastError()); + retok = CopyFileExA(NULL, dest, copy_progress_cb, hfile, NULL, 0); + ok(!retok, "CopyFileExA unexpectedly succeeded\n"); + ok(GetLastError() == ERROR_PATH_NOT_FOUND, "expected ERROR_PATH_NOT_FOUND, got %ld\n", GetLastError()); + ret = DeleteFileA(source); - ok(ret, "DeleteFileA failed with error %d\n", GetLastError()); + ok(ret, "DeleteFileA failed with error %ld\n", GetLastError()); ret = DeleteFileA(dest); ok(!ret, "DeleteFileA unexpectedly succeeded\n"); } @@ -1214,11 +1298,11 @@ static void test_CreateFileA(void) WCHAR curdir[MAX_PATH]; ret = GetTempPathA(MAX_PATH, temp_path); - ok(ret != 0, "GetTempPathA error %d\n", GetLastError()); + ok(ret != 0, "GetTempPathA error %ld\n", GetLastError()); ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n"); ret = GetTempFileNameA(temp_path, prefix, 0, filename); - ok(ret != 0, "GetTempFileNameA error %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameA error %ld\n", GetLastError()); SetLastError(0xdeadbeef); hFile = CreateFileA(filename, GENERIC_READ, 0, NULL, @@ -1230,7 +1314,7 @@ static void test_CreateFileA(void) hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_FLAG_RANDOM_ACCESS, 0); ok(hFile != INVALID_HANDLE_VALUE && GetLastError() == ERROR_ALREADY_EXISTS, - "hFile %p, last error %u\n", hFile, GetLastError()); + "hFile %p, last error %lu\n", hFile, GetLastError()); CloseHandle(hFile); @@ -1238,43 +1322,43 @@ static void test_CreateFileA(void) hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_FLAG_RANDOM_ACCESS, 0); ok(hFile != INVALID_HANDLE_VALUE && GetLastError() == ERROR_ALREADY_EXISTS, - "hFile %p, last error %u\n", hFile, GetLastError()); + "hFile %p, last error %lu\n", hFile, GetLastError()); CloseHandle(hFile); ret = DeleteFileA(filename); - ok(ret, "DeleteFileA: error %d\n", GetLastError()); + ok(ret, "DeleteFileA: error %ld\n", GetLastError()); SetLastError(0xdeadbeef); hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_FLAG_RANDOM_ACCESS, 0); ok(hFile != INVALID_HANDLE_VALUE && GetLastError() == 0, - "hFile %p, last error %u\n", hFile, GetLastError()); + "hFile %p, last error %lu\n", hFile, GetLastError()); CloseHandle(hFile); ret = DeleteFileA(filename); - ok(ret, "DeleteFileA: error %d\n", GetLastError()); + ok(ret, "DeleteFileA: error %ld\n", GetLastError()); SetLastError(0xdeadbeef); hFile = CreateFileA("c:\\*.*", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); ok(hFile == INVALID_HANDLE_VALUE, "hFile should have been INVALID_HANDLE_VALUE\n"); ok(GetLastError() == ERROR_INVALID_NAME || broken(GetLastError() == ERROR_FILE_NOT_FOUND), /* Win98 */ - "LastError should have been ERROR_INVALID_NAME or ERROR_FILE_NOT_FOUND but got %u\n", GetLastError()); + "LastError should have been ERROR_INVALID_NAME or ERROR_FILE_NOT_FOUND but got %lu\n", GetLastError()); /* get windows drive letter */ ret = GetWindowsDirectoryA(windowsdir, sizeof(windowsdir)); ok(ret < sizeof(windowsdir), "windowsdir is abnormally long!\n"); - ok(ret != 0, "GetWindowsDirectory: error %d\n", GetLastError()); + ok(ret != 0, "GetWindowsDirectory: error %ld\n", GetLastError()); /* test error return codes from CreateFile for some cases */ ret = GetTempPathA(MAX_PATH, temp_path); - ok(ret != 0, "GetTempPathA error %d\n", GetLastError()); + ok(ret != 0, "GetTempPathA error %ld\n", GetLastError()); strcpy(dirname, temp_path); strcat(dirname, directory); ret = CreateDirectoryA(dirname, NULL); - ok( ret, "Createdirectory failed, gle=%d\n", GetLastError() ); + ok( ret, "Createdirectory failed, gle=%ld\n", GetLastError() ); /* set current drive & directory to known location */ GetCurrentDirectoryW( MAX_PATH, curdir); SetCurrentDirectoryA( temp_path ); @@ -1311,7 +1395,7 @@ static void test_CreateFileA(void) p[i].err != ERROR_ACCESS_DENIED) { if (p[i].todo_flag) - skip("Either no authority to volume, or is todo_wine for %s err=%d should be %d\n", filename, GetLastError(), p[i].err); + skip("Either no authority to volume, or is todo_wine for %s err=%ld should be %ld\n", filename, GetLastError(), p[i].err); else skip("Do not have authority to access volumes. Test for %s skipped\n", filename); } @@ -1322,7 +1406,7 @@ static void test_CreateFileA(void) ok((hFile == INVALID_HANDLE_VALUE && (p[i].err == GetLastError() || p[i].err2 == GetLastError())) || (hFile != INVALID_HANDLE_VALUE && p[i].err == ERROR_SUCCESS), - "CreateFileA failed on %s, hFile %p, err=%u, should be %u\n", + "CreateFileA failed on %s, hFile %p, err=%lu, should be %lu\n", filename, hFile, GetLastError(), p[i].err); } if (hFile != INVALID_HANDLE_VALUE) @@ -1330,7 +1414,7 @@ static void test_CreateFileA(void) i++; } ret = RemoveDirectoryA(dirname); - ok(ret, "RemoveDirectoryA: error %d\n", GetLastError()); + ok(ret, "RemoveDirectoryA: error %ld\n", GetLastError()); SetCurrentDirectoryW(curdir); /* test opening directory as a directory */ @@ -1342,7 +1426,7 @@ static void test_CreateFileA(void) if (hFile != INVALID_HANDLE_VALUE && GetLastError() != ERROR_PATH_NOT_FOUND) { ok(hFile != INVALID_HANDLE_VALUE && GetLastError() == ERROR_SUCCESS, - "CreateFileA did not work, last error %u on volume <%s>\n", + "CreateFileA did not work, last error %lu on volume <%s>\n", GetLastError(), temp_path ); if (hFile != INVALID_HANDLE_VALUE) @@ -1351,7 +1435,7 @@ static void test_CreateFileA(void) if (ret) { ok(Finfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY, - "CreateFileA probably did not open temp directory %s correctly\n file information does not include FILE_ATTRIBUTE_DIRECTORY, actual=0x%08x\n", + "CreateFileA probably did not open temp directory %s correctly\n file information does not include FILE_ATTRIBUTE_DIRECTORY, actual=0x%08lx\n", temp_path, Finfo.dwFileAttributes); } CloseHandle( hFile ); @@ -1375,7 +1459,7 @@ static void test_CreateFileA(void) (GetLastError() != ERROR_ACCESS_DENIED && GetLastError() != ERROR_BAD_NETPATH)) { /* if we have adm rights to volume, then try rest of tests */ - ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA did not open %s, last error=%u\n", + ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA did not open %s, last error=%lu\n", filename, GetLastError()); if (hFile != INVALID_HANDLE_VALUE) { @@ -1384,7 +1468,7 @@ static void test_CreateFileA(void) /* what the data is at this time. */ len = 512; ret = ReadFile( hFile, buffer, len, &len, NULL ); - todo_wine ok(ret, "Failed to read volume, last error %u, %u, for %s\n", + todo_wine ok(ret, "Failed to read volume, last error %lu, %lu, for %s\n", GetLastError(), ret, filename); if (ret) { @@ -1405,7 +1489,7 @@ static void test_CreateFileA(void) FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL ); todo_wine ok(hFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PATH_NOT_FOUND, - "CreateFileA should have returned ERROR_PATH_NOT_FOUND on %s, but got %u\n", + "CreateFileA should have returned ERROR_PATH_NOT_FOUND on %s, but got %lu\n", filename, GetLastError()); if (hFile != INVALID_HANDLE_VALUE) CloseHandle( hFile ); @@ -1420,7 +1504,7 @@ static void test_CreateFileA(void) NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL ); ok(hFile != INVALID_HANDLE_VALUE, - "CreateFileA should have worked on %s, but got %u\n", + "CreateFileA should have worked on %s, but got %lu\n", filename, GetLastError()); if (hFile != INVALID_HANDLE_VALUE) CloseHandle( hFile ); @@ -1434,7 +1518,7 @@ static void test_CreateFileA(void) FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL ); - ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA did not open %s, last error=%u\n", + ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA did not open %s, last error=%lu\n", filename, GetLastError()); if (hFile != INVALID_HANDLE_VALUE) CloseHandle( hFile ); @@ -1453,7 +1537,7 @@ static void test_CreateFileA(void) strcpy(filename, "c:\\"); filename[0] = windowsdir[0]; ret = pGetVolumeNameForVolumeMountPointA( filename, Volume_1, MAX_PATH ); - ok(ret, "GetVolumeNameForVolumeMountPointA failed, for %s, last error=%d\n", filename, GetLastError()); + ok(ret, "GetVolumeNameForVolumeMountPointA failed, for %s, last error=%ld\n", filename, GetLastError()); if (ret) { ok(strlen(Volume_1) == 49, "GetVolumeNameForVolumeMountPointA returned wrong length name <%s>\n", Volume_1); @@ -1473,7 +1557,7 @@ static void test_CreateFileA(void) filename, hFile); todo_wine ok(hFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PATH_NOT_FOUND, - "CreateFileA should have returned ERROR_PATH_NOT_FOUND on %s, but got %u\n", + "CreateFileA should have returned ERROR_PATH_NOT_FOUND on %s, but got %lu\n", filename, GetLastError()); if (hFile != INVALID_HANDLE_VALUE) CloseHandle( hFile ); @@ -1490,7 +1574,7 @@ static void test_CreateFileA(void) FILE_FLAG_BACKUP_SEMANTICS, NULL ); todo_wine ok(hFile != INVALID_HANDLE_VALUE, - "CreateFileA should have opened %s, but got %u\n", + "CreateFileA should have opened %s, but got %lu\n", filename, GetLastError()); if (hFile != INVALID_HANDLE_VALUE) CloseHandle( hFile ); @@ -1509,7 +1593,7 @@ static void test_CreateFileA(void) if (hFile != INVALID_HANDLE_VALUE || GetLastError() != ERROR_ACCESS_DENIED) { /* if we have adm rights to volume, then try rest of tests */ - ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA did not open %s, last error=%u\n", + ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA did not open %s, last error=%lu\n", filename, GetLastError()); if (hFile != INVALID_HANDLE_VALUE) { @@ -1518,7 +1602,7 @@ static void test_CreateFileA(void) /* what the data is at this time. */ len = 512; ret = ReadFile( hFile, buffer, len, &len, NULL ); - todo_wine ok(ret, "Failed to read volume, last error %u, %u, for %s\n", + todo_wine ok(ret, "Failed to read volume, last error %lu, %lu, for %s\n", GetLastError(), ret, filename); if (ret) { @@ -1554,11 +1638,11 @@ static void test_CreateFileW(void) win_skip("GetTempPathW is not available\n"); return; } - ok(ret != 0, "GetTempPathW error %d\n", GetLastError()); + ok(ret != 0, "GetTempPathW error %ld\n", GetLastError()); ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n"); ret = GetTempFileNameW(temp_path, prefix, 0, filename); - ok(ret != 0, "GetTempFileNameW error %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameW error %ld\n", GetLastError()); SetLastError(0xdeadbeef); hFile = CreateFileW(filename, GENERIC_READ, 0, NULL, @@ -1570,7 +1654,7 @@ static void test_CreateFileW(void) hFile = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_FLAG_RANDOM_ACCESS, 0); ok(hFile != INVALID_HANDLE_VALUE && GetLastError() == ERROR_ALREADY_EXISTS, - "hFile %p, last error %u\n", hFile, GetLastError()); + "hFile %p, last error %lu\n", hFile, GetLastError()); CloseHandle(hFile); @@ -1578,23 +1662,23 @@ static void test_CreateFileW(void) hFile = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_FLAG_RANDOM_ACCESS, 0); ok(hFile != INVALID_HANDLE_VALUE && GetLastError() == ERROR_ALREADY_EXISTS, - "hFile %p, last error %u\n", hFile, GetLastError()); + "hFile %p, last error %lu\n", hFile, GetLastError()); CloseHandle(hFile); ret = DeleteFileW(filename); - ok(ret, "DeleteFileW: error %d\n", GetLastError()); + ok(ret, "DeleteFileW: error %ld\n", GetLastError()); SetLastError(0xdeadbeef); hFile = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_FLAG_RANDOM_ACCESS, 0); ok(hFile != INVALID_HANDLE_VALUE && GetLastError() == 0, - "hFile %p, last error %u\n", hFile, GetLastError()); + "hFile %p, last error %lu\n", hFile, GetLastError()); CloseHandle(hFile); ret = DeleteFileW(filename); - ok(ret, "DeleteFileW: error %d\n", GetLastError()); + ok(ret, "DeleteFileW: error %ld\n", GetLastError()); if (0) { @@ -1602,41 +1686,41 @@ static void test_CreateFileW(void) hFile = CreateFileW(NULL, GENERIC_READ, 0, NULL, CREATE_NEW, FILE_FLAG_RANDOM_ACCESS, 0); ok(hFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PATH_NOT_FOUND, - "CreateFileW(NULL) returned ret=%p error=%u\n",hFile,GetLastError()); + "CreateFileW(NULL) returned ret=%p error=%lu\n",hFile,GetLastError()); } hFile = CreateFileW(emptyW, GENERIC_READ, 0, NULL, CREATE_NEW, FILE_FLAG_RANDOM_ACCESS, 0); ok(hFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PATH_NOT_FOUND, - "CreateFileW(\"\") returned ret=%p error=%d\n",hFile,GetLastError()); + "CreateFileW(\"\") returned ret=%p error=%ld\n",hFile,GetLastError()); /* test the result of opening a nonexistent driver name */ hFile = CreateFileW(bogus, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 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()); + "CreateFileW on invalid VxD name returned ret=%p error=%ld\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()); + "expected CreateFile to succeed on existing directory, error: %ld\n", GetLastError()); CloseHandle(hFile); ret = RemoveDirectoryW(filename); - ok(ret, "DeleteFileW: error %d\n", GetLastError()); + ok(ret, "DeleteFileW: error %ld\n", GetLastError()); } static void test_CreateFile2(void) { - HANDLE hFile; + HANDLE hFile, iocp; WCHAR temp_path[MAX_PATH]; WCHAR filename[MAX_PATH]; CREATEFILE2_EXTENDED_PARAMETERS exparams; static const WCHAR emptyW[]={'\0'}; static const WCHAR prefix[] = {'p','f','x',0}; static const WCHAR bogus[] = { '\\', '\\', '.', '\\', 'B', 'O', 'G', 'U', 'S', 0 }; - DWORD ret; + DWORD i, ret; if (!pCreateFile2) { @@ -1645,16 +1729,16 @@ static void test_CreateFile2(void) } ret = GetTempPathW(MAX_PATH, temp_path); - ok(ret != 0, "GetTempPathW error %d\n", GetLastError()); + ok(ret != 0, "GetTempPathW error %ld\n", GetLastError()); ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n"); ret = GetTempFileNameW(temp_path, prefix, 0, filename); - ok(ret != 0, "GetTempFileNameW error %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameW error %ld\n", GetLastError()); SetLastError(0xdeadbeef); exparams.dwSize = sizeof(exparams); - exparams.dwFileAttributes = FILE_FLAG_RANDOM_ACCESS; - exparams.dwFileFlags = 0; + exparams.dwFileAttributes = 0; + exparams.dwFileFlags = FILE_FLAG_RANDOM_ACCESS; exparams.dwSecurityQosFlags = 0; exparams.lpSecurityAttributes = NULL; exparams.hTemplateFile = 0; @@ -1665,47 +1749,79 @@ static void test_CreateFile2(void) SetLastError(0xdeadbeef); hFile = pCreateFile2(filename, GENERIC_READ, FILE_SHARE_READ, CREATE_ALWAYS, &exparams); ok(hFile != INVALID_HANDLE_VALUE && GetLastError() == ERROR_ALREADY_EXISTS, - "hFile %p, last error %u\n", hFile, GetLastError()); + "hFile %p, last error %lu\n", hFile, GetLastError()); CloseHandle(hFile); SetLastError(0xdeadbeef); hFile = pCreateFile2(filename, GENERIC_READ, FILE_SHARE_READ, OPEN_ALWAYS, &exparams); ok(hFile != INVALID_HANDLE_VALUE && GetLastError() == ERROR_ALREADY_EXISTS, - "hFile %p, last error %u\n", hFile, GetLastError()); + "hFile %p, last error %lu\n", hFile, GetLastError()); CloseHandle(hFile); ret = DeleteFileW(filename); - ok(ret, "DeleteFileW: error %d\n", GetLastError()); + ok(ret, "DeleteFileW: error %ld\n", GetLastError()); SetLastError(0xdeadbeef); hFile = pCreateFile2(filename, GENERIC_READ, FILE_SHARE_READ, OPEN_ALWAYS, &exparams); ok(hFile != INVALID_HANDLE_VALUE && GetLastError() == 0, - "hFile %p, last error %u\n", hFile, GetLastError()); + "hFile %p, last error %lu\n", hFile, GetLastError()); CloseHandle(hFile); ret = DeleteFileW(filename); - ok(ret, "DeleteFileW: error %d\n", GetLastError()); + ok(ret, "DeleteFileW: error %ld\n", GetLastError()); hFile = pCreateFile2(emptyW, GENERIC_READ, 0, CREATE_NEW, &exparams); ok(hFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PATH_NOT_FOUND, - "CreateFile2(\"\") returned ret=%p error=%d\n",hFile,GetLastError()); + "CreateFile2(\"\") returned ret=%p error=%ld\n",hFile,GetLastError()); /* test the result of opening a nonexistent driver name */ exparams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL; hFile = pCreateFile2(bogus, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING, &exparams); ok(hFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND, - "CreateFile2 on invalid VxD name returned ret=%p error=%d\n",hFile,GetLastError()); + "CreateFile2 on invalid VxD name returned ret=%p error=%ld\n",hFile,GetLastError()); ret = CreateDirectoryW(filename, NULL); ok(ret == TRUE, "couldn't create temporary directory\n"); - exparams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS; + exparams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL; + exparams.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS; + SetLastError(0xdeadbeef); hFile = pCreateFile2(filename, GENERIC_READ | GENERIC_WRITE, 0, OPEN_ALWAYS, &exparams); - todo_wine - ok(hFile == INVALID_HANDLE_VALUE, - "expected CreateFile2 to fail on existing directory, error: %d\n", GetLastError()); + ok(hFile != INVALID_HANDLE_VALUE, + "CreateFile2 failed with FILE_FLAG_BACKUP_SEMANTICS on existing directory, error: %ld\n", GetLastError()); CloseHandle(hFile); ret = RemoveDirectoryW(filename); - ok(ret, "DeleteFileW: error %d\n", GetLastError()); + ok(ret, "DeleteFileW: error %ld\n", GetLastError()); + + for (i = 0; i < 2; ++i) + { + memset(&exparams, 0, sizeof(exparams)); + exparams.dwSize = sizeof(exparams); + if (i == 0) + { + exparams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL; + exparams.dwFileFlags = FILE_FLAG_OVERLAPPED | FILE_FLAG_DELETE_ON_CLOSE; + } + else + { + exparams.dwFileFlags = FILE_ATTRIBUTE_NORMAL; + exparams.dwFileAttributes = FILE_FLAG_OVERLAPPED | FILE_FLAG_DELETE_ON_CLOSE; + } + + SetLastError(0xdeadbeef); + hFile = pCreateFile2(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS, &exparams); + ok(hFile != INVALID_HANDLE_VALUE && GetLastError() == 0, "%ld: hFile %p, last error %lu\n", i, hFile, GetLastError()); + + iocp = CreateIoCompletionPort(hFile, NULL, 0, 2); + if (i == 1) ok(iocp == NULL && GetLastError() == ERROR_INVALID_PARAMETER, "%ld: CreateIoCompletionPort returned %p, error %lu\n", i, iocp, GetLastError()); + else ok(iocp != INVALID_HANDLE_VALUE && GetLastError() == 0, "%ld: CreateIoCompletionPort returned %p, error %lu\n", i, iocp, GetLastError()); + + CloseHandle(iocp); + CloseHandle(hFile); + + ret = DeleteFileW(filename); + if (i == 1) ok(ret, "%ld: unexpected DeleteFileW failure, error %lu\n", i, GetLastError()); + else ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, "%ld: unexpected DeleteFileW result, ret %ld error %lu\n", i, ret, GetLastError()); + } } static void test_GetTempFileNameA(void) @@ -1718,7 +1834,7 @@ static void test_GetTempFileNameA(void) result = GetWindowsDirectoryA(windowsdir, sizeof(windowsdir)); ok(result < sizeof(windowsdir), "windowsdir is abnormally long!\n"); - ok(result != 0, "GetWindowsDirectory: error %d\n", GetLastError()); + ok(result != 0, "GetWindowsDirectory: error %ld\n", GetLastError()); /* If the Windows directory is the root directory, it ends in backslash, not else. */ if (strlen(windowsdir) != 3) /* As in "C:\" or "F:\" */ @@ -1731,13 +1847,13 @@ static void test_GetTempFileNameA(void) windowsdrive[2] = '\0'; result = GetTempFileNameA(windowsdrive, "abc", 1, out); - ok(result != 0, "GetTempFileNameA: error %d\n", GetLastError()); + ok(result != 0, "GetTempFileNameA: error %ld\n", GetLastError()); ok(((out[0] == windowsdrive[0]) && (out[1] == ':')) && (out[2] == '\\'), "GetTempFileNameA: first three characters should be %c:\\, string was actually %s\n", windowsdrive[0], out); result = GetTempFileNameA(windowsdir, "abc", 2, out); - ok(result != 0, "GetTempFileNameA: error %d\n", GetLastError()); + ok(result != 0, "GetTempFileNameA: error %ld\n", GetLastError()); expected[0] = '\0'; strcat(expected, windowsdir); strcat(expected, "abc2.tmp"); @@ -1749,53 +1865,76 @@ static void test_DeleteFileA( void ) { BOOL ret; char temp_path[MAX_PATH], temp_file[MAX_PATH]; - HANDLE hfile; + HANDLE hfile, mapping; + char **argv; ret = DeleteFileA(NULL); ok(!ret && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_PATH_NOT_FOUND), - "DeleteFileA(NULL) returned ret=%d error=%d\n",ret,GetLastError()); + "DeleteFileA(NULL) returned ret=%d error=%ld\n",ret,GetLastError()); ret = DeleteFileA(""); ok(!ret && (GetLastError() == ERROR_PATH_NOT_FOUND || GetLastError() == ERROR_BAD_PATHNAME), - "DeleteFileA(\"\") returned ret=%d error=%d\n",ret,GetLastError()); + "DeleteFileA(\"\") returned ret=%d error=%ld\n",ret,GetLastError()); ret = DeleteFileA("nul"); ok(!ret && (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == ERROR_INVALID_FUNCTION), - "DeleteFileA(\"nul\") returned ret=%d error=%d\n",ret,GetLastError()); + "DeleteFileA(\"nul\") returned ret=%d error=%ld\n",ret,GetLastError()); ret = DeleteFileA("nonexist.txt"); - ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, "DeleteFileA(\"nonexist.txt\") returned ret=%d error=%d\n",ret,GetLastError()); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, "DeleteFileA(\"nonexist.txt\") returned ret=%d error=%ld\n",ret,GetLastError()); GetTempPathA(MAX_PATH, temp_path); GetTempFileNameA(temp_path, "tst", 0, temp_file); SetLastError(0xdeadbeef); hfile = CreateFileA(temp_file, GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); - ok(hfile != INVALID_HANDLE_VALUE, "CreateFile error %d\n", GetLastError()); + ok(hfile != INVALID_HANDLE_VALUE, "CreateFile error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = DeleteFileA(temp_file); - ok(ret, "DeleteFile error %d\n", GetLastError()); + ok(ret, "DeleteFile error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = CloseHandle(hfile); - ok(ret, "CloseHandle error %d\n", GetLastError()); + ok(ret, "CloseHandle error %ld\n", GetLastError()); ret = DeleteFileA(temp_file); ok(!ret, "DeleteFile should fail\n"); SetLastError(0xdeadbeef); ret = CreateDirectoryA("testdir", NULL); - ok(ret, "CreateDirectory failed, got err %d\n", GetLastError()); + ok(ret, "CreateDirectory failed, got err %ld\n", GetLastError()); ret = DeleteFileA("testdir"); ok(!ret && GetLastError() == ERROR_ACCESS_DENIED, - "Expected ERROR_ACCESS_DENIED, got error %d\n", GetLastError()); + "Expected ERROR_ACCESS_DENIED, got error %ld\n", GetLastError()); ret = RemoveDirectoryA("testdir"); - ok(ret, "Remove a directory failed, got error %d\n", GetLastError()); + ok(ret, "Remove a directory failed, got error %ld\n", GetLastError()); + + winetest_get_mainargs(&argv); + + ret = CopyFileA(argv[0], temp_file, FALSE); + ok(ret, "got error %lu\n", GetLastError()); + hfile = CreateFileA(temp_file, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, 0); + ok(hfile != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError()); + + mapping = CreateFileMappingA(hfile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL); + ok(!!mapping, "got error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = DeleteFileA(temp_file); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %lu\n", GetLastError()); + + CloseHandle(mapping); + + ret = DeleteFileA(temp_file); + ok(ret, "got error %lu\n", GetLastError()); + + CloseHandle(hfile); } static void test_DeleteFileW( void ) @@ -1814,15 +1953,15 @@ static void test_DeleteFileW( void ) return; } ok(!ret && GetLastError() == ERROR_PATH_NOT_FOUND, - "DeleteFileW(NULL) returned ret=%d error=%d\n",ret,GetLastError()); + "DeleteFileW(NULL) returned ret=%d error=%ld\n",ret,GetLastError()); ret = DeleteFileW(emptyW); ok(!ret && GetLastError() == ERROR_PATH_NOT_FOUND, - "DeleteFileW(\"\") returned ret=%d error=%d\n",ret,GetLastError()); + "DeleteFileW(\"\") returned ret=%d error=%ld\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) + if (ret + ARRAY_SIZE(dirW)-1 + ARRAY_SIZE(subdirW)-1 >= MAX_PATH) { ok(0, "MAX_PATH exceeded in constructing paths\n"); return; @@ -1857,46 +1996,47 @@ static void test_MoveFileA(void) char tempdir[MAX_PATH]; char source[MAX_PATH], dest[MAX_PATH]; static const char prefix[] = "pfx"; + WIN32_FIND_DATAA find_data; HANDLE hfile; HANDLE hmapfile; DWORD ret; BOOL retok; ret = GetTempPathA(MAX_PATH, tempdir); - ok(ret != 0, "GetTempPathA error %d\n", GetLastError()); + ok(ret != 0, "GetTempPathA error %ld\n", GetLastError()); ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n"); ret = GetTempFileNameA(tempdir, prefix, 0, source); - ok(ret != 0, "GetTempFileNameA error %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameA error %ld\n", GetLastError()); ret = GetTempFileNameA(tempdir, prefix, 0, dest); - ok(ret != 0, "GetTempFileNameA error %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameA error %ld\n", GetLastError()); ret = MoveFileA(source, source); - ok(ret, "MoveFileA: failed, error %d\n", GetLastError()); + ok(ret, "MoveFileA: failed, error %ld\n", GetLastError()); ret = MoveFileA(source, dest); ok(!ret && GetLastError() == ERROR_ALREADY_EXISTS, - "MoveFileA: unexpected error %d\n", GetLastError()); + "MoveFileA: unexpected error %ld\n", GetLastError()); ret = DeleteFileA(dest); - ok(ret, "DeleteFileA: error %d\n", GetLastError()); + ok(ret, "DeleteFileA: error %ld\n", GetLastError()); hfile = CreateFileA(source, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); ok(hfile != INVALID_HANDLE_VALUE, "failed to open source file\n"); retok = WriteFile(hfile, prefix, sizeof(prefix), &ret, NULL ); ok( retok && ret == sizeof(prefix), - "WriteFile error %d\n", GetLastError()); + "WriteFile error %ld\n", GetLastError()); hmapfile = CreateFileMappingW(hfile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL); - ok(hmapfile != NULL, "CreateFileMapping: error %d\n", GetLastError()); + ok(hmapfile != NULL, "CreateFileMapping: error %ld\n", GetLastError()); ret = MoveFileA(source, dest); ok(!ret, "MoveFileA: expected failure\n"); ok(GetLastError() == ERROR_SHARING_VIOLATION || broken(GetLastError() == ERROR_ACCESS_DENIED), /* Win9x and WinMe */ - "MoveFileA: expected ERROR_SHARING_VIOLATION, got %d\n", GetLastError()); + "MoveFileA: expected ERROR_SHARING_VIOLATION, got %ld\n", GetLastError()); CloseHandle(hmapfile); CloseHandle(hfile); @@ -1908,13 +2048,13 @@ static void test_MoveFileA(void) ok(hfile != INVALID_HANDLE_VALUE, "failed to open source file\n"); hmapfile = CreateFileMappingW(hfile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL); - ok(hmapfile != NULL, "CreateFileMapping: error %d\n", GetLastError()); + ok(hmapfile != NULL, "CreateFileMapping: error %ld\n", GetLastError()); ret = MoveFileA(source, dest); ok(!ret, "MoveFileA: expected failure\n"); ok(GetLastError() == ERROR_SHARING_VIOLATION || broken(GetLastError() == ERROR_ACCESS_DENIED), /* Win9x and WinMe */ - "MoveFileA: expected ERROR_SHARING_VIOLATION, got %d\n", GetLastError()); + "MoveFileA: expected ERROR_SHARING_VIOLATION, got %ld\n", GetLastError()); CloseHandle(hmapfile); CloseHandle(hfile); @@ -1923,12 +2063,75 @@ static void test_MoveFileA(void) if (ret) MoveFileA(dest, source); ret = MoveFileA(source, dest); - ok(ret, "MoveFileA: failed, error %d\n", GetLastError()); + ok(ret, "MoveFileA: failed, error %ld\n", GetLastError()); lstrcatA(tempdir, "Remove Me"); + + /* test renaming a file "Remove Me" to itself but in lowercase "me" */ + lstrcpyA(source, tempdir); + tempdir[lstrlenA(tempdir) - 2] = 'm'; + + hfile = CreateFileA(source, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0); + ok(hfile != INVALID_HANDLE_VALUE, "failed to create %s\n", source); + CloseHandle(hfile); + + ret = MoveFileA(source, tempdir); + ok(ret, "MoveFileA: failed, error %ld\n", GetLastError()); + + hfile = FindFirstFileA(tempdir, &find_data); + ok(hfile != INVALID_HANDLE_VALUE, "FindFirstFileA: failed, error %ld\n", GetLastError()); + if (hfile != INVALID_HANDLE_VALUE) + { + todo_wine ok(!lstrcmpA(strrchr(tempdir, '\\') + 1, find_data.cFileName), + "MoveFile failed to change casing on same file: got %s\n", find_data.cFileName); + } + CloseHandle(hfile); + + /* test renaming another file "Remove Be" to "Remove Me", which replaces the existing "Remove me" */ + tempdir[lstrlenA(tempdir) - 2] = 'B'; + + hfile = CreateFileA(tempdir, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0); + ok(hfile != INVALID_HANDLE_VALUE, "failed to create %s\n", tempdir); + CloseHandle(hfile); + + ret = MoveFileA(tempdir, source); + ok(!ret, "MoveFileA: expected failure\n"); + ok(GetLastError() == ERROR_ALREADY_EXISTS, "MoveFileA: expected ERROR_ALREADY_EXISTS, got %ld\n", GetLastError()); + ret = MoveFileExA(tempdir, source, MOVEFILE_REPLACE_EXISTING); + ok(ret, "MoveFileExA: failed, error %ld\n", GetLastError()); + + tempdir[lstrlenA(tempdir) - 2] = 'm'; + + hfile = FindFirstFileA(tempdir, &find_data); + ok(hfile != INVALID_HANDLE_VALUE, "FindFirstFileA: failed, error %ld\n", GetLastError()); + if (hfile != INVALID_HANDLE_VALUE) + { + ok(!lstrcmpA(strrchr(source, '\\') + 1, find_data.cFileName), + "MoveFile failed to change casing on existing target file: got %s\n", find_data.cFileName); + } + CloseHandle(hfile); + + ret = DeleteFileA(tempdir); + ok(ret, "DeleteFileA: error %ld\n", GetLastError()); + + /* now test a directory from "Remove me" to uppercase "Me" */ ret = CreateDirectoryA(tempdir, NULL); ok(ret == TRUE, "CreateDirectoryA failed\n"); + lstrcpyA(source, tempdir); + tempdir[lstrlenA(tempdir) - 2] = 'M'; + ret = MoveFileA(source, tempdir); + ok(ret, "MoveFileA: failed, error %ld\n", GetLastError()); + + hfile = FindFirstFileA(tempdir, &find_data); + ok(hfile != INVALID_HANDLE_VALUE, "FindFirstFileA: failed, error %ld\n", GetLastError()); + if (hfile != INVALID_HANDLE_VALUE) + { + todo_wine ok(!lstrcmpA(strrchr(tempdir, '\\') + 1, find_data.cFileName), + "MoveFile failed to change casing on same directory: got %s\n", find_data.cFileName); + } + CloseHandle(hfile); + lstrcpyA(source, dest); lstrcpyA(dest, tempdir); lstrcatA(dest, "\\wild?.*"); @@ -1937,7 +2140,7 @@ static void test_MoveFileA(void) ok(!ret, "MoveFileA: shouldn't move to wildcard file\n"); ok(GetLastError() == ERROR_INVALID_NAME || /* NT */ GetLastError() == ERROR_FILE_NOT_FOUND, /* Win9x */ - "MoveFileA: with wildcards, unexpected error %d\n", GetLastError()); + "MoveFileA: with wildcards, unexpected error %ld\n", GetLastError()); if (ret || (GetLastError() != ERROR_INVALID_NAME)) { WIN32_FIND_DATAA fd; @@ -1962,11 +2165,11 @@ static void test_MoveFileA(void) } } ret = DeleteFileA(source); - ok(ret, "DeleteFileA: error %d\n", GetLastError()); + ok(ret, "DeleteFileA: error %ld\n", GetLastError()); ret = DeleteFileA(dest); - ok(!ret, "DeleteFileA: error %d\n", GetLastError()); + ok(!ret, "DeleteFileA: error %ld\n", GetLastError()); ret = RemoveDirectoryA(tempdir); - ok(ret, "DeleteDirectoryA: error %d\n", GetLastError()); + ok(ret, "DeleteDirectoryA: error %ld\n", GetLastError()); } static void test_MoveFileW(void) @@ -1982,23 +2185,23 @@ static void test_MoveFileW(void) win_skip("GetTempPathW is not available\n"); return; } - ok(ret != 0, "GetTempPathW error %d\n", GetLastError()); + ok(ret != 0, "GetTempPathW error %ld\n", GetLastError()); ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n"); ret = GetTempFileNameW(temp_path, prefix, 0, source); - ok(ret != 0, "GetTempFileNameW error %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameW error %ld\n", GetLastError()); ret = GetTempFileNameW(temp_path, prefix, 0, dest); - ok(ret != 0, "GetTempFileNameW error %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameW error %ld\n", GetLastError()); ret = MoveFileW(source, dest); ok(!ret && GetLastError() == ERROR_ALREADY_EXISTS, - "CopyFileW: unexpected error %d\n", GetLastError()); + "MoveFileW: unexpected error %ld\n", GetLastError()); ret = DeleteFileW(source); - ok(ret, "DeleteFileW: error %d\n", GetLastError()); + ok(ret, "DeleteFileW: error %ld\n", GetLastError()); ret = DeleteFileW(dest); - ok(ret, "DeleteFileW: error %d\n", GetLastError()); + ok(ret, "DeleteFileW: error %ld\n", GetLastError()); } #define PATTERN_OFFSET 0x10 @@ -2015,38 +2218,38 @@ static void test_offset_in_overlapped_structure(void) BOOL ret; ret =GetTempPathA(MAX_PATH, temp_path); - ok( ret, "GetTempPathA error %d\n", GetLastError()); + ok( ret, "GetTempPathA error %ld\n", GetLastError()); ret =GetTempFileNameA(temp_path, "pfx", 0, temp_fname); - ok( ret, "GetTempFileNameA error %d\n", GetLastError()); + ok( ret, "GetTempFileNameA error %ld\n", GetLastError()); /*** Write File *****************************************************/ hFile = CreateFileA(temp_fname, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA error %d\n", GetLastError()); + ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA error %ld\n", GetLastError()); for(i = 0; i < sizeof(buf); i++) buf[i] = i; ret = WriteFile(hFile, buf, sizeof(buf), &done, NULL); - ok( ret, "WriteFile error %d\n", GetLastError()); - ok(done == sizeof(buf), "expected number of bytes written %u\n", done); + ok( ret, "WriteFile error %ld\n", GetLastError()); + ok(done == sizeof(buf), "expected number of bytes written %lu\n", done); memset(&ov, 0, sizeof(ov)); - S(U(ov)).Offset = PATTERN_OFFSET; - S(U(ov)).OffsetHigh = 0; + ov.Offset = PATTERN_OFFSET; + ov.OffsetHigh = 0; rc=WriteFile(hFile, pattern, sizeof(pattern), &done, &ov); /* Win 9x does not support the overlapped I/O on files */ if (rc || GetLastError()!=ERROR_INVALID_PARAMETER) { - ok(rc, "WriteFile error %d\n", GetLastError()); - ok(done == sizeof(pattern), "expected number of bytes written %u\n", done); + ok(rc, "WriteFile error %ld\n", GetLastError()); + ok(done == sizeof(pattern), "expected number of bytes written %lu\n", done); offset = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); - ok(offset == PATTERN_OFFSET + sizeof(pattern), "wrong file offset %d\n", offset); + ok(offset == PATTERN_OFFSET + sizeof(pattern), "wrong file offset %ld\n", offset); - S(U(ov)).Offset = sizeof(buf) * 2; - S(U(ov)).OffsetHigh = 0; + ov.Offset = sizeof(buf) * 2; + ov.OffsetHigh = 0; ret = WriteFile(hFile, pattern, sizeof(pattern), &done, &ov); - ok( ret, "WriteFile error %d\n", GetLastError()); - ok(done == sizeof(pattern), "expected number of bytes written %u\n", done); + ok( ret, "WriteFile error %ld\n", GetLastError()); + ok(done == sizeof(pattern), "expected number of bytes written %lu\n", done); offset = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); - ok(offset == sizeof(buf) * 2 + sizeof(pattern), "wrong file offset %d\n", offset); + ok(offset == sizeof(buf) * 2 + sizeof(pattern), "wrong file offset %ld\n", offset); } CloseHandle(hFile); @@ -2054,26 +2257,26 @@ static void test_offset_in_overlapped_structure(void) /*** Read File *****************************************************/ hFile = CreateFileA(temp_fname, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); - ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA error %d\n", GetLastError()); + ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA error %ld\n", GetLastError()); memset(buf, 0, sizeof(buf)); memset(&ov, 0, sizeof(ov)); - S(U(ov)).Offset = PATTERN_OFFSET; - S(U(ov)).OffsetHigh = 0; + ov.Offset = PATTERN_OFFSET; + ov.OffsetHigh = 0; rc=ReadFile(hFile, buf, sizeof(pattern), &done, &ov); /* Win 9x does not support the overlapped I/O on files */ if (rc || GetLastError()!=ERROR_INVALID_PARAMETER) { - ok(rc, "ReadFile error %d\n", GetLastError()); - ok(done == sizeof(pattern), "expected number of bytes read %u\n", done); + ok(rc, "ReadFile error %ld\n", GetLastError()); + ok(done == sizeof(pattern), "expected number of bytes read %lu\n", done); offset = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); - ok(offset == PATTERN_OFFSET + sizeof(pattern), "wrong file offset %d\n", offset); + ok(offset == PATTERN_OFFSET + sizeof(pattern), "wrong file offset %ld\n", offset); ok(!memcmp(buf, pattern, sizeof(pattern)), "pattern match failed\n"); } CloseHandle(hFile); ret = DeleteFileA(temp_fname); - ok( ret, "DeleteFileA error %d\n", GetLastError()); + ok( ret, "DeleteFileA error %ld\n", GetLastError()); } static void test_LockFile(void) @@ -2090,7 +2293,7 @@ static void test_LockFile(void) CREATE_ALWAYS, 0, 0 ); if (handle == INVALID_HANDLE_VALUE) { - ok(0,"couldn't create file \"%s\" (err=%d)\n",filename,GetLastError()); + ok(0,"couldn't create file \"%s\" (err=%ld)\n",filename,GetLastError()); return; } handle2 = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE, @@ -2098,7 +2301,7 @@ static void test_LockFile(void) OPEN_EXISTING, 0, 0 ); if (handle2 == INVALID_HANDLE_VALUE) { - ok( 0, "couldn't open file \"%s\" (err=%d)\n", filename, GetLastError() ); + ok( 0, "couldn't open file \"%s\" (err=%ld)\n", filename, GetLastError() ); goto cleanup; } ok( WriteFile( handle, sillytext, strlen(sillytext), &written, NULL ), "write failed\n" ); @@ -2124,8 +2327,8 @@ static void test_LockFile(void) ok( !UnlockFile( handle, 10, 0, 20, 0 ), "UnlockFile 10,20 again succeeded\n" ); ok( UnlockFile( handle, 5, 0, 5, 0 ), "UnlockFile 5,5 failed\n" ); - S(U(overlapped)).Offset = 100; - S(U(overlapped)).OffsetHigh = 0; + overlapped.Offset = 100; + overlapped.OffsetHigh = 0; overlapped.hEvent = 0; /* Test for broken LockFileEx a la Windows 95 OSR2. */ @@ -2137,7 +2340,7 @@ static void test_LockFile(void) } /* overlapping shared locks are OK */ - S(U(overlapped)).Offset = 150; + overlapped.Offset = 150; limited_UnLockFile || ok( LockFileEx( handle, 0, 0, 100, 0, &overlapped ), "LockFileEx 150,100 failed\n" ); /* but exclusive is not */ @@ -2146,13 +2349,13 @@ static void test_LockFile(void) "LockFileEx exclusive 150,50 succeeded\n" ); if (!UnlockFileEx( handle, 0, 100, 0, &overlapped )) { /* UnLockFile is capable. */ - S(U(overlapped)).Offset = 100; + overlapped.Offset = 100; ok( !UnlockFileEx( handle, 0, 100, 0, &overlapped ), "UnlockFileEx 150,100 again succeeded\n" ); } /* shared lock can overlap exclusive if handles are equal */ - S(U(overlapped)).Offset = 300; + overlapped.Offset = 300; ok( LockFileEx( handle, LOCKFILE_EXCLUSIVE_LOCK, 0, 100, 0, &overlapped ), "LockFileEx exclusive 300,100 failed\n" ); ok( !LockFileEx( handle2, LOCKFILE_FAIL_IMMEDIATELY, 0, 100, 0, &overlapped ), @@ -2175,7 +2378,7 @@ static void test_LockFile(void) ok( UnlockFile( handle, 0, 0x10000000, 0, 0xf0000000 ), "UnlockFile failed\n" ); } else /* win9x */ - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong LockFile error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong LockFile error %lu\n", GetLastError() ); /* wrap-around lock should not do anything */ /* (but still succeeds on NT4 so we don't check result) */ @@ -2240,8 +2443,6 @@ static BOOL create_fake_dll( LPCSTR filename ) nt->FileHeader.Machine = IMAGE_FILE_MACHINE_I386; #elif defined __x86_64__ nt->FileHeader.Machine = IMAGE_FILE_MACHINE_AMD64; -#elif defined __powerpc__ - nt->FileHeader.Machine = IMAGE_FILE_MACHINE_POWERPC; #elif defined __arm__ nt->FileHeader.Machine = IMAGE_FILE_MACHINE_ARMNT; #elif defined __aarch64__ @@ -2267,6 +2468,7 @@ static BOOL create_fake_dll( LPCSTR filename ) nt->OptionalHeader.SizeOfImage = 0x2000; nt->OptionalHeader.SizeOfHeaders = size; nt->OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI; + nt->OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLLCHARACTERISTICS_NX_COMPAT; nt->OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES; sec = (IMAGE_SECTION_HEADER *)(nt + 1); @@ -2347,25 +2549,25 @@ static void test_file_sharing(void) /* make sure the file exists */ if (!create_fake_dll( filename )) { - ok(0, "couldn't create file \"%s\" (err=%d)\n", filename, GetLastError()); + ok(0, "couldn't create file \"%s\" (err=%ld)\n", filename, GetLastError()); return; } - for (a1 = 0; a1 < sizeof(access_modes)/sizeof(access_modes[0]); a1++) + for (a1 = 0; a1 < ARRAY_SIZE(access_modes); a1++) { - for (s1 = 0; s1 < sizeof(sharing_modes)/sizeof(sharing_modes[0]); s1++) + for (s1 = 0; s1 < ARRAY_SIZE(sharing_modes); s1++) { SetLastError(0xdeadbeef); h = CreateFileA( filename, access_modes[a1].dw, sharing_modes[s1].dw, NULL, OPEN_EXISTING, 0, 0 ); if (h == INVALID_HANDLE_VALUE) { - ok(0,"couldn't create file \"%s\" (err=%d)\n",filename,GetLastError()); + ok(0,"couldn't create file \"%s\" (err=%ld)\n",filename,GetLastError()); return; } - for (a2 = 0; a2 < sizeof(access_modes)/sizeof(access_modes[0]); a2++) + for (a2 = 0; a2 < ARRAY_SIZE(access_modes); a2++) { - for (s2 = 0; s2 < sizeof(sharing_modes)/sizeof(sharing_modes[0]); s2++) + for (s2 = 0; s2 < ARRAY_SIZE(sharing_modes); s2++) { SetLastError(0xdeadbeef); h2 = CreateFileA( filename, access_modes[a2].dw, sharing_modes[s2].dw, @@ -2396,7 +2598,7 @@ static void test_file_sharing(void) } } - for (a1 = 0; a1 < sizeof(mapping_modes)/sizeof(mapping_modes[0]); a1++) + for (a1 = 0; a1 < ARRAY_SIZE(mapping_modes); a1++) { HANDLE m; @@ -2405,17 +2607,17 @@ static void test_file_sharing(void) h = CreateFileA( filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0 ); if (h == INVALID_HANDLE_VALUE) { - ok(0,"couldn't create file \"%s\" (err=%d)\n",filename,GetLastError()); + ok(0,"couldn't create file \"%s\" (err=%ld)\n",filename,GetLastError()); return; } m = CreateFileMappingA( h, NULL, mapping_modes[a1].dw, 0, 0, NULL ); - ok( m != 0, "failed to create mapping %s err %u\n", mapping_modes[a1].str, GetLastError() ); + ok( m != 0, "failed to create mapping %s err %lu\n", mapping_modes[a1].str, GetLastError() ); CloseHandle( h ); if (!m) continue; - for (a2 = 0; a2 < sizeof(access_modes)/sizeof(access_modes[0]); a2++) + for (a2 = 0; a2 < ARRAY_SIZE(access_modes); a2++) { - for (s2 = 0; s2 < sizeof(sharing_modes)/sizeof(sharing_modes[0]); s2++) + for (s2 = 0; s2 < ARRAY_SIZE(sharing_modes); s2++) { SetLastError(0xdeadbeef); h2 = CreateFileA( filename, access_modes[a2].dw, sharing_modes[s2].dw, @@ -2482,15 +2684,15 @@ static void test_file_sharing(void) SetLastError(0xdeadbeef); h = CreateFileA( filename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, 0 ); - ok( h != INVALID_HANDLE_VALUE, "CreateFileA error %d\n", GetLastError() ); + ok( h != INVALID_HANDLE_VALUE, "CreateFileA error %ld\n", GetLastError() ); SetLastError(0xdeadbeef); h2 = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); ok( h2 == INVALID_HANDLE_VALUE, "CreateFileA should fail\n"); - ok( GetLastError() == ERROR_SHARING_VIOLATION, "wrong error code %d\n", GetLastError() ); + ok( GetLastError() == ERROR_SHARING_VIOLATION, "wrong error code %ld\n", GetLastError() ); h2 = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 ); - ok( h2 != INVALID_HANDLE_VALUE, "CreateFileA error %d\n", GetLastError() ); + ok( h2 != INVALID_HANDLE_VALUE, "CreateFileA error %ld\n", GetLastError() ); CloseHandle(h); CloseHandle(h2); @@ -2505,88 +2707,15 @@ static char get_windows_drive(void) return windowsdir[0]; } -static const struct -{ - const char *path; - BOOL expected; -} -invalid_char_tests[] = -{ - { "./test-dir", TRUE }, - { "./test-dir/", FALSE }, - { ".\\test-dir", TRUE }, - { ".\\test-dir\\", FALSE }, - { "/>test-dir", FALSE }, - { "<\"test->dir", FALSE }, - { "dir", FALSE }, - { ">dir", FALSE }, - { ">>test-dir", FALSE }, - { ">test->dir", FALSE }, - { ">test-dir", FALSE }, - { "\"test-dir\"", FALSE }, - { "\"test-file\"", FALSE }, - { "test-/>dir", FALSE }, - { "test-dir/", FALSE }, - { "test-dir//", FALSE }, - { "test-dir/:", FALSE }, - { "test-dir/<", TRUE }, - { "test-dir/>", TRUE }, - { "test-dir/\"", TRUE }, - { "test-dir/\\", FALSE }, - { "test-dir/|", FALSE }, - { "test-dir<", TRUE }, - { "test-dir<><>\"\"\"\"<<<>", TRUE }, - { "test-dir<>", TRUE }, - { "test-dir<\"", TRUE }, - { "test-dir>", TRUE }, - { "test-dir>/", FALSE }, - { "test-dir><", TRUE }, - { "test-dir>>", TRUE }, - { "test-dir>\"", TRUE }, - { "test-dir\"", TRUE }, - { "test-dir\"/", FALSE }, - { "test-dir\"<", TRUE }, - { "test-dir\">", TRUE }, - { "test-dir\"\"", TRUE }, - { "test-dir\"\"\"\"\"", TRUE }, - { "test-dir\\", FALSE }, - { "test-dir\\/", FALSE }, - { "test-dir\\<", TRUE }, - { "test-dir\\>", TRUE }, - { "test-dir\\\"", TRUE }, - { "test-dir\\\\", FALSE }, - { "test-file/", FALSE }, - { "test-file/<", FALSE }, - { "test-file/>", FALSE }, - { "test-file/\"", FALSE }, - { "test-file<", TRUE }, - { "test-file<<", TRUE }, - { "test-file<>", TRUE }, - { "test-file<\"", TRUE }, - { "test-file>", TRUE }, - { "test-file><", TRUE }, - { "test-file>>", TRUE }, - { "test-file>\"", TRUE }, - { "test-file\"", TRUE }, - { "test-file\"<", TRUE }, - { "test-file\">", TRUE }, - { "test-file\"\"", TRUE }, - { "test-file\\", FALSE }, - { "test-file\\<", FALSE }, - { "test-file\\>", FALSE }, - { "test-file\\\"", FALSE }, -}; - static void test_FindFirstFileA(void) { HANDLE handle; WIN32_FIND_DATAA data; - int err, i; + int err; char buffer[5] = "C:\\"; char buffer2[100]; char nonexistent[MAX_PATH]; + BOOL found = FALSE; /* try FindFirstFileA on "C:\" */ buffer[0] = get_windows_drive(); @@ -2618,13 +2747,34 @@ static void test_FindFirstFileA(void) ok( FindNextFileA( handle, &data ), "FindNextFile failed\n" ); ok( !strcmp( data.cFileName, ".." ), "FindNextFile should return '..' as second entry\n" ); while (FindNextFileA( handle, &data )) + { ok ( strcmp( data.cFileName, "." ) && strcmp( data.cFileName, ".." ), "FindNextFile shouldn't return '%s'\n", data.cFileName ); + if (!found && (data.dwFileAttributes == FILE_ATTRIBUTE_NORMAL || + data.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE)) + { + GetWindowsDirectoryA( buffer2, sizeof(buffer2) ); + strcat(buffer2, "\\"); + strcat(buffer2, data.cFileName); + strcat(buffer2, "\\*"); + found = TRUE; + } + } ok ( FindClose(handle) == TRUE, "Failed to close handle %s\n", buffer2 ); + ok ( found, "Windows dir should not be empty\n" ); + if (found) + { + SetLastError( 0xdeadbeef ); + handle = FindFirstFileA(buffer2, &data); + err = GetLastError(); + ok ( handle == INVALID_HANDLE_VALUE, "FindFirstFile on %s should fail\n", buffer2 ); + ok ( err == ERROR_DIRECTORY, "Bad Error number %x\n", err ); + } + /* try FindFirstFileA on "C:\foo\" */ SetLastError( 0xdeadbeaf ); - if (!GetTempFileNameA( buffer, "foo", 0, nonexistent ) && GetLastError() == ERROR_ACCESS_DENIED) + if (!GetTempFileNameA( buffer, "foo", 0, nonexistent )) { char tmp[MAX_PATH]; GetTempPathA( sizeof(tmp), tmp ); @@ -2685,15 +2835,15 @@ static void test_FindFirstFileA(void) ok( 0 == lstrcmpiA(data.cFileName, "nul"), "wrong name %s\n", data.cFileName ); ok( FILE_ATTRIBUTE_ARCHIVE == data.dwFileAttributes || FILE_ATTRIBUTE_DEVICE == data.dwFileAttributes /* Win9x */, - "wrong attributes %x\n", data.dwFileAttributes ); + "wrong attributes %lx\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 ); + ok( 0 == data.nFileSizeHigh, "wrong size %ld\n", data.nFileSizeHigh ); + ok( 0 == data.nFileSizeLow, "wrong size %ld\n", data.nFileSizeLow ); } SetLastError( 0xdeadbeaf ); ok( !FindNextFileA( handle, &data ), "FindNextFileA succeeded\n" ); - ok( GetLastError() == ERROR_NO_MORE_FILES, "bad error %d\n", GetLastError() ); + ok( GetLastError() == ERROR_NO_MORE_FILES, "bad error %ld\n", GetLastError() ); ok( FindClose( handle ), "failed to close handle\n" ); /* try FindFirstFileA on "lpt1" */ @@ -2705,15 +2855,15 @@ static void test_FindFirstFileA(void) ok( 0 == lstrcmpiA(data.cFileName, "lpt1"), "wrong name %s\n", data.cFileName ); ok( FILE_ATTRIBUTE_ARCHIVE == data.dwFileAttributes || FILE_ATTRIBUTE_DEVICE == data.dwFileAttributes /* Win9x */, - "wrong attributes %x\n", data.dwFileAttributes ); + "wrong attributes %lx\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 ); + ok( 0 == data.nFileSizeHigh, "wrong size %ld\n", data.nFileSizeHigh ); + ok( 0 == data.nFileSizeLow, "wrong size %ld\n", data.nFileSizeLow ); } SetLastError( 0xdeadbeaf ); ok( !FindNextFileA( handle, &data ), "FindNextFileA succeeded\n" ); - ok( GetLastError() == ERROR_NO_MORE_FILES, "bad error %d\n", GetLastError() ); + ok( GetLastError() == ERROR_NO_MORE_FILES, "bad error %ld\n", GetLastError() ); ok( FindClose( handle ), "failed to close handle\n" ); /* try FindFirstFileA on "c:\nul\*" */ @@ -2740,8 +2890,12 @@ static void test_FindFirstFileA(void) strcat(buffer2, "foo\\bar\\nul"); handle = FindFirstFileA(buffer2, &data); err = GetLastError(); - ok ( handle == INVALID_HANDLE_VALUE, "FindFirstFile on %s should fail\n", buffer2 ); - ok ( err == ERROR_PATH_NOT_FOUND, "Bad Error number %d\n", err ); + ok( handle == INVALID_HANDLE_VALUE || broken(1), /* win8 */ + "FindFirstFile on %s should fail\n", buffer2 ); + if (handle == INVALID_HANDLE_VALUE) + ok( err == ERROR_PATH_NOT_FOUND, "Bad Error number %d\n", err ); + else + CloseHandle( handle ); /* try FindFirstFileA on "c:\foo\nul\bar" */ SetLastError( 0xdeadbeaf ); @@ -2751,30 +2905,6 @@ static void test_FindFirstFileA(void) err = GetLastError(); ok ( handle == INVALID_HANDLE_VALUE, "FindFirstFile on %s should fail\n", buffer2 ); ok ( err == ERROR_PATH_NOT_FOUND, "Bad Error number %d\n", err ); - - /* try FindFirstFileA with invalid characters */ - CreateDirectoryA("test-dir", NULL); - _lclose(_lcreat("test-file", 0)); - - for (i = 0; i < sizeof(invalid_char_tests) / sizeof(invalid_char_tests[0]); i++) - { - handle = FindFirstFileA(invalid_char_tests[i].path, &data); - if (invalid_char_tests[i].expected) - { - ok(handle != INVALID_HANDLE_VALUE, "FindFirstFileA on %s should succeed\n", - invalid_char_tests[i].path); - } - else - { - ok(handle == INVALID_HANDLE_VALUE, "FindFirstFileA on %s should fail\n", - invalid_char_tests[i].path); - } - if (handle != INVALID_HANDLE_VALUE) - FindClose(handle); - } - - DeleteFileA("test-file"); - RemoveDirectoryA("test-dir"); } static void test_FindNextFileA(void) @@ -2808,7 +2938,7 @@ static void test_FindFirstFileExA(FINDEX_INFO_LEVELS level, FINDEX_SEARCH_OPS se return; } - trace("Running FindFirstFileExA tests with level=%d, search_ops=%d, flags=%u\n", + trace("Running FindFirstFileExA tests with level=%d, search_ops=%d, flags=%lu\n", level, search_ops, flags); CreateDirectoryA("test-dir", NULL); @@ -2836,7 +2966,7 @@ static void test_FindFirstFileExA(FINDEX_INFO_LEVELS level, FINDEX_SEARCH_OPS se #define CHECK_NAME(fn) (strcmp((fn), "file1") == 0 || strcmp((fn), "file2") == 0 || strcmp((fn), "dir1") == 0) #define CHECK_LEVEL(fn) (level != FindExInfoBasic || !(fn)[0]) - ok(handle != INVALID_HANDLE_VALUE, "FindFirstFile failed (err=%u)\n", GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "FindFirstFile failed (err=%lu)\n", GetLastError()); ok(strcmp(search_results.cFileName, ".") == 0, "First entry should be '.', is %s\n", search_results.cFileName); ok(CHECK_LEVEL(search_results.cAlternateFileName), "FindFirstFile unexpectedly returned an alternate filename\n"); @@ -2883,12 +3013,12 @@ static void test_FindFirstFileExA(FINDEX_INFO_LEVELS level, FINDEX_SEARCH_OPS se if (flags & FIND_FIRST_EX_CASE_SENSITIVE) { ok(handle != INVALID_HANDLE_VALUE || GetLastError() == ERROR_PATH_NOT_FOUND, - "Unexpected error %x, expected valid handle or ERROR_PATH_NOT_FOUND\n", GetLastError()); + "Unexpected error %lx, expected valid handle or ERROR_PATH_NOT_FOUND\n", GetLastError()); trace("FindFirstFileExA flag FIND_FIRST_EX_CASE_SENSITIVE is %signored\n", (handle == INVALID_HANDLE_VALUE) ? "not " : ""); } else - ok(handle != INVALID_HANDLE_VALUE, "Unexpected error %x, expected valid handle\n", GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "Unexpected error %lx, expected valid handle\n", GetLastError()); if (handle != INVALID_HANDLE_VALUE) FindClose( handle ); @@ -2906,48 +3036,111 @@ static void test_FindFirstFile_wildcards(void) int i; static const char* files[] = { "..a", "..a.a", ".a", ".a..a", ".a.a", ".aaa", - "a", "a..a", "a.a", "a.a.a", "aa", "aaa", "aaaa" + "a", "a..a", "a.a", "a.a.a", "aa", "aaa", "aaaa", " .a" }; static const struct { - int todo; const char *pattern, *result; } tests[] = { - {0, "*.*.*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, - {0, "*.*.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, - {0, ".*.*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa'"}, - {0, "*.*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, - {0, ".*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa'"}, - {1, "*.", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, - {0, "*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, - {1, "*..*", ", '.', '..', '..a', '..a.a', '.a..a', 'a..a'"}, - {1, "*..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, - {1, ".*.", ", '.', '..', '.a', '.aaa'"}, - {0, "..*", ", '.', '..', '..a', '..a.a'"}, - {0, "**", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, - {0, "**.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, - {0, "*. ", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, - {1, "* .", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, - {0, "* . ", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, - {0, "*.. ", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, - {1, "*. .", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, - {1, "* ..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, - {1, " *..", ", '.aaa'"}, - {0, "..* ", ", '.', '..', '..a', '..a.a'"}, - {1, "?", ", '.', '..', 'a'"}, - {1, "?.", ", '.', '..', 'a'"}, - {1, "?. ", ", '.', '..', 'a'"}, - {1, "??.", ", '.', '..', 'a', 'aa'"}, - {1, "??. ", ", '.', '..', 'a', 'aa'"}, - {1, "???.", ", '.', '..', 'a', 'aa', 'aaa'"}, - {1, "?.??.", ", '.', '..', '.a', 'a', 'a.a'"} + {"*.*.*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {"*.*.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {".*.*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa'"}, + {"*.*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {".*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa'"}, + {". *", ""}, + {"*.", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + {"*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {"*..*", ", '.', '..', '..a', '..a.a', '.a..a', 'a..a'"}, + {"*..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + {".*.", ", '.', '..', '.a', '.aaa'"}, + {"..*", ", '.', '..', '..a', '..a.a'"}, + {"**", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {"**.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {"*. ", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {"* .", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + {"* . ", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {"* . *", ""}, + {"*.. ", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {"*. .", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + {"* ..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + {" *..", ""}, + {"..* ", ", '.', '..', '..a', '..a.a'"}, + {"* .*.", ", ' .a'"}, + + {"a*.", ", '..a', '.a', '.aaa', 'a', 'aa', 'aaa', 'aaaa'"}, + {"*a ", ", '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {"*aa*", ", '.aaa', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, + {"aa*.", ", '.aaa', 'aa', 'aaa', 'aaaa'"}, + {"aa.*", ", 'aa'"}, + {"a a*.*", ""}, + {"a\"*\"a", ", 'a..a', 'a.a.a'"}, + {"aa*.*", ", '.aaa', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, + {"a ?.*", ""}, + {"? a.*", ""}, + {"a* a", ""}, + {" *a", ", ' .a'"}, + {"* *", ", ' .a'"}, + {"a* .", ", 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + {" ?a", ""}, + {"* .a", ", ' .a'"}, + {"< .a", ", ' .a'"}, + {"** .a", ", ' .a'"}, + {"<< .a", ", ' .a'"}, + {"aa? ", ", 'aa', 'aaa'"}, + {"aa\"*", ", 'aa'"}, + {"*.a", ", '..a', '..a.a', '.a', '.a..a', '.a.a', 'a..a', 'a.a', 'a.a.a', ' .a'"}, + {"<.a", ", '..a', '..a.a', '.a', '.a..a', '.a.a', 'a..a', 'a.a', 'a.a.a', ' .a'"}, + + {"<.<.<", ", '..a', '..a.a', '.a..a', '.a.a', 'a..a', 'a.a.a'"}, + {"<.<.< ", ", '..a', '..a.a', '.a..a', '.a.a', 'a..a', 'a.a.a'"}, + {"<.<.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a..a', 'a.a', 'a.a.a', ' .a'"}, + {"< .<.", ", ' .a'"}, + {"< .<. ", ", ' .a'"}, + {"<.<. ", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a..a', 'a.a', 'a.a.a', ' .a'"}, + {".<.<", ", '..a', '..a.a', '.a..a', '.a.a'"}, + {"<.<", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a..a', 'a.a', 'a.a.a', ' .a'"}, + {".<", ", '.', '..', '.a', '.aaa'"}, + {"<.", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + {"<", ", '.', '..', '..a', '.a', '.aaa', 'a', 'aa', 'aaa', 'aaaa'"}, + {"<..<", ", '..a', '.a..a', 'a..a'"}, + {"<..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + {".<.", ", '.', '..', '.a', '.aaa'"}, + {"..<", ", '..a'"}, + {"<<", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {"<<.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {"<. ", ", '.', '..', '..a', '.a', '.aaa', 'a', 'aa', 'aaa', 'aaaa'"}, + {"< .", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + {"< . ", ", '.', '..', '..a', '.a', '.aaa', 'a', 'aa', 'aaa', 'aaaa'"}, + {"<.. ", ", '.', '..', '..a', '.a', '.aaa', 'a', 'aa', 'aaa', 'aaaa'"}, + {"<. .", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + {"< ..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + {" <..", ""}, + {"..< ", ", '..a'"}, + + {"?", ", '.', '..', 'a'"}, + {"?.", ", '.', '..', 'a'"}, + {"?. ", ", '.', '..', 'a'"}, + {"? .*", ""}, + {"??.", ", '.', '..', 'a', 'aa'"}, + {"??. ", ", '.', '..', 'a', 'aa'"}, + {"???.", ", '.', '..', 'a', 'aa', 'aaa'"}, + {"?.??.", ", '.', '..', '.a', 'a', 'a.a', ' .a'"}, + {". ?", ""}, + + {">", ", '.', '..', 'a'"}, + {">.", ", '.', '..', 'a'"}, + {">. ", ", '.', '..', 'a'"}, + {">>.", ", '.', '..', 'a', 'aa'"}, + {">>. ", ", '.', '..', 'a', 'aa'"}, + {">>>.", ", '.', '..', 'a', 'aa', 'aaa'"}, + {">.>>.", ", '.', '..', '.a', 'a.a', ' .a'"}, }; CreateDirectoryA("test-dir", NULL); SetCurrentDirectoryA("test-dir"); - for (i = 0; i < sizeof(files) / sizeof(files[0]); ++i) + for (i = 0; i < ARRAY_SIZE(files); ++i) _lclose(_lcreat(files[i], 0)); - for (i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i) + for (i = 0; i < ARRAY_SIZE(tests); ++i) { char correct[512]; char incorrect[512]; @@ -2957,25 +3150,27 @@ static void test_FindFirstFile_wildcards(void) correct[0] = incorrect[0] = 0; handle = FindFirstFileA(tests[i].pattern, &find_data); - if (handle) do { - char* ptr; - char quoted[16]; + if (handle != INVALID_HANDLE_VALUE) + { + do { + char *ptr; + char quoted[16]; - sprintf( quoted, ", '%.10s'", find_data.cFileName ); + sprintf(quoted, ", '%.10s'", find_data.cFileName); - if ((ptr = strstr(missing, quoted))) - { - int len = strlen(quoted); - while ((ptr[0] = ptr[len]) != 0) - ++ptr; - strcat(correct, quoted); - } - else - strcat(incorrect, quoted); - } while (FindNextFileA(handle, &find_data)); - FindClose(handle); + if ((ptr = strstr(missing, quoted))) + { + int len = strlen(quoted); + while ((ptr[0] = ptr[len]) != 0) + ++ptr; + strcat(correct, quoted); + } + else + strcat(incorrect, quoted); + } while (FindNextFileA(handle, &find_data)); + FindClose(handle); + } - todo_wine_if (tests[i].todo) ok(missing[0] == 0 && incorrect[0] == 0, "FindFirstFile with '%s' found correctly %s, found incorrectly %s, and missed %s\n", tests[i].pattern, @@ -2984,7 +3179,7 @@ static void test_FindFirstFile_wildcards(void) missing[0] ? missing+2 : "none"); } - for (i = 0; i < sizeof(files) / sizeof(files[0]); ++i) + for (i = 0; i < ARRAY_SIZE(files); ++i) DeleteFileA(files[i]); SetCurrentDirectoryA(".."); RemoveDirectoryA("test-dir"); @@ -3008,6 +3203,7 @@ static void test_MapFile(void) { HANDLE handle; HANDLE hmap; + UINT err; ok(test_Mapfile_createtemp(&handle), "Couldn't create test file.\n"); @@ -3026,21 +3222,17 @@ static void test_MapFile(void) ok(test_Mapfile_createtemp(&handle), "Couldn't create test file.\n"); + SetLastError( 0xdeadbeef ); hmap = CreateFileMappingA( handle, NULL, PAGE_READWRITE, 0, 0, NULL ); + err = GetLastError(); ok( hmap == NULL, "mapped zero size file\n"); - ok( GetLastError() == ERROR_FILE_INVALID, "not ERROR_FILE_INVALID\n"); + ok( err == ERROR_FILE_INVALID, "got %u\n", err ); - hmap = CreateFileMappingA( handle, NULL, PAGE_READWRITE, 0x80000000, 0, NULL ); - 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 = CreateFileMappingA( handle, NULL, PAGE_READWRITE, 0x80000000, 0x10000, NULL ); - 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 ); + SetLastError( 0xdeadbeef ); + hmap = CreateFileMappingA( handle, NULL, PAGE_READWRITE, 0x8000000, 0x10000, NULL ); + err = GetLastError(); + ok( hmap == NULL, "mapping should fail\n"); + ok( err == ERROR_NOT_ENOUGH_MEMORY || err == ERROR_INVALID_PARAMETER, "got %u\n", err ); /* On XP you can now map again, on Win 95 you cannot. */ @@ -3051,22 +3243,90 @@ static void test_MapFile(void) static void test_GetFileType(void) { DWORD type, type2; - HANDLE h = CreateFileA( filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + HANDLE h, h2; + BOOL ret; + h = CreateFileA( filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 ); ok( h != INVALID_HANDLE_VALUE, "open %s failed\n", filename ); type = GetFileType(h); - ok( type == FILE_TYPE_DISK, "expected type disk got %d\n", type ); + ok( type == FILE_TYPE_DISK, "expected type disk got %ld\n", type ); CloseHandle( h ); h = CreateFileA( "nul", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0 ); ok( h != INVALID_HANDLE_VALUE, "open nul failed\n" ); type = GetFileType(h); - ok( type == FILE_TYPE_CHAR, "expected type char for nul got %d\n", type ); + ok( type == FILE_TYPE_CHAR, "expected type char for nul got %ld\n", type ); CloseHandle( h ); DeleteFileA( filename ); h = GetStdHandle( STD_OUTPUT_HANDLE ); ok( h != INVALID_HANDLE_VALUE, "GetStdHandle failed\n" ); type = GetFileType( (HANDLE)STD_OUTPUT_HANDLE ); type2 = GetFileType( h ); - ok(type == type2, "expected type %d for STD_OUTPUT_HANDLE got %d\n", type2, type); + ok(type == type2, "expected type %ld for STD_OUTPUT_HANDLE got %ld\n", type2, type); + + ret = CreatePipe( &h, &h2, NULL, 0 ); + ok( ret, "CreatePipe failed\n" ); + type = GetFileType( h ); + ok( type == FILE_TYPE_PIPE, "expected type pipe got %ld\n", type ); + type = GetFileType( h2 ); + ok( type == FILE_TYPE_PIPE, "expected type pipe got %ld\n", type ); + CloseHandle( h2 ); + CloseHandle( h ); + + h = CreateNamedPipeW( L"\\\\.\\pipe\\wine_test", PIPE_ACCESS_DUPLEX, 0, 2, 32, 32, 0, NULL ); + ok( h != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n" ); + type = GetFileType( h ); + ok( type == FILE_TYPE_PIPE, "expected type pipe got %ld\n", type ); + CloseHandle( h ); + + h = CreateFileA( filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( h != INVALID_HANDLE_VALUE, "open %s failed\n", filename ); + h2 = CreateFileMappingW( h, NULL, PAGE_READWRITE, 0, 0x1000, NULL ); + ok( h2 != NULL, "CreateFileMapping failed\n" ); + SetLastError( 12345678 ); + type = GetFileType( h2 ); + todo_wine + ok( type == FILE_TYPE_UNKNOWN, "expected type unknown got %ld\n", type ); + todo_wine + ok( GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE got %lx\n", GetLastError() ); + CloseHandle( h2 ); + CloseHandle( h ); + DeleteFileA( filename ); + + h = CreateFileMappingW( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 0x1000, NULL ); + ok( h != NULL, "CreateFileMapping failed\n" ); + SetLastError( 12345678 ); + type = GetFileType( h ); + todo_wine + ok( type == FILE_TYPE_UNKNOWN, "expected type unknown got %ld\n", type ); + todo_wine + ok( GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE got %lx\n", GetLastError() ); + CloseHandle( h ); + + h = CreateMailslotW( L"\\\\.\\mailslot\\wine_test", 0, 0, NULL ); + ok( h != INVALID_HANDLE_VALUE, "CreateMailslot failed\n" ); + SetLastError( 12345678 ); + type = GetFileType( h ); + ok( type == FILE_TYPE_UNKNOWN, "expected type unknown got %ld\n", type ); + todo_wine + ok( GetLastError() == NO_ERROR, "expected ERROR_NO_ERROR got %lx\n", GetLastError() ); + CloseHandle( h ); + + SetLastError( 12345678 ); + type = GetFileType( GetCurrentProcess() ); + ok( type == FILE_TYPE_UNKNOWN, "expected type unknown got %ld\n", type ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE got %lx\n", GetLastError() ); + + SetLastError( 12345678 ); + type = GetFileType( GetCurrentThread() ); + ok( type == FILE_TYPE_UNKNOWN, "expected type unknown got %ld\n", type ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE got %lx\n", GetLastError() ); + + h = CreateMutexW( NULL, TRUE, NULL ); + ok( h != NULL, "CreateMutex failed\n" ); + SetLastError( 12345678 ); + type = GetFileType( h ); + ok( type == FILE_TYPE_UNKNOWN, "expected type unknown got %ld\n", type ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE got %lx\n", GetLastError() ); + CloseHandle( h ); } static int completion_count; @@ -3085,12 +3345,18 @@ static void test_async_file_errors(void) HANDLE hFile; LPVOID lpBuffer = HeapAlloc(GetProcessHeap(), 0, 4096); OVERLAPPED ovl; - S(U(ovl)).Offset = 0; - S(U(ovl)).OffsetHigh = 0; +#ifdef __REACTOS__ + if (is_reactos()) { + ok(FALSE, "FIXME: test_async_file_errors() crashes on ReactOS!\n"); + return; + } +#endif + ovl.Offset = 0; + ovl.OffsetHigh = 0; ovl.hEvent = hSem; completion_count = 0; szFile[0] = '\0'; - GetWindowsDirectoryA(szFile, sizeof(szFile)/sizeof(szFile[0])-1-strlen("\\win.ini")); + GetWindowsDirectoryA(szFile, ARRAY_SIZE(szFile)-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); @@ -3110,7 +3376,7 @@ static void test_async_file_errors(void) break; if (!GetOverlappedResult(hFile, &ovl, &count, FALSE)) break; - S(U(ovl)).Offset += count; + 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 */ @@ -3137,39 +3403,36 @@ static void test_read_write(void) static const char prefix[] = "pfx"; ret = GetTempPathA(MAX_PATH, temp_path); - ok(ret != 0, "GetTempPathA error %d\n", GetLastError()); + ok(ret != 0, "GetTempPathA error %ld\n", GetLastError()); ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n"); ret = GetTempFileNameA(temp_path, prefix, 0, filename); - ok(ret != 0, "GetTempFileNameA error %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameA error %ld\n", GetLastError()); hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_RANDOM_ACCESS, 0); - ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA: error %d\n", GetLastError()); + ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA: error %ld\n", GetLastError()); user_apc_ran = FALSE; - if (pQueueUserAPC) { - trace("Queueing an user APC\n"); /* verify the file is non alerable */ - ret = pQueueUserAPC(&user_apc, GetCurrentThread(), 0); - ok(ret, "QueueUserAPC failed: %d\n", GetLastError()); - } + ret = QueueUserAPC(&user_apc, GetCurrentThread(), 0); + ok(ret, "QueueUserAPC failed: %ld\n", GetLastError()); SetLastError(12345678); bytes = 12345678; ret = WriteFile(hFile, NULL, 0, &bytes, NULL); ok(ret && GetLastError() == 12345678, - "ret = %d, error %d\n", ret, GetLastError()); - ok(!bytes, "bytes = %d\n", bytes); + "ret = %ld, error %ld\n", ret, GetLastError()); + ok(!bytes, "bytes = %ld\n", bytes); SetLastError(12345678); bytes = 12345678; ret = WriteFile(hFile, NULL, 10, &bytes, NULL); ok((!ret && GetLastError() == ERROR_INVALID_USER_BUFFER) || /* Win2k */ (ret && GetLastError() == 12345678), /* Win9x */ - "ret = %d, error %d\n", ret, GetLastError()); + "ret = %ld, error %ld\n", ret, GetLastError()); ok(!bytes || /* Win2k */ bytes == 10, /* Win9x */ - "bytes = %d\n", bytes); + "bytes = %ld\n", bytes); /* make sure the file contains data */ WriteFile(hFile, "this is the test data", 21, &bytes, NULL); @@ -3179,56 +3442,55 @@ static void test_read_write(void) bytes = 12345678; ret = ReadFile(hFile, NULL, 0, &bytes, NULL); ok(ret && GetLastError() == 12345678, - "ret = %d, error %d\n", ret, GetLastError()); - ok(!bytes, "bytes = %d\n", bytes); + "ret = %ld, error %ld\n", ret, GetLastError()); + ok(!bytes, "bytes = %ld\n", bytes); SetLastError(12345678); bytes = 12345678; ret = ReadFile(hFile, NULL, 10, &bytes, NULL); ok(!ret && (GetLastError() == ERROR_NOACCESS || /* Win2k */ GetLastError() == ERROR_INVALID_PARAMETER), /* Win9x */ - "ret = %d, error %d\n", ret, GetLastError()); - ok(!bytes, "bytes = %d\n", bytes); + "ret = %ld, error %ld\n", ret, GetLastError()); + ok(!bytes, "bytes = %ld\n", bytes); ok(user_apc_ran == FALSE, "UserAPC ran, file using alertable io mode\n"); - if (pQueueUserAPC) - SleepEx(0, TRUE); /* get rid of apc */ + SleepEx(0, TRUE); /* get rid of apc */ /* test passing protected memory as buffer */ mem = VirtualAlloc( NULL, 0x4000, MEM_COMMIT, PAGE_READWRITE ); - ok( mem != NULL, "failed to allocate virtual mem error %u\n", GetLastError() ); + ok( mem != NULL, "failed to allocate virtual mem error %lu\n", GetLastError() ); ret = WriteFile( hFile, mem, 0x4000, &bytes, NULL ); - ok( ret, "WriteFile failed error %u\n", GetLastError() ); - ok( bytes == 0x4000, "only wrote %x bytes\n", bytes ); + ok( ret, "WriteFile failed error %lu\n", GetLastError() ); + ok( bytes == 0x4000, "only wrote %lx bytes\n", bytes ); ret = VirtualProtect( mem + 0x2000, 0x2000, PAGE_NOACCESS, &old_prot ); - ok( ret, "VirtualProtect failed error %u\n", GetLastError() ); + ok( ret, "VirtualProtect failed error %lu\n", GetLastError() ); ret = WriteFile( hFile, mem, 0x4000, &bytes, NULL ); ok( !ret, "WriteFile succeeded\n" ); ok( GetLastError() == ERROR_INVALID_USER_BUFFER || GetLastError() == ERROR_INVALID_PARAMETER, /* win9x */ - "wrong error %u\n", GetLastError() ); - ok( bytes == 0, "wrote %x bytes\n", bytes ); + "wrong error %lu\n", GetLastError() ); + ok( bytes == 0, "wrote %lx bytes\n", bytes ); ret = WriteFile( (HANDLE)0xdead, mem, 0x4000, &bytes, NULL ); ok( !ret, "WriteFile succeeded\n" ); ok( GetLastError() == ERROR_INVALID_HANDLE || /* handle is checked before buffer on NT */ GetLastError() == ERROR_INVALID_PARAMETER, /* win9x */ - "wrong error %u\n", GetLastError() ); - ok( bytes == 0, "wrote %x bytes\n", bytes ); + "wrong error %lu\n", GetLastError() ); + ok( bytes == 0, "wrote %lx bytes\n", bytes ); ret = VirtualProtect( mem, 0x2000, PAGE_NOACCESS, &old_prot ); - ok( ret, "VirtualProtect failed error %u\n", GetLastError() ); + ok( ret, "VirtualProtect failed error %lu\n", GetLastError() ); ret = WriteFile( hFile, mem, 0x4000, &bytes, NULL ); ok( !ret, "WriteFile succeeded\n" ); ok( GetLastError() == ERROR_INVALID_USER_BUFFER || GetLastError() == ERROR_INVALID_PARAMETER, /* win9x */ - "wrong error %u\n", GetLastError() ); - ok( bytes == 0, "wrote %x bytes\n", bytes ); + "wrong error %lu\n", GetLastError() ); + ok( bytes == 0, "wrote %lx bytes\n", bytes ); SetFilePointer( hFile, 0, NULL, FILE_BEGIN ); @@ -3236,28 +3498,28 @@ static void test_read_write(void) ok( !ret, "ReadFile succeeded\n" ); ok( GetLastError() == ERROR_NOACCESS || GetLastError() == ERROR_INVALID_PARAMETER, /* win9x */ - "wrong error %u\n", GetLastError() ); - ok( bytes == 0, "read %x bytes\n", bytes ); + "wrong error %lu\n", GetLastError() ); + ok( bytes == 0, "read %lx bytes\n", bytes ); ret = VirtualProtect( mem, 0x2000, PAGE_READONLY, &old_prot ); - ok( ret, "VirtualProtect failed error %u\n", GetLastError() ); + ok( ret, "VirtualProtect failed error %lu\n", GetLastError() ); ret = ReadFile( hFile, mem, 0x4000, &bytes, NULL ); ok( !ret, "ReadFile succeeded\n" ); ok( GetLastError() == ERROR_NOACCESS || GetLastError() == ERROR_INVALID_PARAMETER, /* win9x */ - "wrong error %u\n", GetLastError() ); - ok( bytes == 0, "read %x bytes\n", bytes ); + "wrong error %lu\n", GetLastError() ); + ok( bytes == 0, "read %lx bytes\n", bytes ); ret = VirtualProtect( mem, 0x2000, PAGE_READWRITE, &old_prot ); - ok( ret, "VirtualProtect failed error %u\n", GetLastError() ); + ok( ret, "VirtualProtect failed error %lu\n", GetLastError() ); ret = ReadFile( hFile, mem, 0x4000, &bytes, NULL ); ok( !ret, "ReadFile succeeded\n" ); ok( GetLastError() == ERROR_NOACCESS || GetLastError() == ERROR_INVALID_PARAMETER, /* win9x */ - "wrong error %u\n", GetLastError() ); - ok( bytes == 0, "read %x bytes\n", bytes ); + "wrong error %lu\n", GetLastError() ); + ok( bytes == 0, "read %lx bytes\n", bytes ); SetFilePointer( hFile, 0x1234, NULL, FILE_BEGIN ); SetEndOfFile( hFile ); @@ -3267,26 +3529,26 @@ static void test_read_write(void) ok( !ret, "ReadFile succeeded\n" ); ok( GetLastError() == ERROR_NOACCESS || GetLastError() == ERROR_INVALID_PARAMETER, /* win9x */ - "wrong error %u\n", GetLastError() ); - ok( bytes == 0, "read %x bytes\n", bytes ); + "wrong error %lu\n", GetLastError() ); + ok( bytes == 0, "read %lx bytes\n", bytes ); ret = ReadFile( hFile, mem, 0x2000, &bytes, NULL ); - ok( ret, "ReadFile failed error %u\n", GetLastError() ); - ok( bytes == 0x1234, "read %x bytes\n", bytes ); + ok( ret, "ReadFile failed error %lu\n", GetLastError() ); + ok( bytes == 0x1234, "read %lx bytes\n", bytes ); ret = ReadFile( hFile, NULL, 1, &bytes, NULL ); ok( !ret, "ReadFile succeeded\n" ); ok( GetLastError() == ERROR_NOACCESS || GetLastError() == ERROR_INVALID_PARAMETER, /* win9x */ - "wrong error %u\n", GetLastError() ); - ok( bytes == 0, "read %x bytes\n", bytes ); + "wrong error %lu\n", GetLastError() ); + ok( bytes == 0, "read %lx bytes\n", bytes ); VirtualFree( mem, 0, MEM_RELEASE ); ret = CloseHandle(hFile); - ok( ret, "CloseHandle: error %d\n", GetLastError()); + ok( ret, "CloseHandle: error %ld\n", GetLastError()); ret = DeleteFileA(filename); - ok( ret, "DeleteFileA: error %d\n", GetLastError()); + ok( ret, "DeleteFileA: error %ld\n", GetLastError()); } static void test_OpenFile(void) @@ -3325,9 +3587,9 @@ static void test_OpenFile(void) SetLastError(0xfaceabee); hFile = OpenFile(buff, &ofs, OF_EXIST); - ok( hFile == TRUE, "%s not found : %d\n", buff, GetLastError() ); + ok( hFile == TRUE, "%s not found : %ld\n", buff, GetLastError() ); ok( GetLastError() == 0xfaceabee || GetLastError() == ERROR_SUCCESS, - "GetLastError() returns %d\n", GetLastError() ); + "GetLastError() returns %ld\n", GetLastError() ); ok( ofs.cBytes == sizeof(ofs), "OpenFile set ofs.cBytes to %d\n", ofs.cBytes ); ok( ofs.nErrCode == ERROR_SUCCESS, "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); ok( lstrcmpiA(ofs.szPathName, buff) == 0, @@ -3348,8 +3610,8 @@ static void test_OpenFile(void) SetLastError(0xfaceabee); hFile = OpenFile(foo, &ofs, OF_EXIST); - ok( hFile == HFILE_ERROR, "hFile != HFILE_ERROR : %d\n", GetLastError()); - ok( GetLastError() == ERROR_FILE_NOT_FOUND, "GetLastError() returns %d\n", GetLastError() ); + ok( hFile == HFILE_ERROR, "hFile != HFILE_ERROR : %ld\n", GetLastError()); + ok( GetLastError() == ERROR_FILE_NOT_FOUND, "GetLastError() returns %ld\n", GetLastError() ); todo_wine ok( ofs.cBytes == 0xA5, "OpenFile set ofs.cBytes to %d\n", ofs.cBytes ); ok( ofs.nErrCode == ERROR_FILE_NOT_FOUND, "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); @@ -3369,9 +3631,9 @@ static void test_OpenFile(void) SetLastError(0xfaceabee); hFile = OpenFile(foo_too_long, &ofs, OF_EXIST); - ok( hFile == HFILE_ERROR, "hFile != HFILE_ERROR : %d\n", GetLastError()); + ok( hFile == HFILE_ERROR, "hFile != HFILE_ERROR : %ld\n", GetLastError()); ok( GetLastError() == ERROR_INVALID_DATA || GetLastError() == ERROR_FILENAME_EXCED_RANGE, - "GetLastError() returns %d\n", GetLastError() ); + "GetLastError() returns %ld\n", GetLastError() ); todo_wine ok( ofs.cBytes == 0xA5, "OpenFile set ofs.cBytes to %d\n", ofs.cBytes ); ok( ofs.nErrCode == ERROR_INVALID_DATA || ofs.nErrCode == ERROR_FILENAME_EXCED_RANGE, @@ -3381,31 +3643,20 @@ static void test_OpenFile(void) ofs.szPathName ); } - 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; - } - p = buff + strlen(buff); - if (p > buff && p[-1] != '\\') *p++ = '\\'; - strcpy( p, filename ); - memset(&ofs, 0xA5, sizeof(ofs)); SetLastError(0xfaceabee); /* Create an empty file */ hFile = OpenFile(filename, &ofs, OF_CREATE); ok( hFile != HFILE_ERROR, "OpenFile failed to create nonexistent file\n" ); ok( GetLastError() == 0xfaceabee || GetLastError() == ERROR_SUCCESS, - "GetLastError() returns %d\n", GetLastError() ); + "GetLastError() returns %ld\n", GetLastError() ); ok( ofs.cBytes == sizeof(OFSTRUCT), "OpenFile set ofs.cBytes to %d\n", ofs.cBytes ); ok( ofs.nErrCode == ERROR_SUCCESS || broken(ofs.nErrCode != ERROR_SUCCESS) /* win9x */, "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); ret = _lclose(hFile); ok( !ret, "_lclose() returns %d\n", ret ); retval = GetFileAttributesA(filename); - ok( retval != INVALID_FILE_ATTRIBUTES, "GetFileAttributesA: error %d\n", GetLastError() ); + ok( retval != INVALID_FILE_ATTRIBUTES, "GetFileAttributesA: error %ld\n", GetLastError() ); memset(&ofs, 0xA5, sizeof(ofs)); SetLastError(0xfaceabee); @@ -3414,12 +3665,12 @@ static void test_OpenFile(void) hFile = OpenFile(filename, &ofs, OF_READ); ok( hFile != HFILE_ERROR, "OpenFile failed on read\n" ); ok( GetLastError() == 0xfaceabee || GetLastError() == ERROR_SUCCESS, - "GetLastError() returns %d\n", GetLastError() ); + "GetLastError() returns %ld\n", GetLastError() ); ok( ofs.cBytes == sizeof(OFSTRUCT), "OpenFile set ofs.cBytes to %d\n", ofs.cBytes ); 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 ); + ok( lstrcmpiA(ofs.szPathName, filename) == 0, + "OpenFile returned '%s', but was expected to return '%s'\n", ofs.szPathName, filename ); ret = _lclose(hFile); ok( !ret, "_lclose() returns %d\n", ret ); @@ -3429,12 +3680,12 @@ static void test_OpenFile(void) hFile = OpenFile(filename, &ofs, OF_WRITE); ok( hFile != HFILE_ERROR, "OpenFile failed on write\n" ); ok( GetLastError() == 0xfaceabee || GetLastError() == ERROR_SUCCESS, - "GetLastError() returns %d\n", GetLastError() ); + "GetLastError() returns %ld\n", GetLastError() ); ok( ofs.cBytes == sizeof(OFSTRUCT), "OpenFile set ofs.cBytes to %d\n", ofs.cBytes ); 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 ); + ok( lstrcmpiA(ofs.szPathName, filename) == 0, + "OpenFile returned '%s', but was expected to return '%s'\n", ofs.szPathName, filename ); ret = _lclose(hFile); ok( !ret, "_lclose() returns %d\n", ret ); @@ -3444,12 +3695,12 @@ static void test_OpenFile(void) hFile = OpenFile(filename, &ofs, OF_READWRITE); ok( hFile != HFILE_ERROR, "OpenFile failed on read/write\n" ); ok( GetLastError() == 0xfaceabee || GetLastError() == ERROR_SUCCESS, - "GetLastError() returns %d\n", GetLastError() ); + "GetLastError() returns %ld\n", GetLastError() ); ok( ofs.cBytes == sizeof(OFSTRUCT), "OpenFile set ofs.cBytes to %d\n", ofs.cBytes ); 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 ); + ok( lstrcmpiA(ofs.szPathName, filename) == 0, + "OpenFile returned '%s', but was expected to return '%s'\n", ofs.szPathName, filename ); ret = _lclose(hFile); ok( !ret, "_lclose() returns %d\n", ret ); @@ -3459,12 +3710,12 @@ static void test_OpenFile(void) hFile = OpenFile(filename, &ofs, OF_EXIST); ok( hFile == 1, "OpenFile failed on finding our created file\n" ); ok( GetLastError() == 0xfaceabee || GetLastError() == ERROR_SUCCESS, - "GetLastError() returns %d\n", GetLastError() ); + "GetLastError() returns %ld\n", GetLastError() ); ok( ofs.cBytes == sizeof(OFSTRUCT), "OpenFile set ofs.cBytes to %d\n", ofs.cBytes ); 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 ); + ok( lstrcmpiA(ofs.szPathName, filename) == 0, + "OpenFile returned '%s', but was expected to return '%s'\n", ofs.szPathName, filename ); memset(&ofs, 0xA5, sizeof(ofs)); SetLastError(0xfaceabee); @@ -3472,12 +3723,12 @@ static void test_OpenFile(void) hFile = OpenFile(filename, &ofs, OF_DELETE); ok( hFile == 1, "OpenFile failed on delete (%d)\n", hFile ); ok( GetLastError() == 0xfaceabee || GetLastError() == ERROR_SUCCESS, - "GetLastError() returns %d\n", GetLastError() ); + "GetLastError() returns %ld\n", GetLastError() ); ok( ofs.cBytes == sizeof(OFSTRUCT), "OpenFile set ofs.cBytes to %d\n", ofs.cBytes ); 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 ); + ok( lstrcmpiA(ofs.szPathName, filename) == 0, + "OpenFile returned '%s', but was expected to return '%s'\n", ofs.szPathName, filename ); retval = GetFileAttributesA(filename); ok( retval == INVALID_FILE_ATTRIBUTES, "GetFileAttributesA succeeded on deleted file\n" ); @@ -3500,27 +3751,27 @@ static void test_overlapped(void) result = 1; r = GetOverlappedResult(0, &ov, &result, 0); if (r) - ok( result == 0, "wrong result %u\n", result ); + ok( result == 0, "wrong result %lu\n", result ); else /* win9x */ - ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %lu\n", GetLastError() ); result = 0; ov.Internal = 0; ov.InternalHigh = 0xabcd; r = GetOverlappedResult(0, &ov, &result, 0); if (r) - ok( result == 0xabcd, "wrong result %u\n", result ); + ok( result == 0xabcd, "wrong result %lu\n", result ); else /* win9x */ - ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %lu\n", GetLastError() ); SetLastError( 0xb00 ); result = 0; ov.Internal = STATUS_INVALID_HANDLE; ov.InternalHigh = 0xabcd; r = GetOverlappedResult(0, &ov, &result, 0); - ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %lu\n", GetLastError() ); ok( r == FALSE, "should return false\n"); - ok( result == 0xabcd || result == 0 /* win9x */, "wrong result %u\n", result ); + ok( result == 0xabcd || result == 0 /* win9x */, "wrong result %lu\n", result ); SetLastError( 0xb00 ); result = 0; @@ -3528,9 +3779,9 @@ static void test_overlapped(void) ov.InternalHigh = 0xabcd; r = GetOverlappedResult(0, &ov, &result, 0); ok( GetLastError() == ERROR_IO_INCOMPLETE || GetLastError() == ERROR_INVALID_HANDLE /* win9x */, - "wrong error %u\n", GetLastError() ); + "wrong error %lu\n", GetLastError() ); ok( r == FALSE, "should return false\n"); - ok( result == 0, "wrong result %u\n", result ); + ok( result == 0, "wrong result %lu\n", result ); SetLastError( 0xb00 ); ov.hEvent = CreateEventW( NULL, 1, 1, NULL ); @@ -3538,13 +3789,13 @@ static void test_overlapped(void) ov.InternalHigh = 0xabcd; r = GetOverlappedResult(0, &ov, &result, 0); ok( GetLastError() == ERROR_IO_INCOMPLETE || GetLastError() == ERROR_INVALID_HANDLE /* win9x */, - "wrong error %u\n", GetLastError() ); + "wrong error %lu\n", GetLastError() ); ok( r == FALSE, "should return false\n"); r = GetOverlappedResult( 0, &ov, &result, TRUE ); ok( r == TRUE, "should return TRUE\n" ); - ok( result == 0xabcd, "wrong result %u\n", result ); - ok( ov.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %08lx\n", ov.Internal ); + ok( result == 0xabcd, "wrong result %lu\n", result ); + ok( ov.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %08Ix\n", ov.Internal ); ResetEvent( ov.hEvent ); @@ -3553,7 +3804,7 @@ static void test_overlapped(void) ov.InternalHigh = 0; r = GetOverlappedResult(0, &ov, &result, 0); ok( GetLastError() == ERROR_IO_INCOMPLETE || GetLastError() == ERROR_INVALID_HANDLE /* win9x */, - "wrong error %u\n", GetLastError() ); + "wrong error %lu\n", GetLastError() ); ok( r == FALSE, "should return false\n"); r = CloseHandle( ov.hEvent ); @@ -3566,19 +3817,19 @@ static void test_RemoveDirectory(void) char directory[] = "removeme"; rc = CreateDirectoryA(directory, NULL); - ok( rc, "Createdirectory failed, gle=%d\n", GetLastError() ); + ok( rc, "Createdirectory failed, gle=%ld\n", GetLastError() ); rc = SetCurrentDirectoryA(directory); - ok( rc, "SetCurrentDirectory failed, gle=%d\n", GetLastError() ); + ok( rc, "SetCurrentDirectory failed, gle=%ld\n", GetLastError() ); rc = RemoveDirectoryA("."); if (!rc) { rc = SetCurrentDirectoryA(".."); - ok( rc, "SetCurrentDirectory failed, gle=%d\n", GetLastError() ); + ok( rc, "SetCurrentDirectory failed, gle=%ld\n", GetLastError() ); rc = RemoveDirectoryA(directory); - ok( rc, "RemoveDirectory failed, gle=%d\n", GetLastError() ); + ok( rc, "RemoveDirectory failed, gle=%ld\n", GetLastError() ); } } @@ -3586,13 +3837,13 @@ static BOOL check_file_time( const FILETIME *ft1, const FILETIME *ft2, UINT tole { ULONGLONG t1 = ((ULONGLONG)ft1->dwHighDateTime << 32) | ft1->dwLowDateTime; ULONGLONG t2 = ((ULONGLONG)ft2->dwHighDateTime << 32) | ft2->dwLowDateTime; - return abs(t1 - t2) <= tolerance; + return (t1 > t2 ? t1 - t2 : t2 - t1) <= tolerance; } static void test_ReplaceFileA(void) { char replaced[MAX_PATH], replacement[MAX_PATH], backup[MAX_PATH]; - HANDLE hReplacedFile, hReplacementFile, hBackupFile; + HANDLE hReplacedFile, hReplacementFile, hBackupFile, mapping; static const char replacedData[] = "file-to-replace"; static const char replacementData[] = "new-file"; static const char backupData[] = "backup-file"; @@ -3601,25 +3852,20 @@ static void test_ReplaceFileA(void) char temp_path[MAX_PATH]; DWORD ret; BOOL retok, removeBackup = FALSE; - - if (!pReplaceFileA) - { - win_skip("ReplaceFileA() is missing\n"); - return; - } + char **argv; ret = GetTempPathA(MAX_PATH, temp_path); - ok(ret != 0, "GetTempPathA error %d\n", GetLastError()); + ok(ret != 0, "GetTempPathA error %ld\n", GetLastError()); ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n"); ret = GetTempFileNameA(temp_path, prefix, 0, replaced); - ok(ret != 0, "GetTempFileNameA error (replaced) %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameA error (replaced) %ld\n", GetLastError()); ret = GetTempFileNameA(temp_path, prefix, 0, replacement); - ok(ret != 0, "GetTempFileNameA error (replacement) %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameA error (replacement) %ld\n", GetLastError()); ret = GetTempFileNameA(temp_path, prefix, 0, backup); - ok(ret != 0, "GetTempFileNameA error (backup) %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameA error (backup) %ld\n", GetLastError()); /* place predictable data in the file to be replaced */ hReplacedFile = CreateFileA(replaced, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0 ); @@ -3627,7 +3873,7 @@ static void test_ReplaceFileA(void) "failed to open replaced file\n"); retok = WriteFile(hReplacedFile, replacedData, sizeof(replacedData), &ret, NULL ); ok( retok && ret == sizeof(replacedData), - "WriteFile error (replaced) %d\n", GetLastError()); + "WriteFile error (replaced) %ld\n", GetLastError()); ok(GetFileSize(hReplacedFile, NULL) == sizeof(replacedData), "replaced file has wrong size\n"); /* place predictable data in the file to be the replacement */ @@ -3636,7 +3882,7 @@ static void test_ReplaceFileA(void) "failed to open replacement file\n"); retok = WriteFile(hReplacementFile, replacementData, sizeof(replacementData), &ret, NULL ); ok( retok && ret == sizeof(replacementData), - "WriteFile error (replacement) %d\n", GetLastError()); + "WriteFile error (replacement) %ld\n", GetLastError()); ok(GetFileSize(hReplacementFile, NULL) == sizeof(replacementData), "replacement file has wrong size\n"); /* place predictable data in the backup file (to be over-written) */ @@ -3645,66 +3891,66 @@ static void test_ReplaceFileA(void) "failed to open backup file\n"); retok = WriteFile(hBackupFile, backupData, sizeof(backupData), &ret, NULL ); ok( retok && ret == sizeof(backupData), - "WriteFile error (replacement) %d\n", GetLastError()); + "WriteFile error (replacement) %ld\n", GetLastError()); ok(GetFileSize(hBackupFile, NULL) == sizeof(backupData), "backup file has wrong size\n"); /* change the filetime on the "replaced" file to ensure that it changes */ ret = GetFileTime(hReplacedFile, NULL, NULL, &ftReplaced); - ok( ret, "GetFileTime error (replaced) %d\n", GetLastError()); + ok( ret, "GetFileTime error (replaced) %ld\n", GetLastError()); ftReplaced.dwLowDateTime -= 600000000; /* 60 second */ ret = SetFileTime(hReplacedFile, NULL, NULL, &ftReplaced); - ok( ret, "SetFileTime error (replaced) %d\n", GetLastError()); + ok( ret, "SetFileTime error (replaced) %ld\n", GetLastError()); GetFileTime(hReplacedFile, NULL, NULL, &ftReplaced); /* get the actual time back */ CloseHandle(hReplacedFile); /* change the filetime on the backup to ensure that it changes */ ret = GetFileTime(hBackupFile, NULL, NULL, &ftBackup); - ok( ret, "GetFileTime error (backup) %d\n", GetLastError()); + ok( ret, "GetFileTime error (backup) %ld\n", GetLastError()); ftBackup.dwLowDateTime -= 1200000000; /* 120 second */ ret = SetFileTime(hBackupFile, NULL, NULL, &ftBackup); - ok( ret, "SetFileTime error (backup) %d\n", GetLastError()); + ok( ret, "SetFileTime error (backup) %ld\n", GetLastError()); GetFileTime(hBackupFile, NULL, NULL, &ftBackup); /* get the actual time back */ CloseHandle(hBackupFile); /* get the filetime on the replacement file to perform checks */ ret = GetFileTime(hReplacementFile, NULL, NULL, &ftReplacement); - ok( ret, "GetFileTime error (replacement) %d\n", GetLastError()); + ok( ret, "GetFileTime error (replacement) %ld\n", GetLastError()); CloseHandle(hReplacementFile); /* perform replacement w/ backup * TODO: flags are not implemented */ SetLastError(0xdeadbeef); - ret = pReplaceFileA(replaced, replacement, backup, 0, 0, 0); - ok(ret, "ReplaceFileA: unexpected error %d\n", GetLastError()); + ret = ReplaceFileA(replaced, replacement, backup, 0, 0, 0); + ok(ret, "ReplaceFileA: unexpected error %ld\n", GetLastError()); /* make sure that the backup has the size of the old "replaced" file */ hBackupFile = CreateFileA(backup, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); ok(hBackupFile != INVALID_HANDLE_VALUE, "failed to open backup file\n"); ret = GetFileSize(hBackupFile, NULL); ok(ret == sizeof(replacedData), - "backup file has wrong size %d\n", ret); + "backup file has wrong size %ld\n", ret); /* make sure that the "replaced" file has the size of the replacement file */ hReplacedFile = CreateFileA(replaced, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); ok(hReplacedFile != INVALID_HANDLE_VALUE, - "failed to open replaced file: %d\n", GetLastError()); + "failed to open replaced file: %ld\n", GetLastError()); if (hReplacedFile != INVALID_HANDLE_VALUE) { ret = GetFileSize(hReplacedFile, NULL); ok(ret == sizeof(replacementData), - "replaced file has wrong size %d\n", ret); + "replaced file has wrong size %ld\n", ret); /* make sure that the replacement file no-longer exists */ hReplacementFile = CreateFileA(replacement, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); ok(hReplacementFile == INVALID_HANDLE_VALUE, - "unexpected error, replacement file should not exist %d\n", GetLastError()); + "unexpected error, replacement file should not exist %ld\n", GetLastError()); /* 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( ret, "GetFileTime error (backup %ld\n", GetLastError()); 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( ret, "GetFileTime error (backup %ld\n", GetLastError()); ok(check_file_time(&ftReplaced, &ftReplacement, 20000000), - "replaced file has wrong filetime %x%08x / %x%08x\n", + "replaced file has wrong filetime %lx%08lx / %lx%08lx\n", ftReplaced.dwHighDateTime, ftReplaced.dwLowDateTime, ftReplacement.dwHighDateTime, ftReplacement.dwLowDateTime ); CloseHandle(hReplacedFile); @@ -3714,73 +3960,114 @@ static void test_ReplaceFileA(void) /* re-create replacement file for pass w/o backup (blank) */ ret = GetTempFileNameA(temp_path, prefix, 0, replacement); - ok(ret != 0, "GetTempFileNameA error (replacement) %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameA error (replacement) %ld\n", GetLastError()); /* perform replacement w/o backup * TODO: flags are not implemented */ SetLastError(0xdeadbeef); - ret = pReplaceFileA(replaced, replacement, NULL, 0, 0, 0); + ret = ReplaceFileA(replaced, replacement, NULL, 0, 0, 0); ok(ret || GetLastError() == ERROR_ACCESS_DENIED, - "ReplaceFileA: unexpected error %d\n", GetLastError()); + "ReplaceFileA: unexpected error %ld\n", GetLastError()); /* re-create replacement file for pass w/ backup (backup-file not existing) */ + DeleteFileA(replacement); ret = GetTempFileNameA(temp_path, prefix, 0, replacement); - ok(ret != 0, "GetTempFileNameA error (replacement) %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameA error (replacement) %ld\n", GetLastError()); ret = DeleteFileA(backup); - ok(ret, "DeleteFileA: error (backup) %d\n", GetLastError()); + ok(ret, "DeleteFileA: error (backup) %ld\n", GetLastError()); /* perform replacement w/ backup (no pre-existing backup) * TODO: flags are not implemented */ SetLastError(0xdeadbeef); - ret = pReplaceFileA(replaced, replacement, backup, 0, 0, 0); + ret = ReplaceFileA(replaced, replacement, backup, 0, 0, 0); ok(ret || GetLastError() == ERROR_ACCESS_DENIED, - "ReplaceFileA: unexpected error %d\n", GetLastError()); + "ReplaceFileA: unexpected error %ld\n", GetLastError()); if (ret) removeBackup = TRUE; /* re-create replacement file for pass w/ no permissions to "replaced" */ + DeleteFileA(replacement); ret = GetTempFileNameA(temp_path, prefix, 0, replacement); - ok(ret != 0, "GetTempFileNameA error (replacement) %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameA error (replacement) %ld\n", GetLastError()); ret = SetFileAttributesA(replaced, FILE_ATTRIBUTE_READONLY); ok(ret || GetLastError() == ERROR_ACCESS_DENIED, - "SetFileAttributesA: error setting to read only %d\n", GetLastError()); + "SetFileAttributesA: error setting to read only %ld\n", GetLastError()); /* perform replacement w/ backup (no permission to "replaced") * TODO: flags are not implemented */ SetLastError(0xdeadbeef); - ret = pReplaceFileA(replaced, replacement, backup, 0, 0, 0); - ok(ret != ERROR_UNABLE_TO_REMOVE_REPLACED, "ReplaceFileA: unexpected error %d\n", GetLastError()); + ret = ReplaceFileA(replaced, replacement, backup, 0, 0, 0); + ok(ret == 0 && GetLastError() == ERROR_ACCESS_DENIED, "ReplaceFileA: unexpected error %ld\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 || broken(GetLastError() == ERROR_FILE_NOT_FOUND), /* win2k */ - "unexpected error, replacement file should still exist %d\n", GetLastError()); + "unexpected error, replacement file should still exist %ld\n", GetLastError()); CloseHandle(hReplacementFile); ret = SetFileAttributesA(replaced, FILE_ATTRIBUTE_NORMAL); ok(ret || GetLastError() == ERROR_ACCESS_DENIED, - "SetFileAttributesA: error setting to normal %d\n", GetLastError()); + "SetFileAttributesA: error setting to normal %ld\n", GetLastError()); + + /* replacement readonly */ + DeleteFileA(replacement); + ret = GetTempFileNameA(temp_path, prefix, 0, replacement); + ok(ret != 0, "GetTempFileNameA error (replacement) %#lx\n", GetLastError()); + ret = SetFileAttributesA(replacement, FILE_ATTRIBUTE_READONLY); + ok(ret, "SetFileAttributesA: error setting to readonly %#lx\n", GetLastError()); + ret = ReplaceFileA(replaced, replacement, NULL, 0, 0, 0); + ok(GetLastError() == ERROR_ACCESS_DENIED, "ReplaceFileA: unexpected error %#lx\n", GetLastError()); + ret = SetFileAttributesA(replacement, FILE_ATTRIBUTE_NORMAL); + ok(ret, "SetFileAttributesA: error setting to normal %#lx\n", GetLastError()); + + /* re-create replacement file for pass w/ replaced opened with + * the same permissions as an exe (Replicating an exe trying to + * replace itself) + */ + DeleteFileA(replacement); + ret = GetTempFileNameA(temp_path, prefix, 0, replacement); + ok(ret != 0, "GetTempFileNameA error (replacement) %ld\n", GetLastError()); + + /* make sure that the replaced file is opened like an exe*/ + hReplacedFile = CreateFileA(replaced, GENERIC_READ | SYNCHRONIZE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, 0); + ok(hReplacedFile != INVALID_HANDLE_VALUE, + "unexpected error, replaced file should be able to be opened %ld\n", GetLastError()); + /*Calling ReplaceFileA on an exe should succeed*/ + ret = ReplaceFileA(replaced, replacement, NULL, 0, 0, 0); + ok(ret, "ReplaceFileA: unexpected error %ld\n", GetLastError()); + CloseHandle(hReplacedFile); + + /* replace file while replacement is opened */ + ret = GetTempFileNameA(temp_path, prefix, 0, replacement); + ok(ret != 0, "GetTempFileNameA error (replacement) %ld\n", GetLastError()); + hReplacementFile = CreateFileA(replacement, GENERIC_READ | SYNCHRONIZE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, 0); + ok(hReplacementFile != INVALID_HANDLE_VALUE, "unexpected error, replacement file should be able to be opened %ld\n", + GetLastError()); + ret = ReplaceFileA(replaced, replacement, NULL, 0, 0, 0); + ok(!ret, "expect failure\n"); + ok(GetLastError() == ERROR_SHARING_VIOLATION, "expect ERROR_SHARING_VIOLATION, got %#lx.\n", GetLastError()); + CloseHandle(hReplacementFile); /* replacement file still exists, make pass w/o "replaced" */ ret = DeleteFileA(replaced); ok(ret || GetLastError() == ERROR_ACCESS_DENIED, - "DeleteFileA: error (replaced) %d\n", GetLastError()); + "DeleteFileA: error (replaced) %ld\n", GetLastError()); /* perform replacement w/ backup (no pre-existing backup or "replaced") * TODO: flags are not implemented */ SetLastError(0xdeadbeef); - ret = pReplaceFileA(replaced, replacement, backup, 0, 0, 0); + ret = ReplaceFileA(replaced, replacement, backup, 0, 0, 0); ok(!ret && (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_ACCESS_DENIED), - "ReplaceFileA: unexpected error %d\n", GetLastError()); + "ReplaceFileA: unexpected error %ld\n", GetLastError()); /* perform replacement w/o existing "replacement" file * TODO: flags are not implemented */ SetLastError(0xdeadbeef); - ret = pReplaceFileA(replaced, replacement, NULL, 0, 0, 0); + ret = ReplaceFileA(replaced, replacement, NULL, 0, 0, 0); ok(!ret && (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_ACCESS_DENIED), - "ReplaceFileA: unexpected error %d\n", GetLastError()); + "ReplaceFileA: unexpected error %ld\n", GetLastError()); DeleteFileA( replacement ); /* @@ -3795,8 +4082,45 @@ static void test_ReplaceFileA(void) ret = DeleteFileA(backup); ok(ret || broken(GetLastError() == ERROR_ACCESS_DENIED), /* win2k */ - "DeleteFileA: error (backup) %d\n", GetLastError()); + "DeleteFileA: error (backup) %ld\n", GetLastError()); } + + ret = GetTempFileNameA(temp_path, prefix, 0, replaced); + ok(ret, "got error %lu\n", GetLastError()); + hReplacedFile = CreateFileA(replaced, 0, 0, NULL, OPEN_EXISTING, 0, 0); + ok(hReplacedFile != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError()); + + ret = GetTempFileNameA(temp_path, prefix, 0, replacement); + ok(ret, "got error %lu\n", GetLastError()); + + ret = ReplaceFileA(replaced, replacement, NULL, 0, 0, 0); + ok(ret, "got error %lu\n", GetLastError()); + + CloseHandle(hReplacedFile); + ret = DeleteFileA(replaced); + ok(ret, "got error %lu\n", GetLastError()); + + winetest_get_mainargs(&argv); + + ret = CopyFileA(argv[0], replaced, FALSE); + ok(ret, "got error %lu\n", GetLastError()); + hReplacedFile = CreateFileA(replaced, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, 0); + ok(hReplacedFile != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError()); + + mapping = CreateFileMappingA(hReplacedFile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL); + ok(!!mapping, "got error %lu\n", GetLastError()); + + ret = GetTempFileNameA(temp_path, prefix, 0, replacement); + ok(ret, "got error %lu\n", GetLastError()); + + ret = ReplaceFileA(replaced, replacement, NULL, 0, 0, 0); + ok(ret, "got error %lu\n", GetLastError()); + + CloseHandle(mapping); + CloseHandle(hReplacedFile); + ret = DeleteFileA(replaced); + ok(ret, "got error %lu\n", GetLastError()); } /* @@ -3823,59 +4147,60 @@ static void test_ReplaceFileW(void) win_skip("GetTempPathW is not available\n"); return; } - ok(ret != 0, "GetTempPathW error %d\n", GetLastError()); + ok(ret != 0, "GetTempPathW error %ld\n", GetLastError()); ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n"); ret = GetTempFileNameW(temp_path, prefix, 0, replaced); - ok(ret != 0, "GetTempFileNameW error (replaced) %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameW error (replaced) %ld\n", GetLastError()); ret = GetTempFileNameW(temp_path, prefix, 0, replacement); - ok(ret != 0, "GetTempFileNameW error (replacement) %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameW error (replacement) %ld\n", GetLastError()); ret = GetTempFileNameW(temp_path, prefix, 0, backup); - ok(ret != 0, "GetTempFileNameW error (backup) %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameW error (backup) %ld\n", GetLastError()); ret = pReplaceFileW(replaced, replacement, backup, 0, 0, 0); - ok(ret, "ReplaceFileW: error %d\n", GetLastError()); + ok(ret, "ReplaceFileW: error %ld\n", GetLastError()); ret = GetTempFileNameW(temp_path, prefix, 0, replacement); - ok(ret != 0, "GetTempFileNameW error (replacement) %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameW error (replacement) %ld\n", GetLastError()); ret = pReplaceFileW(replaced, replacement, NULL, 0, 0, 0); ok(ret || GetLastError() == ERROR_ACCESS_DENIED, - "ReplaceFileW: error %d\n", GetLastError()); + "ReplaceFileW: error %ld\n", GetLastError()); ret = GetTempFileNameW(temp_path, prefix, 0, replacement); - ok(ret != 0, "GetTempFileNameW error (replacement) %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameW error (replacement) %ld\n", GetLastError()); ret = DeleteFileW(backup); - ok(ret, "DeleteFileW: error (backup) %d\n", GetLastError()); + ok(ret, "DeleteFileW: error (backup) %ld\n", GetLastError()); ret = pReplaceFileW(replaced, replacement, backup, 0, 0, 0); ok(ret || GetLastError() == ERROR_ACCESS_DENIED, - "ReplaceFileW: error %d\n", GetLastError()); + "ReplaceFileW: error %ld\n", GetLastError()); ret = GetTempFileNameW(temp_path, prefix, 0, replacement); - ok(ret != 0, "GetTempFileNameW error (replacement) %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameW error (replacement) %ld\n", GetLastError()); ret = SetFileAttributesW(replaced, FILE_ATTRIBUTE_READONLY); ok(ret || GetLastError() == ERROR_ACCESS_DENIED, - "SetFileAttributesW: error setting to read only %d\n", GetLastError()); + "SetFileAttributesW: error setting to read only %ld\n", GetLastError()); + SetLastError(0xdeadbeef); ret = pReplaceFileW(replaced, replacement, backup, 0, 0, 0); - ok(ret != ERROR_UNABLE_TO_REMOVE_REPLACED, - "ReplaceFileW: unexpected error %d\n", GetLastError()); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %lu\n", GetLastError()); ret = SetFileAttributesW(replaced, FILE_ATTRIBUTE_NORMAL); ok(ret || GetLastError() == ERROR_ACCESS_DENIED, - "SetFileAttributesW: error setting to normal %d\n", GetLastError()); + "SetFileAttributesW: error setting to normal %ld\n", GetLastError()); if (ret) removeBackup = TRUE; ret = DeleteFileW(replaced); - ok(ret, "DeleteFileW: error (replaced) %d\n", GetLastError()); + ok(ret, "DeleteFileW: error (replaced) %ld\n", GetLastError()); ret = pReplaceFileW(replaced, replacement, backup, 0, 0, 0); - ok(!ret, "ReplaceFileW: error %d\n", GetLastError()); + ok(!ret, "ReplaceFileW: error %ld\n", GetLastError()); ret = pReplaceFileW(replaced, replacement, NULL, 0, 0, 0); ok(!ret && (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_ACCESS_DENIED), - "ReplaceFileW: unexpected error %d\n", GetLastError()); + "ReplaceFileW: unexpected error %ld\n", GetLastError()); DeleteFileW( replacement ); if (removeBackup) @@ -3883,7 +4208,7 @@ static void test_ReplaceFileW(void) ret = DeleteFileW(backup); ok(ret || broken(GetLastError() == ERROR_ACCESS_DENIED), /* win2k */ - "DeleteFileW: error (backup) %d\n", GetLastError()); + "DeleteFileW: error (backup) %ld\n", GetLastError()); } } @@ -3940,57 +4265,57 @@ static void test_CreateFile(void) ok(hfile == INVALID_HANDLE_VALUE, "CreateFile should fail\n"); if (i == 0 || i == 5) { -/* FIXME: remove once Wine is fixed */ -todo_wine_if (i == 5) - ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError()); + /* FIXME: remove once Wine is fixed */ + todo_wine_if (i == 5) + ok(GetLastError() == ERROR_INVALID_PARAMETER, "%ld: expected ERROR_INVALID_PARAMETER, got %ld\n", i, GetLastError()); } else { -/* FIXME: remove once Wine is fixed */ -todo_wine_if (i == 1) - ok(GetLastError() == ERROR_ACCESS_DENIED, "%d: expected ERROR_ACCESS_DENIED, got %d\n", i, GetLastError()); + /* FIXME: remove once Wine is fixed */ + todo_wine_if (i == 1) + ok(GetLastError() == ERROR_ACCESS_DENIED, "%ld: expected ERROR_ACCESS_DENIED, got %ld\n", i, GetLastError()); } SetLastError(0xdeadbeef); hfile = CreateFileA(temp_path, GENERIC_WRITE, 0, NULL, i, 0, 0); ok(hfile == INVALID_HANDLE_VALUE, "CreateFile should fail\n"); if (i == 0) - ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "%ld: expected ERROR_INVALID_PARAMETER, got %ld\n", i, GetLastError()); else { -/* FIXME: remove once Wine is fixed */ -todo_wine_if (i == 1) - ok(GetLastError() == ERROR_ACCESS_DENIED, "%d: expected ERROR_ACCESS_DENIED, got %d\n", i, GetLastError()); + /* FIXME: remove once Wine is fixed */ + todo_wine_if (i == 1) + ok(GetLastError() == ERROR_ACCESS_DENIED, "%ld: expected ERROR_ACCESS_DENIED, got %ld\n", i, GetLastError()); } } - for (i = 0; i < sizeof(td)/sizeof(td[0]); i++) + for (i = 0; i < ARRAY_SIZE(td); i++) { SetLastError(0xdeadbeef); hfile = CreateFileA(file_name, td[i].access, 0, NULL, td[i].disposition, 0, 0); if (!td[i].error) { - ok(hfile != INVALID_HANDLE_VALUE, "%d: CreateFile error %d\n", i, GetLastError()); + ok(hfile != INVALID_HANDLE_VALUE, "%ld: CreateFile error %ld\n", i, GetLastError()); written = 0xdeadbeef; SetLastError(0xdeadbeef); ret = WriteFile(hfile, &td[i].error, sizeof(td[i].error), &written, NULL); if (td[i].access & GENERIC_WRITE) - ok(ret, "%d: WriteFile error %d\n", i, GetLastError()); + ok(ret, "%ld: WriteFile error %ld\n", i, GetLastError()); else { - ok(!ret, "%d: WriteFile should fail\n", i); - ok(GetLastError() == ERROR_ACCESS_DENIED, "%d: expected ERROR_ACCESS_DENIED, got %d\n", i, GetLastError()); + ok(!ret, "%ld: WriteFile should fail\n", i); + ok(GetLastError() == ERROR_ACCESS_DENIED, "%ld: expected ERROR_ACCESS_DENIED, got %ld\n", i, GetLastError()); } SetLastError(0xdeadbeef); ret = SetFileTime(hfile, NULL, NULL, NULL); if (td[i].access & GENERIC_WRITE) /* actually FILE_WRITE_ATTRIBUTES */ - ok(ret, "%d: SetFileTime error %d\n", i, GetLastError()); + ok(ret, "%ld: SetFileTime error %ld\n", i, GetLastError()); else { todo_wine { - ok(!ret, "%d: SetFileTime should fail\n", i); - ok(GetLastError() == ERROR_ACCESS_DENIED, "%d: expected ERROR_ACCESS_DENIED, got %d\n", i, GetLastError()); + ok(!ret, "%ld: SetFileTime should fail\n", i); + ok(GetLastError() == ERROR_ACCESS_DENIED, "%ld: expected ERROR_ACCESS_DENIED, got %ld\n", i, GetLastError()); } } CloseHandle(hfile); @@ -4002,15 +4327,15 @@ todo_wine_if (i == 1) { todo_wine { - ok(hfile == INVALID_HANDLE_VALUE, "%d: CreateFile should fail\n", i); - ok(GetLastError() == td[i].error, "%d: expected %d, got %d\n", i, td[i].error, GetLastError()); + ok(hfile == INVALID_HANDLE_VALUE, "%ld: CreateFile should fail\n", i); + ok(GetLastError() == td[i].error, "%ld: expected %ld, got %ld\n", i, td[i].error, GetLastError()); } CloseHandle(hfile); } else { - ok(hfile == INVALID_HANDLE_VALUE, "%d: CreateFile should fail\n", i); - ok(GetLastError() == td[i].error, "%d: expected %d, got %d\n", i, td[i].error, GetLastError()); + ok(hfile == INVALID_HANDLE_VALUE, "%ld: CreateFile should fail\n", i); + ok(GetLastError() == td[i].error, "%ld: expected %ld, got %ld\n", i, td[i].error, GetLastError()); } } @@ -4056,26 +4381,26 @@ static void test_GetFileInformationByHandleEx(void) } ret2 = GetTempPathA(sizeof(tempPath), tempPath); - ok(ret2, "GetFileInformationByHandleEx: GetTempPathA failed, got error %u.\n", GetLastError()); + ok(ret2, "GetFileInformationByHandleEx: GetTempPathA failed, got error %lu.\n", GetLastError()); /* ensure the existence of a file in the temp folder */ ret2 = GetTempFileNameA(tempPath, "abc", 0, tempFileName); - ok(ret2, "GetFileInformationByHandleEx: GetTempFileNameA failed, got error %u.\n", GetLastError()); + ok(ret2, "GetFileInformationByHandleEx: GetTempFileNameA failed, got error %lu.\n", GetLastError()); ret2 = GetFileAttributesA(tempFileName); ok(ret2 != INVALID_FILE_ATTRIBUTES, "GetFileInformationByHandleEx: " - "GetFileAttributesA failed to find the temp file, got error %u.\n", GetLastError()); + "GetFileAttributesA failed to find the temp file, got error %lu.\n", GetLastError()); directory = CreateFileA(tempPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); ok(directory != INVALID_HANDLE_VALUE, "GetFileInformationByHandleEx: failed to open the temp folder, " - "got error %u.\n", GetLastError()); + "got error %lu.\n", GetLastError()); - for (i = 0; i < sizeof(checks) / sizeof(checks[0]); i += 1) + for (i = 0; i < ARRAY_SIZE(checks); i += 1) { SetLastError(0xdeadbeef); ret = pGetFileInformationByHandleEx(directory, checks[i].handleClass, checks[i].ptr, checks[i].size); - ok(!ret && GetLastError() == checks[i].errorCode, "GetFileInformationByHandleEx: expected error %u, " - "got %u.\n", checks[i].errorCode, GetLastError()); + ok(!ret && GetLastError() == checks[i].errorCode, "GetFileInformationByHandleEx: expected error %lu, " + "got %lu.\n", checks[i].errorCode, GetLastError()); } while (TRUE) @@ -4084,7 +4409,7 @@ static void test_GetFileInformationByHandleEx(void) ret = pGetFileInformationByHandleEx(directory, FileIdBothDirectoryInfo, buffer, sizeof(buffer)); if (!ret && GetLastError() == ERROR_NO_MORE_FILES) break; - ok(ret, "GetFileInformationByHandleEx: failed to query for FileIdBothDirectoryInfo, got error %u.\n", GetLastError()); + ok(ret, "GetFileInformationByHandleEx: failed to query for FileIdBothDirectoryInfo, got error %lu.\n", GetLastError()); if (!ret) break; bothDirInfo = (FILE_ID_BOTH_DIR_INFO *)buffer; @@ -4104,12 +4429,12 @@ static void test_GetFileInformationByHandleEx(void) file = CreateFileA(tempFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL); ok(file != INVALID_HANDLE_VALUE, "GetFileInformationByHandleEx: failed to open the temp file, " - "got error %u.\n", GetLastError()); + "got error %lu.\n", GetLastError()); /* Test FileBasicInfo; make sure the write time changes when a file is updated */ memset(buffer, 0xff, sizeof(buffer)); ret = pGetFileInformationByHandleEx(file, FileBasicInfo, buffer, sizeof(buffer)); - ok(ret, "GetFileInformationByHandleEx: failed to get FileBasicInfo, %u\n", GetLastError()); + ok(ret, "GetFileInformationByHandleEx: failed to get FileBasicInfo, %lu\n", GetLastError()); basicInfo = (FILE_BASIC_INFO *)buffer; prevWrite = basicInfo->LastWriteTime; CloseHandle(file); @@ -4120,7 +4445,7 @@ static void test_GetFileInformationByHandleEx(void) file = CreateFileA(tempFileName, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL); ok(file != INVALID_HANDLE_VALUE, "GetFileInformationByHandleEx: failed to open the temp file, " - "got error %u.\n", GetLastError()); + "got error %lu.\n", GetLastError()); ret = WriteFile(file, tempFileName, strlen(tempFileName), &written, NULL); ok(ret, "GetFileInformationByHandleEx: Write failed\n"); CloseHandle(file); @@ -4128,11 +4453,11 @@ static void test_GetFileInformationByHandleEx(void) file = CreateFileA(tempFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL); ok(file != INVALID_HANDLE_VALUE, "GetFileInformationByHandleEx: failed to open the temp file, " - "got error %u.\n", GetLastError()); + "got error %lu.\n", GetLastError()); memset(buffer, 0xff, sizeof(buffer)); ret = pGetFileInformationByHandleEx(file, FileBasicInfo, buffer, sizeof(buffer)); - ok(ret, "GetFileInformationByHandleEx: failed to get FileBasicInfo, %u\n", GetLastError()); + ok(ret, "GetFileInformationByHandleEx: failed to get FileBasicInfo, %lu\n", GetLastError()); basicInfo = (FILE_BASIC_INFO *)buffer; /* Could also check that the creation time didn't change - on windows * it doesn't, but on wine, it does change even if it shouldn't. */ @@ -4142,7 +4467,7 @@ static void test_GetFileInformationByHandleEx(void) /* Test FileStandardInfo, check some basic parameters */ memset(buffer, 0xff, sizeof(buffer)); ret = pGetFileInformationByHandleEx(file, FileStandardInfo, buffer, sizeof(buffer)); - ok(ret, "GetFileInformationByHandleEx: failed to get FileStandardInfo, %u\n", GetLastError()); + ok(ret, "GetFileInformationByHandleEx: failed to get FileStandardInfo, %lu\n", GetLastError()); standardInfo = (FILE_STANDARD_INFO *)buffer; ok(standardInfo->NumberOfLinks == 1, "GetFileInformationByHandleEx: Unexpected number of links\n"); ok(standardInfo->DeletePending == FALSE, "GetFileInformationByHandleEx: Unexpected pending delete\n"); @@ -4151,7 +4476,7 @@ static void test_GetFileInformationByHandleEx(void) /* Test FileNameInfo */ memset(buffer, 0xff, sizeof(buffer)); ret = pGetFileInformationByHandleEx(file, FileNameInfo, buffer, sizeof(buffer)); - ok(ret, "GetFileInformationByHandleEx: failed to get FileNameInfo, %u\n", GetLastError()); + ok(ret, "GetFileInformationByHandleEx: failed to get FileNameInfo, %lu\n", GetLastError()); nameInfo = (FILE_NAME_INFO *)buffer; strPtr = strchr(tempFileName, '\\'); ok(strPtr != NULL, "GetFileInformationByHandleEx: Temp filename didn't contain backslash\n"); @@ -4164,23 +4489,23 @@ static void test_GetFileInformationByHandleEx(void) /* invalid classes */ SetLastError(0xdeadbeef); ret = pGetFileInformationByHandleEx(file, FileEndOfFileInfo, &eofinfo, sizeof(eofinfo)); - ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError()); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %ld\n", ret, GetLastError()); SetLastError(0xdeadbeef); ret = pGetFileInformationByHandleEx(file, FileIoPriorityHintInfo, &priohintinfo, sizeof(priohintinfo)); - ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError()); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %ld\n", ret, GetLastError()); SetLastError(0xdeadbeef); ret = pGetFileInformationByHandleEx(file, FileAllocationInfo, &allocinfo, sizeof(allocinfo)); - ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError()); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %ld\n", ret, GetLastError()); SetLastError(0xdeadbeef); ret = pGetFileInformationByHandleEx(file, FileDispositionInfo, &dispinfo, sizeof(dispinfo)); - ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError()); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %ld\n", ret, GetLastError()); SetLastError(0xdeadbeef); ret = pGetFileInformationByHandleEx(file, FileRenameInfo, &renameinfo, sizeof(renameinfo)); - ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError()); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %ld\n", ret, GetLastError()); CloseHandle(file); DeleteFileA(tempFileName); @@ -4203,46 +4528,46 @@ static void test_OpenFileById(void) } ret2 = GetTempPathA(sizeof(tempPath), tempPath); - ok(ret2, "OpenFileById: GetTempPath failed, got error %u.\n", GetLastError()); + ok(ret2, "OpenFileById: GetTempPath failed, got error %lu.\n", GetLastError()); /* ensure the existence of a file in the temp folder */ ret2 = GetTempFileNameA(tempPath, "abc", 0, tempFileName); - ok(ret2, "OpenFileById: GetTempFileNameA failed, got error %u.\n", GetLastError()); + ok(ret2, "OpenFileById: GetTempFileNameA failed, got error %lu.\n", GetLastError()); ret2 = GetFileAttributesA(tempFileName); ok(ret2 != INVALID_FILE_ATTRIBUTES, - "OpenFileById: GetFileAttributesA failed to find the temp file, got error %u\n", GetLastError()); + "OpenFileById: GetFileAttributesA failed to find the temp file, got error %lu\n", GetLastError()); - ret2 = MultiByteToWideChar(CP_ACP, 0, tempFileName + strlen(tempPath), -1, tempFileNameW, sizeof(tempFileNameW)/sizeof(tempFileNameW[0])); - ok(ret2, "OpenFileById: MultiByteToWideChar failed to convert tempFileName, got error %u.\n", GetLastError()); + ret2 = MultiByteToWideChar(CP_ACP, 0, tempFileName + strlen(tempPath), -1, tempFileNameW, ARRAY_SIZE(tempFileNameW)); + ok(ret2, "OpenFileById: MultiByteToWideChar failed to convert tempFileName, got error %lu.\n", GetLastError()); tempFileNameLen = ret2 - 1; tempFile = CreateFileA(tempFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); ok(tempFile != INVALID_HANDLE_VALUE, "OpenFileById: failed to create a temp file, " - "got error %u.\n", GetLastError()); - ret2 = sprintf(tickCount, "%u", GetTickCount()); + "got error %lu.\n", GetLastError()); + ret2 = sprintf(tickCount, "%lu", GetTickCount()); ret = WriteFile(tempFile, tickCount, ret2, &count, NULL); - ok(ret, "OpenFileById: WriteFile failed, got error %u.\n", GetLastError()); + ok(ret, "OpenFileById: WriteFile failed, got error %lu.\n", GetLastError()); CloseHandle(tempFile); directory = CreateFileA(tempPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); ok(directory != INVALID_HANDLE_VALUE, "OpenFileById: failed to open the temp folder, " - "got error %u.\n", GetLastError()); + "got error %lu.\n", GetLastError()); /* get info about the temp folder itself */ bothDirInfo = (FILE_ID_BOTH_DIR_INFO *)buffer; ret = pGetFileInformationByHandleEx(directory, FileIdBothDirectoryInfo, buffer, sizeof(buffer)); - ok(ret, "OpenFileById: failed to query for FileIdBothDirectoryInfo, got error %u.\n", GetLastError()); + ok(ret, "OpenFileById: failed to query for FileIdBothDirectoryInfo, got error %lu.\n", GetLastError()); ok(bothDirInfo->FileNameLength == sizeof(WCHAR) && bothDirInfo->FileName[0] == '.', - "OpenFileById: failed to return the temp folder at the first entry, got error %u.\n", GetLastError()); + "OpenFileById: failed to return the temp folder at the first entry, got error %lu.\n", GetLastError()); /* open the temp folder itself */ fileIdDescr.dwSize = sizeof(fileIdDescr); fileIdDescr.Type = FileIdType; - U(fileIdDescr).FileId = bothDirInfo->FileId; + fileIdDescr.FileId = bothDirInfo->FileId; handle = pOpenFileById(directory, &fileIdDescr, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, 0); todo_wine - ok(handle != INVALID_HANDLE_VALUE, "OpenFileById: failed to open the temp folder itself, got error %u.\n", GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "OpenFileById: failed to open the temp folder itself, got error %lu.\n", GetLastError()); CloseHandle(handle); /* find the temp file in the temp folder */ @@ -4250,7 +4575,7 @@ static void test_OpenFileById(void) while (!found) { ret = pGetFileInformationByHandleEx(directory, FileIdBothDirectoryInfo, buffer, sizeof(buffer)); - ok(ret, "OpenFileById: failed to query for FileIdBothDirectoryInfo, got error %u.\n", GetLastError()); + ok(ret, "OpenFileById: failed to query for FileIdBothDirectoryInfo, got error %lu.\n", GetLastError()); if (!ret) break; bothDirInfo = (FILE_ID_BOTH_DIR_INFO *)buffer; @@ -4272,17 +4597,17 @@ static void test_OpenFileById(void) SetLastError(0xdeadbeef); handle = pOpenFileById(directory, NULL, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, 0); ok(handle == INVALID_HANDLE_VALUE && GetLastError() == ERROR_INVALID_PARAMETER, - "OpenFileById: expected ERROR_INVALID_PARAMETER, got error %u.\n", GetLastError()); + "OpenFileById: expected ERROR_INVALID_PARAMETER, got error %lu.\n", GetLastError()); fileIdDescr.dwSize = sizeof(fileIdDescr); fileIdDescr.Type = FileIdType; - U(fileIdDescr).FileId = bothDirInfo->FileId; + fileIdDescr.FileId = bothDirInfo->FileId; handle = pOpenFileById(directory, &fileIdDescr, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, 0); - ok(handle != INVALID_HANDLE_VALUE, "OpenFileById: failed to open the file, got error %u.\n", GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "OpenFileById: failed to open the file, got error %lu.\n", GetLastError()); ret = ReadFile(handle, buffer, sizeof(buffer), &count, NULL); buffer[count] = 0; - ok(ret, "OpenFileById: ReadFile failed, got error %u.\n", GetLastError()); + ok(ret, "OpenFileById: ReadFile failed, got error %lu.\n", GetLastError()); ok(strcmp(tickCount, buffer) == 0, "OpenFileById: invalid contents of the temp file.\n"); CloseHandle(handle); @@ -4314,13 +4639,13 @@ static void test_SetFileValidData(void) ret = pSetFileValidData(INVALID_HANDLE_VALUE, 0); error = GetLastError(); ok(!ret, "SetFileValidData succeeded\n"); - ok(error == ERROR_INVALID_HANDLE, "got %u\n", error); + ok(error == ERROR_INVALID_HANDLE, "got %lu\n", error); SetLastError(0xdeadbeef); ret = pSetFileValidData(INVALID_HANDLE_VALUE, -1); error = GetLastError(); ok(!ret, "SetFileValidData succeeded\n"); - ok(error == ERROR_INVALID_HANDLE, "got %u\n", error); + ok(error == ERROR_INVALID_HANDLE, "got %lu\n", error); /* file opened for reading */ handle = CreateFileA(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); @@ -4329,13 +4654,13 @@ static void test_SetFileValidData(void) ret = pSetFileValidData(handle, 0); ok(!ret, "SetFileValidData succeeded\n"); error = GetLastError(); - ok(error == ERROR_ACCESS_DENIED, "got %u\n", error); + ok(error == ERROR_ACCESS_DENIED, "got %lu\n", error); SetLastError(0xdeadbeef); ret = pSetFileValidData(handle, -1); error = GetLastError(); ok(!ret, "SetFileValidData succeeded\n"); - ok(error == ERROR_ACCESS_DENIED, "got %u\n", error); + ok(error == ERROR_ACCESS_DENIED, "got %lu\n", error); CloseHandle(handle); handle = CreateFileA(filename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); @@ -4344,7 +4669,7 @@ static void test_SetFileValidData(void) ret = pSetFileValidData(handle, 0); error = GetLastError(); ok(!ret, "SetFileValidData succeeded\n"); - todo_wine ok(error == ERROR_PRIVILEGE_NOT_HELD, "got %u\n", error); + todo_wine ok(error == ERROR_PRIVILEGE_NOT_HELD, "got %lu\n", error); CloseHandle(handle); privs.PrivilegeCount = 1; @@ -4366,58 +4691,58 @@ static void test_SetFileValidData(void) ret = pSetFileValidData(handle, 0); error = GetLastError(); ok(!ret, "SetFileValidData succeeded\n"); - ok(error == ERROR_INVALID_PARAMETER, "got %u\n", error); + ok(error == ERROR_INVALID_PARAMETER, "got %lu\n", error); SetLastError(0xdeadbeef); ret = pSetFileValidData(handle, -1); error = GetLastError(); ok(!ret, "SetFileValidData succeeded\n"); - ok(error == ERROR_INVALID_PARAMETER, "got %u\n", error); + ok(error == ERROR_INVALID_PARAMETER, "got %lu\n", error); SetLastError(0xdeadbeef); ret = pSetFileValidData(handle, 2); error = GetLastError(); todo_wine ok(!ret, "SetFileValidData succeeded\n"); - todo_wine ok(error == ERROR_INVALID_PARAMETER, "got %u\n", error); + todo_wine ok(error == ERROR_INVALID_PARAMETER, "got %lu\n", error); ret = pSetFileValidData(handle, 4); - ok(ret, "SetFileValidData failed %u\n", GetLastError()); + ok(ret, "SetFileValidData failed %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = pSetFileValidData(handle, 8); error = GetLastError(); ok(!ret, "SetFileValidData succeeded\n"); - ok(error == ERROR_INVALID_PARAMETER, "got %u\n", error); + ok(error == ERROR_INVALID_PARAMETER, "got %lu\n", error); count = SetFilePointer(handle, 1024, NULL, FILE_END); - ok(count != INVALID_SET_FILE_POINTER, "SetFilePointer failed %u\n", GetLastError()); + ok(count != INVALID_SET_FILE_POINTER, "SetFilePointer failed %lu\n", GetLastError()); ret = SetEndOfFile(handle); - ok(ret, "SetEndOfFile failed %u\n", GetLastError()); + ok(ret, "SetEndOfFile failed %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = pSetFileValidData(handle, 2); error = GetLastError(); todo_wine ok(!ret, "SetFileValidData succeeded\n"); - todo_wine ok(error == ERROR_INVALID_PARAMETER, "got %u\n", error); + todo_wine ok(error == ERROR_INVALID_PARAMETER, "got %lu\n", error); ret = pSetFileValidData(handle, 4); - ok(ret, "SetFileValidData failed %u\n", GetLastError()); + ok(ret, "SetFileValidData failed %lu\n", GetLastError()); ret = pSetFileValidData(handle, 8); - ok(ret, "SetFileValidData failed %u\n", GetLastError()); + ok(ret, "SetFileValidData failed %lu\n", GetLastError()); ret = pSetFileValidData(handle, 4); error = GetLastError(); todo_wine ok(!ret, "SetFileValidData succeeded\n"); - todo_wine ok(error == ERROR_INVALID_PARAMETER, "got %u\n", error); + todo_wine ok(error == ERROR_INVALID_PARAMETER, "got %lu\n", error); ret = pSetFileValidData(handle, 1024); - ok(ret, "SetFileValidData failed %u\n", GetLastError()); + ok(ret, "SetFileValidData failed %lu\n", GetLastError()); ret = pSetFileValidData(handle, 2048); error = GetLastError(); ok(!ret, "SetFileValidData succeeded\n"); - ok(error == ERROR_INVALID_PARAMETER, "got %u\n", error); + ok(error == ERROR_INVALID_PARAMETER, "got %lu\n", error); privs.Privileges[0].Attributes = 0; AdjustTokenPrivileges(token, FALSE, &privs, sizeof(privs), NULL, NULL); @@ -4427,60 +4752,361 @@ static void test_SetFileValidData(void) DeleteFileA(filename); } +static void test_ReOpenFile(void) +{ + char path[MAX_PATH], filename[MAX_PATH], buffer[4]; + HANDLE file, new; + unsigned int i; + DWORD size; + BOOL ret; + + static const DWORD invalid_attributes[] = + { + FILE_ATTRIBUTE_ARCHIVE, + FILE_ATTRIBUTE_ENCRYPTED, + FILE_ATTRIBUTE_HIDDEN, + FILE_ATTRIBUTE_NORMAL, + FILE_ATTRIBUTE_OFFLINE, + FILE_ATTRIBUTE_READONLY, + FILE_ATTRIBUTE_SYSTEM, + FILE_ATTRIBUTE_TEMPORARY, + }; + + static const DWORD valid_attributes[] = + { + FILE_FLAG_BACKUP_SEMANTICS, + FILE_FLAG_NO_BUFFERING, + FILE_FLAG_OVERLAPPED, + FILE_FLAG_RANDOM_ACCESS, + FILE_FLAG_SEQUENTIAL_SCAN, + FILE_FLAG_WRITE_THROUGH, + }; + + if (!pReOpenFile) + { + win_skip("ReOpenFile() is not available\n"); + return; + } + + GetTempPathA(sizeof(path), path); + GetTempFileNameA(path, "tst", 0, filename); + + file = CreateFileA(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + ok(file != INVALID_HANDLE_VALUE, "failed to create file, error %lu\n", GetLastError()); + ret = WriteFile(file, "foo", 4, &size, NULL); + ok(ret, "failed to write file, error %lu\n", GetLastError()); + + for (i = 0; i < ARRAY_SIZE(invalid_attributes); ++i) + { + SetLastError(0xdeadbeef); + new = pReOpenFile(file, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, invalid_attributes[i]); + ok(new == INVALID_HANDLE_VALUE, "got %p\n", new); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError()); + } + + new = pReOpenFile(file, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0); + ok(new != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError()); + + ret = ReadFile(new, buffer, sizeof(buffer), &size, NULL); + ok(ret, "failed to read file, error %lu\n", GetLastError()); + ok(size == 4, "got size %lu\n", size); + ok(!strcmp(buffer, "foo"), "got wrong data\n"); + CloseHandle(new); + + for (i = 0; i < ARRAY_SIZE(valid_attributes); ++i) + { + new = pReOpenFile(file, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, valid_attributes[i]); + ok(new != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError()); + CloseHandle(new); + } + + SetLastError(0xdeadbeef); + new = pReOpenFile(file, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0); + ok(new == INVALID_HANDLE_VALUE, "got %p\n", new); + ok(GetLastError() == ERROR_SHARING_VIOLATION, "got error %lu\n", GetLastError()); + + CloseHandle(file); + ret = DeleteFileA(filename); + ok(ret, "failed to delete file, error %lu\n", GetLastError()); + + file = CreateNamedPipeA("\\\\.\\pipe\\test_pipe", PIPE_ACCESS_DUPLEX, 0, 1, 1000, 1000, 1000, NULL); + ok(file != INVALID_HANDLE_VALUE, "failed to create pipe, error %lu\n", GetLastError()); + + new = pReOpenFile(file, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0); + ok(new != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError()); + + ret = WriteFile(file, "foo", 4, &size, NULL); + ok(ret, "failed to write file, error %lu\n", GetLastError()); + ret = ReadFile(new, buffer, sizeof(buffer), &size, NULL); + ok(ret, "failed to read file, error %lu\n", GetLastError()); + ok(size == 4, "got size %lu\n", size); + ok(!strcmp(buffer, "foo"), "got wrong data\n"); + + CloseHandle(new); + CloseHandle(file); +} + static void test_WriteFileGather(void) { char temp_path[MAX_PATH], filename[MAX_PATH]; - HANDLE hfile, hiocp1, hiocp2; - DWORD ret, size; + HANDLE hfile, hiocp1, hiocp2, evt; + DWORD ret, size, tx; ULONG_PTR key; FILE_SEGMENT_ELEMENT fse[2]; OVERLAPPED ovl, *povl = NULL; SYSTEM_INFO si; - LPVOID buf = NULL; + char *wbuf = NULL, *rbuf1, *rbuf2; + BOOL br; + + evt = CreateEventW( NULL, TRUE, FALSE, NULL ); ret = GetTempPathA( MAX_PATH, temp_path ); - ok( ret != 0, "GetTempPathA error %d\n", GetLastError() ); + ok( ret != 0, "GetTempPathA error %ld\n", GetLastError() ); ok( ret < MAX_PATH, "temp path should fit into MAX_PATH\n" ); ret = GetTempFileNameA( temp_path, "wfg", 0, filename ); - ok( ret != 0, "GetTempFileNameA error %d\n", GetLastError() ); + ok( ret != 0, "GetTempFileNameA error %ld\n", GetLastError() ); hfile = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED | FILE_ATTRIBUTE_NORMAL, 0 ); - ok( hfile != INVALID_HANDLE_VALUE, "CreateFile failed err %u\n", GetLastError() ); + ok( hfile != INVALID_HANDLE_VALUE, "CreateFile failed err %lu\n", GetLastError() ); if (hfile == INVALID_HANDLE_VALUE) return; hiocp1 = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 999, 0 ); hiocp2 = CreateIoCompletionPort( hfile, hiocp1, 999, 0 ); - ok( hiocp2 != 0, "CreateIoCompletionPort failed err %u\n", GetLastError() ); + ok( hiocp2 != 0, "CreateIoCompletionPort failed err %lu\n", GetLastError() ); GetSystemInfo( &si ); - buf = VirtualAlloc( NULL, si.dwPageSize, MEM_COMMIT, PAGE_READWRITE ); - ok( buf != NULL, "VirtualAlloc failed err %u\n", GetLastError() ); + wbuf = VirtualAlloc( NULL, si.dwPageSize, MEM_COMMIT, PAGE_READWRITE ); + ok( wbuf != NULL, "VirtualAlloc failed err %lu\n", GetLastError() ); + + rbuf1 = VirtualAlloc( NULL, si.dwPageSize, MEM_COMMIT, PAGE_READWRITE ); + ok( rbuf1 != NULL, "VirtualAlloc failed err %lu\n", GetLastError() ); + + rbuf2 = VirtualAlloc( NULL, si.dwPageSize, MEM_COMMIT, PAGE_READWRITE ); + ok( rbuf2 != NULL, "VirtualAlloc failed err %lu\n", GetLastError() ); memset( &ovl, 0, sizeof(ovl) ); + ovl.hEvent = evt; memset( fse, 0, sizeof(fse) ); - fse[0].Buffer = buf; + fse[0].Buffer = wbuf; + memset( wbuf, 0x42, si.dwPageSize ); + SetLastError( 0xdeadbeef ); if (!WriteFileGather( hfile, fse, si.dwPageSize, NULL, &ovl )) - ok( GetLastError() == ERROR_IO_PENDING, "WriteFileGather failed err %u\n", GetLastError() ); + ok( GetLastError() == ERROR_IO_PENDING, "WriteFileGather failed err %lu\n", GetLastError() ); ret = GetQueuedCompletionStatus( hiocp2, &size, &key, &povl, 1000 ); - ok( ret, "GetQueuedCompletionStatus failed err %u\n", GetLastError()); + ok( ret, "GetQueuedCompletionStatus failed err %lu\n", GetLastError()); ok( povl == &ovl, "wrong ovl %p\n", povl ); +#ifdef __REACTOS__ + if (is_reactos()) { + ok(FALSE, "FIXME: Calls to GetOverlappedResult hang on ReactOS!\n"); + } else { +#endif + tx = 0; + br = GetOverlappedResult( hfile, &ovl, &tx, TRUE ); + ok( br == TRUE, "GetOverlappedResult failed: %lu\n", GetLastError() ); + ok( tx == si.dwPageSize, "got unexpected bytes transferred: %lu\n", tx ); +#ifdef __REACTOS__ + } +#endif + + ResetEvent( evt ); + + /* read exact size */ memset( &ovl, 0, sizeof(ovl) ); + ovl.hEvent = evt; memset( fse, 0, sizeof(fse) ); - fse[0].Buffer = buf; - if (!ReadFileScatter( hfile, fse, si.dwPageSize, NULL, &ovl )) - ok( GetLastError() == ERROR_IO_PENDING, "ReadFileScatter failed err %u\n", GetLastError() ); + fse[0].Buffer = rbuf1; + memset( rbuf1, 0, si.dwPageSize ); + SetLastError( 0xdeadbeef ); + br = ReadFileScatter( hfile, fse, si.dwPageSize, NULL, &ovl ); + ok( br == FALSE, "ReadFileScatter should be asynchronous\n" ); + ok( GetLastError() == ERROR_IO_PENDING, "ReadFileScatter failed err %lu\n", GetLastError() ); ret = GetQueuedCompletionStatus( hiocp2, &size, &key, &povl, 1000 ); - ok( ret, "GetQueuedCompletionStatus failed err %u\n", GetLastError()); + ok( ret, "GetQueuedCompletionStatus failed err %lu\n", GetLastError()); ok( povl == &ovl, "wrong ovl %p\n", povl ); +#ifdef __REACTOS__ + if (is_reactos()) { + ok(FALSE, "FIXME: Calls to GetOverlappedResult hang on ReactOS!\n"); + } else { +#endif + tx = 0; + br = GetOverlappedResult( hfile, &ovl, &tx, TRUE ); + ok( br == TRUE, "GetOverlappedResult failed: %lu\n", GetLastError() ); + ok( tx == si.dwPageSize, "got unexpected bytes transferred: %lu\n", tx ); +#ifdef __REACTOS__ + } +#endif + + ok( memcmp( rbuf1, wbuf, si.dwPageSize ) == 0, + "data was not read into buffer\n" ); + + ResetEvent( evt ); + + /* start read at EOF */ + memset( &ovl, 0, sizeof(ovl) ); + ovl.hEvent = evt; + ovl.OffsetHigh = 0; + ovl.Offset = si.dwPageSize; + memset( fse, 0, sizeof(fse) ); + fse[0].Buffer = rbuf1; + SetLastError( 0xdeadbeef ); + br = ReadFileScatter( hfile, fse, si.dwPageSize, NULL, &ovl ); + ok( br == FALSE, "ReadFileScatter should have failed\n" ); + ok( GetLastError() == ERROR_HANDLE_EOF || + GetLastError() == ERROR_IO_PENDING, "ReadFileScatter gave wrong error %lu\n", GetLastError() ); + if (GetLastError() == ERROR_IO_PENDING) + { + SetLastError( 0xdeadbeef ); + ret = GetQueuedCompletionStatus( hiocp2, &size, &key, &povl, 1000 ); + ok( !ret, "GetQueuedCompletionStatus should have returned failure\n" ); + ok( GetLastError() == ERROR_HANDLE_EOF, "Got wrong error: %lu\n", GetLastError() ); + ok( povl == &ovl, "wrong ovl %p\n", povl ); + + SetLastError( 0xdeadbeef ); + br = GetOverlappedResult( hfile, &ovl, &tx, TRUE ); + ok( br == FALSE, "GetOverlappedResult should have failed\n" ); + ok( GetLastError() == ERROR_HANDLE_EOF, "Got wrong error: %lu\n", GetLastError() ); + } + else + { + SetLastError( 0xdeadbeef ); + ret = GetQueuedCompletionStatus( hiocp2, &size, &key, &povl, 100 ); + ok( !ret, "GetQueuedCompletionStatus failed err %lu\n", GetLastError() ); + ok( GetLastError() == WAIT_TIMEOUT, "GetQueuedCompletionStatus gave wrong error %lu\n", GetLastError() ); + ok( povl == NULL, "wrong ovl %p\n", povl ); + } + + ResetEvent( evt ); + + /* read past EOF */ + memset( &ovl, 0, sizeof(ovl) ); + ovl.hEvent = evt; + memset( fse, 0, sizeof(fse) ); + fse[0].Buffer = rbuf1; + fse[1].Buffer = rbuf2; + memset( rbuf1, 0, si.dwPageSize ); + memset( rbuf2, 0x17, si.dwPageSize ); + SetLastError( 0xdeadbeef ); + br = ReadFileScatter( hfile, fse, si.dwPageSize * 2, NULL, &ovl ); + ok( br == FALSE, "ReadFileScatter should be asynchronous\n" ); + ok( GetLastError() == ERROR_IO_PENDING, "ReadFileScatter failed err %lu\n", GetLastError() ); + + ret = GetQueuedCompletionStatus( hiocp2, &size, &key, &povl, 1000 ); + ok( ret, "GetQueuedCompletionStatus failed err %lu\n", GetLastError() ); + ok( povl == &ovl, "wrong ovl %p\n", povl ); + +#ifdef __REACTOS__ + if (is_reactos()) { + ok(FALSE, "FIXME: Calls to GetOverlappedResult hang on ReactOS!\n"); + } else { +#endif + tx = 0; + br = GetOverlappedResult( hfile, &ovl, &tx, TRUE ); + ok( br == TRUE, "GetOverlappedResult failed: %lu\n", GetLastError() ); + ok( tx == si.dwPageSize, "got unexpected bytes transferred: %lu\n", tx ); +#ifdef __REACTOS__ + } +#endif + + ok( memcmp( rbuf1, wbuf, si.dwPageSize ) == 0, + "data was not read into buffer\n" ); + memset( rbuf1, 0x17, si.dwPageSize ); + ok( memcmp( rbuf2, rbuf1, si.dwPageSize ) == 0, + "data should not have been read into buffer\n" ); + + ResetEvent( evt ); + + /* partial page read */ + memset( &ovl, 0, sizeof(ovl) ); + ovl.hEvent = evt; + memset( fse, 0, sizeof(fse) ); + fse[0].Buffer = rbuf1; + memset( rbuf1, 0, si.dwPageSize ); + SetLastError( 0xdeadbeef ); + br = ReadFileScatter( hfile, fse, si.dwPageSize / 2, NULL, &ovl ); + ok( br == FALSE, "ReadFileScatter should be asynchronous\n" ); + ok( GetLastError() == ERROR_IO_PENDING, "ReadFileScatter failed err %lu\n", GetLastError() ); + + ret = GetQueuedCompletionStatus( hiocp2, &size, &key, &povl, 1000 ); + ok( ret, "GetQueuedCompletionStatus failed err %lu\n", GetLastError() ); + ok( povl == &ovl, "wrong ovl %p\n", povl ); + +#ifdef __REACTOS__ + if (is_reactos()) { + ok(FALSE, "FIXME: Calls to GetOverlappedResult hang on ReactOS!\n"); + } else { +#endif + tx = 0; + br = GetOverlappedResult( hfile, &ovl, &tx, TRUE ); + ok( br == TRUE, "GetOverlappedResult failed: %lu\n", GetLastError() ); + ok( tx == si.dwPageSize / 2, "got unexpected bytes transferred: %lu\n", tx ); +#ifdef __REACTOS__ + } +#endif + + ok( memcmp( rbuf1, wbuf, si.dwPageSize / 2 ) == 0, + "invalid data was read into buffer\n" ); + memset( rbuf2, 0, si.dwPageSize ); + ok( memcmp( rbuf1 + si.dwPageSize / 2, rbuf2, si.dwPageSize - si.dwPageSize / 2 ) == 0, + "invalid data was read into buffer\n" ); + + if (pSetFileCompletionNotificationModes) + { + br = pSetFileCompletionNotificationModes(hfile, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS); + ok(br, "SetFileCompletionNotificationModes failed, error %lu.\n", GetLastError()); + + br = ReadFileScatter(hfile, fse, si.dwPageSize, NULL, &ovl); + ok(br == FALSE, "ReadFileScatter should be asynchronous.\n"); + ok(GetLastError() == ERROR_IO_PENDING, "ReadFileScatter failed, error %lu.\n", GetLastError()); + + br = GetQueuedCompletionStatus(hiocp2, &size, &key, &povl, 1000); + ok(br, "GetQueuedCompletionStatus failed, err %lu.\n", GetLastError()); + ok(povl == &ovl, "Wrong ovl %p.\n", povl); + +#ifdef __REACTOS__ + if (is_reactos()) { + ok(FALSE, "FIXME: Calls to GetOverlappedResult hang on ReactOS!\n"); + } else { +#endif + br = GetOverlappedResult(hfile, &ovl, &tx, TRUE); + ok(br, "GetOverlappedResult failed, err %lu.\n", GetLastError()); + ok(tx == si.dwPageSize, "Got unexpected size %lu.\n", tx); +#ifdef __REACTOS__ + } +#endif + + ResetEvent(evt); + } + else + win_skip("SetFileCompletionNotificationModes not available.\n"); + CloseHandle( hfile ); CloseHandle( hiocp1 ); CloseHandle( hiocp2 ); - VirtualFree( buf, 0, MEM_RELEASE ); + + /* file handle must be overlapped */ + hfile = CreateFileA( filename, GENERIC_READ, 0, 0, OPEN_EXISTING, + FILE_FLAG_NO_BUFFERING | FILE_ATTRIBUTE_NORMAL, 0 ); + ok( hfile != INVALID_HANDLE_VALUE, "CreateFile failed err %lu\n", GetLastError() ); + + memset( &ovl, 0, sizeof(ovl) ); + memset( fse, 0, sizeof(fse) ); + fse[0].Buffer = rbuf1; + memset( rbuf1, 0, si.dwPageSize ); + SetLastError( 0xdeadbeef ); + br = ReadFileScatter( hfile, fse, si.dwPageSize, NULL, &ovl ); + ok( br == FALSE, "ReadFileScatter should fail\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "ReadFileScatter failed err %lu\n", GetLastError() ); + + VirtualFree( wbuf, 0, MEM_RELEASE ); + VirtualFree( rbuf1, 0, MEM_RELEASE ); + VirtualFree( rbuf2, 0, MEM_RELEASE ); + CloseHandle( evt ); DeleteFileA( filename ); } @@ -4526,27 +5152,27 @@ static void test_file_access(void) GetTempPathA(MAX_PATH, path); GetTempFileNameA(path, "foo", 0, fname); - for (i = 0; i < sizeof(td)/sizeof(td[0]); i++) + for (i = 0; i < ARRAY_SIZE(td); i++) { SetLastError(0xdeadbeef); hfile = CreateFileA(fname, td[i].access, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, 0); if (td[i].create_error) { - ok(hfile == INVALID_HANDLE_VALUE, "%d: CreateFile should fail\n", i); - ok(td[i].create_error == GetLastError(), "%d: expected %d, got %d\n", i, td[i].create_error, GetLastError()); + ok(hfile == INVALID_HANDLE_VALUE, "%ld: CreateFile should fail\n", i); + ok(td[i].create_error == GetLastError(), "%ld: expected %d, got %ld\n", i, td[i].create_error, GetLastError()); continue; } else - ok(hfile != INVALID_HANDLE_VALUE, "%d: CreateFile error %d\n", i, GetLastError()); + ok(hfile != INVALID_HANDLE_VALUE, "%ld: CreateFile error %ld\n", i, GetLastError()); - for (j = 0; j < sizeof(td)/sizeof(td[0]); j++) + for (j = 0; j < ARRAY_SIZE(td); j++) { SetLastError(0xdeadbeef); ret = DuplicateHandle(GetCurrentProcess(), hfile, GetCurrentProcess(), &hdup, td[j].access, 0, 0); if (is_access_compatible(td[i].access, td[j].access)) - ok(ret, "DuplicateHandle(%#x => %#x) error %d\n", td[i].access, td[j].access, GetLastError()); + ok(ret, "DuplicateHandle(%#x => %#x) error %ld\n", td[i].access, td[j].access, GetLastError()); else { /* FIXME: Remove once Wine is fixed */ @@ -4556,7 +5182,7 @@ static void test_file_access(void) (!(td[i].access & (GENERIC_WRITE)) && (td[j].access & FILE_APPEND_DATA)))) { ok(!ret, "DuplicateHandle(%#x => %#x) should fail\n", td[i].access, td[j].access); - ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError()); } } if (ret) CloseHandle(hdup); @@ -4567,38 +5193,38 @@ static void test_file_access(void) ret = WriteFile(hfile, "\x5e\xa7", 2, &bytes, NULL); if (td[i].write_error) { - ok(!ret, "%d: WriteFile should fail\n", i); - ok(td[i].write_error == GetLastError(), "%d: expected %d, got %d\n", i, td[i].write_error, GetLastError()); - ok(bytes == 0, "%d: expected 0, got %u\n", i, bytes); + ok(!ret, "%ld: WriteFile should fail\n", i); + ok(td[i].write_error == GetLastError(), "%ld: expected %d, got %ld\n", i, td[i].write_error, GetLastError()); + ok(bytes == 0, "%ld: expected 0, got %lu\n", i, bytes); } else { - ok(ret, "%d: WriteFile error %d\n", i, GetLastError()); - ok(bytes == 2, "%d: expected 2, got %u\n", i, bytes); + ok(ret, "%ld: WriteFile error %ld\n", i, GetLastError()); + ok(bytes == 2, "%ld: expected 2, got %lu\n", i, bytes); } SetLastError(0xdeadbeef); ret = SetFilePointer(hfile, 0, NULL, FILE_BEGIN); - ok(ret != INVALID_SET_FILE_POINTER, "SetFilePointer error %d\n", GetLastError()); + ok(ret != INVALID_SET_FILE_POINTER, "SetFilePointer error %ld\n", GetLastError()); SetLastError(0xdeadbeef); bytes = 0xdeadbeef; ret = ReadFile(hfile, buf, sizeof(buf), &bytes, NULL); if (td[i].read_error) { - ok(!ret, "%d: ReadFile should fail\n", i); - ok(td[i].read_error == GetLastError(), "%d: expected %d, got %d\n", i, td[i].read_error, GetLastError()); - ok(bytes == 0, "%d: expected 0, got %u\n", i, bytes); + ok(!ret, "%ld: ReadFile should fail\n", i); + ok(td[i].read_error == GetLastError(), "%ld: expected %d, got %ld\n", i, td[i].read_error, GetLastError()); + ok(bytes == 0, "%ld: expected 0, got %lu\n", i, bytes); } else { - ok(ret, "%d: ReadFile error %d\n", i, GetLastError()); + ok(ret, "%ld: ReadFile error %ld\n", i, GetLastError()); if (td[i].write_error) - ok(bytes == 0, "%d: expected 0, got %u\n", i, bytes); + ok(bytes == 0, "%ld: expected 0, got %lu\n", i, bytes); else { - ok(bytes == 2, "%d: expected 2, got %u\n", i, bytes); - ok(buf[0] == 0x5e && buf[1] == 0xa7, "%d: expected 5ea7, got %02x%02x\n", i, buf[0], buf[1]); + ok(bytes == 2, "%ld: expected 2, got %lu\n", i, bytes); + ok(buf[0] == 0x5e && buf[1] == 0xa7, "%ld: expected 5ea7, got %02x%02x\n", i, buf[0], buf[1]); } } @@ -4619,73 +5245,73 @@ static void test_GetFinalPathNameByHandleA(void) if (!pGetFinalPathNameByHandleA) { - skip("GetFinalPathNameByHandleA is missing\n"); + win_skip("GetFinalPathNameByHandleA is missing\n"); return; } /* Test calling with INVALID_HANDLE_VALUE */ SetLastError(0xdeadbeaf); count = pGetFinalPathNameByHandleA(INVALID_HANDLE_VALUE, result_path, MAX_PATH, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); - ok(count == 0, "Expected length 0, got %u\n", count); - ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %u\n", GetLastError()); + ok(count == 0, "Expected length 0, got %lu\n", count); + ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %lu\n", GetLastError()); count = GetTempPathA(MAX_PATH, temp_path); - ok(count, "Failed to get temp path, error %u\n", GetLastError()); + ok(count, "Failed to get temp path, error %lu\n", GetLastError()); ret = GetTempFileNameA(temp_path, prefix, 0, test_path); - ok(ret != 0, "GetTempFileNameA error %u\n", GetLastError()); + ok(ret != 0, "GetTempFileNameA error %lu\n", GetLastError()); ret = GetLongPathNameA(test_path, long_path, MAX_PATH); - ok(ret != 0, "GetLongPathNameA error %u\n", GetLastError()); + ok(ret != 0, "GetLongPathNameA error %lu\n", GetLastError()); strcpy(dos_path, dos_prefix); strcat(dos_path, long_path); count = pGetFinalPathNameByHandleA(INVALID_HANDLE_VALUE, NULL, 0, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); - ok(count == 0, "Expected length 0, got %u\n", count); - ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %u\n", GetLastError()); + ok(count == 0, "Expected length 0, got %lu\n", count); + ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %lu\n", GetLastError()); file = CreateFileA(test_path, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, 0); - ok(file != INVALID_HANDLE_VALUE, "CreateFileA error %u\n", GetLastError()); + ok(file != INVALID_HANDLE_VALUE, "CreateFileA error %lu\n", GetLastError()); if (0) { /* Windows crashes on NULL path */ count = pGetFinalPathNameByHandleA(file, NULL, MAX_PATH, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); - ok(count == 0, "Expected length 0, got %u\n", count); - ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %u\n", GetLastError()); + ok(count == 0, "Expected length 0, got %lu\n", count); + ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %lu\n", GetLastError()); } /* Test 0-length path */ count = pGetFinalPathNameByHandleA(file, result_path, 0, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); - ok(count == strlen(dos_path), "Expected length %u, got %u\n", lstrlenA(dos_path), count); + ok(count == strlen(dos_path), "Expected length %u, got %lu\n", lstrlenA(dos_path), count); /* Test 0 and NULL path */ count = pGetFinalPathNameByHandleA(file, NULL, 0, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); - ok(count == strlen(dos_path), "Expected length %u, got %u\n", lstrlenA(dos_path), count); + ok(count == strlen(dos_path), "Expected length %u, got %lu\n", lstrlenA(dos_path), count); /* Test VOLUME_NAME_DOS with sufficient buffer size */ memset(result_path, 0x11, sizeof(result_path)); count = pGetFinalPathNameByHandleA(file, result_path, MAX_PATH, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); - ok(count == strlen(dos_path), "Expected length %u, got %u\n", (DWORD)strlen(dos_path), count); + ok(count == strlen(dos_path), "Expected length %lu, got %lu\n", (DWORD)strlen(dos_path), count); ok(lstrcmpiA(dos_path, result_path) == 0, "Expected %s, got %s\n", dos_path, result_path); /* Test VOLUME_NAME_DOS with insufficient buffer size */ memset(result_path, 0x11, sizeof(result_path)); count = pGetFinalPathNameByHandleA(file, result_path, strlen(dos_path)-2, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); - ok(count == strlen(dos_path), "Expected length %u, got %u\n", (DWORD)strlen(dos_path), count); + ok(count == strlen(dos_path), "Expected length %lu, got %lu\n", (DWORD)strlen(dos_path), count); ok(result_path[0] == 0x11, "Result path was modified\n"); memset(result_path, 0x11, sizeof(result_path)); count = pGetFinalPathNameByHandleA(file, result_path, strlen(dos_path)-1, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); - ok(count == strlen(dos_path), "Expected length %u, got %u\n", (DWORD)strlen(dos_path), count); + ok(count == strlen(dos_path), "Expected length %lu, got %lu\n", (DWORD)strlen(dos_path), count); ok(result_path[0] == 0x11, "Result path was modified\n"); memset(result_path, 0x11, sizeof(result_path)); count = pGetFinalPathNameByHandleA(file, result_path, strlen(dos_path), FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); - ok(count == strlen(dos_path), "Expected length %u, got %u\n", (DWORD)strlen(dos_path), count); + ok(count == strlen(dos_path), "Expected length %lu, got %lu\n", (DWORD)strlen(dos_path), count); ok(result_path[0] == 0x11, "Result path was modified\n"); memset(result_path, 0x11, sizeof(result_path)); count = pGetFinalPathNameByHandleA(file, result_path, strlen(dos_path)+1, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); - ok(count == strlen(dos_path), "Expected length %u, got %u\n", (DWORD)strlen(dos_path), count); + ok(count == strlen(dos_path), "Expected length %lu, got %lu\n", (DWORD)strlen(dos_path), count); ok(result_path[0] != 0x11, "Result path was not modified\n"); ok(!result_path[strlen(dos_path)], "Expected nullterminated string\n"); ok(result_path[strlen(dos_path)+1] == 0x11, "Buffer overflow\n"); @@ -4712,84 +5338,84 @@ static void test_GetFinalPathNameByHandleW(void) if (!pGetFinalPathNameByHandleW) { - skip("GetFinalPathNameByHandleW is missing\n"); + win_skip("GetFinalPathNameByHandleW is missing\n"); return; } /* Test calling with INVALID_HANDLE_VALUE */ SetLastError(0xdeadbeaf); count = pGetFinalPathNameByHandleW(INVALID_HANDLE_VALUE, result_path, MAX_PATH, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); - ok(count == 0, "Expected length 0, got %u\n", count); - ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %u\n", GetLastError()); + ok(count == 0, "Expected length 0, got %lu\n", count); + ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %lu\n", GetLastError()); count = pGetFinalPathNameByHandleW(INVALID_HANDLE_VALUE, NULL, 0, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); - ok(count == 0, "Expected length 0, got %u\n", count); - ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %u\n", GetLastError()); + ok(count == 0, "Expected length 0, got %lu\n", count); + ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %lu\n", GetLastError()); count = GetTempPathW(MAX_PATH, temp_path); - ok(count, "Failed to get temp path, error %u\n", GetLastError()); + ok(count, "Failed to get temp path, error %lu\n", GetLastError()); ret = GetTempFileNameW(temp_path, prefix, 0, test_path); - ok(ret != 0, "GetTempFileNameW error %u\n", GetLastError()); + ok(ret != 0, "GetTempFileNameW error %lu\n", GetLastError()); ret = GetLongPathNameW(test_path, long_path, MAX_PATH); - ok(ret != 0, "GetLongPathNameW error %u\n", GetLastError()); + ok(ret != 0, "GetLongPathNameW error %lu\n", GetLastError()); lstrcpyW(dos_path, dos_prefix); lstrcatW(dos_path, long_path); file = CreateFileW(test_path, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, 0); - ok(file != INVALID_HANDLE_VALUE, "CreateFileW error %u\n", GetLastError()); + ok(file != INVALID_HANDLE_VALUE, "CreateFileW error %lu\n", GetLastError()); if (0) { /* Windows crashes on NULL path */ count = pGetFinalPathNameByHandleW(file, NULL, MAX_PATH, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); - ok(count == 0, "Expected length 0, got %u\n", count); - ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %u\n", GetLastError()); + ok(count == 0, "Expected length 0, got %lu\n", count); + ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %lu\n", GetLastError()); } /* Test 0-length path */ count = pGetFinalPathNameByHandleW(file, result_path, 0, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); ok(count == lstrlenW(dos_path) + 1 || - broken(count == lstrlenW(dos_path) + 2), "Expected length %u, got %u\n", lstrlenW(dos_path) + 1, count); + broken(count == lstrlenW(dos_path) + 2), "Expected length %u, got %lu\n", lstrlenW(dos_path) + 1, count); /* Test 0 and NULL path */ count = pGetFinalPathNameByHandleW(file, NULL, 0, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); ok(count == lstrlenW(dos_path) + 1 || - broken(count == lstrlenW(dos_path) + 2), "Expected length %u, got %u\n", lstrlenW(dos_path) + 1, count); + broken(count == lstrlenW(dos_path) + 2), "Expected length %u, got %lu\n", lstrlenW(dos_path) + 1, count); /* Test VOLUME_NAME_DOS with sufficient buffer size */ memset(result_path, 0x11, sizeof(result_path)); count = pGetFinalPathNameByHandleW(file, result_path, MAX_PATH, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); - ok(count == lstrlenW(dos_path), "Expected length %u, got %u\n", lstrlenW(dos_path), count); + ok(count == lstrlenW(dos_path), "Expected length %u, got %lu\n", lstrlenW(dos_path), count); ok(lstrcmpiW(dos_path, result_path) == 0, "Expected %s, got %s\n", wine_dbgstr_w(dos_path), wine_dbgstr_w(result_path)); /* Test VOLUME_NAME_DOS with insufficient buffer size */ memset(result_path, 0x11, sizeof(result_path)); count = pGetFinalPathNameByHandleW(file, result_path, lstrlenW(dos_path)-1, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); - ok(count == lstrlenW(dos_path) + 1, "Expected length %u, got %u\n", lstrlenW(dos_path) + 1, count); + ok(count == lstrlenW(dos_path) + 1, "Expected length %u, got %lu\n", lstrlenW(dos_path) + 1, count); ok(result_path[0] == 0x1111, "Result path was modified\n"); memset(result_path, 0x11, sizeof(result_path)); count = pGetFinalPathNameByHandleW(file, result_path, lstrlenW(dos_path), FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); - ok(count == lstrlenW(dos_path) + 1, "Expected length %u, got %u\n", lstrlenW(dos_path) + 1, count); + ok(count == lstrlenW(dos_path) + 1, "Expected length %u, got %lu\n", lstrlenW(dos_path) + 1, count); ok(result_path[0] == 0x1111, "Result path was modified\n"); memset(result_path, 0x11, sizeof(result_path)); count = pGetFinalPathNameByHandleW(file, result_path, lstrlenW(dos_path)+1, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); - ok(count == lstrlenW(dos_path), "Expected length %u, got %u\n", lstrlenW(dos_path), count); + ok(count == lstrlenW(dos_path), "Expected length %u, got %lu\n", lstrlenW(dos_path), count); ok(result_path[0] != 0x1111, "Result path was not modified\n"); ok(!result_path[lstrlenW(dos_path)], "Expected nullterminated string\n"); ok(result_path[lstrlenW(dos_path)+1] == 0x1111, "Buffer overflow\n"); success = GetVolumePathNameW(long_path, drive_part, MAX_PATH); - ok(success, "GetVolumePathNameW error %u\n", GetLastError()); - success = GetVolumeNameForVolumeMountPointW(drive_part, volume_path, sizeof(volume_path) / sizeof(WCHAR)); - ok(success, "GetVolumeNameForVolumeMountPointW error %u\n", GetLastError()); + ok(success, "GetVolumePathNameW error %lu\n", GetLastError()); + success = GetVolumeNameForVolumeMountPointW(drive_part, volume_path, ARRAY_SIZE(volume_path)); + ok(success, "GetVolumeNameForVolumeMountPointW error %lu\n", GetLastError()); /* Test for VOLUME_NAME_GUID */ lstrcatW(volume_path, long_path + lstrlenW(drive_part)); memset(result_path, 0x11, sizeof(result_path)); count = pGetFinalPathNameByHandleW(file, result_path, MAX_PATH, FILE_NAME_NORMALIZED | VOLUME_NAME_GUID); - ok(count == lstrlenW(volume_path), "Expected length %u, got %u\n", lstrlenW(volume_path), count); + ok(count == lstrlenW(volume_path), "Expected length %u, got %lu\n", lstrlenW(volume_path), count); ok(lstrcmpiW(volume_path, result_path) == 0, "Expected %s, got %s\n", wine_dbgstr_w(volume_path), wine_dbgstr_w(result_path)); @@ -4797,19 +5423,19 @@ static void test_GetFinalPathNameByHandleW(void) file_part = long_path + lstrlenW(drive_part) - 1; memset(result_path, 0x11, sizeof(result_path)); count = pGetFinalPathNameByHandleW(file, result_path, MAX_PATH, FILE_NAME_NORMALIZED | VOLUME_NAME_NONE); - ok(count == lstrlenW(file_part), "Expected length %u, got %u\n", lstrlenW(file_part), count); + ok(count == lstrlenW(file_part), "Expected length %u, got %lu\n", lstrlenW(file_part), count); ok(lstrcmpiW(file_part, result_path) == 0, "Expected %s, got %s\n", wine_dbgstr_w(file_part), wine_dbgstr_w(result_path)); drive_part[lstrlenW(drive_part)-1] = 0; - success = QueryDosDeviceW(drive_part, nt_path, sizeof(nt_path) / sizeof(WCHAR)); - ok(success, "QueryDosDeviceW error %u\n", GetLastError()); + success = QueryDosDeviceW(drive_part, nt_path, ARRAY_SIZE(nt_path)); + ok(success, "QueryDosDeviceW error %lu\n", GetLastError()); /* Test for VOLUME_NAME_NT */ lstrcatW(nt_path, file_part); memset(result_path, 0x11, sizeof(result_path)); count = pGetFinalPathNameByHandleW(file, result_path, MAX_PATH, FILE_NAME_NORMALIZED | VOLUME_NAME_NT); - ok(count == lstrlenW(nt_path), "Expected length %u, got %u\n", lstrlenW(nt_path), count); + ok(count == lstrlenW(nt_path), "Expected length %u, got %lu\n", lstrlenW(nt_path), count); ok(lstrcmpiW(nt_path, result_path) == 0, "Expected %s, got %s\n", wine_dbgstr_w(nt_path), wine_dbgstr_w(result_path)); @@ -4823,84 +5449,911 @@ static void test_SetFileInformationByHandle(void) FILE_STANDARD_INFO stdinfo = { {{0}},{{0}},0,FALSE,FALSE }; FILE_COMPRESSION_INFO compressinfo; FILE_DISPOSITION_INFO dispinfo; + DECLSPEC_ALIGN(8) FILE_IO_PRIORITY_HINT_INFO hintinfo; + FILE_BASIC_INFO basicinfo = { {{0}} }; char tempFileName[MAX_PATH]; char tempPath[MAX_PATH]; + LARGE_INTEGER atime; HANDLE file; BOOL ret; +#if defined(__REACTOS__) && DLL_EXPORT_VERSION >= 0x600 + /* FIXME: SetFileInformationByHandle is a STUB on ReactOS. */ + if (is_reactos() || !pSetFileInformationByHandle) +#else if (!pSetFileInformationByHandle) +#endif { win_skip("SetFileInformationByHandle is not supported\n"); return; } ret = GetTempPathA(sizeof(tempPath), tempPath); - ok(ret, "GetTempPathA failed, got error %u.\n", GetLastError()); + ok(ret, "GetTempPathA failed, got error %lu.\n", GetLastError()); /* ensure the existence of a file in the temp folder */ ret = GetTempFileNameA(tempPath, "abc", 0, tempFileName); - ok(ret, "GetTempFileNameA failed, got error %u.\n", GetLastError()); + ok(ret, "GetTempFileNameA failed, got error %lu.\n", GetLastError()); - file = CreateFileA(tempFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + file = CreateFileA(tempFileName, GENERIC_READ | FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL); - ok(file != INVALID_HANDLE_VALUE, "failed to open the temp file, error %u.\n", GetLastError()); + ok(file != INVALID_HANDLE_VALUE, "failed to open the temp file, error %lu.\n", GetLastError()); /* invalid classes */ SetLastError(0xdeadbeef); ret = pSetFileInformationByHandle(file, FileStandardInfo, &stdinfo, sizeof(stdinfo)); - ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError()); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %ld\n", ret, GetLastError()); memset(&compressinfo, 0, sizeof(compressinfo)); SetLastError(0xdeadbeef); ret = pSetFileInformationByHandle(file, FileCompressionInfo, &compressinfo, sizeof(compressinfo)); - ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError()); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %ld\n", ret, GetLastError()); SetLastError(0xdeadbeef); ret = pSetFileInformationByHandle(file, FileAttributeTagInfo, &fileattrinfo, sizeof(fileattrinfo)); - ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError()); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %ld\n", ret, GetLastError()); + + SetLastError(0xdeadbeef); + hintinfo.PriorityHint = MaximumIoPriorityHintType; + ret = pSetFileInformationByHandle(file, FileIoPriorityHintInfo, &hintinfo, sizeof(hintinfo)); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %ld\n", ret, GetLastError()); + + hintinfo.PriorityHint = IoPriorityHintNormal; + ret = pSetFileInformationByHandle(file, FileIoPriorityHintInfo, &hintinfo, sizeof(hintinfo)); + ok(ret, "setting FileIoPriorityHintInfo got %d, error %ld\n", ret, GetLastError()); + + hintinfo.PriorityHint = IoPriorityHintVeryLow; + ret = pSetFileInformationByHandle(file, FileIoPriorityHintInfo, &hintinfo, sizeof(hintinfo)); + ok(ret, "setting FileIoPriorityHintInfo got %d, error %ld\n", ret, GetLastError()); + + SetLastError(0xdeadbeef); + ret = pSetFileInformationByHandle(file, FileIoPriorityHintInfo, &hintinfo, sizeof(hintinfo) - 1); + ok(!ret && GetLastError() == ERROR_BAD_LENGTH, "got %d, error %ld\n", ret, GetLastError()); + + SetLastError(0xdeadbeef); + hintinfo.PriorityHint = IoPriorityHintVeryLow - 1; + ret = pSetFileInformationByHandle(file, FileIoPriorityHintInfo, &hintinfo, sizeof(hintinfo)); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %ld\n", ret, GetLastError()); memset(&protinfo, 0, sizeof(protinfo)); protinfo.StructureVersion = 1; protinfo.StructureSize = sizeof(protinfo); SetLastError(0xdeadbeef); ret = pSetFileInformationByHandle(file, FileRemoteProtocolInfo, &protinfo, sizeof(protinfo)); - ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError()); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %ld\n", ret, GetLastError()); /* test FileDispositionInfo, additional details already covered by ntdll tests */ SetLastError(0xdeadbeef); ret = pSetFileInformationByHandle(file, FileDispositionInfo, &dispinfo, 0); -todo_wine - ok(!ret && GetLastError() == ERROR_BAD_LENGTH, "got %d, error %d\n", ret, GetLastError()); + todo_wine + ok(!ret && GetLastError() == ERROR_BAD_LENGTH, "got %d, error %ld\n", ret, GetLastError()); + + SetLastError(0xdeadbeef); + ret = pSetFileInformationByHandle(file, FileBasicInfo, &basicinfo, 0); + todo_wine + ok(!ret && GetLastError() == ERROR_BAD_LENGTH, "got %d, error %ld\n", ret, GetLastError()); + + memset(&basicinfo, 0, sizeof(basicinfo)); + ret = pGetFileInformationByHandleEx(file, FileBasicInfo, &basicinfo, sizeof(basicinfo)); + ok(ret, "Failed to get basic info, error %ld.\n", GetLastError()); + atime = basicinfo.LastAccessTime; + + basicinfo.LastAccessTime.QuadPart++; + ret = pSetFileInformationByHandle(file, FileBasicInfo, &basicinfo, sizeof(basicinfo)); + ok(ret, "Failed to set basic info, error %ld.\n", GetLastError()); + + memset(&basicinfo, 0, sizeof(basicinfo)); + ret = pGetFileInformationByHandleEx(file, FileBasicInfo, &basicinfo, sizeof(basicinfo)); + ok(ret, "Failed to get basic info, error %ld.\n", GetLastError()); + ok(atime.QuadPart + 1 == basicinfo.LastAccessTime.QuadPart, "Unexpected access time.\n"); + + memset(&basicinfo, 0, sizeof(basicinfo)); + basicinfo.LastAccessTime.QuadPart = -1; + ret = pSetFileInformationByHandle(file, FileBasicInfo, &basicinfo, sizeof(basicinfo)); + ok(ret, "Failed to set basic info, error %ld.\n", GetLastError()); + + memset(&basicinfo, 0, sizeof(basicinfo)); + ret = pGetFileInformationByHandleEx(file, FileBasicInfo, &basicinfo, sizeof(basicinfo)); + ok(ret, "Failed to get basic info, error %ld.\n", GetLastError()); + ok(atime.QuadPart + 1 == basicinfo.LastAccessTime.QuadPart, "Unexpected access time.\n"); dispinfo.DeleteFile = TRUE; ret = pSetFileInformationByHandle(file, FileDispositionInfo, &dispinfo, sizeof(dispinfo)); - ok(ret, "setting FileDispositionInfo failed, error %d\n", GetLastError()); + ok(ret, "setting FileDispositionInfo failed, error %ld\n", GetLastError()); CloseHandle(file); } -static void test_GetFileAttributesExW(void) +static void test_SetFileRenameInfo(void) { - static const WCHAR path1[] = {'\\','\\','?','\\',0}; - static const WCHAR path2[] = {'\\','?','?','\\',0}; - static const WCHAR path3[] = {'\\','D','o','s','D','e','v','i','c','e','s','\\',0}; - WIN32_FILE_ATTRIBUTE_DATA info; + WCHAR tempFileFrom[MAX_PATH], tempFileTo1[MAX_PATH], tempFileTo2[MAX_PATH]; + WCHAR tempPath[MAX_PATH]; + FILE_RENAME_INFORMATION *fri; + HANDLE file; + DWORD size; BOOL ret; +#if defined(__REACTOS__) && DLL_EXPORT_VERSION >= 0x600 + /* FIXME: SetFileInformationByHandle is a STUB on ReactOS. */ + if (is_reactos() || !pSetFileInformationByHandle) +#else + if (!pSetFileInformationByHandle) +#endif + { + win_skip("SetFileInformationByHandle is not supported\n"); + return; + } + + ret = GetTempPathW(MAX_PATH, tempPath); + ok(ret, "GetTempPathW failed, got error %lu.\n", GetLastError()); + + ret = GetTempFileNameW(tempPath, L"abc", 0, tempFileFrom); + ok(ret, "GetTempFileNameW failed, got error %lu.\n", GetLastError()); + + ret = GetTempFileNameW(tempPath, L"abc", 0, tempFileTo1); + ok(ret, "GetTempFileNameW failed, got error %lu.\n", GetLastError()); + + ret = GetTempFileNameW(tempPath, L"abc", 1, tempFileTo2); + ok(ret, "GetTempFileNameW failed, got error %lu.\n", GetLastError()); + + file = CreateFileW(tempFileFrom, GENERIC_READ | GENERIC_WRITE | DELETE, 0, 0, OPEN_EXISTING, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "failed to create temp file, error %lu.\n", GetLastError()); + + size = sizeof(FILE_RENAME_INFORMATION) + MAX_PATH; + fri = HeapAlloc(GetProcessHeap(), 0, size); + + fri->ReplaceIfExists = FALSE; + fri->RootDirectory = NULL; + fri->FileNameLength = wcslen(tempFileTo1) * sizeof(WCHAR); + memcpy(fri->FileName, tempFileTo1, fri->FileNameLength + sizeof(WCHAR)); + ret = pSetFileInformationByHandle(file, FileRenameInfo, fri, size); + ok(!ret && GetLastError() == ERROR_ALREADY_EXISTS, "FileRenameInfo unexpected result %ld\n", GetLastError()); + + fri->ReplaceIfExists = TRUE; + ret = pSetFileInformationByHandle(file, FileRenameInfo, fri, size); + ok(ret, "FileRenameInfo failed, error %ld\n", GetLastError()); + + fri->ReplaceIfExists = FALSE; + fri->FileNameLength = wcslen(tempFileTo2) * sizeof(WCHAR); + memcpy(fri->FileName, tempFileTo2, fri->FileNameLength + sizeof(WCHAR)); + ret = pSetFileInformationByHandle(file, FileRenameInfo, fri, size); + ok(ret, "FileRenameInfo failed, error %ld\n", GetLastError()); + CloseHandle(file); + + file = CreateFileW(tempFileTo2, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "file not renamed, error %ld\n", GetLastError()); + + fri->FileNameLength = wcslen(tempFileTo1) * sizeof(WCHAR); + memcpy(fri->FileName, tempFileTo1, fri->FileNameLength + sizeof(WCHAR)); + ret = pSetFileInformationByHandle(file, FileRenameInfo, fri, size); + todo_wine + ok(!ret && GetLastError() == ERROR_ACCESS_DENIED, "FileRenameInfo unexpected result %ld\n", GetLastError()); + CloseHandle(file); + + HeapFree(GetProcessHeap(), 0, fri); + DeleteFileW(tempFileFrom); + DeleteFileW(tempFileTo1); + DeleteFileW(tempFileTo2); +} + +static void test_GetFileAttributesExW(void) +{ + static const struct + { + const WCHAR *path; + DWORD expected_error; + } + tests[] = + { + {L"\\\\?\\", ERROR_INVALID_NAME}, + {L"\\??\\", ERROR_INVALID_NAME}, + {L"\\DosDevices\\", ERROR_FILE_NOT_FOUND}, + {L"\\\\?\\C:\\windows\\system32\\..\\system32\\kernel32.dll", ERROR_INVALID_NAME}, + }; + WIN32_FILE_ATTRIBUTE_DATA info; + DWORD error, test_idx; + BOOL ret; + + for (test_idx = 0; test_idx < ARRAY_SIZE(tests); ++test_idx) + { + winetest_push_context("Test %lu", test_idx); + + SetLastError(0xdeadbeef); + ret = GetFileAttributesExW(tests[test_idx].path, GetFileExInfoStandard, &info); + error = GetLastError(); + ok(!ret, "GetFileAttributesExW succeeded\n"); + ok(error == tests[test_idx].expected_error, "Expected error %lu, got %lu\n", + tests[test_idx].expected_error, error); + + winetest_pop_context(); + } +} + +static void test_post_completion(void) +{ + OVERLAPPED ovl, ovl2, *povl; + OVERLAPPED_ENTRY entries[2]; + ULONG_PTR key; + HANDLE port; + ULONG count; + DWORD size; + BOOL ret; + + port = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 999, 0 ); + ok(port != NULL, "CreateIoCompletionPort failed: %lu\n", GetLastError()); + + ret = GetQueuedCompletionStatus( port, &size, &key, &povl, 0 ); + ok(!ret, "GetQueuedCompletionStatus succeeded\n"); + ok(GetLastError() == WAIT_TIMEOUT, "wrong error %lu\n", GetLastError()); + + ret = PostQueuedCompletionStatus( port, 123, 456, &ovl ); + ok(ret, "PostQueuedCompletionStatus failed: %lu\n", GetLastError()); + + ret = GetQueuedCompletionStatus( port, &size, &key, &povl, 0 ); + ok(ret, "GetQueuedCompletionStatus failed: %lu\n", GetLastError()); + ok(size == 123, "wrong size %lu\n", size); + ok(key == 456, "wrong key %Iu\n", key); + ok(povl == &ovl, "wrong ovl %p\n", povl); + + ret = GetQueuedCompletionStatus( port, &size, &key, &povl, 0 ); + ok(!ret, "GetQueuedCompletionStatus succeeded\n"); + ok(GetLastError() == WAIT_TIMEOUT, "wrong error %lu\n", GetLastError()); + +#if defined(__REACTOS__) && DLL_EXPORT_VERSION >= 0x600 + /* FIXME: GetQueuedCompletionStatusEx is a STUB on ReactOS. */ + if (is_reactos() || !pGetQueuedCompletionStatusEx) +#else + if (!pGetQueuedCompletionStatusEx) +#endif + { + win_skip("GetQueuedCompletionStatusEx not available\n"); + CloseHandle( port ); + return; + } + + count = 0xdeadbeef; + ret = pGetQueuedCompletionStatusEx( port, entries, 2, &count, 0, FALSE ); + ok(!ret, "GetQueuedCompletionStatusEx succeeded\n"); + ok(GetLastError() == WAIT_TIMEOUT, "wrong error %lu\n", GetLastError()); + ok(count <= 1, "wrong count %lu\n", count); + + ret = PostQueuedCompletionStatus( port, 123, 456, &ovl ); + ok(ret, "PostQueuedCompletionStatus failed: %lu\n", GetLastError()); + + count = 0xdeadbeef; + memset( entries, 0xcc, sizeof(entries) ); + ret = pGetQueuedCompletionStatusEx( port, entries, 2, &count, 0, FALSE ); + ok(ret, "GetQueuedCompletionStatusEx failed\n"); + ok(count == 1, "wrong count %lu\n", count); + ok(entries[0].lpCompletionKey == 456, "wrong key %Iu\n", entries[0].lpCompletionKey); + ok(entries[0].lpOverlapped == &ovl, "wrong ovl %p\n", entries[0].lpOverlapped); + ok(!(ULONG)entries[0].Internal, "wrong internal %#lx\n", (ULONG)entries[0].Internal); + ok(entries[0].dwNumberOfBytesTransferred == 123, "wrong size %lu\n", entries[0].dwNumberOfBytesTransferred); + + ret = PostQueuedCompletionStatus( port, 123, 456, &ovl ); + ok(ret, "PostQueuedCompletionStatus failed: %lu\n", GetLastError()); + + ret = PostQueuedCompletionStatus( port, 654, 321, &ovl2 ); + ok(ret, "PostQueuedCompletionStatus failed: %lu\n", GetLastError()); + + count = 0xdeadbeef; + memset( entries, 0xcc, sizeof(entries) ); + ret = pGetQueuedCompletionStatusEx( port, entries, 2, &count, 0, FALSE ); + ok(ret, "GetQueuedCompletionStatusEx failed\n"); + ok(count == 2, "wrong count %lu\n", count); + ok(entries[0].lpCompletionKey == 456, "wrong key %Iu\n", entries[0].lpCompletionKey); + ok(entries[0].lpOverlapped == &ovl, "wrong ovl %p\n", entries[0].lpOverlapped); + ok(!(ULONG)entries[0].Internal, "wrong internal %#lx\n", (ULONG)entries[0].Internal); + ok(entries[0].dwNumberOfBytesTransferred == 123, "wrong size %lu\n", entries[0].dwNumberOfBytesTransferred); + ok(entries[1].lpCompletionKey == 321, "wrong key %Iu\n", entries[1].lpCompletionKey); + ok(entries[1].lpOverlapped == &ovl2, "wrong ovl %p\n", entries[1].lpOverlapped); + ok(!(ULONG)entries[1].Internal, "wrong internal %#lx\n", (ULONG)entries[1].Internal); + ok(entries[1].dwNumberOfBytesTransferred == 654, "wrong size %lu\n", entries[1].dwNumberOfBytesTransferred); + + user_apc_ran = FALSE; + QueueUserAPC( user_apc, GetCurrentThread(), 0 ); + + ret = pGetQueuedCompletionStatusEx( port, entries, 2, &count, 0, FALSE ); + ok(!ret, "GetQueuedCompletionStatusEx succeeded\n"); + ok(GetLastError() == WAIT_TIMEOUT, "wrong error %lu\n", GetLastError()); + ok(count <= 1, "wrong count %lu\n", count); + ok(!user_apc_ran, "user APC should not have run\n"); + + ret = pGetQueuedCompletionStatusEx( port, entries, 2, &count, 0, TRUE ); + ok(!ret || broken(ret) /* Vista */, "GetQueuedCompletionStatusEx succeeded\n"); + if (!ret) + ok(GetLastError() == WAIT_IO_COMPLETION, "wrong error %lu\n", GetLastError()); + ok(count <= 1, "wrong count %lu\n", count); + ok(user_apc_ran, "user APC should have run\n"); + + user_apc_ran = FALSE; + QueueUserAPC( user_apc, GetCurrentThread(), 0 ); + + ret = PostQueuedCompletionStatus( port, 123, 456, &ovl ); + ok(ret, "PostQueuedCompletionStatus failed: %lu\n", GetLastError()); + + ret = pGetQueuedCompletionStatusEx( port, entries, 2, &count, 0, TRUE ); + ok(ret, "GetQueuedCompletionStatusEx failed\n"); + ok(count == 1, "wrong count %lu\n", count); + ok(!user_apc_ran, "user APC should not have run\n"); + + SleepEx(0, TRUE); + + CloseHandle( port ); +} + +#define TEST_OVERLAPPED_READ_SIZE 4096 + +static void test_overlapped_read(void) +{ + DECLSPEC_ALIGN(TEST_OVERLAPPED_READ_SIZE) static unsigned char buffer[TEST_OVERLAPPED_READ_SIZE]; + static const char prefix[] = "pfx"; + char temp_path[MAX_PATH]; + char file_name[MAX_PATH]; + DWORD bytes_count; + OVERLAPPED ov; + HANDLE hfile; + DWORD err; + DWORD ret; + + ret = GetTempPathA(MAX_PATH, temp_path); + ok(ret, "Unexpected error %lu.\n", GetLastError()); + ret = GetTempFileNameA(temp_path, prefix, 0, file_name); + ok(ret, "Unexpected error %lu.\n", GetLastError()); + + hfile = CreateFileA(file_name, GENERIC_WRITE, 0, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL); + ok(hfile != INVALID_HANDLE_VALUE, "Failed to create file, GetLastError() %lu.\n", GetLastError()); + memset(buffer, 0x55, sizeof(buffer)); + ret = WriteFile(hfile, buffer, TEST_OVERLAPPED_READ_SIZE, &bytes_count, NULL); + ok(ret && bytes_count == TEST_OVERLAPPED_READ_SIZE, + "Unexpected WriteFile result, ret %#lx, bytes_count %lu, GetLastError() %lu.\n", + ret, bytes_count, GetLastError()); + CloseHandle(hfile); + + hfile = CreateFileA(file_name, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL); + ok(hfile != INVALID_HANDLE_VALUE, "Failed to create file, GetLastError() %lu.\n", GetLastError()); + + memset(&ov, 0, sizeof(ov)); + + bytes_count = 0xffffffff; + ret = ReadFile(hfile, buffer, TEST_OVERLAPPED_READ_SIZE, &bytes_count, &ov); + ok(!ret && GetLastError() == ERROR_IO_PENDING, + "Unexpected ReadFile result, ret %#lx, GetLastError() %lu.\n", ret, GetLastError()); + ok(!bytes_count, "Unexpected read size %lu.\n", bytes_count); + ret = GetOverlappedResult(hfile, &ov, &bytes_count, TRUE); + ok(ret, "Unexpected error %lu.\n", GetLastError()); + ok(bytes_count == TEST_OVERLAPPED_READ_SIZE, "Unexpected read size %lu.\n", bytes_count); + + ov.Offset = bytes_count; + ret = ReadFile(hfile, buffer, TEST_OVERLAPPED_READ_SIZE, &bytes_count, &ov); + err = GetLastError(); + /* Win8+ return ERROR_IO_PENDING like stated in MSDN, while older ones + * return ERROR_HANDLE_EOF right away. */ + ok(!ret && (err == ERROR_IO_PENDING || broken(err == ERROR_HANDLE_EOF)), + "Unexpected ReadFile result, ret %#lx, GetLastError() %lu.\n", ret, GetLastError()); + if (err == ERROR_IO_PENDING) + { + ret = GetOverlappedResult(hfile, &ov, &bytes_count, TRUE); + ok(!ret && GetLastError() == ERROR_HANDLE_EOF, "Unexpected result %#lx, GetLasttError() %lu.\n", + ret, GetLastError()); + } + ok(!bytes_count, "Unexpected read size %lu.\n", bytes_count); + + CloseHandle(hfile); + ret = DeleteFileA(file_name); + ok(ret, "Unexpected error %lu.\n", GetLastError()); +} + +static void test_file_readonly_access(void) +{ + static const DWORD default_sharing = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + static const CHAR prefix[] = "pfx"; + CHAR file_name[MAX_PATH], file_name2[MAX_PATH]; + CHAR temp_path[MAX_PATH]; + HANDLE handle; + DWORD error; + DWORD ret; + + /* Set up */ + ret = GetTempPathA(MAX_PATH, temp_path); + ok(ret != 0, "GetTempPathA error %ld\n", GetLastError()); + ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n"); + + ret = GetTempFileNameA(temp_path, prefix, 0, file_name); + ok(ret != 0, "GetTempFileNameA error %ld\n", GetLastError()); + ret = DeleteFileA(file_name); + ok(ret, "expect success\n"); + + ret = GetTempFileNameA(temp_path, prefix, 0, file_name2); + ok(ret != 0, "GetTempFileNameA error %ld\n", GetLastError()); + ret = DeleteFileA(file_name2); + ok(ret, "expect success\n"); + + handle = CreateFileA(file_name, 0, default_sharing, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_READONLY, 0); + ok(handle != INVALID_HANDLE_VALUE, "CreateFileA: error %ld\n", GetLastError()); + CloseHandle(handle); + + /* CreateFile GENERIC_WRITE */ SetLastError(0xdeadbeef); - ret = GetFileAttributesExW(path1, GetFileExInfoStandard, &info); - ok(!ret, "GetFileAttributesExW succeeded\n"); - ok(GetLastError() == ERROR_INVALID_NAME, "Expected error ERROR_INVALID_NAME, got %u\n", GetLastError()); + handle = CreateFileA(file_name, GENERIC_WRITE, default_sharing, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + error = GetLastError(); + ok(handle == INVALID_HANDLE_VALUE, "expect failure\n"); + ok(error == ERROR_ACCESS_DENIED, "wrong error code: %#lx\n", error); + + /* CreateFile DELETE without FILE_FLAG_DELETE_ON_CLOSE */ + handle = CreateFileA(file_name, DELETE, default_sharing, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + ok(handle != INVALID_HANDLE_VALUE, "expect success\n"); + CloseHandle(handle); + + /* CreateFile DELETE with FILE_FLAG_DELETE_ON_CLOSE */ + SetLastError(0xdeadbeef); + handle = CreateFileA(file_name, DELETE, default_sharing, NULL, OPEN_EXISTING, + FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_NORMAL, 0); + error = GetLastError(); + ok(handle == INVALID_HANDLE_VALUE, "expect failure\n"); + ok(error == ERROR_ACCESS_DENIED, "wrong error code: %#lx\n", error); + + ret = MoveFileA(file_name, file_name2); + ok(ret, "expect success\n"); + ret = MoveFileA(file_name2, file_name); + ok(ret, "expect success\n"); SetLastError(0xdeadbeef); - ret = GetFileAttributesExW(path2, GetFileExInfoStandard, &info); - ok(!ret, "GetFileAttributesExW succeeded\n"); - ok(GetLastError() == ERROR_INVALID_NAME, "Expected error ERROR_INVALID_NAME, got %u\n", GetLastError()); + ret = DeleteFileA(file_name); + error = GetLastError(); + ok(!ret, "expect failure\n"); + ok(error == ERROR_ACCESS_DENIED, "wrong error code: %#lx\n", error); + + ret = GetFileAttributesA(file_name); + ok(ret & FILE_ATTRIBUTE_READONLY, "got wrong attribute: %#lx.\n", ret); + + /* Clean up */ + SetFileAttributesA(file_name, FILE_ATTRIBUTE_NORMAL); + ret = DeleteFileA(file_name); + ok(ret, "DeleteFileA: error %ld\n", GetLastError()); +} + +static void test_find_file_stream(void) +{ + WCHAR path[] = {'C',':','\\','w','i','n','d','o','w','s',0}; + HANDLE handle; + int error; + WIN32_FIND_STREAM_DATA data; + + if (!pFindFirstStreamW) + { + win_skip("FindFirstStreamW is missing\n"); + return; + } SetLastError(0xdeadbeef); - ret = GetFileAttributesExW(path3, GetFileExInfoStandard, &info); - ok(!ret, "GetFileAttributesExW succeeded\n"); - ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected error ERROR_FILE_NOT_FOUND, got %u\n", GetLastError()); + handle = pFindFirstStreamW(path, FindStreamInfoStandard, &data, 0); + error = GetLastError(); + ok(handle == INVALID_HANDLE_VALUE, "Expected INVALID_HANDLE_VALUE, got %p\n", handle); + ok(error == ERROR_HANDLE_EOF, "Expected ERROR_HANDLE_EOF, got %d\n", error); +} + +static void test_SetFileTime(void) +{ + static const WCHAR prefix[] = {'p','f','x',0}; + WCHAR path[MAX_PATH], temp_path[MAX_PATH]; + FILETIME ft1, ft2; + DWORD ret, len; + HANDLE hfile; + + ret = GetTempPathW(MAX_PATH, temp_path); + ok(ret != 0, "GetTempPathW error %ld\n", GetLastError()); + ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n"); + + ret = GetTempFileNameW(temp_path, prefix, 0, path); + ok(ret != 0, "GetTempFileNameW error %ld\n", GetLastError()); + + hfile = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, 0); + ok(hfile != INVALID_HANDLE_VALUE, "failed to open source file\n"); + ret = WriteFile(hfile, prefix, sizeof(prefix), &len, NULL ); + ok(ret && len == sizeof(prefix), "WriteFile error %ld\n", GetLastError()); + ok(GetFileSize(hfile, NULL) == sizeof(prefix), "source file has wrong size\n"); + + ret = GetFileTime(hfile, NULL, NULL, &ft1); + ok(ret, "GetFileTime error %ld\n", GetLastError()); + ft2 = ft1; + ft2.dwLowDateTime -= 600000000; /* 60 second */ + ret = SetFileTime(hfile, NULL, NULL, &ft2); + ok(ret, "SetFileTime error %ld\n", GetLastError()); + memset(&ft2, 0, sizeof(ft2)); + ret = GetFileTime(hfile, NULL, NULL, &ft2); /* get the actual time back */ + ok(ret, "GetFileTime error %ld\n", GetLastError()); + ok(memcmp(&ft1, &ft2, sizeof(ft1)), "Unexpected write time.\n"); + + memset(&ft1, 0xff, sizeof(ft1)); + ret = SetFileTime(hfile, NULL, NULL, &ft1); + ok(ret, "SetFileTime error %ld\n", GetLastError()); + memset(&ft1, 0, sizeof(ft1)); + ret = GetFileTime(hfile, NULL, NULL, &ft1); /* get the actual time back */ + ok(ret, "GetFileTime error %ld\n", GetLastError()); + ok(!memcmp(&ft1, &ft2, sizeof(ft1)), "Unexpected write time.\n"); + + CloseHandle(hfile); +} + +static void test_hard_link(void) +{ + char cwd[MAX_PATH], temp_dir[MAX_PATH], name_buffer[200], buffer[20]; + FILE_NAME_INFORMATION *name_info = (FILE_NAME_INFORMATION *)name_buffer; + IO_STATUS_BLOCK io; + NTSTATUS status; + HANDLE file; + DWORD size; + BOOL ret; + + GetCurrentDirectoryA( sizeof(cwd), cwd ); + GetTempPathA( sizeof(temp_dir), temp_dir ); + SetCurrentDirectoryA( temp_dir ); + + ret = CreateDirectoryA( "winetest_dir1", NULL ); + ok(ret, "failed to create directory, error %lu\n", GetLastError()); + ret = CreateDirectoryA( "winetest_dir2", NULL ); + ok(ret, "failed to create directory, error %lu\n", GetLastError()); + create_file( "winetest_file1" ); + create_file( "winetest_file2" ); + + ret = CreateHardLinkA( "winetest_file3", "winetest_file1", NULL ); + ok(ret, "got error %lu\n", GetLastError()); + + file = CreateFileA( "winetest_file3", FILE_READ_DATA, 0, NULL, OPEN_EXISTING, 0, NULL ); + ok(file != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError()); + + status = NtQueryInformationFile( file, &io, name_buffer, sizeof(name_buffer), FileNameInformation ); + ok(!status, "got status %#lx\n", status); +#ifdef __REACTOS__ + if (!status) +#endif + ok(!wcsncmp(name_info->FileName + (name_info->FileNameLength / sizeof(WCHAR)) - wcslen(L"\\winetest_file3"), + L"\\winetest_file3", wcslen(L"\\winetest_file3")), "got name %s\n", + debugstr_wn(name_info->FileName, name_info->FileNameLength / sizeof(WCHAR))); + + ret = ReadFile( file, buffer, sizeof(buffer), &size, NULL ); + ok(ret, "got error %lu\n", GetLastError()); + ok(!memcmp( buffer, "winetest_file1", size ), "got file contents %s\n", debugstr_an( buffer, size )); + + CloseHandle( file ); + + ret = DeleteFileA( "winetest_file3" ); + ok(ret, "failed to delete file, error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = CreateHardLinkA( "winetest_file2", "winetest_file1", NULL ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_ALREADY_EXISTS, "got error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = CreateHardLinkA( "WineTest_File1", "winetest_file1", NULL ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_ALREADY_EXISTS, "got error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = CreateHardLinkA( "winetest_file3", "winetest_dir1", NULL ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = CreateHardLinkA( "winetest_dir2", "winetest_dir1", NULL ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED + || GetLastError() == ERROR_ALREADY_EXISTS /* XP */, "got error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = CreateHardLinkA( "winetest_dir1", "winetest_file1", NULL ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_ALREADY_EXISTS, "got error %lu\n", GetLastError()); + + ret = RemoveDirectoryA( "winetest_dir1" ); + ok(ret, "failed to remove directory, error %lu\n", GetLastError()); + ret = RemoveDirectoryA( "winetest_dir2" ); + ok(ret, "failed to remove directory, error %lu\n", GetLastError()); + ret = DeleteFileA( "winetest_file1" ); + ok(ret, "failed to delete file, error %lu\n", GetLastError()); + ret = DeleteFileA( "winetest_file2" ); + ok(ret, "failed to delete file, error %lu\n", GetLastError()); + SetCurrentDirectoryA( cwd ); +} + +static void test_move_file(void) +{ + char cwd[MAX_PATH], temp_dir[MAX_PATH]; + HANDLE file; + BOOL ret; + + GetCurrentDirectoryA( sizeof(cwd), cwd ); + GetTempPathA( sizeof(temp_dir), temp_dir ); + SetCurrentDirectoryA( temp_dir ); + + ret = CreateDirectoryA( "winetest_dir1", NULL ); + ok(ret, "failed to create directory, error %lu\n", GetLastError()); + ret = CreateDirectoryA( "winetest_dir2", NULL ); + ok(ret, "failed to create directory, error %lu\n", GetLastError()); + create_file( "winetest_file1" ); + create_file( "winetest_file2" ); + + ret = MoveFileA( "winetest_file1", "winetest_file3" ); + ok(ret, "failed to move file, error %lu\n", GetLastError()); + ret = GetFileAttributesA( "winetest_file1" ); + ok(ret == INVALID_FILE_ATTRIBUTES, "got %#x\n", ret); + ret = GetFileAttributesA( "winetest_file3" ); + ok(ret != INVALID_FILE_ATTRIBUTES, "got %#x\n", ret); + + SetLastError(0xdeadbeef); + ret = MoveFileA( "winetest_file3", "winetest_file2" ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_ALREADY_EXISTS, "got error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = MoveFileA( "winetest_file1", "winetest_file4" ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "got error %lu\n", GetLastError()); + + ret = MoveFileA( "winetest_dir1", "winetest_dir3" ); + ok(ret, "failed to move file, error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = MoveFileA( "winetest_dir3", "winetest_dir2" ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_ALREADY_EXISTS, "got error %lu\n", GetLastError()); + + file = CreateFileA( "winetest_file3", DELETE, 0, NULL, OPEN_EXISTING, 0, 0 ); + ok(file != INVALID_HANDLE_VALUE, "failed to open file, error %lu\n", GetLastError()); + ret = MoveFileA( "winetest_file3", "winetest_file1" ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_SHARING_VIOLATION, "got error %lu\n", GetLastError()); + CloseHandle( file ); + + file = CreateFileA( "winetest_file3", 0, 0, NULL, OPEN_EXISTING, 0, 0 ); + ok(file != INVALID_HANDLE_VALUE, "failed to open file, error %lu\n", GetLastError()); + ret = MoveFileA( "winetest_file3", "winetest_file1" ); + ok(ret, "failed to move file, error %lu\n", GetLastError()); + ret = GetFileAttributesA( "winetest_file1" ); + ok(ret != INVALID_FILE_ATTRIBUTES, "got %#x\n", ret); + ret = GetFileAttributesA( "winetest_file3" ); + ok(ret == INVALID_FILE_ATTRIBUTES, "got %#x\n", ret); + CloseHandle( file ); + + ret = MoveFileExA( "winetest_file1", "winetest_file2", MOVEFILE_REPLACE_EXISTING ); + ok(ret, "failed to move file, error %lu\n", GetLastError()); + + file = CreateFileA( "winetest_file1", GENERIC_ALL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, CREATE_NEW, 0, 0 ); + ok(file != INVALID_HANDLE_VALUE, "failed to open file, error %lu\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = MoveFileExA( "winetest_file2", "winetest_file1", MOVEFILE_REPLACE_EXISTING ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %lu\n", GetLastError()); + CloseHandle( file ); + + SetLastError(0xdeadbeef); + ret = MoveFileExA( "winetest_file2", "winetest_dir2", MOVEFILE_REPLACE_EXISTING ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = MoveFileExA( "winetest_dir3", "winetest_dir2", MOVEFILE_REPLACE_EXISTING ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %lu\n", GetLastError()); + + ret = MoveFileExA( "winetest_dir2", "winetest_file2", MOVEFILE_REPLACE_EXISTING ); + ok(ret, "failed to move file, error %lu\n", GetLastError()); + + ret = RemoveDirectoryA( "winetest_dir3" ); + ok(ret, "failed to remove directory, error %lu\n", GetLastError()); + ret = RemoveDirectoryA( "winetest_file2" ); + ok(ret, "failed to remove directory, error %lu\n", GetLastError()); + ret = DeleteFileA( "winetest_file1" ); + ok(ret, "failed to delete file, error %lu\n", GetLastError()); + SetCurrentDirectoryA( cwd ); +} + +static void test_eof(void) +{ + char temp_path[MAX_PATH], filename[MAX_PATH], buffer[20]; + OVERLAPPED overlapped = {0}; + LARGE_INTEGER file_size; + HANDLE file, mapping; + unsigned int i; + void *view; + DWORD size; + BOOL ret; + + static const struct + { + DWORD protection; + DWORD view_access; + } + map_tests[] = + { + {PAGE_READONLY, FILE_MAP_READ}, + {PAGE_READWRITE, FILE_MAP_WRITE}, + }; + + GetTempPathA(sizeof(temp_path), temp_path); + GetTempFileNameA(temp_path, "eof", 0, filename); + + file = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "failed to create file, error %lu\n", GetLastError()); + + ret = GetFileSizeEx(file, &file_size); + ok(ret, "failed to get size, error %lu\n", GetLastError()); + ok(!file_size.QuadPart, "got size %I64d\n", file_size.QuadPart); + + SetFilePointer(file, 2, NULL, SEEK_SET); + + ret = GetFileSizeEx(file, &file_size); + ok(ret, "failed to get size, error %lu\n", GetLastError()); + ok(!file_size.QuadPart, "got size %I64d\n", file_size.QuadPart); + + SetLastError(0xdeadbeef); + ret = ReadFile(file, buffer, sizeof(buffer), &size, NULL); + ok(ret, "failed to read, error %lu\n", GetLastError()); + ok(!size, "got size %lu\n", size); + ok(GetLastError() == 0xdeadbeef, "got error %lu\n", GetLastError()); + + SetFilePointer(file, 2, NULL, SEEK_SET); + + SetLastError(0xdeadbeef); + size = 0xdeadbeef; + overlapped.Offset = 2; + ret = ReadFile(file, buffer, sizeof(buffer), &size, &overlapped); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_HANDLE_EOF, "got error %lu\n", GetLastError()); + ok(!size, "got size %lu\n", size); + ok((NTSTATUS)overlapped.Internal == STATUS_PENDING || (NTSTATUS)overlapped.Internal == STATUS_END_OF_FILE, + "got status %#lx\n", (NTSTATUS)overlapped.Internal); + ok(!overlapped.InternalHigh, "got size %Iu\n", overlapped.InternalHigh); + + SetFilePointer(file, 2, NULL, SEEK_SET); + + ret = SetEndOfFile(file); + ok(ret, "failed to set EOF, error %lu\n", GetLastError()); + + ret = GetFileSizeEx(file, &file_size); + ok(ret, "failed to get size, error %lu\n", GetLastError()); + ok(file_size.QuadPart == 2, "got size %I64d\n", file_size.QuadPart); + + ret = WriteFile(file, "data", 4, &size, NULL); + ok(ret, "failed to write, error %lu\n", GetLastError()); + ok(size == 4, "got size %lu\n", size); + + ret = GetFileSizeEx(file, &file_size); + ok(ret, "failed to get size, error %lu\n", GetLastError()); + ok(file_size.QuadPart == 6, "got size %I64d\n", file_size.QuadPart); + + SetFilePointer(file, 4, NULL, SEEK_SET); + ret = SetEndOfFile(file); + ok(ret, "failed to set EOF, error %lu\n", GetLastError()); + + ret = GetFileSizeEx(file, &file_size); + ok(ret, "failed to get size, error %lu\n", GetLastError()); + ok(file_size.QuadPart == 4, "got size %I64d\n", file_size.QuadPart); + + SetFilePointer(file, 0, NULL, SEEK_SET); + ret = ReadFile(file, buffer, sizeof(buffer), &size, NULL); + ok(ret, "failed to read, error %lu\n", GetLastError()); + ok(size == 4, "got size %lu\n", size); + ok(!memcmp(buffer, "\0\0da", 4), "wrong data\n"); + + SetFilePointer(file, 6, NULL, SEEK_SET); + ret = SetEndOfFile(file); + ok(ret, "failed to set EOF, error %lu\n", GetLastError()); + + ret = GetFileSizeEx(file, &file_size); + ok(ret, "failed to get size, error %lu\n", GetLastError()); + ok(file_size.QuadPart == 6, "got size %I64d\n", file_size.QuadPart); + + SetFilePointer(file, 0, NULL, SEEK_SET); + ret = ReadFile(file, buffer, sizeof(buffer), &size, NULL); + ok(ret, "failed to read, error %lu\n", GetLastError()); + ok(size == 6, "got size %lu\n", size); + ok(!memcmp(buffer, "\0\0da\0\0", 6), "wrong data\n"); + + ret = SetEndOfFile(file); + ok(ret, "failed to set EOF, error %lu\n", GetLastError()); + + SetFilePointer(file, 2, NULL, SEEK_SET); + ret = WriteFile(file, "data", 4, &size, NULL); + ok(ret, "failed to write, error %lu\n", GetLastError()); + ok(size == 4, "got size %lu\n", size); + + ret = GetFileSizeEx(file, &file_size); + ok(ret, "failed to get size, error %lu\n", GetLastError()); + ok(file_size.QuadPart == 6, "got size %I64d\n", file_size.QuadPart); + + SetFilePointer(file, 0, NULL, SEEK_SET); + ret = ReadFile(file, buffer, sizeof(buffer), &size, NULL); + ok(ret, "failed to read, error %lu\n", GetLastError()); + ok(size == 6, "got size %lu\n", size); + ok(!memcmp(buffer, "\0\0data", 6), "wrong data\n"); + + for (i = 0; i < ARRAY_SIZE(map_tests); ++i) + { + mapping = CreateFileMappingA(file, NULL, map_tests[i].protection, 0, 4, NULL); + ok(!!mapping, "failed to create mapping, error %lu\n", GetLastError()); + + ret = GetFileSizeEx(file, &file_size); + ok(ret, "failed to get size, error %lu\n", GetLastError()); + ok(file_size.QuadPart == 6, "got size %I64d\n", file_size.QuadPart); + + SetFilePointer(file, 6, NULL, SEEK_SET); + ret = SetEndOfFile(file); + ok(ret, "failed to set EOF, error %lu\n", GetLastError()); + ret = GetFileSizeEx(file, &file_size); + ok(ret, "failed to get size, error %lu\n", GetLastError()); + ok(file_size.QuadPart == 6, "got size %I64d\n", file_size.QuadPart); + + SetFilePointer(file, 8, NULL, SEEK_SET); + ret = SetEndOfFile(file); + ok(ret, "failed to set EOF, error %lu\n", GetLastError()); + ret = GetFileSizeEx(file, &file_size); + ok(ret, "failed to get size, error %lu\n", GetLastError()); + ok(file_size.QuadPart == 8, "got size %I64d\n", file_size.QuadPart); + + SetLastError(0xdeadbeef); + SetFilePointer(file, 6, NULL, SEEK_SET); + ret = SetEndOfFile(file); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_USER_MAPPED_FILE, "got error %lu\n", GetLastError()); + ret = GetFileSizeEx(file, &file_size); + ok(ret, "failed to get size, error %lu\n", GetLastError()); + ok(file_size.QuadPart == 8, "got size %I64d\n", file_size.QuadPart); + + SetFilePointer(file, 8192, NULL, SEEK_SET); + ret = SetEndOfFile(file); + ok(ret, "failed to set EOF, error %lu\n", GetLastError()); + ret = GetFileSizeEx(file, &file_size); + ok(ret, "failed to get size, error %lu\n", GetLastError()); + ok(file_size.QuadPart == 8192, "got size %I64d\n", file_size.QuadPart); + + SetFilePointer(file, 8191, NULL, SEEK_SET); + ret = SetEndOfFile(file); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_USER_MAPPED_FILE, "got error %lu\n", GetLastError()); + ret = GetFileSizeEx(file, &file_size); + ok(ret, "failed to get size, error %lu\n", GetLastError()); + ok(file_size.QuadPart == 8192, "got size %I64d\n", file_size.QuadPart); + + view = MapViewOfFile(mapping, map_tests[i].view_access, 0, 0, 4); + ok(!!view, "failed to map view, error %lu\n", GetLastError()); + + CloseHandle(mapping); + + SetFilePointer(file, 16384, NULL, SEEK_SET); + ret = SetEndOfFile(file); + ok(ret, "failed to set EOF, error %lu\n", GetLastError()); + ret = GetFileSizeEx(file, &file_size); + ok(ret, "failed to get size, error %lu\n", GetLastError()); + ok(file_size.QuadPart == 16384, "got size %I64d\n", file_size.QuadPart); + + SetFilePointer(file, 16383, NULL, SEEK_SET); + ret = SetEndOfFile(file); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_USER_MAPPED_FILE, "got error %lu\n", GetLastError()); + ret = GetFileSizeEx(file, &file_size); + ok(ret, "failed to get size, error %lu\n", GetLastError()); + ok(file_size.QuadPart == 16384, "got size %I64d\n", file_size.QuadPart); + + ret = UnmapViewOfFile(view); + ok(ret, "failed to unmap view, error %lu\n", GetLastError()); + + SetFilePointer(file, 6, NULL, SEEK_SET); + ret = SetEndOfFile(file); + ok(ret, "failed to set EOF, error %lu\n", GetLastError()); + ret = GetFileSizeEx(file, &file_size); + ok(ret, "failed to get size, error %lu\n", GetLastError()); + ok(file_size.QuadPart == 6, "got size %I64d\n", file_size.QuadPart); + } + + CloseHandle(file); + ret = DeleteFileA(filename); + ok(ret, "failed to delete %s, error %lu\n", debugstr_a(filename), GetLastError()); } START_TEST(file) @@ -4911,11 +6364,11 @@ START_TEST(file) InitFunctionPointers(); ret = GetTempPathA(MAX_PATH, temp_path); - ok(ret != 0, "GetTempPath error %u\n", GetLastError()); + ok(ret != 0, "GetTempPath error %lu\n", GetLastError()); ret = GetTempFileNameA(temp_path, "tmp", 0, filename); - ok(ret != 0, "GetTempFileName error %u\n", GetLastError()); + ok(ret != 0, "GetTempFileName error %lu\n", GetLastError()); ret = DeleteFileA(filename); - ok(ret != 0, "DeleteFile error %u\n", GetLastError()); + ok(ret != 0, "DeleteFile error %lu\n", GetLastError()); test__hread( ); test__hwrite( ); @@ -4970,5 +6423,15 @@ START_TEST(file) test_GetFinalPathNameByHandleA(); test_GetFinalPathNameByHandleW(); test_SetFileInformationByHandle(); + test_SetFileRenameInfo(); test_GetFileAttributesExW(); + test_post_completion(); + test_overlapped_read(); + test_file_readonly_access(); + test_find_file_stream(); + test_SetFileTime(); + test_ReOpenFile(); + test_hard_link(); + test_move_file(); + test_eof(); } diff --git a/modules/rostests/winetests/kernel32/format_msg.c b/modules/rostests/winetests/kernel32/format_msg.c index 290bce9f719..6f94b4fe9b8 100644 --- a/modules/rostests/winetests/kernel32/format_msg.c +++ b/modules/rostests/winetests/kernel32/format_msg.c @@ -29,433 +29,308 @@ static DWORD WINAPIV doit(DWORD flags, LPCVOID src, DWORD msg_id, DWORD lang_id, LPSTR out, DWORD outsize, ... ) { - __ms_va_list list; + va_list list; DWORD r; - __ms_va_start(list, outsize); + va_start(list, outsize); r = FormatMessageA(flags, src, msg_id, lang_id, out, outsize, &list); - __ms_va_end(list); + va_end(list); return r; } static DWORD WINAPIV doitW(DWORD flags, LPCVOID src, DWORD msg_id, DWORD lang_id, LPWSTR out, DWORD outsize, ... ) { - __ms_va_list list; + va_list list; DWORD r; - __ms_va_start(list, outsize); + va_start(list, outsize); r = FormatMessageW(flags, src, msg_id, lang_id, out, outsize, &list); - __ms_va_end(list); + va_end(list); return r; } static void test_message_from_string_wide(void) { - static const WCHAR test[] = {'t','e','s','t',0}; - static const WCHAR empty[] = {0}; - static const WCHAR te[] = {'t','e',0}; - static const WCHAR st[] = {'s','t',0}; - static const WCHAR t[] = {'t',0}; - static const WCHAR e[] = {'e',0}; - static const WCHAR s[] = {'s',0}; - static const WCHAR fmt_null[] = {'%',0}; - static const WCHAR fmt_tnull[] = {'t','e','s','t','%',0}; - static const WCHAR fmt_1[] = {'%','1',0}; - static const WCHAR fmt_12[] = {'%','1','%','2',0}; - static const WCHAR fmt_123[] = {'%','1','%','3','%','2','%','1',0}; - static const WCHAR fmt_123c[] = {'%','1','!','c','!','%','2','!','c','!','%','3','!','c','!','%','1','!','c','!',0}; - static const WCHAR fmt_123lc[] = {'%','1','!','l','c','!','%','2','!','l','c','!','%','3','!','l','c','!','%','1','!','l','c','!',0}; - static const WCHAR fmt_123wc[] = {'%','1','!','w','c','!','%','2','!','w','c','!','%','3','!','w','c','!','%','1','!','w','c','!',0}; - static const WCHAR fmt_123C[] = {'%','1','!','C','!','%','2','!','C','!','%','3','!','C','!','%','1','!','C','!',0}; - static const WCHAR fmt_123d[] = {'%','1','!','d','!','%','2','!','d','!','%','3','!','d','!',0}; - static const WCHAR fmt_1s[] = {'%','1','!','s','!',0}; - static const WCHAR fmt_s[] = {'%','!','s','!',0}; - static const WCHAR fmt_ls[] = {'%','!','l','s','!',0}; - static const WCHAR fmt_ws[] = {'%','!','w','s','!',0}; - static const WCHAR fmt_S[] = {'%','!','S','!',0}; - static const WCHAR fmt_14d[] = {'%','1','!','4','d','!',0}; - static const WCHAR fmt_14x[] = {'%','1','!','4','x','!',0}; - static const WCHAR fmt_14X[] = {'%','1','!','4','X','!',0}; - static const WCHAR fmt_1_4X[] = {'%','1','!','-','4','X','!',0}; - static const WCHAR fmt_1_4d[] = {'%','1','!','-','4','d','!',0}; - static const WCHAR fmt_2pct[] = {' ','%','%','%','%',' ',0}; - static const WCHAR fmt_2dot1d[] = {' ', '%','.','%','.',' ',' ','%','1','!','d','!',0}; - static const WCHAR fmt_t0t[] = {'t','e','s','t','%','0','t','e','s','t',0}; - static const WCHAR fmt_yah[] = {'y','a','h','%','!','%','0',' ',' ',' ',0}; - static const WCHAR fmt_space[] = {'%',' ','%',' ',' ',' ',0}; - static const WCHAR fmt_nrt[] = {'%','n','%','r','%','t',0}; - static const WCHAR fmt_hi_lf[] = {'h','i','\n',0}; - static const WCHAR fmt_hi_crlf[] = {'h','i','\r','\n',0}; - static const WCHAR fmt_cr[] = {'\r',0}; - static const WCHAR fmt_crcrlf[] = {'\r','\r','\n',0}; - static const WCHAR fmt_13s[] = {'%','1','!','3','s','!',0}; - static const WCHAR fmt_1os[] = {'%','1','!','*','s','!',0}; - static const WCHAR fmt_142u[] = {'%','1','!','4','.','2','u','!',0}; - static const WCHAR fmt_1oou[] = {'%','1','!','*','.','*','u','!',0}; - static const WCHAR fmt_1oou1oou[] = {'%','1','!','*','.','*','u','!',',','%','1','!','*','.','*','u','!',0}; - static const WCHAR fmt_1oou3oou[] = {'%','1','!','*','.','*','u','!',',','%','3','!','*','.','*','u','!',0}; - static const WCHAR fmt_1oou4oou[] = {'%','1','!','*','.','*','u','!',',','%','4','!','*','.','*','u','!',0}; - - static const WCHAR s_123d[] = {'1','2','3',0}; - static const WCHAR s_14d[] = {' ',' ',' ','1',0}; - static const WCHAR s_14x[] = {' ',' ',' ','b',0}; - static const WCHAR s_14X[] = {' ',' ',' ','B',0}; - static const WCHAR s_1_4X[] = {'B',' ',' ',' ',0}; - static const WCHAR s_14d2[] = {' ',' ','1','1',0}; - static const WCHAR s_1_4d[] = {'1',' ',' ',' ',0}; - static const WCHAR s_1AB[] = {' ','1','A','B',0}; - static const WCHAR s_2pct[] = {' ','%','%',' ',0}; - static const WCHAR s_2dot147[] = {' ','.','.',' ',' ','4','2','7',0}; - static const WCHAR s_yah[] = {'y','a','h','!',0}; - static const WCHAR s_space[] = {' ',' ',' ',' ',0}; - static const WCHAR s_nrt[] = {'\r','\n','\r','\t',0}; - static const WCHAR s_hi_crlf[] = {'h','i','\r','\n',0}; - static const WCHAR s_crlf[] = {'\r','\n',0}; - static const WCHAR s_crlfcrlf[] = {'\r','\n','\r','\n',0}; - static const WCHAR s_hi_sp[] = {'h','i',' ',0}; - static const WCHAR s_sp[] = {' ',0}; - static const WCHAR s_2sp[] = {' ',' ',0}; - static const WCHAR s_spt[] = {' ',' ','t',0}; - static const WCHAR s_sp3t[] = {' ',' ',' ','t',0}; - static const WCHAR s_sp03[] = {' ',' ','0','3',0}; - static const WCHAR s_sp001[] = {' ',' ','0','0','1',0}; - static const WCHAR s_sp001002[] = {' ',' ','0','0','1',',',' ','0','0','0','2',0}; - static const WCHAR s_sp001sp002[] = {' ',' ','0','0','1',',',' ',' ','0','0','0','2',0}; - static const WCHAR s_sp002sp001[] = {' ',' ','0','0','0','2',',',' ',' ','0','0','1',0}; - static const WCHAR s_sp002sp003[] = {' ',' ','0','0','0','2',',',' ','0','0','0','0','3',0}; - static const WCHAR s_sp001004[] = {' ',' ','0','0','1',',','0','0','0','0','0','4',0}; - static const WCHAR s_null[] = {'(','n','u','l','l',')',0}; - - static const WCHAR init_buf[] = {'x', 'x', 'x', 'x', 'x', 'x'}; - static const WCHAR broken_buf[] = {'t','e','s','t','x','x'}; - WCHAR out[0x100] = {0}; DWORD r, error; /* the basics */ - r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, test, 0, - 0, out, sizeof(out)/sizeof(WCHAR), NULL); - ok(!lstrcmpW(test, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4, "failed: r=%d\n", r); + r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, L"test", 0, 0, out, ARRAY_SIZE(out), NULL); + ok(!lstrcmpW(L"test", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4, "failed: r=%ld\n", r); /* null string, crashes on Windows */ if (0) { SetLastError(0xdeadbeef); - memcpy(out, init_buf, sizeof(init_buf)); - FormatMessageW(FORMAT_MESSAGE_FROM_STRING, NULL, 0, - 0, out, sizeof(out)/sizeof(WCHAR), NULL); + lstrcpyW( out, L"xxxxxx" ); + FormatMessageW(FORMAT_MESSAGE_FROM_STRING, NULL, 0, 0, out, ARRAY_SIZE(out), NULL); } /* empty string */ SetLastError(0xdeadbeef); - memcpy(out, init_buf, sizeof(init_buf)); - r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, empty, 0, - 0, out, sizeof(out)/sizeof(WCHAR), NULL); + lstrcpyW( out, L"xxxxxx" ); + r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, L"", 0, 0, out, ARRAY_SIZE(out), NULL); error = GetLastError(); - ok(!lstrcmpW(empty, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==0, "succeeded: r=%d\n", r); - ok(error==0xdeadbeef, "last error %u\n", error); + ok(!lstrcmpW(L"", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==0, "succeeded: r=%ld\n", r); + ok(error == ERROR_NO_WORK_DONE || broken(error == 0xdeadbeef), "last error %lu\n", error); /* format placeholder with no specifier */ SetLastError(0xdeadbeef); - memcpy(out, init_buf, sizeof(init_buf)); - r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, fmt_null, 0, - 0, out, sizeof(out)/sizeof(WCHAR), NULL); + lstrcpyW( out, L"xxxxxx" ); + r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, L"%", 0, 0, out, ARRAY_SIZE(out), NULL); error = GetLastError(); - ok(!memcmp(out, init_buf, sizeof(init_buf)), + ok(!lstrcmpW( out, L"xxxxxx" ), "Expected the buffer to be unchanged\n"); - ok(r==0, "succeeded: r=%d\n", r); - ok(error==ERROR_INVALID_PARAMETER, "last error %u\n", error); + ok(r==0, "succeeded: r=%ld\n", r); + ok(error==ERROR_INVALID_PARAMETER, "last error %lu\n", error); /* test string with format placeholder with no specifier */ SetLastError(0xdeadbeef); - memcpy(out, init_buf, sizeof(init_buf)); - r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, fmt_tnull, 0, - 0, out, sizeof(out)/sizeof(WCHAR), NULL); + lstrcpyW( out, L"xxxxxx" ); + r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, L"test%", 0, 0, out, ARRAY_SIZE(out), NULL); error = GetLastError(); - ok(!memcmp(out, init_buf, sizeof(init_buf)) || - broken(!memcmp(out, broken_buf, sizeof(broken_buf))), /* W2K3+ */ + ok(!lstrcmpW(out, L"testxx") || broken(!lstrcmpW( out, L"xxxxxx" )), /* winxp */ "Expected the buffer to be unchanged\n"); - ok(r==0, "succeeded: r=%d\n", r); - ok(error==ERROR_INVALID_PARAMETER, "last error %u\n", error); + ok(r==0, "succeeded: r=%ld\n", r); + ok(error==ERROR_INVALID_PARAMETER, "last error %lu\n", error); /* insertion with no variadic arguments */ SetLastError(0xdeadbeef); - memcpy(out, init_buf, sizeof(init_buf)); - r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, fmt_1, 0, - 0, out, sizeof(out)/sizeof(WCHAR), NULL); + lstrcpyW( out, L"xxxxxx" ); + r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, L"%1", 0, 0, out, ARRAY_SIZE(out), NULL); error = GetLastError(); - ok(!memcmp(out, init_buf, sizeof(init_buf)), + ok(!lstrcmpW( out, L"xxxxxx" ), "Expected the buffer to be unchanged\n"); - ok(r==0, "succeeded: r=%d\n", r); - ok(error==ERROR_INVALID_PARAMETER, "last error %u\n", error); + ok(r==0, "succeeded: r=%ld\n", r); + ok(error==ERROR_INVALID_PARAMETER, "last error %lu\n", error); SetLastError(0xdeadbeef); - memcpy(out, init_buf, sizeof(init_buf)); - r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, fmt_1, 0, - 0, out, sizeof(out)/sizeof(WCHAR), NULL); + lstrcpyW( out, L"xxxxxx" ); + r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, L"%1", 0, + 0, out, ARRAY_SIZE(out), NULL); error = GetLastError(); - ok(!memcmp(out, init_buf, sizeof(init_buf)), + ok(!lstrcmpW( out, L"xxxxxx" ), "Expected the buffer to be unchanged\n"); - ok(r==0, "succeeded: r=%d\n", r); - ok(error==ERROR_INVALID_PARAMETER, "last error %u\n", error); + ok(r==0, "succeeded: r=%ld\n", r); + ok(error==ERROR_INVALID_PARAMETER, "last error %lu\n", error); /* using the format feature */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1s, 0, - 0, out, sizeof(out)/sizeof(WCHAR), test); - ok(!lstrcmpW(test, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!s!", 0, 0, out, ARRAY_SIZE(out), L"test"); + ok(!lstrcmpW(L"test", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%ld\n", r); /* no format */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1, 0, - 0, out, sizeof(out)/sizeof(WCHAR), test); - ok(!lstrcmpW(test, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1", 0, 0, out, ARRAY_SIZE(out), L"test"); + ok(!lstrcmpW(L"test", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%ld\n", r); /* two pieces */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_12, 0, - 0, out, sizeof(out)/sizeof(WCHAR), te, st); - ok(!lstrcmpW(test, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1%2", 0, 0, out, ARRAY_SIZE(out), L"te", L"st"); + ok(!lstrcmpW(L"test", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%ld\n", r); /* three pieces */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_123, 0, - 0, out, sizeof(out)/sizeof(WCHAR), t, s, e); - ok(!lstrcmpW(test, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1%3%2%1", 0, 0, out, ARRAY_SIZE(out), L"t", L"s", L"e"); + ok(!lstrcmpW(L"test", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%ld\n", r); - /* s doesn't seem to work in format strings */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_s, 0, - 0, out, sizeof(out)/sizeof(WCHAR), test); - ok(!lstrcmpW(&fmt_s[1], out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==3, "failed: r=%d\n", r); + /* ls is unicode */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!ls!", 0, 0, out, ARRAY_SIZE(out), L"test"); + ok(!lstrcmpW(L"test", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4, "failed: r=%ld\n", r); - /* nor ls */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_ls, 0, - 0, out, sizeof(out)/sizeof(WCHAR), test); - ok(!lstrcmpW(&fmt_ls[1], out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4, "failed: r=%d\n", r); + /* S is ansi */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!S!", 0, 0, out, ARRAY_SIZE(out), "test"); + ok(!lstrcmpW(L"test", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4, "failed: r=%ld\n", r); - /* nor S */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_S, 0, - 0, out, sizeof(out)/sizeof(WCHAR), test); - ok(!lstrcmpW(&fmt_S[1], out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==3, "failed: r=%d\n", r); - - /* nor ws */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_ws, 0, - 0, out, sizeof(out)/sizeof(WCHAR), test); - ok(!lstrcmpW(&fmt_ws[1], out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4, "failed: r=%d\n", r); + /* ws is unicode */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!ws!", 0, 0, out, ARRAY_SIZE(out), L"test"); + ok(!lstrcmpW(L"test", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4, "failed: r=%ld\n", r); /* as characters */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_123c, 0, - 0, out, sizeof(out)/sizeof(WCHAR), 't', 'e', 's'); - ok(!lstrcmpW(test, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!c!%2!c!%3!c!%1!c!", 0, 0, out, ARRAY_SIZE(out), 't', 'e', 's'); + ok(!lstrcmpW(L"test", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%ld\n", r); /* lc is unicode */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_123lc, 0, - 0, out, sizeof(out)/sizeof(WCHAR), 't', 'e', 's'); - ok(!lstrcmpW(test, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!lc!%2!lc!%3!lc!%1!lc!", 0, 0, out, ARRAY_SIZE(out), 't', 'e', 's'); + ok(!lstrcmpW(L"test", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%ld\n", r); /* wc is unicode */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_123wc, 0, - 0, out, sizeof(out)/sizeof(WCHAR), 't', 'e', 's'); - ok(!lstrcmpW(test, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!wc!%2!wc!%3!wc!%1!wc!", 0, 0, out, ARRAY_SIZE(out), 't', 'e', 's'); + ok(!lstrcmpW(L"test", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%ld\n", r); /* C is unicode */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_123C, 0, - 0, out, sizeof(out)/sizeof(WCHAR), 't', 'e', 's'); - ok(!lstrcmpW(test, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!C!%2!C!%3!C!%1!C!", 0, 0, out, ARRAY_SIZE(out), 't', 'e', 's'); + ok(!lstrcmpW(L"test", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%ld\n", r); /* some numbers */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_123d, 0, - 0, out, sizeof(out)/sizeof(WCHAR), 1, 2, 3); - ok(!lstrcmpW(s_123d, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==3,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!d!%2!d!%3!d!", 0, 0, out, ARRAY_SIZE(out), 1, 2, 3); + ok(!lstrcmpW(L"123", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==3,"failed: r=%ld\n", r); /* a single digit with some spacing */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_14d, 0, - 0, out, sizeof(out)/sizeof(WCHAR), 1); - ok(!lstrcmpW(s_14d, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!4d!", 0, 0, out, ARRAY_SIZE(out), 1); + ok(!lstrcmpW(L" 1", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%ld\n", r); /* a single digit, left justified */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1_4d, 0, - 0, out, sizeof(out)/sizeof(CHAR), 1); - ok(!lstrcmpW(s_1_4d, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!-4d!", 0, 0, out, ARRAY_SIZE(out), 1); + ok(!lstrcmpW(L"1 ", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%ld\n", r); /* two digit decimal number */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_14d, 0, - 0, out, sizeof(out)/sizeof(WCHAR), 11); - ok(!lstrcmpW(s_14d2, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!4d!", 0, 0, out, ARRAY_SIZE(out), 11); + ok(!lstrcmpW(L" 11", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%ld\n", r); /* a hex number */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_14x, 0, - 0, out, sizeof(out)/sizeof(WCHAR), 11); - ok(!lstrcmpW(s_14x, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!4x!", 0, 0, out, ARRAY_SIZE(out), 11); + ok(!lstrcmpW(L" b", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%ld\n", r); /* a hex number, upper case */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_14X, 0, - 0, out, sizeof(out)/sizeof(WCHAR), 11); - ok(!lstrcmpW(s_14X, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!4X!", 0, 0, out, ARRAY_SIZE(out), 11); + ok(!lstrcmpW(L" B", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%ld\n", r); /* a hex number, upper case, left justified */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1_4X, 0, - 0, out, sizeof(out)/sizeof(WCHAR), 11); - ok(!lstrcmpW(s_1_4X, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!-4X!", 0, 0, out, ARRAY_SIZE(out), 11); + ok(!lstrcmpW(L"B ", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%ld\n", r); /* a long hex number, upper case */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_14X, 0, - 0, out, sizeof(out)/sizeof(WCHAR), 0x1ab); - ok(!lstrcmpW(s_1AB, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!4X!", 0, 0, out, ARRAY_SIZE(out), 0x1ab); + ok(!lstrcmpW(L" 1AB", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%ld\n", r); /* two percent... */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_2pct, 0, - 0, out, sizeof(out)/sizeof(WCHAR)); - ok(!lstrcmpW(s_2pct, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L" %%%% ", 0, 0, out, ARRAY_SIZE(out)); + ok(!lstrcmpW(L" %% ", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%ld\n", r); /* periods are special cases */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_2dot1d, 0, - 0, out, sizeof(out)/sizeof(WCHAR), 0x1ab); - ok(!lstrcmpW(s_2dot147, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==8,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L" %.%. %1!d!", 0, 0, out, ARRAY_SIZE(out), 0x1ab); + ok(!lstrcmpW(L" .. 427", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==8,"failed: r=%ld\n", r); /* %0 ends the line */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_t0t, 0, - 0, out, sizeof(out)/sizeof(WCHAR)); - ok(!lstrcmpW(test, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"test%0test", 0, 0, out, ARRAY_SIZE(out)); + ok(!lstrcmpW(L"test", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%ld\n", r); /* %! prints an exclamation */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_yah, 0, - 0, out, sizeof(out)/sizeof(WCHAR)); - ok(!lstrcmpW(s_yah, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"yah%!%0 ", 0, 0, out, ARRAY_SIZE(out)); + ok(!lstrcmpW(L"yah!", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%ld\n", r); /* %space */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_space, 0, - 0, out, sizeof(out)/sizeof(WCHAR)); - ok(!lstrcmpW(s_space, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"% % ", 0, 0, out, ARRAY_SIZE(out)); + ok(!lstrcmpW(L" ", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%ld\n", r); /* %n yields \r\n, %r yields \r, %t yields \t */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_nrt, 0, - 0, out, sizeof(out)/sizeof(WCHAR)); - ok(!lstrcmpW(s_nrt, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%n%r%t", 0, 0, out, ARRAY_SIZE(out)); + ok(!lstrcmpW(L"\r\n\r\t", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%ld\n", r); /* line feed */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_hi_lf, 0, - 0, out, sizeof(out)/sizeof(WCHAR)); - ok(!lstrcmpW(s_hi_crlf, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"hi\n", 0, 0, out, ARRAY_SIZE(out)); + ok(!lstrcmpW(L"hi\r\n", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%ld\n", r); /* carriage return line feed */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_hi_crlf, 0, - 0, out, sizeof(out)/sizeof(WCHAR)); - ok(!lstrcmpW(s_hi_crlf, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"hi\r\n", 0, 0, out, ARRAY_SIZE(out)); + ok(!lstrcmpW(L"hi\r\n", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%ld\n", r); /* carriage return */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_cr, 0, - 0, out, sizeof(out)/sizeof(WCHAR)); - ok(!lstrcmpW(s_crlf, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==2,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"\r", 0, 0, out, ARRAY_SIZE(out)); + ok(!lstrcmpW(L"\r\n", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==2,"failed: r=%ld\n", r); /* double carriage return line feed */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_crcrlf, 0, - 0, out, sizeof(out)/sizeof(WCHAR)); - ok(!lstrcmpW(s_crlfcrlf, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==4,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"\r\r\n", 0, 0, out, ARRAY_SIZE(out)); + ok(!lstrcmpW(L"\r\n\r\n", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%ld\n", r); /* null string as argument */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1, 0, - 0, out, sizeof(out)/sizeof(WCHAR), NULL); - ok(!lstrcmpW(s_null, out),"failed out=[%s]\n", wine_dbgstr_w(out)); - ok(r==6,"failed: r=%d\n",r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1", 0, 0, out, ARRAY_SIZE(out), NULL); + ok(!lstrcmpW(L"(null)", out),"failed out=[%s]\n", wine_dbgstr_w(out)); + ok(r==6,"failed: r=%ld\n",r); /* precision and width */ - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_13s, - 0, 0, out, sizeof(out)/sizeof(WCHAR), t ); - ok(!lstrcmpW(s_spt, out),"failed out=[%s]\n", wine_dbgstr_w(out)); - ok(r==3, "failed: r=%d\n",r); - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1os, - 0, 0, out, sizeof(out)/sizeof(WCHAR), 4, t ); - ok(!lstrcmpW( s_sp3t, out),"failed out=[%s]\n", wine_dbgstr_w(out)); - ok(r==4,"failed: r=%d\n",r); - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_142u, - 0, 0, out, sizeof(out)/sizeof(WCHAR), 3 ); - ok(!lstrcmpW( s_sp03, out),"failed out=[%s]\n", wine_dbgstr_w(out)); - ok(r==4,"failed: r=%d\n",r); - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1oou, - 0, 0, out, sizeof(out)/sizeof(WCHAR), 5, 3, 1 ); - ok(!lstrcmpW( s_sp001, out),"failed out=[%s]\n", wine_dbgstr_w(out)); - ok(r==5,"failed: r=%d\n",r); - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1oou1oou, - 0, 0, out, sizeof(out)/sizeof(WCHAR), 5, 3, 1, 4, 2 ); - ok(!lstrcmpW( s_sp001002, out),"failed out=[%s]\n", wine_dbgstr_w(out)); - ok(r==11,"failed: r=%d\n",r); - r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1oou3oou, - 0, 0, out, sizeof(out)/sizeof(WCHAR), 5, 3, 1, 6, 4, 2 ); - ok(!lstrcmpW( s_sp001sp002, out) || - broken(!lstrcmpW(s_sp001004, out)), /* NT4/Win2k */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!3s!", 0, 0, out, ARRAY_SIZE(out), L"t" ); + ok(!lstrcmpW(L" t", out),"failed out=[%s]\n", wine_dbgstr_w(out)); + ok(r==3, "failed: r=%ld\n",r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!*s!", 0, 0, out, ARRAY_SIZE(out), 4, L"t" ); + ok(!lstrcmpW( L" t", out),"failed out=[%s]\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%ld\n",r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!4.2u!", 0, 0, out, ARRAY_SIZE(out), 3 ); + ok(!lstrcmpW( L" 03", out),"failed out=[%s]\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%ld\n",r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!*.*u!", 0, 0, out, ARRAY_SIZE(out), 5, 3, 1 ); + ok(!lstrcmpW( L" 001", out),"failed out=[%s]\n", wine_dbgstr_w(out)); + ok(r==5,"failed: r=%ld\n",r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!*.*u!,%1!*.*u!", 0, 0, out, ARRAY_SIZE(out), + 5, 3, 1, 4, 2 ); + ok(!lstrcmpW( L" 001, 0002", out),"failed out=[%s]\n", wine_dbgstr_w(out)); + ok(r==11,"failed: r=%ld\n",r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!*.*u!,%3!*.*u!", 0, 0, out, ARRAY_SIZE(out), + 5, 3, 1, 6, 4, 2 ); + ok(!lstrcmpW( L" 001, 0002", out) || + broken(!lstrcmpW(L" 001,000004", out)), /* NT4/Win2k */ "failed out=[%s]\n", wine_dbgstr_w(out)); - ok(r==12,"failed: r=%d\n",r); + ok(r==12,"failed: r=%ld\n",r); /* args are not counted the same way with an argument array */ { ULONG_PTR args[] = { 6, 4, 2, 5, 3, 1 }; - r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, fmt_1oou1oou, - 0, 0, out, sizeof(out)/sizeof(WCHAR), (__ms_va_list *)args ); - ok(!lstrcmpW(s_sp002sp003, out),"failed out=[%s]\n", wine_dbgstr_w(out)); - ok(r==13,"failed: r=%d\n",r); - r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, fmt_1oou4oou, - 0, 0, out, sizeof(out)/sizeof(WCHAR), (__ms_va_list *)args ); - ok(!lstrcmpW(s_sp002sp001, out),"failed out=[%s]\n", wine_dbgstr_w(out)); - ok(r==12,"failed: r=%d\n",r); + r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, L"%1!*.*u!,%1!*.*u!", + 0, 0, out, ARRAY_SIZE(out), (va_list *)args ); + ok(!lstrcmpW(L" 0002, 00003", out),"failed out=[%s]\n", wine_dbgstr_w(out)); + ok(r==13,"failed: r=%ld\n",r); + r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, L"%1!*.*u!,%4!*.*u!", + 0, 0, out, ARRAY_SIZE(out), (va_list *)args ); + ok(!lstrcmpW(L" 0002, 001", out),"failed out=[%s]\n", wine_dbgstr_w(out)); + ok(r==12,"failed: r=%ld\n",r); } /* change of pace... test the low byte of dwflags */ /* line feed */ - r = doitW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, fmt_hi_lf, 0, - 0, out, sizeof(out)/sizeof(WCHAR)); - ok(!lstrcmpW(s_hi_sp, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==3,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, L"hi\n", 0, + 0, out, ARRAY_SIZE(out)); + ok(!lstrcmpW(L"hi ", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==3,"failed: r=%ld\n", r); /* carriage return line feed */ - r = doitW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, fmt_hi_crlf, 0, - 0, out, sizeof(out)/sizeof(WCHAR)); - ok(!lstrcmpW(s_hi_sp, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==3,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, L"hi\r\n", 0, + 0, out, ARRAY_SIZE(out)); + ok(!lstrcmpW(L"hi ", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==3,"failed: r=%ld\n", r); /* carriage return */ - r = doitW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, fmt_cr, 0, - 0, out, sizeof(out)/sizeof(WCHAR)); - ok(!lstrcmpW(s_sp, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==1,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, L"\r", 0, + 0, out, ARRAY_SIZE(out)); + ok(!lstrcmpW(L" ", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==1,"failed: r=%ld\n", r); /* double carriage return line feed */ - r = doitW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, fmt_crcrlf, 0, - 0, out, sizeof(out)/sizeof(WCHAR)); - ok(!lstrcmpW(s_2sp, out), "failed out=%s\n", wine_dbgstr_w(out)); - ok(r==2,"failed: r=%d\n", r); + r = doitW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, L"\r\r\n", 0, + 0, out, ARRAY_SIZE(out)); + ok(!lstrcmpW(L" ", out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==2,"failed: r=%ld\n", r); } static void test_message_from_string(void) @@ -463,283 +338,249 @@ static void test_message_from_string(void) CHAR out[0x100] = {0}; DWORD r; static const char init_buf[] = {'x', 'x', 'x', 'x', 'x', 'x'}; - static const WCHAR szwTest[] = { 't','e','s','t',0}; /* the basics */ - r = FormatMessageA(FORMAT_MESSAGE_FROM_STRING, "test", 0, - 0, out, sizeof(out)/sizeof(CHAR),NULL); + r = FormatMessageA(FORMAT_MESSAGE_FROM_STRING, "test", 0, 0, out, ARRAY_SIZE(out),NULL); ok(!strcmp("test", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* null string, crashes on Windows */ if (0) { SetLastError(0xdeadbeef); memcpy(out, init_buf, sizeof(init_buf)); - FormatMessageA(FORMAT_MESSAGE_FROM_STRING, NULL, 0, - 0, out, sizeof(out)/sizeof(CHAR), NULL); + FormatMessageA(FORMAT_MESSAGE_FROM_STRING, NULL, 0, 0, out, ARRAY_SIZE(out), NULL); } /* empty string */ SetLastError(0xdeadbeef); memcpy(out, init_buf, sizeof(init_buf)); - r = FormatMessageA(FORMAT_MESSAGE_FROM_STRING, "", 0, - 0, out, sizeof(out)/sizeof(CHAR), NULL); + r = FormatMessageA(FORMAT_MESSAGE_FROM_STRING, "", 0, 0, out, ARRAY_SIZE(out), NULL); ok(!memcmp(out, init_buf, sizeof(init_buf)), "Expected the buffer to be untouched\n"); - ok(r==0, "succeeded: r=%d\n", r); - ok(GetLastError()==0xdeadbeef, - "last error %u\n", GetLastError()); + ok(r==0, "succeeded: r=%ld\n", r); + ok(GetLastError() == ERROR_NO_WORK_DONE || broken(GetLastError() == 0xdeadbeef), + "last error %lu\n", GetLastError()); /* format placeholder with no specifier */ SetLastError(0xdeadbeef); memcpy(out, init_buf, sizeof(init_buf)); - r = FormatMessageA(FORMAT_MESSAGE_FROM_STRING, "%", 0, - 0, out, sizeof(out)/sizeof(CHAR), NULL); + r = FormatMessageA(FORMAT_MESSAGE_FROM_STRING, "%", 0, 0, out, ARRAY_SIZE(out), NULL); ok(!memcmp(out, init_buf, sizeof(init_buf)), "Expected the buffer to be untouched\n"); - ok(r==0, "succeeded: r=%d\n", r); + ok(r==0, "succeeded: r=%ld\n", r); ok(GetLastError()==ERROR_INVALID_PARAMETER, - "last error %u\n", GetLastError()); + "last error %lu\n", GetLastError()); /* test string with format placeholder with no specifier */ SetLastError(0xdeadbeef); memcpy(out, init_buf, sizeof(init_buf)); - r = FormatMessageA(FORMAT_MESSAGE_FROM_STRING, "test%", 0, - 0, out, sizeof(out)/sizeof(CHAR), NULL); + r = FormatMessageA(FORMAT_MESSAGE_FROM_STRING, "test%", 0, 0, out, ARRAY_SIZE(out), NULL); ok(!memcmp(out, init_buf, sizeof(init_buf)), "Expected the buffer to be untouched\n"); - ok(r==0, "succeeded: r=%d\n", r); + ok(r==0, "succeeded: r=%ld\n", r); ok(GetLastError()==ERROR_INVALID_PARAMETER, - "last error %u\n", GetLastError()); + "last error %lu\n", GetLastError()); /* insertion with no variadic arguments */ SetLastError(0xdeadbeef); memcpy(out, init_buf, sizeof(init_buf)); - r = FormatMessageA(FORMAT_MESSAGE_FROM_STRING, "%1", 0, - 0, out, sizeof(out)/sizeof(CHAR), NULL); + r = FormatMessageA(FORMAT_MESSAGE_FROM_STRING, "%1", 0, 0, out, ARRAY_SIZE(out), NULL); ok(!memcmp(out, init_buf, sizeof(init_buf)), "Expected the buffer to be untouched\n"); - ok(r==0, "succeeded: r=%d\n", r); - ok(GetLastError()==ERROR_INVALID_PARAMETER, "last error %u\n", GetLastError()); + ok(r==0, "succeeded: r=%ld\n", r); + ok(GetLastError()==ERROR_INVALID_PARAMETER, "last error %lu\n", GetLastError()); SetLastError(0xdeadbeef); memcpy(out, init_buf, sizeof(init_buf)); r = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, "%1", 0, - 0, out, sizeof(out)/sizeof(CHAR), NULL); + 0, out, ARRAY_SIZE(out), NULL); ok(!memcmp(out, init_buf, sizeof(init_buf)), "Expected the buffer to be untouched\n"); - ok(r==0, "succeeded: r=%d\n", r); - ok(GetLastError()==ERROR_INVALID_PARAMETER, "last error %u\n", GetLastError()); + ok(r==0, "succeeded: r=%ld\n", r); + ok(GetLastError()==ERROR_INVALID_PARAMETER, "last error %lu\n", GetLastError()); /* using the format feature */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!s!", 0, - 0, out, sizeof(out)/sizeof(CHAR), "test"); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!s!", 0, 0, out, ARRAY_SIZE(out), "test"); ok(!strcmp("test", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* no format */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "%1", 0, - 0, out, sizeof(out)/sizeof(CHAR), "test"); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1", 0, 0, out, ARRAY_SIZE(out), "test"); ok(!strcmp("test", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* two pieces */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "%1%2", 0, - 0, out, sizeof(out)/sizeof(CHAR), "te","st"); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1%2", 0, 0, out, ARRAY_SIZE(out), "te","st"); ok(!strcmp("test", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* three pieces */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "%1%3%2%1", 0, - 0, out, sizeof(out)/sizeof(CHAR), "t","s","e"); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1%3%2%1", 0, 0, out, ARRAY_SIZE(out), "t","s","e"); ok(!strcmp("test", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); - /* s doesn't seem to work in format strings */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "%!s!", 0, - 0, out, sizeof(out)/sizeof(CHAR), "test"); - ok(!strcmp("!s!", out),"failed out=[%s]\n",out); - ok(r==3,"failed: r=%d\n",r); + /* s is ansi */ + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!s!", 0, 0, out, ARRAY_SIZE(out), "test"); + ok(!strcmp("test", out),"failed out=[%s]\n",out); + ok(r==4,"failed: r=%ld\n",r); /* ls is unicode */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!ls!", 0, - 0, out, sizeof(out)/sizeof(CHAR), szwTest); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!ls!", 0, 0, out, ARRAY_SIZE(out), L"test"); ok(!strcmp("test", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* S is unicode */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!S!", 0, - 0, out, sizeof(out)/sizeof(CHAR), szwTest); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!S!", 0, 0, out, ARRAY_SIZE(out), L"test"); ok(!strcmp("test", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* ws is unicode */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!ws!", 0, - 0, out, sizeof(out)/sizeof(CHAR), szwTest); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!ws!", 0, 0, out, ARRAY_SIZE(out), L"test"); ok(!strcmp("test", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* as characters */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!c!%2!c!%3!c!%1!c!", 0, - 0, out, sizeof(out)/sizeof(CHAR), 't','e','s'); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!c!%2!c!%3!c!%1!c!", 0, 0, out, ARRAY_SIZE(out), + 't','e','s'); ok(!strcmp("test", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* lc is unicode */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!lc!%2!lc!%3!lc!%1!lc!", 0, - 0, out, sizeof(out)/sizeof(CHAR), 't','e','s'); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!lc!%2!lc!%3!lc!%1!lc!", 0, 0, out, ARRAY_SIZE(out), + 't','e','s'); ok(!strcmp("test", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* wc is unicode */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!wc!%2!wc!%3!wc!%1!wc!", 0, - 0, out, sizeof(out)/sizeof(CHAR), 't','e','s'); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!wc!%2!wc!%3!wc!%1!wc!", 0, 0, out, ARRAY_SIZE(out), + 't','e','s'); ok(!strcmp("test", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* C is unicode */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!C!%2!C!%3!C!%1!C!", 0, - 0, out, sizeof(out)/sizeof(CHAR), 't','e','s'); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!C!%2!C!%3!C!%1!C!", 0, 0, out, ARRAY_SIZE(out), + 't','e','s'); ok(!strcmp("test", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* some numbers */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!d!%2!d!%3!d!", 0, - 0, out, sizeof(out)/sizeof(CHAR), 1,2,3); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!d!%2!d!%3!d!", 0, 0, out, ARRAY_SIZE(out), 1,2,3); ok(!strcmp("123", out),"failed out=[%s]\n",out); - ok(r==3,"failed: r=%d\n",r); + ok(r==3,"failed: r=%ld\n",r); /* a single digit with some spacing */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!4d!", 0, - 0, out, sizeof(out)/sizeof(CHAR), 1); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!4d!", 0, 0, out, ARRAY_SIZE(out), 1); ok(!strcmp(" 1", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* a single digit, left justified */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!-4d!", 0, - 0, out, sizeof(out)/sizeof(CHAR), 1); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!-4d!", 0, 0, out, ARRAY_SIZE(out), 1); ok(!strcmp("1 ", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* two digit decimal number */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!4d!", 0, - 0, out, sizeof(out)/sizeof(CHAR), 11); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!4d!", 0, 0, out, ARRAY_SIZE(out), 11); ok(!strcmp(" 11", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* a hex number */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!4x!", 0, - 0, out, sizeof(out)/sizeof(CHAR), 11); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!4x!", 0, 0, out, ARRAY_SIZE(out), 11); ok(!strcmp(" b", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* a hex number, upper case */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!4X!", 0, - 0, out, sizeof(out)/sizeof(CHAR), 11); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!4X!", 0, 0, out, ARRAY_SIZE(out), 11); ok(!strcmp(" B", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* a hex number, upper case, left justified */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!-4X!", 0, - 0, out, sizeof(out)/sizeof(CHAR), 11); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!-4X!", 0, 0, out, ARRAY_SIZE(out), 11); ok(!strcmp("B ", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* a long hex number, upper case */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!4X!", 0, - 0, out, sizeof(out)/sizeof(CHAR), 0x1ab); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!4X!", 0, 0, out, ARRAY_SIZE(out), 0x1ab); ok(!strcmp(" 1AB", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* two percent... */ - r = doit(FORMAT_MESSAGE_FROM_STRING, " %%%% ", 0, - 0, out, sizeof(out)/sizeof(CHAR)); + r = doit(FORMAT_MESSAGE_FROM_STRING, " %%%% ", 0, 0, out, ARRAY_SIZE(out)); ok(!strcmp(" %% ", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* periods are special cases */ - r = doit(FORMAT_MESSAGE_FROM_STRING, " %.%. %1!d!", 0, - 0, out, sizeof(out)/sizeof(CHAR), 0x1ab); + r = doit(FORMAT_MESSAGE_FROM_STRING, " %.%. %1!d!", 0, 0, out, ARRAY_SIZE(out), 0x1ab); ok(!strcmp(" .. 427", out),"failed out=[%s]\n",out); - ok(r==7,"failed: r=%d\n",r); + ok(r==7,"failed: r=%ld\n",r); /* %0 ends the line */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "test%0test", 0, - 0, out, sizeof(out)/sizeof(CHAR)); + r = doit(FORMAT_MESSAGE_FROM_STRING, "test%0test", 0, 0, out, ARRAY_SIZE(out)); ok(!strcmp("test", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* %! prints an exclamation */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "yah%!%0 ", 0, - 0, out, sizeof(out)/sizeof(CHAR)); + r = doit(FORMAT_MESSAGE_FROM_STRING, "yah%!%0 ", 0, 0, out, ARRAY_SIZE(out)); ok(!strcmp("yah!", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* %space */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "% % ", 0, - 0, out, sizeof(out)/sizeof(CHAR)); + r = doit(FORMAT_MESSAGE_FROM_STRING, "% % ", 0, 0, out, ARRAY_SIZE(out)); ok(!strcmp(" ", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* %n yields \r\n, %r yields \r, %t yields \t */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "%n%r%t", 0, - 0, out, sizeof(out)/sizeof(CHAR)); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%n%r%t", 0, 0, out, ARRAY_SIZE(out)); ok(!strcmp("\r\n\r\t", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* line feed */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "hi\n", 0, - 0, out, sizeof(out)/sizeof(CHAR)); + r = doit(FORMAT_MESSAGE_FROM_STRING, "hi\n", 0, 0, out, ARRAY_SIZE(out)); ok(!strcmp("hi\r\n", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* carriage return line feed */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "hi\r\n", 0, - 0, out, sizeof(out)/sizeof(CHAR)); + r = doit(FORMAT_MESSAGE_FROM_STRING, "hi\r\n", 0, 0, out, ARRAY_SIZE(out)); ok(!strcmp("hi\r\n", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* carriage return */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "\r", 0, - 0, out, sizeof(out)/sizeof(CHAR)); + r = doit(FORMAT_MESSAGE_FROM_STRING, "\r", 0, 0, out, ARRAY_SIZE(out)); ok(!strcmp("\r\n", out),"failed out=[%s]\n",out); - ok(r==2,"failed: r=%d\n",r); + ok(r==2,"failed: r=%ld\n",r); /* double carriage return line feed */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "\r\r\n", 0, - 0, out, sizeof(out)/sizeof(CHAR)); + r = doit(FORMAT_MESSAGE_FROM_STRING, "\r\r\n", 0, 0, out, ARRAY_SIZE(out)); ok(!strcmp("\r\n\r\n", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); /* null string as argument */ - r = doit(FORMAT_MESSAGE_FROM_STRING, "%1", 0, - 0, out, sizeof(out)/sizeof(CHAR), NULL); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1", 0, 0, out, ARRAY_SIZE(out), NULL); ok(!strcmp("(null)", out),"failed out=[%s]\n",out); - ok(r==6,"failed: r=%d\n",r); + ok(r==6,"failed: r=%ld\n",r); /* precision and width */ r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!3s!", 0, 0, out, sizeof(out), "t" ); ok(!strcmp(" t", out),"failed out=[%s]\n",out); - ok(r==3, "failed: r=%d\n",r); + ok(r==3, "failed: r=%ld\n",r); r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!*s!", 0, 0, out, sizeof(out), 4, "t"); if (!strcmp("*s",out)) win_skip( "width/precision not supported\n" ); else { ok(!strcmp( " t", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!4.2u!", 0, 0, out, sizeof(out), 3 ); ok(!strcmp( " 03", out),"failed out=[%s]\n",out); - ok(r==4,"failed: r=%d\n",r); + ok(r==4,"failed: r=%ld\n",r); r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!*.*u!", 0, 0, out, sizeof(out), 5, 3, 1 ); ok(!strcmp( " 001", out),"failed out=[%s]\n",out); - ok(r==5,"failed: r=%d\n",r); + ok(r==5,"failed: r=%ld\n",r); r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!*.*u!,%1!*.*u!", 0, 0, out, sizeof(out), 5, 3, 1, 4, 2 ); ok(!strcmp( " 001, 0002", out),"failed out=[%s]\n",out); - ok(r==11,"failed: r=%d\n",r); + ok(r==11,"failed: r=%ld\n",r); r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!*.*u!,%3!*.*u!", 0, 0, out, sizeof(out), 5, 3, 1, 6, 4, 2 ); /* older Win versions marked as broken even though this is arguably the correct behavior */ @@ -747,18 +588,18 @@ static void test_message_from_string(void) ok(!strcmp( " 001, 0002", out) || broken(!strcmp(" 001,000004", out)), /* NT4/Win2k */ "failed out=[%s]\n",out); - ok(r==12,"failed: r=%d\n",r); + ok(r==12,"failed: r=%ld\n",r); /* args are not counted the same way with an argument array */ { ULONG_PTR args[] = { 6, 4, 2, 5, 3, 1 }; r = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, - "%1!*.*u!,%1!*.*u!", 0, 0, out, sizeof(out), (__ms_va_list *)args ); + "%1!*.*u!,%1!*.*u!", 0, 0, out, sizeof(out), (va_list *)args ); ok(!strcmp(" 0002, 00003", out),"failed out=[%s]\n",out); - ok(r==13,"failed: r=%d\n",r); + ok(r==13,"failed: r=%ld\n",r); r = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, - "%1!*.*u!,%4!*.*u!", 0, 0, out, sizeof(out), (__ms_va_list *)args ); + "%1!*.*u!,%4!*.*u!", 0, 0, out, sizeof(out), (va_list *)args ); ok(!strcmp(" 0002, 001", out),"failed out=[%s]\n",out); - ok(r==12,"failed: r=%d\n",r); + ok(r==12,"failed: r=%ld\n",r); } } @@ -766,27 +607,27 @@ static void test_message_from_string(void) /* line feed */ r = doit(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, "hi\n", 0, - 0, out, sizeof(out)/sizeof(CHAR)); + 0, out, ARRAY_SIZE(out)); ok(!strcmp("hi ", out), "failed out=[%s]\n",out); - ok(r==3, "failed: r=%d\n",r); + ok(r==3, "failed: r=%ld\n",r); /* carriage return line feed */ r = doit(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, "hi\r\n", 0, - 0, out, sizeof(out)/sizeof(CHAR)); + 0, out, ARRAY_SIZE(out)); ok(!strcmp("hi ", out),"failed out=[%s]\n",out); - ok(r==3,"failed: r=%d\n",r); + ok(r==3,"failed: r=%ld\n",r); /* carriage return */ r = doit(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, "\r", 0, - 0, out, sizeof(out)/sizeof(CHAR)); + 0, out, ARRAY_SIZE(out)); ok(!strcmp(" ", out),"failed out=[%s]\n",out); - ok(r==1,"failed: r=%d\n",r); + ok(r==1,"failed: r=%ld\n",r); /* double carriage return line feed */ r = doit(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, "\r\r\n", 0, - 0, out, sizeof(out)/sizeof(CHAR)); + 0, out, ARRAY_SIZE(out)); ok(!strcmp(" ", out),"failed out=[%s]\n",out); - ok(r==2,"failed: r=%d\n",r); + ok(r==2,"failed: r=%ld\n",r); } static void test_message_ignore_inserts(void) @@ -797,206 +638,182 @@ static void test_message_ignore_inserts(void) CHAR out[256]; ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, "test", 0, 0, out, - sizeof(out)/sizeof(CHAR), NULL); - ok(ret == 4, "Expected FormatMessageA to return 4, got %d\n", ret); + ARRAY_SIZE(out), NULL); + ok(ret == 4, "Expected FormatMessageA to return 4, got %ld\n", ret); ok(!strcmp("test", out), "Expected output string \"test\", got %s\n", out); /* The %0 escape sequence is handled. */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, "test%0", 0, 0, out, - sizeof(out)/sizeof(CHAR), NULL); - ok(ret == 4, "Expected FormatMessageA to return 4, got %d\n", ret); + ARRAY_SIZE(out), NULL); + ok(ret == 4, "Expected FormatMessageA to return 4, got %ld\n", ret); ok(!strcmp("test", out), "Expected output string \"test\", got %s\n", out); ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, "test%0test", 0, 0, out, - sizeof(out)/sizeof(CHAR), NULL); - ok(ret == 4, "Expected FormatMessageA to return 4, got %d\n", ret); + ARRAY_SIZE(out), NULL); + ok(ret == 4, "Expected FormatMessageA to return 4, got %ld\n", ret); ok(!strcmp("test", out), "Expected output string \"test\", got %s\n", out); /* While FormatMessageA returns 0 in this case, no last error code is set. */ SetLastError(0xdeadbeef); memcpy(out, init_buf, sizeof(init_buf)); ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, "%0test", 0, 0, out, - sizeof(out)/sizeof(CHAR), NULL); - ok(ret == 0, "Expected FormatMessageA to return 0, got %d\n", ret); + ARRAY_SIZE(out), NULL); + ok(ret == 0, "Expected FormatMessageA to return 0, got %ld\n", ret); ok(!memcmp(out, init_buf, sizeof(init_buf)), "Expected the output buffer to be untouched\n"); - ok(GetLastError() == 0xdeadbeef, "Expected GetLastError() to return 0xdeadbeef, got %u\n", GetLastError()); + ok(GetLastError() == ERROR_NO_WORK_DONE || broken(GetLastError() == 0xdeadbeef), + "Expected GetLastError() to return ERROR_NO_WORK_DONE, got %lu\n", GetLastError()); /* Insert sequences are ignored. */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, "test%1%2!*.*s!%99", 0, 0, out, - sizeof(out)/sizeof(CHAR), NULL); - ok(ret == 17, "Expected FormatMessageA to return 17, got %d\n", ret); + ARRAY_SIZE(out), NULL); + ok(ret == 17, "Expected FormatMessageA to return 17, got %ld\n", ret); ok(!strcmp("test%1%2!*.*s!%99", out), "Expected output string \"test%%1%%2!*.*s!%%99\", got %s\n", out); /* Only the "%n", "%r", and "%t" escape sequences are processed. */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, "%%% %.%!", 0, 0, out, - sizeof(out)/sizeof(CHAR), NULL); - ok(ret == 8, "Expected FormatMessageA to return 8, got %d\n", ret); + ARRAY_SIZE(out), NULL); + ok(ret == 8, "Expected FormatMessageA to return 8, got %ld\n", ret); ok(!strcmp("%%% %.%!", out), "Expected output string \"%%%%%% %%.%%!\", got %s\n", out); ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, "%n%r%t", 0, 0, out, - sizeof(out)/sizeof(CHAR), NULL); - ok(ret == 4, "Expected FormatMessageA to return 4, got %d\n", ret); + ARRAY_SIZE(out), NULL); + ok(ret == 4, "Expected FormatMessageA to return 4, got %ld\n", ret); ok(!strcmp("\r\n\r\t", out), "Expected output string \"\\r\\n\\r\\t\", got %s\n", out); /* CRLF characters are processed normally. */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, "hi\n", 0, 0, out, - sizeof(out)/sizeof(CHAR), NULL); - ok(ret == 4, "Expected FormatMessageA to return 4, got %d\n", ret); + ARRAY_SIZE(out), NULL); + ok(ret == 4, "Expected FormatMessageA to return 4, got %ld\n", ret); ok(!strcmp("hi\r\n", out), "Expected output string \"hi\\r\\n\", got %s\n", out); ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, "hi\r\n", 0, 0, out, - sizeof(out)/sizeof(CHAR), NULL); - ok(ret == 4, "Expected FormatMessageA to return 4, got %d\n", ret); + ARRAY_SIZE(out), NULL); + ok(ret == 4, "Expected FormatMessageA to return 4, got %ld\n", ret); ok(!strcmp("hi\r\n", out), "Expected output string \"hi\\r\\n\", got %s\n", out); ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, "\r", 0, 0, out, - sizeof(out)/sizeof(CHAR), NULL); - ok(ret == 2, "Expected FormatMessageA to return 2, got %d\n", ret); + ARRAY_SIZE(out), NULL); + ok(ret == 2, "Expected FormatMessageA to return 2, got %ld\n", ret); ok(!strcmp("\r\n", out), "Expected output string \"\\r\\n\", got %s\n", out); ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, "\r\r\n", 0, 0, out, - sizeof(out)/sizeof(CHAR), NULL); - ok(ret == 4, "Expected FormatMessageA to return 4, got %d\n", ret); + ARRAY_SIZE(out), NULL); + ok(ret == 4, "Expected FormatMessageA to return 4, got %ld\n", ret); ok(!strcmp("\r\n\r\n", out), "Expected output string \"\\r\\n\\r\\n\", got %s\n", out); /* The width parameter is handled the same also. */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS | - FORMAT_MESSAGE_MAX_WIDTH_MASK, "hi\n", 0, 0, out, - sizeof(out)/sizeof(CHAR), NULL); + FORMAT_MESSAGE_MAX_WIDTH_MASK, "hi\n", 0, 0, out, ARRAY_SIZE(out), NULL); ok(!strcmp("hi ", out), "Expected output string \"hi \", got %s\n", out); - ok(ret == 3, "Expected FormatMessageA to return 3, got %d\n", ret); + ok(ret == 3, "Expected FormatMessageA to return 3, got %ld\n", ret); ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS | - FORMAT_MESSAGE_MAX_WIDTH_MASK, "hi\r\n", 0, 0, out, - sizeof(out)/sizeof(CHAR), NULL); - ok(ret == 3, "Expected FormatMessageA to return 3, got %d\n", ret); + FORMAT_MESSAGE_MAX_WIDTH_MASK, "hi\r\n", 0, 0, out, ARRAY_SIZE(out), NULL); + ok(ret == 3, "Expected FormatMessageA to return 3, got %ld\n", ret); ok(!strcmp("hi ", out), "Expected output string \"hi \", got %s\n", out); ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS | - FORMAT_MESSAGE_MAX_WIDTH_MASK, "\r", 0, 0, out, - sizeof(out)/sizeof(CHAR), NULL); - ok(ret == 1, "Expected FormatMessageA to return 1, got %d\n", ret); + FORMAT_MESSAGE_MAX_WIDTH_MASK, "\r", 0, 0, out, ARRAY_SIZE(out), NULL); + ok(ret == 1, "Expected FormatMessageA to return 1, got %ld\n", ret); ok(!strcmp(" ", out), "Expected output string \" \", got %s\n", out); ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS | - FORMAT_MESSAGE_MAX_WIDTH_MASK, "\r\r\n", 0, 0, out, - sizeof(out)/sizeof(CHAR), NULL); - ok(ret == 2, "Expected FormatMessageA to return 2, got %d\n", ret); + FORMAT_MESSAGE_MAX_WIDTH_MASK, "\r\r\n", 0, 0, out, ARRAY_SIZE(out), NULL); + ok(ret == 2, "Expected FormatMessageA to return 2, got %ld\n", ret); ok(!strcmp(" ", out), "Expected output string \" \", got %s\n", out); } static void test_message_ignore_inserts_wide(void) { - static const WCHAR test[] = {'t','e','s','t',0}; - static const WCHAR empty[] = {0}; - static const WCHAR fmt_t0[] = {'t','e','s','t','%','0',0}; - static const WCHAR fmt_t0t[] = {'t','e','s','t','%','0','t','e','s','t',0}; - static const WCHAR fmt_0t[] = {'%','0','t','e','s','t',0}; - static const WCHAR fmt_t12oos99[] = {'t','e','s','t','%','1','%','2','!','*','.','*','s','!','%','9','9',0}; - static const WCHAR fmt_pctspacedot[] = {'%','%','%',' ','%','.','%','!',0}; - static const WCHAR fmt_nrt[] = {'%','n','%','r','%','t',0}; - static const WCHAR fmt_hi_lf[] = {'h','i','\n',0}; - static const WCHAR fmt_hi_crlf[] = {'h','i','\r','\n',0}; - static const WCHAR fmt_cr[] = {'\r',0}; - static const WCHAR fmt_crcrlf[] = {'\r','\r','\n',0}; - - static const WCHAR s_nrt[] = {'\r','\n','\r','\t',0}; - static const WCHAR s_hi_crlf[] = {'h','i','\r','\n',0}; - static const WCHAR s_crlf[] = {'\r','\n',0}; - static const WCHAR s_crlfcrlf[] = {'\r','\n','\r','\n',0}; - static const WCHAR s_hi_sp[] = {'h','i',' ',0}; - static const WCHAR s_sp[] = {' ',0}; - static const WCHAR s_2sp[] = {' ',' ',0}; - DWORD ret; WCHAR out[256]; - ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, test, 0, 0, out, - sizeof(out)/sizeof(WCHAR), NULL); - ok(ret == 4, "Expected FormatMessageW to return 4, got %d\n", ret); - ok(!lstrcmpW(test, out), "Expected output string \"test\", got %s\n", wine_dbgstr_w(out)); + ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, L"test", 0, 0, out, + ARRAY_SIZE(out), NULL); + ok(ret == 4, "Expected FormatMessageW to return 4, got %ld\n", ret); + ok(!lstrcmpW(L"test", out), "Expected output string \"test\", got %s\n", wine_dbgstr_w(out)); /* The %0 escape sequence is handled. */ - ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, fmt_t0, 0, 0, out, - sizeof(out)/sizeof(WCHAR), NULL); - ok(ret == 4, "Expected FormatMessageW to return 4, got %d\n", ret); - ok(!lstrcmpW(test, out), "Expected output string \"test\", got %s\n", wine_dbgstr_w(out)); + ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, L"test%0", 0, 0, out, + ARRAY_SIZE(out), NULL); + ok(ret == 4, "Expected FormatMessageW to return 4, got %ld\n", ret); + ok(!lstrcmpW(L"test", out), "Expected output string \"test\", got %s\n", wine_dbgstr_w(out)); - ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, fmt_t0t, 0, 0, out, - sizeof(out)/sizeof(WCHAR), NULL); - ok(ret == 4, "Expected FormatMessageW to return 4, got %d\n", ret); - ok(!lstrcmpW(test, out), "Expected output string \"test\", got %s\n", wine_dbgstr_w(out)); + ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, L"test%0test", 0, 0, out, + ARRAY_SIZE(out), NULL); + ok(ret == 4, "Expected FormatMessageW to return 4, got %ld\n", ret); + ok(!lstrcmpW(L"test", out), "Expected output string \"test\", got %s\n", wine_dbgstr_w(out)); /* While FormatMessageA returns 0 in this case, no last error code is set. */ SetLastError(0xdeadbeef); - ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, fmt_0t, 0, 0, out, - sizeof(out)/sizeof(WCHAR), NULL); - ok(ret == 0, "Expected FormatMessageW to return 0, got %d\n", ret); - ok(!lstrcmpW(empty, out), "Expected the output buffer to be the empty string, got %s\n", wine_dbgstr_w(out)); - ok(GetLastError() == 0xdeadbeef, "Expected GetLastError() to return 0xdeadbeef, got %u\n", GetLastError()); + ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, L"%0test", 0, 0, out, + ARRAY_SIZE(out), NULL); + ok(ret == 0, "Expected FormatMessageW to return 0, got %ld\n", ret); + ok(!lstrcmpW(L"", out), "Expected the output buffer to be the empty string, got %s\n", wine_dbgstr_w(out)); + ok(GetLastError() == ERROR_NO_WORK_DONE || broken(GetLastError() == 0xdeadbeef), + "Expected GetLastError() to return ERROR_NO_WORK_DONE, got %lu\n", GetLastError()); /* Insert sequences are ignored. */ - ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, fmt_t12oos99, 0, 0, out, - sizeof(out)/sizeof(WCHAR), NULL); - ok(ret == 17, "Expected FormatMessageW to return 17, got %d\n", ret); - ok(!lstrcmpW(fmt_t12oos99, out), "Expected output string \"test%%1%%2!*.*s!%%99\", got %s\n", wine_dbgstr_w(out)); + ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, L"test%1%2!*.*s!%99", 0, 0, out, + ARRAY_SIZE(out), NULL); + ok(ret == 17, "Expected FormatMessageW to return 17, got %ld\n", ret); + ok(!lstrcmpW(L"test%1%2!*.*s!%99", out), "Expected output string \"test%%1%%2!*.*s!%%99\", got %s\n", wine_dbgstr_w(out)); /* Only the "%n", "%r", and "%t" escape sequences are processed. */ - ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, fmt_pctspacedot, 0, 0, out, - sizeof(out)/sizeof(WCHAR), NULL); - ok(ret == 8, "Expected FormatMessageW to return 8, got %d\n", ret); - ok(!lstrcmpW(fmt_pctspacedot, out), "Expected output string \"%%%%%% %%.%%!\", got %s\n", wine_dbgstr_w(out)); + ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, L"%%% %.%!", 0, 0, out, + ARRAY_SIZE(out), NULL); + ok(ret == 8, "Expected FormatMessageW to return 8, got %ld\n", ret); + ok(!lstrcmpW(L"%%% %.%!", out), "Expected output string \"%%%%%% %%.%%!\", got %s\n", wine_dbgstr_w(out)); - ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, fmt_nrt, 0, 0, out, - sizeof(out)/sizeof(WCHAR), NULL); - ok(ret == 4, "Expected FormatMessageW to return 4, got %d\n", ret); - ok(!lstrcmpW(s_nrt, out), "Expected output string \"\\r\\n\\r\\t\", got %s\n", wine_dbgstr_w(out)); + ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, L"%n%r%t", 0, 0, out, + ARRAY_SIZE(out), NULL); + ok(ret == 4, "Expected FormatMessageW to return 4, got %ld\n", ret); + ok(!lstrcmpW(L"\r\n\r\t", out), "Expected output string \"\\r\\n\\r\\t\", got %s\n", wine_dbgstr_w(out)); /* CRLF characters are processed normally. */ - ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, fmt_hi_lf, 0, 0, out, - sizeof(out)/sizeof(WCHAR), NULL); - ok(ret == 4, "Expected FormatMessageW to return 4, got %d\n", ret); - ok(!lstrcmpW(s_hi_crlf, out), "Expected output string \"hi\\r\\n\", got %s\n", wine_dbgstr_w(out)); + ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, L"hi\n", 0, 0, out, + ARRAY_SIZE(out), NULL); + ok(ret == 4, "Expected FormatMessageW to return 4, got %ld\n", ret); + ok(!lstrcmpW(L"hi\r\n", out), "Expected output string \"hi\\r\\n\", got %s\n", wine_dbgstr_w(out)); - ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, fmt_hi_crlf, 0, 0, out, - sizeof(out)/sizeof(WCHAR), NULL); - ok(ret == 4, "Expected FormatMessageW to return 4, got %d\n", ret); - ok(!lstrcmpW(s_hi_crlf, out), "Expected output string \"hi\\r\\n\", got %s\n", wine_dbgstr_w(out)); + ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, L"hi\r\n", 0, 0, out, + ARRAY_SIZE(out), NULL); + ok(ret == 4, "Expected FormatMessageW to return 4, got %ld\n", ret); + ok(!lstrcmpW(L"hi\r\n", out), "Expected output string \"hi\\r\\n\", got %s\n", wine_dbgstr_w(out)); - ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, fmt_cr, 0, 0, out, - sizeof(out)/sizeof(WCHAR), NULL); - ok(ret == 2, "Expected FormatMessageW to return 2, got %d\n", ret); - ok(!lstrcmpW(s_crlf, out), "Expected output string \"\\r\\n\", got %s\n", wine_dbgstr_w(out)); + ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, L"\r", 0, 0, out, + ARRAY_SIZE(out), NULL); + ok(ret == 2, "Expected FormatMessageW to return 2, got %ld\n", ret); + ok(!lstrcmpW(L"\r\n", out), "Expected output string \"\\r\\n\", got %s\n", wine_dbgstr_w(out)); - ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, fmt_crcrlf, 0, 0, out, - sizeof(out)/sizeof(WCHAR), NULL); - ok(ret == 4, "Expected FormatMessageW to return 4, got %d\n", ret); - ok(!lstrcmpW(s_crlfcrlf, out), "Expected output string \"\\r\\n\\r\\n\", got %s\n", wine_dbgstr_w(out)); + ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, L"\r\r\n", 0, 0, out, + ARRAY_SIZE(out), NULL); + ok(ret == 4, "Expected FormatMessageW to return 4, got %ld\n", ret); + ok(!lstrcmpW(L"\r\n\r\n", out), "Expected output string \"\\r\\n\\r\\n\", got %s\n", wine_dbgstr_w(out)); /* The width parameter is handled the same also. */ ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS | - FORMAT_MESSAGE_MAX_WIDTH_MASK, fmt_hi_lf, 0, 0, out, - sizeof(out)/sizeof(WCHAR), NULL); - ok(ret == 3, "Expected FormatMessageW to return 3, got %d\n", ret); - ok(!lstrcmpW(s_hi_sp, out), "Expected output string \"hi \", got %s\n", wine_dbgstr_w(out)); + FORMAT_MESSAGE_MAX_WIDTH_MASK, L"hi\n", 0, 0, out, + ARRAY_SIZE(out), NULL); + ok(ret == 3, "Expected FormatMessageW to return 3, got %ld\n", ret); + ok(!lstrcmpW(L"hi ", out), "Expected output string \"hi \", got %s\n", wine_dbgstr_w(out)); ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS | - FORMAT_MESSAGE_MAX_WIDTH_MASK, fmt_hi_crlf, 0, 0, out, - sizeof(out)/sizeof(WCHAR), NULL); - ok(ret == 3, "Expected FormatMessageW to return 3, got %d\n", ret); - ok(!lstrcmpW(s_hi_sp, out), "Expected output string \"hi \", got %s\n", wine_dbgstr_w(out)); + FORMAT_MESSAGE_MAX_WIDTH_MASK, L"hi\r\n", 0, 0, out, + ARRAY_SIZE(out), NULL); + ok(ret == 3, "Expected FormatMessageW to return 3, got %ld\n", ret); + ok(!lstrcmpW(L"hi ", out), "Expected output string \"hi \", got %s\n", wine_dbgstr_w(out)); ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS | - FORMAT_MESSAGE_MAX_WIDTH_MASK, fmt_cr, 0, 0, out, - sizeof(out)/sizeof(WCHAR), NULL); - ok(ret == 1, "Expected FormatMessageW to return 1, got %d\n", ret); - ok(!lstrcmpW(s_sp, out), "Expected output string \" \", got %s\n", wine_dbgstr_w(out)); + FORMAT_MESSAGE_MAX_WIDTH_MASK, L"\r", 0, 0, out, ARRAY_SIZE(out), NULL); + ok(ret == 1, "Expected FormatMessageW to return 1, got %ld\n", ret); + ok(!lstrcmpW(L" ", out), "Expected output string \" \", got %s\n", wine_dbgstr_w(out)); ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS | - FORMAT_MESSAGE_MAX_WIDTH_MASK, fmt_crcrlf, 0, 0, out, - sizeof(out)/sizeof(WCHAR), NULL); - ok(ret == 2, "Expected FormatMessageW to return 2, got %d\n", ret); - ok(!lstrcmpW(s_2sp, out), "Expected output string \" \", got %s\n", wine_dbgstr_w(out)); + FORMAT_MESSAGE_MAX_WIDTH_MASK, L"\r\r\n", 0, 0, out, + ARRAY_SIZE(out), NULL); + ok(ret == 2, "Expected FormatMessageW to return 2, got %ld\n", ret); + ok(!lstrcmpW(L" ", out), "Expected output string \" \", got %s\n", wine_dbgstr_w(out)); } static void test_message_wrap(void) @@ -1008,134 +825,134 @@ static void test_message_wrap(void) /* No need for wrapping */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 20, "short long line", 0, 0, out, sizeof(out), NULL); - ok(ret == 15, "Expected FormatMessageW to return 15, got %d\n", ret); + ok(ret == 15, "Expected FormatMessageW to return 15, got %ld\n", ret); ok(!strcmp("short long line", out),"failed out=[%s]\n",out); /* Wrap the last word */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 11, "short long line", 0, 0, out, sizeof(out), NULL); - ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret); + ok(ret == 16, "Expected FormatMessageW to return 16, got %ld\n", ret); ok(!strcmp("short long\r\nline", out),"failed out=[%s]\n",out); /* Wrap the very last word */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 20, "short long long line", 0, 0, out, sizeof(out), NULL); - ok(ret == 21, "Expected FormatMessageW to return 21, got %d\n", ret); + ok(ret == 21, "Expected FormatMessageW to return 21, got %ld\n", ret); ok(!strcmp("short long long\r\nline", out),"failed out=[%s]\n",out); /* Strictly less than 10 characters per line! */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 10, "short long line", 0, 0, out, sizeof(out), NULL); - ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret); + ok(ret == 16, "Expected FormatMessageW to return 16, got %ld\n", ret); ok(!strcmp("short\r\nlong line", out),"failed out=[%s]\n",out); /* Handling of duplicate spaces */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 16, "short long line", 0, 0, out, sizeof(out), NULL); - ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret); + ok(ret == 16, "Expected FormatMessageW to return 16, got %ld\n", ret); ok(!strcmp("short long\r\nline", out),"failed out=[%s]\n",out); ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 16, "short long wordlongerthanaline", 0, 0, out, sizeof(out), NULL); - ok(ret == 33, "Expected FormatMessageW to return 33, got %d\n", ret); + ok(ret == 33, "Expected FormatMessageW to return 33, got %ld\n", ret); ok(!strcmp("short long\r\nwordlongerthanal\r\nine", out),"failed out=[%s]\n",out); /* Breaking in the middle of spaces */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 12, "short long line", 0, 0, out, sizeof(out), NULL); - ok(ret == 18, "Expected FormatMessageW to return 18, got %d\n", ret); + ok(ret == 18, "Expected FormatMessageW to return 18, got %ld\n", ret); ok(!strcmp("short long\r\n line", out),"failed out=[%s]\n",out); ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 12, "short long wordlongerthanaline", 0, 0, out, sizeof(out), NULL); - ok(ret == 35, "Expected FormatMessageW to return 35, got %d\n", ret); + ok(ret == 35, "Expected FormatMessageW to return 35, got %ld\n", ret); ok(!strcmp("short long\r\n\r\nwordlongerth\r\nanaline", out),"failed out=[%s]\n",out); /* Handling of start-of-string spaces */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 15, " short line", 0, 0, out, sizeof(out), NULL); - ok(ret == 13, "Expected FormatMessageW to return 13, got %d\n", ret); + ok(ret == 13, "Expected FormatMessageW to return 13, got %ld\n", ret); ok(!strcmp(" short line", out),"failed out=[%s]\n",out); ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 11, " shortlong line", 0, 0, out, sizeof(out), NULL); - ok(ret == 17, "Expected FormatMessageW to return 17, got %d\n", ret); + ok(ret == 17, "Expected FormatMessageW to return 17, got %ld\n", ret); ok(!strcmp("\r\nshortlong\r\nline", out),"failed out=[%s]\n",out); /* Handling of start-of-line spaces */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 11, "l1%n shortlong line", 0, 0, out, sizeof(out), NULL); - ok(ret == 21, "Expected FormatMessageW to return 21, got %d\n", ret); + ok(ret == 21, "Expected FormatMessageW to return 21, got %ld\n", ret); ok(!strcmp("l1\r\n\r\nshortlong\r\nline", out),"failed out=[%s]\n",out); /* Pure space wrapping */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 5, " ", 0, 0, out, sizeof(out), NULL); - ok(ret == 7, "Expected FormatMessageW to return 7, got %d\n", ret); + ok(ret == 7, "Expected FormatMessageW to return 7, got %ld\n", ret); ok(!strcmp("\r\n\r\n\r\n ", out),"failed out=[%s]\n",out); /* Handling of trailing spaces */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 5, "l1 ", 0, 0, out, sizeof(out), NULL); - ok(ret == 10, "Expected FormatMessageW to return 10, got %d\n", ret); + ok(ret == 10, "Expected FormatMessageW to return 10, got %ld\n", ret); ok(!strcmp("l1\r\n\r\n\r\n ", out),"failed out=[%s]\n",out); /* Word that just fills the line */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 8, "shortlon", 0, 0, out, sizeof(out), NULL); - ok(ret == 10, "Expected FormatMessageW to return 10, got %d\n", ret); + ok(ret == 10, "Expected FormatMessageW to return 10, got %ld\n", ret); ok(!strcmp("shortlon\r\n", out),"failed out=[%s]\n",out); /* Word longer than the line */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 8, "shortlongline", 0, 0, out, sizeof(out), NULL); - ok(ret == 15, "Expected FormatMessageW to return 15, got %d\n", ret); + ok(ret == 15, "Expected FormatMessageW to return 15, got %ld\n", ret); ok(!strcmp("shortlon\r\ngline", out),"failed out=[%s]\n",out); /* Wrap the line multiple times */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 7, "short long line", 0, 0, out, sizeof(out), NULL); - ok(ret == 17, "Expected FormatMessageW to return 17, got %d\n", ret); + ok(ret == 17, "Expected FormatMessageW to return 17, got %ld\n", ret); ok(!strcmp("short\r\nlong\r\nline", out),"failed out=[%s]\n",out); /* '\n's in the source are ignored */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 11, "short\nlong line", 0, 0, out, sizeof(out), NULL); - ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret); + ok(ret == 16, "Expected FormatMessageW to return 16, got %ld\n", ret); ok(!strcmp("short long\r\nline", out),"failed out=[%s]\n",out); /* Wrap even before a '%n' */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 8, "shortlon%n", 0, 0, out, sizeof(out), NULL); - ok(ret == 12, "Expected FormatMessageW to return 12, got %d\n", ret); + ok(ret == 12, "Expected FormatMessageW to return 12, got %ld\n", ret); ok(!strcmp("shortlon\r\n\r\n", out),"failed out=[%s]\n",out); /* '%n's count as starting a new line and combine with line wrapping */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 10, "short%nlong line", 0, 0, out, sizeof(out), NULL); - ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret); + ok(ret == 16, "Expected FormatMessageW to return 16, got %ld\n", ret); ok(!strcmp("short\r\nlong line", out),"failed out=[%s]\n",out); ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 8, "short%nlong line", 0, 0, out, sizeof(out), NULL); - ok(ret == 17, "Expected FormatMessageW to return 17, got %d\n", ret); + ok(ret == 17, "Expected FormatMessageW to return 17, got %ld\n", ret); ok(!strcmp("short\r\nlong\r\nline", out),"failed out=[%s]\n",out); /* '%r's also count as starting a new line and all */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 10, "short%rlong line", 0, 0, out, sizeof(out), NULL); - ok(ret == 15, "Expected FormatMessageW to return 15, got %d\n", ret); + ok(ret == 15, "Expected FormatMessageW to return 15, got %ld\n", ret); ok(!strcmp("short\rlong line", out),"failed out=[%s]\n",out); ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 8, "short%rlong line", 0, 0, out, sizeof(out), NULL); - ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret); + ok(ret == 16, "Expected FormatMessageW to return 16, got %ld\n", ret); ok(!strcmp("short\rlong\r\nline", out),"failed out=[%s]\n",out); /* IGNORE_INSERTS does not prevent line wrapping or disable '%n' */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS | 8, "short%nlong line%1", 0, 0, out, sizeof(out), NULL); - ok(ret == 19, "Expected FormatMessageW to return 19, got %d\n", ret); + ok(ret == 19, "Expected FormatMessageW to return 19, got %ld\n", ret); ok(!strcmp("short\r\nlong\r\nline%1", out),"failed out=[%s]\n",out); /* MAX_WIDTH_MASK is the same as specifying an infinite line width */ @@ -1148,59 +965,82 @@ static void test_message_wrap(void) } ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, in, 0, 0, out, sizeof(out), NULL); - ok(ret == 272, "Expected FormatMessageW to return 272, got %d\n", ret); + ok(ret == 272, "Expected FormatMessageW to return 272, got %ld\n", ret); ok(!strcmp(ref, out),"failed out=[%s]\n",out); /* Wrapping and non-space characters */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 11, "short long\tline", 0, 0, out, sizeof(out), NULL); - ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret); + ok(ret == 16, "Expected FormatMessageW to return 16, got %ld\n", ret); ok(!strcmp("short\r\nlong\tline", out),"failed out=[%s]\n",out); ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 11, "short long-line", 0, 0, out, sizeof(out), NULL); - ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret); + ok(ret == 16, "Expected FormatMessageW to return 16, got %ld\n", ret); ok(!strcmp("short\r\nlong-line", out),"failed out=[%s]\n",out); ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 11, "short long_line", 0, 0, out, sizeof(out), NULL); - ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret); + ok(ret == 16, "Expected FormatMessageW to return 16, got %ld\n", ret); ok(!strcmp("short\r\nlong_line", out),"failed out=[%s]\n",out); ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 11, "short long.line", 0, 0, out, sizeof(out), NULL); - ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret); + ok(ret == 16, "Expected FormatMessageW to return 16, got %ld\n", ret); ok(!strcmp("short\r\nlong.line", out),"failed out=[%s]\n",out); ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 11, "short long,line", 0, 0, out, sizeof(out), NULL); - ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret); + ok(ret == 16, "Expected FormatMessageW to return 16, got %ld\n", ret); ok(!strcmp("short\r\nlong,line", out),"failed out=[%s]\n",out); ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 11, "short long!line", 0, 0, out, sizeof(out), NULL); - ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret); + ok(ret == 16, "Expected FormatMessageW to return 16, got %ld\n", ret); ok(!strcmp("short\r\nlong!line", out),"failed out=[%s]\n",out); ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | 11, "short long?line", 0, 0, out, sizeof(out), NULL); - ok(ret == 16, "Expected FormatMessageW to return 16, got %d\n", ret); + ok(ret == 16, "Expected FormatMessageW to return 16, got %ld\n", ret); ok(!strcmp("short\r\nlong?line", out),"failed out=[%s]\n",out); } +static void test_message_arg_eaten( const WCHAR *src, ... ) +{ + DWORD ret; + va_list list; + WCHAR *arg, out[1]; + + out[0] = 0xcccc; + va_start(list, src); + SetLastError(0xdeadbeef); + ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, src, 0, 0, out, ARRAY_SIZE(out), &list); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %lu\n", GetLastError()); + ok(ret == 0, "Expected FormatMessageW to return 0, got %lu\n", ret); + ok(out[0] == 0, "Expected null, got %ls\n", out); + arg = va_arg( list, WCHAR * ); +#ifdef __REACTOS__ + ok(!!arg, "arg should not be NULL!\n"); + if (arg) +#endif + ok(!wcscmp( L"unused", arg ), "Expected 'unused', got %s\n", wine_dbgstr_w(arg)); + va_end(list); +} + static void test_message_insufficient_buffer(void) { static const char init_buf[] = {'x', 'x', 'x', 'x', 'x'}; static const char expected_buf[] = {'x', 'x', 'x', 'x', 'x'}; - DWORD ret; + DWORD ret, size, i; CHAR out[5]; SetLastError(0xdeadbeef); memcpy(out, init_buf, sizeof(init_buf)); ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING, "test", 0, 0, out, 0, NULL); - ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret); + ok(ret == 0, "Expected FormatMessageA to return 0, got %lu\n", ret); ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %u\n", + "Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %lu\n", GetLastError()); ok(!memcmp(expected_buf, out, sizeof(expected_buf)), "Expected the buffer to be untouched\n"); @@ -1208,68 +1048,137 @@ static void test_message_insufficient_buffer(void) SetLastError(0xdeadbeef); memcpy(out, init_buf, sizeof(init_buf)); ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING, "test", 0, 0, out, 1, NULL); - ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret); + ok(ret == 0, "Expected FormatMessageA to return 0, got %lu\n", ret); ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %u\n", + "Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %lu\n", GetLastError()); ok(!memcmp(expected_buf, out, sizeof(expected_buf)), "Expected the buffer to be untouched\n"); SetLastError(0xdeadbeef); memcpy(out, init_buf, sizeof(init_buf)); - ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING, "test", 0, 0, out, sizeof(out)/sizeof(out[0]) - 1, NULL); - ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret); + ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING, "test", 0, 0, out, ARRAY_SIZE(out) - 1, NULL); + ok(ret == 0, "Expected FormatMessageA to return 0, got %lu\n", ret); ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %u\n", + "Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %lu\n", GetLastError()); ok(!memcmp(expected_buf, out, sizeof(expected_buf)), "Expected the buffer to be untouched\n"); + + for (size = 32700; size < 32800; size++) + { + char *tmp = HeapAlloc( GetProcessHeap(), 0, size ); + char *buf = HeapAlloc( GetProcessHeap(), 0, size ); + + for (i = 0; i < size; i++) tmp[i] = 'A' + i % 26; + tmp[size - 1] = 0; + SetLastError( 0xdeadbeef ); + ret = FormatMessageA( FORMAT_MESSAGE_FROM_STRING, tmp, 0, 0, buf, size, NULL ); + if (size < 32768) + { + ok( ret == size - 1, "%lu: got %lu\n", size, ret ); + ok( !strcmp( tmp, buf ), "wrong buffer\n" ); + } + else + { + ok( ret == 0, "%lu: got %lu\n", size, ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); + } + + SetLastError( 0xdeadbeef ); + ret = doit( FORMAT_MESSAGE_FROM_STRING, "%1", 0, 0, buf, size, tmp ); + if (size < 32768) + { + ok( ret == size - 1, "%lu: got %lu\n", size, ret ); + ok( !strcmp( tmp, buf ), "wrong buffer\n" ); + } + else + { + ok( ret == 0, "%lu: got %lu\n", size, ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == ERROR_MORE_DATA), /* winxp */ + "wrong error %lu\n", GetLastError() ); + } + HeapFree( GetProcessHeap(), 0, buf ); + + SetLastError( 0xdeadbeef ); + ret = FormatMessageA( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, + tmp, 0, 0, (char *)&buf, size, NULL ); + if (size < 32768) + { + ok( ret == size - 1, "%lu: got %lu\n", size, ret ); + ok( !strcmp( tmp, buf ), "wrong buffer\n" ); + HeapFree( GetProcessHeap(), 0, buf ); + } + else + { + ok( ret == 0, "%lu: got %lu\n", size, ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); + } + HeapFree( GetProcessHeap(), 0, tmp ); + } } static void test_message_insufficient_buffer_wide(void) { - static const WCHAR test[] = {'t','e','s','t',0}; - static const WCHAR init_buf[] = {'x', 'x', 'x', 'x', 'x'}; - static const WCHAR expected_buf[] = {'x', 'x', 'x', 'x', 'x'}; - static const WCHAR broken_buf[] = {0, 'x', 'x', 'x', 'x'}; - static const WCHAR broken2_buf[] = {'t','e','s',0,'x'}; - - DWORD ret; - WCHAR out[5]; + DWORD ret, size, i; + WCHAR out[8]; SetLastError(0xdeadbeef); - memcpy(out, init_buf, sizeof(init_buf)); - ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, test, 0, 0, out, 0, NULL); - ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret); + lstrcpyW( out, L"xxxxxx" ); + ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, L"test", 0, 0, out, 0, NULL); + ok(ret == 0, "Expected FormatMessageA to return 0, got %lu\n", ret); ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %u\n", + "Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %lu\n", GetLastError()); - ok(!memcmp(expected_buf, out, sizeof(expected_buf)), - "Expected the buffer to be untouched\n"); - - /* Windows Server 2003 and newer report failure but copy a - * truncated string to the buffer for non-zero buffer sizes. */ - SetLastError(0xdeadbeef); - memcpy(out, init_buf, sizeof(init_buf)); - ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, test, 0, 0, out, 1, NULL); - ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret); - ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %u\n", - GetLastError()); - ok(!memcmp(expected_buf, out, sizeof(expected_buf)) || - broken(!memcmp(broken_buf, out, sizeof(broken_buf))), /* W2K3+ */ + ok(!lstrcmpW( out, L"xxxxxx" ), "Expected the buffer to be untouched\n"); SetLastError(0xdeadbeef); - memcpy(out, init_buf, sizeof(init_buf)); - ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, test, 0, 0, out, sizeof(out)/sizeof(out[0]) - 1, NULL); - ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret); + lstrcpyW( out, L"xxxxxx" ); + ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, L"test", 0, 0, out, 1, NULL); + ok(ret == 0, "Expected FormatMessageA to return 0, got %lu\n", ret); ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %u\n", + "Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %lu\n", GetLastError()); - ok(!memcmp(expected_buf, out, sizeof(expected_buf)) || - broken(!memcmp(broken2_buf, out, sizeof(broken2_buf))), /* W2K3+ */ - "Expected the buffer to be untouched\n"); + ok(!memcmp(out, L"\0xxxxx", 6 * sizeof(WCHAR)) || + broken(!lstrcmpW( out, L"xxxxxx" )), /* winxp */ + "Expected the buffer to be truncated\n"); + + SetLastError(0xdeadbeef); + lstrcpyW( out, L"xxxxxx" ); + ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, L"test", 0, 0, out, 4, NULL); + ok(ret == 0, "Expected FormatMessageA to return 0, got %lu\n", ret); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %lu\n", + GetLastError()); + ok(!memcmp(out, L"tes\0xx", 6 * sizeof(WCHAR)) || + broken(!lstrcmpW( out, L"xxxxxx" )), /* winxp */ + "Expected the buffer to be truncated\n"); + + for (size = 1000; size < 1000000; size += size / 10) + { + WCHAR *tmp = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ); + WCHAR *buf = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ); + for (i = 0; i < size; i++) tmp[i] = 'A' + i % 26; + tmp[size - 1] = 0; + ret = FormatMessageW( FORMAT_MESSAGE_FROM_STRING, tmp, 0, 0, buf, size, NULL ); + ok(ret == size - 1 || broken(!ret), /* winxp */ "got %lu\n", ret); + if (!ret) break; + ok( !lstrcmpW( tmp, buf ), "wrong buffer\n" ); + ret = doitW( FORMAT_MESSAGE_FROM_STRING, L"%1", 0, 0, buf, size, tmp ); + ok(ret == size - 1, "got %lu\n", ret); + ok( !lstrcmpW( tmp, buf ), "wrong buffer\n" ); + HeapFree( GetProcessHeap(), 0, buf ); + ret = FormatMessageW( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, + tmp, 0, 0, (WCHAR *)&buf, size, NULL ); + ok(ret == size - 1, "got %lu\n", ret); + ok( !lstrcmpW( tmp, buf ), "wrong buffer\n" ); + HeapFree( GetProcessHeap(), 0, tmp ); + HeapFree( GetProcessHeap(), 0, buf ); + } + + /* va_arg is eaten even in case of insufficient buffer */ + test_message_arg_eaten( L"%1!s! %2!s!", L"eaten", L"unused" ); } static void test_message_null_buffer(void) @@ -1280,14 +1189,14 @@ static void test_message_null_buffer(void) SetLastError(0xdeadbeef); ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, 0, 0, NULL, 0, NULL); error = GetLastError(); - ok(!ret, "FormatMessageA returned %u\n", ret); - ok(error == ERROR_INSUFFICIENT_BUFFER, "last error %u\n", error); + ok(!ret, "FormatMessageA returned %lu\n", ret); + ok(error == ERROR_INSUFFICIENT_BUFFER, "last error %lu\n", error); SetLastError(0xdeadbeef); ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, 0, 0, NULL, 1, NULL); error = GetLastError(); - ok(!ret, "FormatMessageA returned %u\n", ret); - ok(error == ERROR_INSUFFICIENT_BUFFER, "last error %u\n", error); + ok(!ret, "FormatMessageA returned %lu\n", ret); + ok(error == ERROR_INSUFFICIENT_BUFFER, "last error %lu\n", error); if (0) /* crashes on Windows */ { @@ -1298,20 +1207,20 @@ static void test_message_null_buffer(void) SetLastError(0xdeadbeef); 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(!ret, "FormatMessageA returned %lu\n", ret); + ok(error == ERROR_NOT_ENOUGH_MEMORY, "last error %lu\n", error); SetLastError(0xdeadbeef); ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, 0, 0, NULL, 1, NULL); error = GetLastError(); - ok(!ret, "FormatMessageA returned %u\n", ret); - ok(error == ERROR_NOT_ENOUGH_MEMORY, "last error %u\n", error); + ok(!ret, "FormatMessageA returned %lu\n", ret); + ok(error == ERROR_NOT_ENOUGH_MEMORY, "last error %lu\n", error); SetLastError(0xdeadbeef); ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, 0, 0, NULL, 256, NULL); error = GetLastError(); - ok(!ret, "FormatMessageA returned %u\n", ret); - ok(error == ERROR_NOT_ENOUGH_MEMORY, "last error %u\n", error); + ok(!ret, "FormatMessageA returned %lu\n", ret); + ok(error == ERROR_NOT_ENOUGH_MEMORY, "last error %lu\n", error); } static void test_message_null_buffer_wide(void) @@ -1321,38 +1230,38 @@ static void test_message_null_buffer_wide(void) SetLastError(0xdeadbeef); ret = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, 0, 0, NULL, 0, NULL); error = GetLastError(); - ok(!ret, "FormatMessageW returned %u\n", ret); - ok(error == ERROR_INVALID_PARAMETER, "last error %u\n", error); + ok(!ret, "FormatMessageW returned %lu\n", ret); + ok(error == ERROR_INVALID_PARAMETER, "last error %lu\n", error); SetLastError(0xdeadbeef); ret = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, 0, 0, NULL, 1, NULL); error = GetLastError(); - ok(!ret, "FormatMessageW returned %u\n", ret); - ok(error == ERROR_INVALID_PARAMETER, "last error %u\n", error); + ok(!ret, "FormatMessageW returned %lu\n", ret); + ok(error == ERROR_INVALID_PARAMETER, "last error %lu\n", error); SetLastError(0xdeadbeef); ret = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, 0, 0, NULL, 256, NULL); error = GetLastError(); - ok(!ret, "FormatMessageW returned %u\n", ret); - ok(error == ERROR_INVALID_PARAMETER, "last error %u\n", error); + ok(!ret, "FormatMessageW returned %lu\n", ret); + ok(error == ERROR_INVALID_PARAMETER, "last error %lu\n", error); SetLastError(0xdeadbeef); ret = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, 0, 0, NULL, 0, NULL); error = GetLastError(); - ok(!ret, "FormatMessageW returned %u\n", ret); - ok(error == ERROR_INVALID_PARAMETER, "last error %u\n", error); + ok(!ret, "FormatMessageW returned %lu\n", ret); + ok(error == ERROR_INVALID_PARAMETER, "last error %lu\n", error); SetLastError(0xdeadbeef); ret = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, 0, 0, NULL, 1, NULL); error = GetLastError(); - ok(!ret, "FormatMessageW returned %u\n", ret); - ok(error == ERROR_INVALID_PARAMETER, "last error %u\n", error); + ok(!ret, "FormatMessageW returned %lu\n", ret); + ok(error == ERROR_INVALID_PARAMETER, "last error %lu\n", error); SetLastError(0xdeadbeef); ret = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, 0, 0, NULL, 256, NULL); error = GetLastError(); - ok(!ret, "FormatMessageW returned %u\n", ret); - ok(error == ERROR_INVALID_PARAMETER, "last error %u\n", error); + ok(!ret, "FormatMessageW returned %lu\n", ret); + ok(error == ERROR_INVALID_PARAMETER, "last error %lu\n", error); } static void test_message_allocate_buffer(void) @@ -1371,15 +1280,15 @@ static void test_message_allocate_buffer(void) buf = (char *)0xdeadbeef; ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, "", 0, 0, (char *)&buf, 0, NULL); - ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret); + ok(ret == 0, "Expected FormatMessageA to return 0, got %lu\n", ret); ok(buf == NULL, "Expected output buffer pointer to be NULL\n"); - ok(GetLastError() == 0xdeadbeef, - "Expected last error to be untouched, got %u\n", GetLastError()); + ok(GetLastError() == ERROR_NO_WORK_DONE || broken(GetLastError() == 0xdeadbeef), + "Expected GetLastError() to return ERROR_NO_WORK_DONE, got %lu\n", GetLastError()); buf = (char *)0xdeadbeef; ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, "test", 0, 0, (char *)&buf, 0, NULL); - ok(ret == 4, "Expected FormatMessageA to return 4, got %u\n", ret); + ok(ret == 4, "Expected FormatMessageA to return 4, got %lu\n", ret); ok(buf != NULL && buf != (char *)0xdeadbeef, "Expected output buffer pointer to be valid\n"); if (buf != NULL && buf != (char *)0xdeadbeef) @@ -1392,7 +1301,7 @@ static void test_message_allocate_buffer(void) buf = (char *)0xdeadbeef; ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, "test", 0, 0, (char *)&buf, strlen("test"), NULL); - ok(ret == 4, "Expected FormatMessageA to return 4, got %u\n", ret); + ok(ret == 4, "Expected FormatMessageA to return 4, got %lu\n", ret); ok(buf != NULL && buf != (char *)0xdeadbeef, "Expected output buffer pointer to be valid\n"); if (buf != NULL && buf != (char *)0xdeadbeef) @@ -1405,7 +1314,7 @@ static void test_message_allocate_buffer(void) buf = (char *)0xdeadbeef; ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, "test", 0, 0, (char *)&buf, strlen("test") + 1, NULL); - ok(ret == 4, "Expected FormatMessageA to return 4, got %u\n", ret); + ok(ret == 4, "Expected FormatMessageA to return 4, got %lu\n", ret); ok(buf != NULL && buf != (char *)0xdeadbeef, "Expected output buffer pointer to be valid\n"); if (buf != NULL && buf != (char *)0xdeadbeef) @@ -1418,7 +1327,7 @@ static void test_message_allocate_buffer(void) buf = (char *)0xdeadbeef; ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, "test", 0, 0, (char *)&buf, strlen("test") + 2, NULL); - ok(ret == 4, "Expected FormatMessageA to return 4, got %u\n", ret); + ok(ret == 4, "Expected FormatMessageA to return 4, got %lu\n", ret); ok(buf != NULL && buf != (char *)0xdeadbeef, "Expected output buffer pointer to be valid\n"); if (buf != NULL && buf != (char *)0xdeadbeef) @@ -1431,7 +1340,7 @@ static void test_message_allocate_buffer(void) buf = (char *)0xdeadbeef; ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, "test", 0, 0, (char *)&buf, 1024, NULL); - ok(ret == 4, "Expected FormatMessageA to return 4, got %u\n", ret); + ok(ret == 4, "Expected FormatMessageA to return 4, got %lu\n", ret); ok(buf != NULL && buf != (char *)0xdeadbeef, "Expected output buffer pointer to be valid\n"); if (buf != NULL && buf != (char *)0xdeadbeef) @@ -1444,9 +1353,6 @@ static void test_message_allocate_buffer(void) static void test_message_allocate_buffer_wide(void) { - static const WCHAR empty[] = {0}; - static const WCHAR test[] = {'t','e','s','t',0}; - DWORD ret; WCHAR *buf; @@ -1467,73 +1373,82 @@ static void test_message_allocate_buffer_wide(void) SetLastError(0xdeadbeef); buf = (WCHAR *)0xdeadbeef; ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, - empty, 0, 0, (WCHAR *)&buf, 0, NULL); - ok(ret == 0, "Expected FormatMessageW to return 0, got %u\n", ret); + L"", 0, 0, (WCHAR *)&buf, 0, NULL); + ok(ret == 0, "Expected FormatMessageW to return 0, got %lu\n", ret); ok(buf == NULL, "Expected output buffer pointer to be NULL\n"); - ok(GetLastError() == 0xdeadbeef, - "Expected last error to be untouched, got %u\n", GetLastError()); + ok(GetLastError() == ERROR_NO_WORK_DONE || broken(GetLastError() == 0xdeadbeef), + "Expected GetLastError() to return ERROR_NO_WORK_DONE, got %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + buf = (WCHAR *)0xdeadbeef; + ret = doitW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, L"%1", + 0, 0, (WCHAR *)&buf, 0, L"" ); + ok(ret == 0, "Expected FormatMessageW to return 0, got %lu\n", ret); + ok(buf == NULL, "Expected output buffer pointer to be NULL\n"); + ok(GetLastError() == ERROR_NO_WORK_DONE || broken(GetLastError() == 0xdeadbeef), + "Expected GetLastError() to return ERROR_NO_WORK_DONE, got %lu\n", GetLastError()); buf = (WCHAR *)0xdeadbeef; ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, - test, 0, 0, (WCHAR *)&buf, 0, NULL); - ok(ret == 4, "Expected FormatMessageA to return 4, got %u\n", ret); + L"test", 0, 0, (WCHAR *)&buf, 0, NULL); + ok(ret == 4, "Expected FormatMessageA to return 4, got %lu\n", ret); ok(buf != NULL && buf != (WCHAR *)0xdeadbeef, "Expected output buffer pointer to be valid\n"); if (buf != NULL && buf != (WCHAR *)0xdeadbeef) { - ok(!lstrcmpW(test, buf), + ok(!lstrcmpW(L"test", buf), "Expected buffer to contain \"test\", got %s\n", wine_dbgstr_w(buf)); LocalFree(buf); } buf = (WCHAR *)0xdeadbeef; ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, - test, 0, 0, (WCHAR *)&buf, sizeof(test)/sizeof(WCHAR) - 1, NULL); - ok(ret == 4, "Expected FormatMessageA to return 4, got %u\n", ret); + L"test", 0, 0, (WCHAR *)&buf, 4, NULL); + ok(ret == 4, "Expected FormatMessageA to return 4, got %lu\n", ret); ok(buf != NULL && buf != (WCHAR *)0xdeadbeef, "Expected output buffer pointer to be valid\n"); if (buf != NULL && buf != (WCHAR *)0xdeadbeef) { - ok(!lstrcmpW(test, buf), + ok(!lstrcmpW(L"test", buf), "Expected buffer to contain \"test\", got %s\n", wine_dbgstr_w(buf)); LocalFree(buf); } buf = (WCHAR *)0xdeadbeef; ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, - test, 0, 0, (WCHAR *)&buf, sizeof(test)/sizeof(WCHAR), NULL); - ok(ret == 4, "Expected FormatMessageA to return 4, got %u\n", ret); + L"test", 0, 0, (WCHAR *)&buf, 5, NULL); + ok(ret == 4, "Expected FormatMessageA to return 4, got %lu\n", ret); ok(buf != NULL && buf != (WCHAR *)0xdeadbeef, "Expected output buffer pointer to be valid\n"); if (buf != NULL && buf != (WCHAR *)0xdeadbeef) { - ok(!lstrcmpW(test, buf), + ok(!lstrcmpW(L"test", buf), "Expected buffer to contain \"test\", got %s\n", wine_dbgstr_w(buf)); LocalFree(buf); } buf = (WCHAR *)0xdeadbeef; ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, - test, 0, 0, (WCHAR *)&buf, sizeof(test)/sizeof(WCHAR) + 1, NULL); - ok(ret == 4, "Expected FormatMessageA to return 4, got %u\n", ret); + L"test", 0, 0, (WCHAR *)&buf, 6, NULL); + ok(ret == 4, "Expected FormatMessageA to return 4, got %lu\n", ret); ok(buf != NULL && buf != (WCHAR *)0xdeadbeef, "Expected output buffer pointer to be valid\n"); if (buf != NULL && buf != (WCHAR *)0xdeadbeef) { - ok(!lstrcmpW(test, buf), + ok(!lstrcmpW(L"test", buf), "Expected buffer to contain \"test\", got %s\n", wine_dbgstr_w(buf)); LocalFree(buf); } buf = (WCHAR *)0xdeadbeef; ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, - test, 0, 0, (WCHAR *)&buf, 1024, NULL); - ok(ret == 4, "Expected FormatMessageA to return 4, got %u\n", ret); + L"test", 0, 0, (WCHAR *)&buf, 1024, NULL); + ok(ret == 4, "Expected FormatMessageA to return 4, got %lu\n", ret); ok(buf != NULL && buf != (WCHAR *)0xdeadbeef, "Expected output buffer pointer to be valid\n"); if (buf != NULL && buf != (WCHAR *)0xdeadbeef) { - ok(!lstrcmpW(test, buf), + ok(!lstrcmpW(L"test", buf), "Expected buffer to contain \"test\", got %s\n", wine_dbgstr_w(buf)); LocalFree(buf); } @@ -1551,71 +1466,79 @@ static void test_message_from_hmodule(void) /*Test existing messageID; as the message strings from wine's kernel32 differ from windows' kernel32 we don't compare the strings but only test that FormatMessage doesn't return 0*/ ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE, h, 7/*=ERROR_ARENA_TRASHED*/, - MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), out, sizeof(out)/sizeof(CHAR), NULL); + MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), out, ARRAY_SIZE(out), NULL); ok(ret != 0, "FormatMessageA returned 0\n"); /* Test HRESULT. It's not documented but in practice _com_error::ErrorMessage relies on this. */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE, h, 0x80070005 /* E_ACCESSDENIED */, - MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), out, sizeof(out)/sizeof(CHAR), NULL); + MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), out, ARRAY_SIZE(out), NULL); ok(ret != 0, "FormatMessageA returned 0\n"); ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE, h, TRUST_E_NOSIGNATURE, - MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), out, sizeof(out)/sizeof(CHAR), NULL); + MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), out, ARRAY_SIZE(out), NULL); ok(ret != 0, "FormatMessageA returned 0\n"); /* Test a message string with an insertion without passing any variadic arguments. */ ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE, h, 193 /* ERROR_BAD_EXE_FORMAT */, - MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), out, sizeof(out)/sizeof(CHAR), NULL); + MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), out, ARRAY_SIZE(out), NULL); ok(ret == 0, "FormatMessageA returned non-zero\n"); ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY, h, 193 /* ERROR_BAD_EXE_FORMAT */, - MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), out, sizeof(out)/sizeof(CHAR), NULL); + MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), out, ARRAY_SIZE(out), NULL); ok(ret == 0, "FormatMessageA returned non-zero\n"); /*Test nonexistent messageID with varying language IDs Note: FormatMessageW behaves the same*/ SetLastError(0xdeadbeef); ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE, h, 3044, - MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), out, sizeof(out)/sizeof(CHAR), NULL); + MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), out, ARRAY_SIZE(out), NULL); error = GetLastError(); - ok(ret == 0, "FormatMessageA returned %u instead of 0\n", ret); - ok(error == ERROR_MR_MID_NOT_FOUND || error == ERROR_MUI_FILE_NOT_FOUND, "last error %u\n", error); + ok(ret == 0, "FormatMessageA returned %lu instead of 0\n", ret); + ok(error == ERROR_MR_MID_NOT_FOUND || + error == ERROR_MUI_FILE_NOT_FOUND || + error == ERROR_RESOURCE_TYPE_NOT_FOUND, "Unexpected last error %lu.\n", error); SetLastError(0xdeadbeef); ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE, h, 3044, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), out, sizeof(out)/sizeof(CHAR), NULL); + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), out, ARRAY_SIZE(out), NULL); error = GetLastError(); - ok(ret == 0, "FormatMessageA returned %u instead of 0\n", ret); - ok(error == ERROR_MR_MID_NOT_FOUND || error == ERROR_MUI_FILE_NOT_LOADED, "last error %u\n", error); + ok(ret == 0, "FormatMessageA returned %lu instead of 0\n", ret); + ok(error == ERROR_MR_MID_NOT_FOUND || + error == ERROR_MUI_FILE_NOT_LOADED || + error == ERROR_RESOURCE_TYPE_NOT_FOUND, "Unexpected last error %lu.\n", error); SetLastError(0xdeadbeef); ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE, h, 3044, - MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT), out, sizeof(out)/sizeof(CHAR), NULL); + MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT), out, ARRAY_SIZE(out), NULL); error = GetLastError(); - ok(ret == 0, "FormatMessageA returned %u instead of 0\n", ret); - ok(error == ERROR_MR_MID_NOT_FOUND || error == ERROR_MUI_FILE_NOT_LOADED, "last error %u\n", error); + ok(ret == 0, "FormatMessageA returned %lu instead of 0\n", ret); + ok(error == ERROR_MR_MID_NOT_FOUND || + error == ERROR_MUI_FILE_NOT_LOADED || + error == ERROR_RESOURCE_TYPE_NOT_FOUND, "Unexpected last error %lu.\n", error); SetLastError(0xdeadbeef); ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE, h, 3044, - MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), out, sizeof(out)/sizeof(CHAR), NULL); + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), out, ARRAY_SIZE(out), NULL); error = GetLastError(); - ok(ret == 0, "FormatMessageA returned %u instead of 0\n", ret); + ok(ret == 0, "FormatMessageA returned %lu instead of 0\n", ret); ok(error == ERROR_RESOURCE_LANG_NOT_FOUND || + error == ERROR_RESOURCE_TYPE_NOT_FOUND || error == ERROR_MR_MID_NOT_FOUND || error == ERROR_MUI_FILE_NOT_FOUND || error == ERROR_MUI_FILE_NOT_LOADED, - "last error %u\n", error); + "last error %lu\n", error); SetLastError(0xdeadbeef); ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE, h, 3044, - MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK), out, sizeof(out)/sizeof(CHAR), NULL); + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK), out, ARRAY_SIZE(out), NULL); error = GetLastError(); - ok(ret == 0, "FormatMessageA returned %u instead of 0\n", ret); + ok(ret == 0, "FormatMessageA returned %lu instead of 0\n", ret); ok(error == ERROR_RESOURCE_LANG_NOT_FOUND || + error == ERROR_RESOURCE_TYPE_NOT_FOUND || error == ERROR_MR_MID_NOT_FOUND || error == ERROR_MUI_FILE_NOT_FOUND || error == ERROR_MUI_FILE_NOT_LOADED, - "last error %u\n", error); + "last error %lu\n", error); } static void test_message_invalid_flags(void) @@ -1628,51 +1551,51 @@ static void test_message_invalid_flags(void) SetLastError(0xdeadbeef); memcpy(out, init_buf, sizeof(init_buf)); - ret = FormatMessageA(0, "test", 0, 0, out, sizeof(out)/sizeof(CHAR), NULL); - ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret); + ret = FormatMessageA(0, "test", 0, 0, out, ARRAY_SIZE(out), NULL); + ok(ret == 0, "Expected FormatMessageA to return 0, got %lu\n", ret); ok(!memcmp(out, init_buf, sizeof(init_buf)), "Expected the output buffer to be untouched\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n", + "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ptr = (char *)0xdeadbeef; ret = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER, "test", 0, 0, (char *)&ptr, 0, NULL); - ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret); + ok(ret == 0, "Expected FormatMessageA to return 0, got %lu\n", ret); ok(ptr == NULL, "Expected output pointer to be initialized to NULL, got %p\n", ptr); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n", + "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); memcpy(out, init_buf, sizeof(init_buf)); - ret = FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS, "test", 0, 0, out, sizeof(out)/sizeof(CHAR), NULL); - ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret); + ret = FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS, "test", 0, 0, out, ARRAY_SIZE(out), NULL); + ok(ret == 0, "Expected FormatMessageA to return 0, got %lu\n", ret); ok(!memcmp(out, init_buf, sizeof(init_buf)), "Expected the output buffer to be untouched\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n", + "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); memcpy(out, init_buf, sizeof(init_buf)); - ret = FormatMessageA(FORMAT_MESSAGE_ARGUMENT_ARRAY, "test", 0, 0, out, sizeof(out)/sizeof(CHAR), NULL); - ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret); + ret = FormatMessageA(FORMAT_MESSAGE_ARGUMENT_ARRAY, "test", 0, 0, out, ARRAY_SIZE(out), NULL); + ok(ret == 0, "Expected FormatMessageA to return 0, got %lu\n", ret); ok(!memcmp(out, init_buf, sizeof(init_buf)), "Expected the output buffer to be untouched\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n", + "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); memcpy(out, init_buf, sizeof(init_buf)); - ret = FormatMessageA(FORMAT_MESSAGE_MAX_WIDTH_MASK, "test", 0, 0, out, sizeof(out)/sizeof(CHAR), NULL); - ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret); + ret = FormatMessageA(FORMAT_MESSAGE_MAX_WIDTH_MASK, "test", 0, 0, out, ARRAY_SIZE(out), NULL); + ok(ret == 0, "Expected FormatMessageA to return 0, got %lu\n", ret); ok(!memcmp(out, init_buf, sizeof(init_buf)), "Expected the output buffer to be untouched\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n", + "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); /* Simultaneously setting FORMAT_MESSAGE_FROM_STRING with other source @@ -1681,116 +1604,109 @@ static void test_message_invalid_flags(void) memcpy(out, init_buf, sizeof(init_buf)); ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_FROM_SYSTEM, - "test", 0, 0, out, sizeof(out)/sizeof(CHAR), NULL); - ok(ret == 4, "Expected FormatMessageA to return 4, got %u\n", ret); + "test", 0, 0, out, ARRAY_SIZE(out), NULL); + ok(ret == 4, "Expected FormatMessageA to return 4, got %lu\n", ret); ok(!strcmp("test", out), "Expected the output buffer to be untouched\n"); memcpy(out, init_buf, sizeof(init_buf)); ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_FROM_HMODULE, - "test", 0, 0, out, sizeof(out)/sizeof(CHAR), NULL); - ok(ret == 4, "Expected FormatMessageA to return 4, got %u\n", ret); + "test", 0, 0, out, ARRAY_SIZE(out), NULL); + ok(ret == 4, "Expected FormatMessageA to return 4, got %lu\n", ret); ok(!strcmp("test", out), "Expected the output buffer to be untouched\n"); memcpy(out, init_buf, sizeof(init_buf)); ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_FROM_HMODULE | - FORMAT_MESSAGE_FROM_SYSTEM, "test", 0, 0, out, - sizeof(out)/sizeof(CHAR), NULL); - ok(ret == 4, "Expected FormatMessageA to return 4, got %u\n", ret); + FORMAT_MESSAGE_FROM_SYSTEM, "test", 0, 0, out, ARRAY_SIZE(out), NULL); + ok(ret == 4, "Expected FormatMessageA to return 4, got %lu\n", ret); ok(!strcmp("test", out), "Expected the output buffer to be untouched\n"); } static void test_message_invalid_flags_wide(void) { - static const WCHAR init_buf[] = {'x', 'x', 'x', 'x', 'x'}; - static const WCHAR test[] = {'t','e','s','t',0}; - DWORD ret; - WCHAR out[5]; + WCHAR out[8]; WCHAR *ptr; SetLastError(0xdeadbeef); - memcpy(out, init_buf, sizeof(init_buf)); - ret = FormatMessageW(0, test, 0, 0, out, sizeof(out)/sizeof(WCHAR), NULL); - ok(ret == 0, "Expected FormatMessageW to return 0, got %u\n", ret); - ok(!memcmp(out, init_buf, sizeof(init_buf)), + lstrcpyW( out, L"xxxxxx" ); + ret = FormatMessageW(0, L"test", 0, 0, out, ARRAY_SIZE(out), NULL); + ok(ret == 0, "Expected FormatMessageW to return 0, got %lu\n", ret); + ok(!lstrcmpW( out, L"xxxxxx" ), "Expected the output buffer to be untouched\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n", + "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ptr = (WCHAR *)0xdeadbeef; - ret = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER, test, 0, 0, (WCHAR *)&ptr, 0, NULL); - ok(ret == 0, "Expected FormatMessageW to return 0, got %u\n", ret); + ret = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER, L"test", 0, 0, (WCHAR *)&ptr, 0, NULL); + ok(ret == 0, "Expected FormatMessageW to return 0, got %lu\n", ret); ok(ptr == NULL, "Expected output pointer to be initialized to NULL, got %p\n", ptr); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n", + "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); - memcpy(out, init_buf, sizeof(init_buf)); - ret = FormatMessageW(FORMAT_MESSAGE_IGNORE_INSERTS, test, 0, 0, out, sizeof(out)/sizeof(WCHAR), NULL); - ok(ret == 0, "Expected FormatMessageW to return 0, got %u\n", ret); - ok(!memcmp(out, init_buf, sizeof(init_buf)), + lstrcpyW( out, L"xxxxxx" ); + ret = FormatMessageW(FORMAT_MESSAGE_IGNORE_INSERTS, L"test", 0, 0, out, ARRAY_SIZE(out), NULL); + ok(ret == 0, "Expected FormatMessageW to return 0, got %lu\n", ret); + ok(!lstrcmpW( out, L"xxxxxx" ), "Expected the output buffer to be untouched\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n", + "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); - memcpy(out, init_buf, sizeof(init_buf)); - ret = FormatMessageW(FORMAT_MESSAGE_ARGUMENT_ARRAY, test, 0, 0, out, sizeof(out)/sizeof(WCHAR), NULL); - ok(ret == 0, "Expected FormatMessageW to return 0, got %u\n", ret); - ok(!memcmp(out, init_buf, sizeof(init_buf)), + lstrcpyW( out, L"xxxxxx" ); + ret = FormatMessageW(FORMAT_MESSAGE_ARGUMENT_ARRAY, L"test", 0, 0, out, ARRAY_SIZE(out), NULL); + ok(ret == 0, "Expected FormatMessageW to return 0, got %lu\n", ret); + ok(!lstrcmpW( out, L"xxxxxx" ), "Expected the output buffer to be untouched\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n", + "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); - memcpy(out, init_buf, sizeof(init_buf)); - ret = FormatMessageW(FORMAT_MESSAGE_MAX_WIDTH_MASK, test, 0, 0, out, sizeof(out)/sizeof(WCHAR), NULL); - ok(ret == 0, "Expected FormatMessageW to return 0, got %u\n", ret); - ok(!memcmp(out, init_buf, sizeof(init_buf)), + lstrcpyW( out, L"xxxxxx" ); + ret = FormatMessageW(FORMAT_MESSAGE_MAX_WIDTH_MASK, L"test", 0, 0, out, ARRAY_SIZE(out), NULL); + ok(ret == 0, "Expected FormatMessageW to return 0, got %lu\n", ret); + ok(!lstrcmpW( out, L"xxxxxx" ), "Expected the output buffer to be untouched\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n", + "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); /* Simultaneously setting FORMAT_MESSAGE_FROM_STRING with other source * flags is apparently permissible, and FORMAT_MESSAGE_FROM_STRING takes * precedence in this case. */ - memcpy(out, init_buf, sizeof(init_buf)); + lstrcpyW( out, L"xxxxxx" ); ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_FROM_SYSTEM, - test, 0, 0, out, sizeof(out)/sizeof(WCHAR), NULL); - ok(ret == 4, "Expected FormatMessageW to return 4, got %u\n", ret); - ok(!lstrcmpW(test, out), + L"test", 0, 0, out, ARRAY_SIZE(out), NULL); + ok(ret == 4, "Expected FormatMessageW to return 4, got %lu\n", ret); + ok(!lstrcmpW(L"test", out), "Expected the output buffer to be untouched\n"); - memcpy(out, init_buf, sizeof(init_buf)); + lstrcpyW( out, L"xxxxxx" ); ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_FROM_HMODULE, - test, 0, 0, out, sizeof(out)/sizeof(WCHAR), NULL); - ok(ret == 4, "Expected FormatMessageW to return 4, got %u\n", ret); - ok(!lstrcmpW(test, out), + L"test", 0, 0, out, ARRAY_SIZE(out), NULL); + ok(ret == 4, "Expected FormatMessageW to return 4, got %lu\n", ret); + ok(!lstrcmpW(L"test", out), "Expected the output buffer to be untouched\n"); - memcpy(out, init_buf, sizeof(init_buf)); + lstrcpyW( out, L"xxxxxx" ); ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_FROM_HMODULE | - FORMAT_MESSAGE_FROM_SYSTEM, test, 0, 0, out, - sizeof(out)/sizeof(WCHAR), NULL); - ok(ret == 4, "Expected FormatMessageW to return 4, got %u\n", ret); - ok(!lstrcmpW(test, out), + FORMAT_MESSAGE_FROM_SYSTEM, L"test", 0, 0, out, ARRAY_SIZE(out), NULL); + ok(ret == 4, "Expected FormatMessageW to return 4, got %lu\n", ret); + ok(!lstrcmpW(L"test", out), "Expected the output buffer to be untouched\n"); } static void test_message_from_64bit_number(void) { - static const WCHAR I64d[] = {'%', '1', '!', 'I', '6', '4', 'd', '!', 0}; - static const WCHAR I64u[] = {'%', '1', '!', 'I', '6', '4', 'u', '!', 0}; WCHAR outW[0x100], expW[0x100]; char outA[0x100]; DWORD r; @@ -1822,42 +1738,61 @@ static void test_message_from_64bit_number(void) }; int i; - for (i = 0; i < sizeof(unsigned_tests) / sizeof(unsigned_tests[0]); i++) + for (i = 0; i < ARRAY_SIZE(unsigned_tests); i++) { - r = doitW(FORMAT_MESSAGE_FROM_STRING, I64u, - 0, 0, outW, sizeof(outW) / sizeof(WCHAR), unsigned_tests[i].number); - MultiByteToWideChar(CP_ACP, 0, unsigned_tests[i].expected, -1, expW, sizeof(expW) / sizeof(WCHAR)); -todo_wine { + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!I64u!", 0, 0, outW, ARRAY_SIZE(outW), + unsigned_tests[i].number); + MultiByteToWideChar(CP_ACP, 0, unsigned_tests[i].expected, -1, expW, ARRAY_SIZE(expW)); ok(!lstrcmpW(outW, expW),"[%d] failed, expected %s, got %s\n", i, unsigned_tests[i].expected, wine_dbgstr_w(outW)); - ok(r == unsigned_tests[i].len,"[%d] failed: r=%d\n", i, r); -} + ok(r == unsigned_tests[i].len,"[%d] failed: r=%ld\n", i, r); r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!I64u!", 0, 0, outA, sizeof(outA), unsigned_tests[i].number); -todo_wine { ok(!strcmp(outA, unsigned_tests[i].expected),"[%d] failed, expected %s, got %s\n", i, unsigned_tests[i].expected, outA); - ok(r == unsigned_tests[i].len,"[%d] failed: r=%d\n", i, r); -} + ok(r == unsigned_tests[i].len,"[%d] failed: r=%ld\n", i, r); } - for (i = 0; i < sizeof(signed_tests) / sizeof(signed_tests[0]); i++) + for (i = 0; i < ARRAY_SIZE(signed_tests); i++) { - r = doitW(FORMAT_MESSAGE_FROM_STRING, I64d, - 0, 0, outW, sizeof(outW) / sizeof(WCHAR), signed_tests[i].number); - MultiByteToWideChar(CP_ACP, 0, signed_tests[i].expected, -1, expW, sizeof(expW) / sizeof(WCHAR)); -todo_wine { + r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!I64d!", 0, 0, outW, ARRAY_SIZE(outW), + signed_tests[i].number); + MultiByteToWideChar(CP_ACP, 0, signed_tests[i].expected, -1, expW, ARRAY_SIZE(expW)); ok(!lstrcmpW(outW, expW),"[%d] failed, expected %s, got %s\n", i, signed_tests[i].expected, wine_dbgstr_w(outW)); - ok(r == signed_tests[i].len,"[%d] failed: r=%d\n", i, r); -} + ok(r == signed_tests[i].len,"[%d] failed: r=%ld\n", i, r); r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!I64d!", 0, 0, outA, sizeof(outA), signed_tests[i].number); -todo_wine { ok(!strcmp(outA, signed_tests[i].expected),"[%d] failed, expected %s, got %s\n", i, signed_tests[i].expected, outA); - ok(r == signed_tests[i].len,"[%d] failed: r=%d\n", i, r); + ok(r == signed_tests[i].len,"[%d] failed: r=%ld\n", i, r); + } } + +static void test_message_system_errors(void) +{ + static const struct + { + DWORD error_code; + BOOL broken; + } + tests[] = + { + {E_NOTIMPL}, + {E_FAIL}, + {DXGI_ERROR_INVALID_CALL, TRUE /* Available since Win8 */}, + {DXGI_ERROR_NOT_CURRENTLY_AVAILABLE, TRUE /* Available since Win8 */}, + }; + + char buffer[256]; + unsigned int i; + DWORD len; + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + len = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, tests[i].error_code, + LANG_USER_DEFAULT, buffer, ARRAY_SIZE(buffer), NULL); + ok(len || broken(tests[i].broken), "Got zero len, code %#lx.\n", tests[i].error_code); } } @@ -1889,4 +1824,5 @@ START_TEST(format_msg) test_message_allocate_buffer_wide(); test_message_invalid_flags_wide(); test_message_from_64bit_number(); + test_message_system_errors(); } diff --git a/modules/rostests/winetests/kernel32/generated.c b/modules/rostests/winetests/kernel32/generated.c index 7c57feaab78..1b0489094ea 100644 --- a/modules/rostests/winetests/kernel32/generated.c +++ b/modules/rostests/winetests/kernel32/generated.c @@ -25,7 +25,7 @@ #if defined(_MSC_VER) && (_MSC_VER >= 1300) && defined(__cplusplus) # define _TYPE_ALIGNMENT(type) __alignof(type) -#elif defined(__GNUC__) +#elif defined(__GNUC__) || defined(__clang__) # define _TYPE_ALIGNMENT(type) __alignof__(type) #else /* @@ -47,23 +47,23 @@ * Test helper macros */ -#define TEST_TYPE_SIZE(type, size) C_ASSERT(sizeof(type) == size); +#define TEST_TYPE_SIZE(type, size) C_ASSERT(sizeof(type) == size); #ifdef TYPE_ALIGNMENT -# define TEST_TYPE_ALIGN(type, align) C_ASSERT(TYPE_ALIGNMENT(type) == align); +# define TEST_TYPE_ALIGN(type, align) C_ASSERT(TYPE_ALIGNMENT(type) == align); #else # define TEST_TYPE_ALIGN(type, align) #endif #ifdef _TYPE_ALIGNMENT -# define TEST_TARGET_ALIGN(type, align) C_ASSERT(_TYPE_ALIGNMENT(*(type)0) == align); -# define TEST_FIELD_ALIGN(type, field, align) C_ASSERT(_TYPE_ALIGNMENT(((type*)0)->field) == align); +# define TEST_TARGET_ALIGN(type, align) C_ASSERT(_TYPE_ALIGNMENT(*(type)0) == align); +# define TEST_FIELD_ALIGN(type, field, align) C_ASSERT(_TYPE_ALIGNMENT(((type*)0)->field) == align); #else # define TEST_TARGET_ALIGN(type, align) # define TEST_FIELD_ALIGN(type, field, align) #endif -#define TEST_FIELD_OFFSET(type, field, offset) C_ASSERT(FIELD_OFFSET(type, field) == offset); +#define TEST_FIELD_OFFSET(type, field, offset) C_ASSERT(FIELD_OFFSET(type, field) == offset); #define TEST_TARGET_SIZE(type, size) TEST_TYPE_SIZE(*(type)0, size) #define TEST_FIELD_SIZE(type, field, size) TEST_TYPE_SIZE((((type*)0)->field), size) @@ -1140,15 +1140,6 @@ static void test_pack_LPTHREAD_START_ROUTINE(void) TEST_TYPE_ALIGN (LPTHREAD_START_ROUTINE, 8) } -static void test_pack_LPTIME_ZONE_INFORMATION(void) -{ - /* LPTIME_ZONE_INFORMATION */ - TEST_TYPE_SIZE (LPTIME_ZONE_INFORMATION, 8) - TEST_TYPE_ALIGN (LPTIME_ZONE_INFORMATION, 8) - TEST_TARGET_SIZE (LPTIME_ZONE_INFORMATION, 172) - TEST_TARGET_ALIGN(LPTIME_ZONE_INFORMATION, 4) -} - static void test_pack_LPWIN32_FILE_ATTRIBUTE_DATA(void) { /* LPWIN32_FILE_ATTRIBUTE_DATA */ @@ -1523,15 +1514,6 @@ static void test_pack_PTIMERAPCROUTINE(void) TEST_TYPE_ALIGN (PTIMERAPCROUTINE, 8) } -static void test_pack_PTIME_ZONE_INFORMATION(void) -{ - /* PTIME_ZONE_INFORMATION */ - TEST_TYPE_SIZE (PTIME_ZONE_INFORMATION, 8) - TEST_TYPE_ALIGN (PTIME_ZONE_INFORMATION, 8) - TEST_TARGET_SIZE (PTIME_ZONE_INFORMATION, 172) - TEST_TARGET_ALIGN(PTIME_ZONE_INFORMATION, 4) -} - static void test_pack_PWIN32_FIND_DATAA(void) { /* PWIN32_FIND_DATAA */ @@ -1762,34 +1744,6 @@ static void test_pack_SYSTEM_POWER_STATUS(void) TEST_FIELD_OFFSET(SYSTEM_POWER_STATUS, BatteryFullLifeTime, 8) } -static void test_pack_TIME_ZONE_INFORMATION(void) -{ - /* TIME_ZONE_INFORMATION */ - TEST_TYPE_SIZE (TIME_ZONE_INFORMATION, 172) - TEST_TYPE_ALIGN (TIME_ZONE_INFORMATION, 4) - TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, Bias, 4) - TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, Bias, 4) - TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, Bias, 0) - TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, StandardName, 64) - TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, StandardName, 2) - TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, StandardName, 4) - TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, StandardDate, 16) - TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, StandardDate, 2) - TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, StandardDate, 68) - TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, StandardBias, 4) - TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, StandardBias, 4) - TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, StandardBias, 84) - TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, DaylightName, 64) - TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, DaylightName, 2) - TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, DaylightName, 88) - TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, DaylightDate, 16) - TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, DaylightDate, 2) - TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, DaylightDate, 152) - TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, DaylightBias, 4) - TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, DaylightBias, 4) - TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, DaylightBias, 168) -} - static void test_pack_UNLOAD_DLL_DEBUG_INFO(void) { /* UNLOAD_DLL_DEBUG_INFO */ @@ -1928,6 +1882,95 @@ static void test_pack_WIN32_STREAM_ID(void) TEST_FIELD_OFFSET(WIN32_STREAM_ID, cStreamName, 20) } +static void test_pack_DYNAMIC_TIME_ZONE_INFORMATION(void) +{ + /* DYNAMIC_TIME_ZONE_INFORMATION */ + TEST_TYPE_SIZE (DYNAMIC_TIME_ZONE_INFORMATION, 432) + TEST_TYPE_ALIGN (DYNAMIC_TIME_ZONE_INFORMATION, 4) + TEST_FIELD_SIZE (DYNAMIC_TIME_ZONE_INFORMATION, Bias, 4) + TEST_FIELD_ALIGN (DYNAMIC_TIME_ZONE_INFORMATION, Bias, 4) + TEST_FIELD_OFFSET(DYNAMIC_TIME_ZONE_INFORMATION, Bias, 0) + TEST_FIELD_SIZE (DYNAMIC_TIME_ZONE_INFORMATION, StandardName, 64) + TEST_FIELD_ALIGN (DYNAMIC_TIME_ZONE_INFORMATION, StandardName, 2) + TEST_FIELD_OFFSET(DYNAMIC_TIME_ZONE_INFORMATION, StandardName, 4) + TEST_FIELD_SIZE (DYNAMIC_TIME_ZONE_INFORMATION, StandardDate, 16) + TEST_FIELD_ALIGN (DYNAMIC_TIME_ZONE_INFORMATION, StandardDate, 2) + TEST_FIELD_OFFSET(DYNAMIC_TIME_ZONE_INFORMATION, StandardDate, 68) + TEST_FIELD_SIZE (DYNAMIC_TIME_ZONE_INFORMATION, StandardBias, 4) + TEST_FIELD_ALIGN (DYNAMIC_TIME_ZONE_INFORMATION, StandardBias, 4) + TEST_FIELD_OFFSET(DYNAMIC_TIME_ZONE_INFORMATION, StandardBias, 84) + TEST_FIELD_SIZE (DYNAMIC_TIME_ZONE_INFORMATION, DaylightName, 64) + TEST_FIELD_ALIGN (DYNAMIC_TIME_ZONE_INFORMATION, DaylightName, 2) + TEST_FIELD_OFFSET(DYNAMIC_TIME_ZONE_INFORMATION, DaylightName, 88) + TEST_FIELD_SIZE (DYNAMIC_TIME_ZONE_INFORMATION, DaylightDate, 16) + TEST_FIELD_ALIGN (DYNAMIC_TIME_ZONE_INFORMATION, DaylightDate, 2) + TEST_FIELD_OFFSET(DYNAMIC_TIME_ZONE_INFORMATION, DaylightDate, 152) + TEST_FIELD_SIZE (DYNAMIC_TIME_ZONE_INFORMATION, DaylightBias, 4) + TEST_FIELD_ALIGN (DYNAMIC_TIME_ZONE_INFORMATION, DaylightBias, 4) + TEST_FIELD_OFFSET(DYNAMIC_TIME_ZONE_INFORMATION, DaylightBias, 168) + TEST_FIELD_SIZE (DYNAMIC_TIME_ZONE_INFORMATION, TimeZoneKeyName, 256) + TEST_FIELD_ALIGN (DYNAMIC_TIME_ZONE_INFORMATION, TimeZoneKeyName, 2) + TEST_FIELD_OFFSET(DYNAMIC_TIME_ZONE_INFORMATION, TimeZoneKeyName, 172) + TEST_FIELD_SIZE (DYNAMIC_TIME_ZONE_INFORMATION, DynamicDaylightTimeDisabled, 1) + TEST_FIELD_ALIGN (DYNAMIC_TIME_ZONE_INFORMATION, DynamicDaylightTimeDisabled, 1) + TEST_FIELD_OFFSET(DYNAMIC_TIME_ZONE_INFORMATION, DynamicDaylightTimeDisabled, 428) +} + +static void test_pack_LPTIME_ZONE_INFORMATION(void) +{ + /* LPTIME_ZONE_INFORMATION */ + TEST_TYPE_SIZE (LPTIME_ZONE_INFORMATION, 8) + TEST_TYPE_ALIGN (LPTIME_ZONE_INFORMATION, 8) + TEST_TARGET_SIZE (LPTIME_ZONE_INFORMATION, 172) + TEST_TARGET_ALIGN(LPTIME_ZONE_INFORMATION, 4) +} + +static void test_pack_PDYNAMIC_TIME_ZONE_INFORMATION(void) +{ + /* PDYNAMIC_TIME_ZONE_INFORMATION */ + TEST_TYPE_SIZE (PDYNAMIC_TIME_ZONE_INFORMATION, 8) + TEST_TYPE_ALIGN (PDYNAMIC_TIME_ZONE_INFORMATION, 8) + TEST_TARGET_SIZE (PDYNAMIC_TIME_ZONE_INFORMATION, 432) + TEST_TARGET_ALIGN(PDYNAMIC_TIME_ZONE_INFORMATION, 4) +} + +static void test_pack_PTIME_ZONE_INFORMATION(void) +{ + /* PTIME_ZONE_INFORMATION */ + TEST_TYPE_SIZE (PTIME_ZONE_INFORMATION, 8) + TEST_TYPE_ALIGN (PTIME_ZONE_INFORMATION, 8) + TEST_TARGET_SIZE (PTIME_ZONE_INFORMATION, 172) + TEST_TARGET_ALIGN(PTIME_ZONE_INFORMATION, 4) +} + +static void test_pack_TIME_ZONE_INFORMATION(void) +{ + /* TIME_ZONE_INFORMATION */ + TEST_TYPE_SIZE (TIME_ZONE_INFORMATION, 172) + TEST_TYPE_ALIGN (TIME_ZONE_INFORMATION, 4) + TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, Bias, 4) + TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, Bias, 4) + TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, Bias, 0) + TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, StandardName, 64) + TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, StandardName, 2) + TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, StandardName, 4) + TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, StandardDate, 16) + TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, StandardDate, 2) + TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, StandardDate, 68) + TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, StandardBias, 4) + TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, StandardBias, 4) + TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, StandardBias, 84) + TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, DaylightName, 64) + TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, DaylightName, 2) + TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, DaylightName, 88) + TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, DaylightDate, 16) + TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, DaylightDate, 2) + TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, DaylightDate, 152) + TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, DaylightBias, 4) + TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, DaylightBias, 4) + TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, DaylightBias, 168) +} + #else /* _WIN64 */ static void test_pack_LPOSVERSIONINFOA(void) @@ -2997,15 +3040,6 @@ static void test_pack_LPTHREAD_START_ROUTINE(void) TEST_TYPE_ALIGN (LPTHREAD_START_ROUTINE, 4) } -static void test_pack_LPTIME_ZONE_INFORMATION(void) -{ - /* LPTIME_ZONE_INFORMATION */ - TEST_TYPE_SIZE (LPTIME_ZONE_INFORMATION, 4) - TEST_TYPE_ALIGN (LPTIME_ZONE_INFORMATION, 4) - TEST_TARGET_SIZE (LPTIME_ZONE_INFORMATION, 172) - TEST_TARGET_ALIGN(LPTIME_ZONE_INFORMATION, 4) -} - static void test_pack_LPWIN32_FILE_ATTRIBUTE_DATA(void) { /* LPWIN32_FILE_ATTRIBUTE_DATA */ @@ -3380,15 +3414,6 @@ static void test_pack_PTIMERAPCROUTINE(void) TEST_TYPE_ALIGN (PTIMERAPCROUTINE, 4) } -static void test_pack_PTIME_ZONE_INFORMATION(void) -{ - /* PTIME_ZONE_INFORMATION */ - TEST_TYPE_SIZE (PTIME_ZONE_INFORMATION, 4) - TEST_TYPE_ALIGN (PTIME_ZONE_INFORMATION, 4) - TEST_TARGET_SIZE (PTIME_ZONE_INFORMATION, 172) - TEST_TARGET_ALIGN(PTIME_ZONE_INFORMATION, 4) -} - static void test_pack_PWIN32_FIND_DATAA(void) { /* PWIN32_FIND_DATAA */ @@ -3619,34 +3644,6 @@ static void test_pack_SYSTEM_POWER_STATUS(void) TEST_FIELD_OFFSET(SYSTEM_POWER_STATUS, BatteryFullLifeTime, 8) } -static void test_pack_TIME_ZONE_INFORMATION(void) -{ - /* TIME_ZONE_INFORMATION */ - TEST_TYPE_SIZE (TIME_ZONE_INFORMATION, 172) - TEST_TYPE_ALIGN (TIME_ZONE_INFORMATION, 4) - TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, Bias, 4) - TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, Bias, 4) - TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, Bias, 0) - TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, StandardName, 64) - TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, StandardName, 2) - TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, StandardName, 4) - TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, StandardDate, 16) - TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, StandardDate, 2) - TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, StandardDate, 68) - TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, StandardBias, 4) - TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, StandardBias, 4) - TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, StandardBias, 84) - TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, DaylightName, 64) - TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, DaylightName, 2) - TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, DaylightName, 88) - TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, DaylightDate, 16) - TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, DaylightDate, 2) - TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, DaylightDate, 152) - TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, DaylightBias, 4) - TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, DaylightBias, 4) - TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, DaylightBias, 168) -} - static void test_pack_UNLOAD_DLL_DEBUG_INFO(void) { /* UNLOAD_DLL_DEBUG_INFO */ @@ -3785,6 +3782,95 @@ static void test_pack_WIN32_STREAM_ID(void) TEST_FIELD_OFFSET(WIN32_STREAM_ID, cStreamName, 20) } +static void test_pack_DYNAMIC_TIME_ZONE_INFORMATION(void) +{ + /* DYNAMIC_TIME_ZONE_INFORMATION */ + TEST_TYPE_SIZE (DYNAMIC_TIME_ZONE_INFORMATION, 432) + TEST_TYPE_ALIGN (DYNAMIC_TIME_ZONE_INFORMATION, 4) + TEST_FIELD_SIZE (DYNAMIC_TIME_ZONE_INFORMATION, Bias, 4) + TEST_FIELD_ALIGN (DYNAMIC_TIME_ZONE_INFORMATION, Bias, 4) + TEST_FIELD_OFFSET(DYNAMIC_TIME_ZONE_INFORMATION, Bias, 0) + TEST_FIELD_SIZE (DYNAMIC_TIME_ZONE_INFORMATION, StandardName, 64) + TEST_FIELD_ALIGN (DYNAMIC_TIME_ZONE_INFORMATION, StandardName, 2) + TEST_FIELD_OFFSET(DYNAMIC_TIME_ZONE_INFORMATION, StandardName, 4) + TEST_FIELD_SIZE (DYNAMIC_TIME_ZONE_INFORMATION, StandardDate, 16) + TEST_FIELD_ALIGN (DYNAMIC_TIME_ZONE_INFORMATION, StandardDate, 2) + TEST_FIELD_OFFSET(DYNAMIC_TIME_ZONE_INFORMATION, StandardDate, 68) + TEST_FIELD_SIZE (DYNAMIC_TIME_ZONE_INFORMATION, StandardBias, 4) + TEST_FIELD_ALIGN (DYNAMIC_TIME_ZONE_INFORMATION, StandardBias, 4) + TEST_FIELD_OFFSET(DYNAMIC_TIME_ZONE_INFORMATION, StandardBias, 84) + TEST_FIELD_SIZE (DYNAMIC_TIME_ZONE_INFORMATION, DaylightName, 64) + TEST_FIELD_ALIGN (DYNAMIC_TIME_ZONE_INFORMATION, DaylightName, 2) + TEST_FIELD_OFFSET(DYNAMIC_TIME_ZONE_INFORMATION, DaylightName, 88) + TEST_FIELD_SIZE (DYNAMIC_TIME_ZONE_INFORMATION, DaylightDate, 16) + TEST_FIELD_ALIGN (DYNAMIC_TIME_ZONE_INFORMATION, DaylightDate, 2) + TEST_FIELD_OFFSET(DYNAMIC_TIME_ZONE_INFORMATION, DaylightDate, 152) + TEST_FIELD_SIZE (DYNAMIC_TIME_ZONE_INFORMATION, DaylightBias, 4) + TEST_FIELD_ALIGN (DYNAMIC_TIME_ZONE_INFORMATION, DaylightBias, 4) + TEST_FIELD_OFFSET(DYNAMIC_TIME_ZONE_INFORMATION, DaylightBias, 168) + TEST_FIELD_SIZE (DYNAMIC_TIME_ZONE_INFORMATION, TimeZoneKeyName, 256) + TEST_FIELD_ALIGN (DYNAMIC_TIME_ZONE_INFORMATION, TimeZoneKeyName, 2) + TEST_FIELD_OFFSET(DYNAMIC_TIME_ZONE_INFORMATION, TimeZoneKeyName, 172) + TEST_FIELD_SIZE (DYNAMIC_TIME_ZONE_INFORMATION, DynamicDaylightTimeDisabled, 1) + TEST_FIELD_ALIGN (DYNAMIC_TIME_ZONE_INFORMATION, DynamicDaylightTimeDisabled, 1) + TEST_FIELD_OFFSET(DYNAMIC_TIME_ZONE_INFORMATION, DynamicDaylightTimeDisabled, 428) +} + +static void test_pack_LPTIME_ZONE_INFORMATION(void) +{ + /* LPTIME_ZONE_INFORMATION */ + TEST_TYPE_SIZE (LPTIME_ZONE_INFORMATION, 4) + TEST_TYPE_ALIGN (LPTIME_ZONE_INFORMATION, 4) + TEST_TARGET_SIZE (LPTIME_ZONE_INFORMATION, 172) + TEST_TARGET_ALIGN(LPTIME_ZONE_INFORMATION, 4) +} + +static void test_pack_PDYNAMIC_TIME_ZONE_INFORMATION(void) +{ + /* PDYNAMIC_TIME_ZONE_INFORMATION */ + TEST_TYPE_SIZE (PDYNAMIC_TIME_ZONE_INFORMATION, 4) + TEST_TYPE_ALIGN (PDYNAMIC_TIME_ZONE_INFORMATION, 4) + TEST_TARGET_SIZE (PDYNAMIC_TIME_ZONE_INFORMATION, 432) + TEST_TARGET_ALIGN(PDYNAMIC_TIME_ZONE_INFORMATION, 4) +} + +static void test_pack_PTIME_ZONE_INFORMATION(void) +{ + /* PTIME_ZONE_INFORMATION */ + TEST_TYPE_SIZE (PTIME_ZONE_INFORMATION, 4) + TEST_TYPE_ALIGN (PTIME_ZONE_INFORMATION, 4) + TEST_TARGET_SIZE (PTIME_ZONE_INFORMATION, 172) + TEST_TARGET_ALIGN(PTIME_ZONE_INFORMATION, 4) +} + +static void test_pack_TIME_ZONE_INFORMATION(void) +{ + /* TIME_ZONE_INFORMATION */ + TEST_TYPE_SIZE (TIME_ZONE_INFORMATION, 172) + TEST_TYPE_ALIGN (TIME_ZONE_INFORMATION, 4) + TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, Bias, 4) + TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, Bias, 4) + TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, Bias, 0) + TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, StandardName, 64) + TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, StandardName, 2) + TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, StandardName, 4) + TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, StandardDate, 16) + TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, StandardDate, 2) + TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, StandardDate, 68) + TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, StandardBias, 4) + TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, StandardBias, 4) + TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, StandardBias, 84) + TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, DaylightName, 64) + TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, DaylightName, 2) + TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, DaylightName, 88) + TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, DaylightDate, 16) + TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, DaylightDate, 2) + TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, DaylightDate, 152) + TEST_FIELD_SIZE (TIME_ZONE_INFORMATION, DaylightBias, 4) + TEST_FIELD_ALIGN (TIME_ZONE_INFORMATION, DaylightBias, 4) + TEST_FIELD_OFFSET(TIME_ZONE_INFORMATION, DaylightBias, 168) +} + #endif /* _WIN64 */ static void test_pack(void) @@ -3806,6 +3892,7 @@ static void test_pack(void) test_pack_CRITICAL_SECTION_DEBUG(); test_pack_DCB(); test_pack_DEBUG_EVENT(); + test_pack_DYNAMIC_TIME_ZONE_INFORMATION(); test_pack_ENUMRESLANGPROCA(); test_pack_ENUMRESLANGPROCW(); test_pack_ENUMRESNAMEPROCA(); @@ -3881,6 +3968,7 @@ static void test_pack(void) test_pack_PCACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA(); test_pack_PCRITICAL_SECTION(); test_pack_PCRITICAL_SECTION_DEBUG(); + test_pack_PDYNAMIC_TIME_ZONE_INFORMATION(); test_pack_PFIBER_START_ROUTINE(); test_pack_PHKEY(); test_pack_POFSTRUCT(); diff --git a/modules/rostests/winetests/kernel32/get_fpu_cw.asm b/modules/rostests/winetests/kernel32/get_fpu_cw.asm new file mode 100644 index 00000000000..069023cc696 --- /dev/null +++ b/modules/rostests/winetests/kernel32/get_fpu_cw.asm @@ -0,0 +1,10 @@ +.code + +PUBLIC get_fpu_cw_raw +get_fpu_cw_raw PROC + fnstcw word ptr [rcx] + stmxcsr dword ptr [rdx] + ret +get_fpu_cw_raw ENDP + +END diff --git a/modules/rostests/winetests/kernel32/heap.c b/modules/rostests/winetests/kernel32/heap.c index fefd3e79561..18fa6536d0b 100644 --- a/modules/rostests/winetests/kernel32/heap.c +++ b/modules/rostests/winetests/kernel32/heap.c @@ -30,866 +30,3443 @@ #include "winternl.h" #include "wine/test.h" -#define MAGIC_DEAD 0xdeadbeef - /* some undocumented flags (names are made up) */ +#define HEAP_ADD_USER_INFO 0x00000100 +#define HEAP_PRIVATE 0x00001000 #define HEAP_PAGE_ALLOCS 0x01000000 #define HEAP_VALIDATE 0x10000000 #define HEAP_VALIDATE_ALL 0x20000000 #define HEAP_VALIDATE_PARAMS 0x40000000 -static BOOL (WINAPI *pHeapQueryInformation)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T); -static BOOL (WINAPI *pGetPhysicallyInstalledSystemMemory)(ULONGLONG *); +#define BLOCK_ALIGN (2 * sizeof(void *) - 1) +#define ALIGN_BLOCK_SIZE(x) (((x) + BLOCK_ALIGN) & ~BLOCK_ALIGN) + +/* use function pointers to avoid warnings for invalid parameter tests */ +static LPVOID (WINAPI *pHeapAlloc)(HANDLE,DWORD,SIZE_T); +static LPVOID (WINAPI *pHeapReAlloc)(HANDLE,DWORD,LPVOID,SIZE_T); +static BOOL (WINAPI *pHeapFree)(HANDLE,DWORD,LPVOID); +static BOOL (WINAPI *pGetPhysicallyInstalledSystemMemory)( ULONGLONG * ); +static BOOLEAN (WINAPI *pRtlGetUserInfoHeap)(HANDLE,ULONG,void*,void**,ULONG*); +static BOOLEAN (WINAPI *pRtlSetUserValueHeap)(HANDLE,ULONG,void*,void*); +static BOOLEAN (WINAPI *pRtlSetUserFlagsHeap)(HANDLE,ULONG,void*,ULONG,ULONG); +static HGLOBAL (WINAPI *pGlobalAlloc)(UINT,SIZE_T); +static HGLOBAL (WINAPI *pGlobalFree)(HGLOBAL); +static HGLOBAL (WINAPI *pLocalAlloc)(UINT,SIZE_T); +static HGLOBAL (WINAPI *pLocalFree)(HLOCAL); +static BOOL (WINAPI *pHeapQueryInformation)(HANDLE,HEAP_INFORMATION_CLASS,void*,SIZE_T,SIZE_T*); +static BOOL (WINAPI *pHeapSetInformation)(HANDLE,HEAP_INFORMATION_CLASS,void*,SIZE_T); +static UINT (WINAPI *pGlobalFlags)(HGLOBAL); static ULONG (WINAPI *pRtlGetNtGlobalFlags)(void); -struct heap_layout +static void load_functions(void) { - DWORD_PTR unknown[2]; - DWORD pattern; - DWORD flags; - DWORD force_flags; + HMODULE kernel32 = GetModuleHandleW( L"kernel32.dll" ); + HMODULE ntdll = GetModuleHandleW( L"ntdll.dll" ); + +#define LOAD_FUNC(m, f) p ## f = (void *)GetProcAddress( m, #f ); + LOAD_FUNC( kernel32, HeapAlloc ); + LOAD_FUNC( kernel32, HeapReAlloc ); + LOAD_FUNC( kernel32, HeapFree ); + LOAD_FUNC( kernel32, HeapQueryInformation ); + LOAD_FUNC( kernel32, HeapSetInformation ); + LOAD_FUNC( kernel32, GetPhysicallyInstalledSystemMemory ); + LOAD_FUNC( kernel32, GlobalAlloc ); + LOAD_FUNC( kernel32, GlobalFlags ); + LOAD_FUNC( kernel32, GlobalFree ); + LOAD_FUNC( kernel32, LocalAlloc ); + LOAD_FUNC( kernel32, LocalFree ); + LOAD_FUNC( ntdll, RtlGetNtGlobalFlags ); + LOAD_FUNC( ntdll, RtlGetUserInfoHeap ); + LOAD_FUNC( ntdll, RtlSetUserValueHeap ); + LOAD_FUNC( ntdll, RtlSetUserFlagsHeap ); +#undef LOAD_FUNC +} + +struct heap +{ + UINT_PTR unknown1[2]; + UINT ffeeffee; + UINT auto_flags; + UINT_PTR unknown2[7]; + UINT unknown3[2]; + UINT_PTR unknown4[3]; + UINT flags; + UINT force_flags; }; -static SIZE_T resize_9x(SIZE_T size) + +/* undocumented RtlWalkHeap structure */ + +struct rtl_heap_entry { - DWORD dwSizeAligned = (size + 3) & ~3; - return max(dwSizeAligned, 12); /* at least 12 bytes */ -} + LPVOID lpData; + SIZE_T cbData; /* differs from PROCESS_HEAP_ENTRY */ + BYTE cbOverhead; + BYTE iRegionIndex; + WORD wFlags; /* value differs from PROCESS_HEAP_ENTRY */ + union { + struct { + HANDLE hMem; + DWORD dwReserved[3]; + } Block; + struct { + DWORD dwCommittedSize; + DWORD dwUnCommittedSize; + LPVOID lpFirstBlock; + LPVOID lpLastBlock; + } Region; + }; +}; -static void test_sized_HeapAlloc(int nbytes) +/* rtl_heap_entry flags, names made up */ + +#define RTL_HEAP_ENTRY_BUSY 0x0001 +#define RTL_HEAP_ENTRY_REGION 0x0002 +#define RTL_HEAP_ENTRY_BLOCK 0x0010 +#define RTL_HEAP_ENTRY_UNCOMMITTED 0x1000 +#define RTL_HEAP_ENTRY_COMMITTED 0x4000 +#define RTL_HEAP_ENTRY_LFH 0x8000 + + +struct heap_thread_params { - BOOL success; - char *buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nbytes); - ok(buf != NULL, "allocate failed\n"); - ok(buf[0] == 0, "buffer not zeroed\n"); - success = HeapFree(GetProcessHeap(), 0, buf); - ok(success, "free failed\n"); -} + HANDLE ready_event; + HANDLE start_event; + BOOL done; -static void test_sized_HeapReAlloc(int nbytes1, int nbytes2) + HANDLE heap; + DWORD flags; + BOOL lock; +}; + +DWORD WINAPI heap_thread_proc( void *arg ) { - BOOL success; - char *buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nbytes1); - ok(buf != NULL, "allocate failed\n"); - ok(buf[0] == 0, "buffer not zeroed\n"); - buf = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buf, nbytes2); - ok(buf != NULL, "reallocate failed\n"); - ok(buf[nbytes2-1] == 0, "buffer not zeroed\n"); - success = HeapFree(GetProcessHeap(), 0, buf); - ok(success, "free failed\n"); -} + struct heap_thread_params *params = arg; + void *ptr; + DWORD res; + BOOL ret; -static void test_heap(void) -{ - LPVOID mem; - LPVOID msecond; - DWORD res; - UINT flags; - HGLOBAL gbl; - HGLOBAL hsecond; - SIZE_T size, size2; - const SIZE_T max_size = 1024, init_size = 10; - /* use function pointers to avoid warnings for invalid parameter tests */ - LPVOID (WINAPI *pHeapAlloc)(HANDLE,DWORD,SIZE_T); - LPVOID (WINAPI *pHeapReAlloc)(HANDLE,DWORD,LPVOID,SIZE_T); + SetEvent( params->ready_event ); - pHeapAlloc = (void *)GetProcAddress( GetModuleHandleA("kernel32"), "HeapAlloc" ); - pHeapReAlloc = (void *)GetProcAddress( GetModuleHandleA("kernel32"), "HeapReAlloc" ); - - /* Heap*() functions */ - mem = HeapAlloc(GetProcessHeap(), 0, 0); - ok(mem != NULL, "memory not allocated for size 0\n"); - HeapFree(GetProcessHeap(), 0, mem); - - mem = HeapReAlloc(GetProcessHeap(), 0, NULL, 10); - ok(mem == NULL, "memory allocated by HeapReAlloc\n"); - - for (size = 0; size <= 256; size++) + while (!(res = WaitForSingleObject( params->start_event, INFINITE )) && !params->done) { - SIZE_T heap_size; - mem = HeapAlloc(GetProcessHeap(), 0, size); - heap_size = HeapSize(GetProcessHeap(), 0, mem); - ok(heap_size == size || heap_size == resize_9x(size), - "HeapSize returned %lu instead of %lu or %lu\n", heap_size, size, resize_9x(size)); - HeapFree(GetProcessHeap(), 0, mem); + if (params->lock) + { + ret = HeapLock( params->heap ); + ok( ret, "HeapLock failed, error %lu\n", GetLastError() ); + } + + ptr = HeapAlloc( params->heap, params->flags, 0 ); + ok( !!ptr, "HeapAlloc failed, error %lu\n", GetLastError() ); + ret = HeapFree( params->heap, params->flags, ptr ); + ok( ret, "HeapFree failed, error %lu\n", GetLastError() ); + + if (params->lock) + { + ret = HeapUnlock( params->heap ); + ok( ret, "HeapUnlock failed, error %lu\n", GetLastError() ); + } + + SetEvent( params->ready_event ); } + ok( !res, "WaitForSingleObject returned %#lx, error %lu\n", res, GetLastError() ); - /* test some border cases of HeapAlloc and HeapReAlloc */ - mem = HeapAlloc(GetProcessHeap(), 0, 0); - ok(mem != NULL, "memory not allocated for size 0\n"); - msecond = pHeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, ~(SIZE_T)0 - 7); - ok(msecond == NULL, "HeapReAlloc(~0 - 7) should have failed\n"); - msecond = pHeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, ~(SIZE_T)0); - ok(msecond == NULL, "HeapReAlloc(~0) should have failed\n"); - HeapFree(GetProcessHeap(), 0, mem); - mem = pHeapAlloc(GetProcessHeap(), 0, ~(SIZE_T)0); - ok(mem == NULL, "memory allocated for size ~0\n"); - mem = HeapAlloc(GetProcessHeap(), 0, 17); - msecond = HeapReAlloc(GetProcessHeap(), 0, mem, 0); - ok(msecond != NULL, "HeapReAlloc(0) should have succeeded\n"); - size = HeapSize(GetProcessHeap(), 0, msecond); - ok(size == 0 || broken(size == 1) /* some vista and win7 */, - "HeapSize should have returned 0 instead of %lu\n", size); - HeapFree(GetProcessHeap(), 0, msecond); - - /* large blocks must be 16-byte aligned */ - mem = HeapAlloc(GetProcessHeap(), 0, 512 * 1024); - 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"); - - gbl = GlobalReAlloc(gbl, 10, GMEM_MOVEABLE); - ok(gbl != NULL, "Can't realloc global memory\n"); - size = GlobalSize(gbl); - ok(size >= 10 && size <= 16, "Memory not resized to size 10, instead size=%ld\n", size); - - gbl = GlobalReAlloc(gbl, 0, GMEM_MOVEABLE); - ok(gbl != NULL, "GlobalReAlloc should not fail on size 0\n"); - - size = GlobalSize(gbl); - ok(size == 0, "Memory not resized to size 0, instead size=%ld\n", size); - ok(GlobalFree(gbl) == NULL, "Memory not freed\n"); - size = GlobalSize(gbl); - ok(size == 0, "Memory should have been freed, size=%ld\n", size); - - gbl = GlobalReAlloc(0, 10, GMEM_MOVEABLE); - ok(gbl == NULL, "global realloc allocated memory\n"); - - /* GlobalLock / GlobalUnlock with a valid handle */ - gbl = GlobalAlloc(GMEM_MOVEABLE, 256); - - SetLastError(MAGIC_DEAD); - mem = GlobalLock(gbl); /* #1 */ - ok(mem != NULL, "returned %p with %d (expected '!= NULL')\n", mem, GetLastError()); - SetLastError(MAGIC_DEAD); - flags = GlobalFlags(gbl); - ok( flags == 1, "returned 0x%04x with %d (expected '0x0001')\n", - flags, GetLastError()); - - SetLastError(MAGIC_DEAD); - msecond = GlobalLock(gbl); /* #2 */ - ok( msecond == mem, "returned %p with %d (expected '%p')\n", - msecond, GetLastError(), mem); - SetLastError(MAGIC_DEAD); - flags = GlobalFlags(gbl); - ok( flags == 2, "returned 0x%04x with %d (expected '0x0002')\n", - flags, GetLastError()); - SetLastError(MAGIC_DEAD); - - SetLastError(MAGIC_DEAD); - res = GlobalUnlock(gbl); /* #1 */ - ok(res, "returned %d with %d (expected '!= 0')\n", res, GetLastError()); - SetLastError(MAGIC_DEAD); - flags = GlobalFlags(gbl); - ok( flags , "returned 0x%04x with %d (expected '!= 0')\n", - flags, GetLastError()); - - SetLastError(MAGIC_DEAD); - res = GlobalUnlock(gbl); /* #0 */ - /* NT: ERROR_SUCCESS (documented on MSDN), 9x: untouched */ - ok(!res && ((GetLastError() == ERROR_SUCCESS) || (GetLastError() == MAGIC_DEAD)), - "returned %d with %d (expected '0' with: ERROR_SUCCESS or " - "MAGIC_DEAD)\n", res, GetLastError()); - SetLastError(MAGIC_DEAD); - flags = GlobalFlags(gbl); - ok( !flags , "returned 0x%04x with %d (expected '0')\n", - flags, GetLastError()); - - /* Unlock an already unlocked Handle */ - SetLastError(MAGIC_DEAD); - res = GlobalUnlock(gbl); - /* NT: ERROR_NOT_LOCKED, 9x: untouched */ - ok( !res && - ((GetLastError() == ERROR_NOT_LOCKED) || (GetLastError() == MAGIC_DEAD)), - "returned %d with %d (expected '0' with: ERROR_NOT_LOCKED or " - "MAGIC_DEAD)\n", res, GetLastError()); - - GlobalFree(gbl); - /* invalid handles are caught in windows: */ - SetLastError(MAGIC_DEAD); - hsecond = GlobalFree(gbl); /* invalid handle: free memory twice */ - ok( (hsecond == gbl) && (GetLastError() == ERROR_INVALID_HANDLE), - "returned %p with 0x%08x (expected %p with ERROR_INVALID_HANDLE)\n", - hsecond, GetLastError(), gbl); - SetLastError(MAGIC_DEAD); - hsecond = GlobalFree(LongToHandle(0xdeadbeef)); /* bogus handle */ - ok( (hsecond == LongToHandle(0xdeadbeef)) && (GetLastError() == ERROR_INVALID_HANDLE), - "returned %p with 0x%08x (expected %p with ERROR_INVALID_HANDLE)\n", - hsecond, GetLastError(), LongToHandle(0xdeadbeef)); - SetLastError(MAGIC_DEAD); - hsecond = GlobalFree(LongToHandle(0xdeadbee0)); /* bogus pointer */ - ok( (hsecond == LongToHandle(0xdeadbee0)) && - ((GetLastError() == ERROR_INVALID_HANDLE) || broken(GetLastError() == ERROR_NOACCESS) /* wvista+ */), - "returned %p with 0x%08x (expected %p with ERROR_NOACCESS)\n", - hsecond, GetLastError(), LongToHandle(0xdeadbee0)); - - SetLastError(MAGIC_DEAD); - flags = GlobalFlags(gbl); - ok( (flags == GMEM_INVALID_HANDLE) && (GetLastError() == ERROR_INVALID_HANDLE), - "returned 0x%04x with 0x%08x (expected GMEM_INVALID_HANDLE with " - "ERROR_INVALID_HANDLE)\n", flags, GetLastError()); - SetLastError(MAGIC_DEAD); - size = GlobalSize(gbl); - ok( (size == 0) && (GetLastError() == ERROR_INVALID_HANDLE), - "returned %ld with 0x%08x (expected '0' with ERROR_INVALID_HANDLE)\n", - size, GetLastError()); - - SetLastError(MAGIC_DEAD); - mem = GlobalLock(gbl); - ok( (mem == NULL) && (GetLastError() == ERROR_INVALID_HANDLE), - "returned %p with 0x%08x (expected NULL with ERROR_INVALID_HANDLE)\n", - mem, GetLastError()); - - /* documented on MSDN: GlobalUnlock() return FALSE on failure. - Win9x and wine return FALSE with ERROR_INVALID_HANDLE, but on - NT 3.51 and XPsp2, TRUE with ERROR_INVALID_HANDLE is returned. - The similar Test for LocalUnlock() works on all Systems */ - SetLastError(MAGIC_DEAD); - res = GlobalUnlock(gbl); - ok(GetLastError() == ERROR_INVALID_HANDLE, - "returned %d with %d (expected ERROR_INVALID_HANDLE)\n", - res, GetLastError()); - - gbl = GlobalAlloc(GMEM_DDESHARE, 100); - - /* first free */ - mem = GlobalFree(gbl); - ok(mem == NULL, "Expected NULL, got %p\n", mem); - - /* invalid free */ - if (sizeof(void *) != 8) /* crashes on 64-bit */ - { - SetLastError(MAGIC_DEAD); - mem = GlobalFree(gbl); - 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()); - } - - /* GMEM_FIXED block expands in place only without flags */ - for (size = 1; size <= max_size; size <<= 1) { - gbl = GlobalAlloc(GMEM_FIXED, init_size); - SetLastError(MAGIC_DEAD); - hsecond = GlobalReAlloc(gbl, size + init_size, 0); - ok(hsecond == gbl || (hsecond == NULL && GetLastError() == ERROR_NOT_ENOUGH_MEMORY), - "got %p with %x (expected %p or NULL) @%ld\n", hsecond, GetLastError(), gbl, size); - GlobalFree(gbl); - } - - /* GMEM_FIXED block can be relocated with GMEM_MOVEABLE */ - for (size = 1; size <= max_size; size <<= 1) { - gbl = GlobalAlloc(GMEM_FIXED, init_size); - SetLastError(MAGIC_DEAD); - hsecond = GlobalReAlloc(gbl, size + init_size, GMEM_MOVEABLE); - ok(hsecond != NULL, - "got %p with %x (expected non-NULL) @%ld\n", hsecond, GetLastError(), size); - mem = GlobalLock(hsecond); - ok(mem == hsecond, "got %p (expected %p) @%ld\n", mem, hsecond, size); - GlobalFree(hsecond); - } - - gbl = GlobalAlloc(GMEM_DDESHARE, 100); - - res = GlobalUnlock(gbl); - ok(res == 1 || - broken(res == 0), /* win9x */ - "Expected 1 or 0, got %d\n", res); - - res = GlobalUnlock(gbl); - ok(res == 1 || - broken(res == 0), /* win9x */ - "Expected 1 or 0, got %d\n", res); - - GlobalFree(gbl); - - gbl = GlobalAlloc(GMEM_FIXED, 100); - - SetLastError(0xdeadbeef); - res = GlobalUnlock(gbl); - ok(res == 1 || - broken(res == 0), /* win9x */ - "Expected 1 or 0, got %d\n", res); - ok(GetLastError() == 0xdeadbeef, "got %d\n", GetLastError()); - - GlobalFree(gbl); - - /* GlobalSize on an invalid handle */ - if (sizeof(void *) != 8) /* crashes on 64-bit Vista */ - { - SetLastError(MAGIC_DEAD); - size = GlobalSize((HGLOBAL)0xc042); - ok(size == 0, "Expected 0, got %ld\n", size); - 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_FIXED, 0 ); - SetLastError(0xdeadbeef); - size = GlobalSize( gbl ); - ok( size == 1, "wrong size %lu\n", size ); - GlobalFree( gbl ); - - /* ####################################### */ - /* Local*() functions */ - gbl = LocalAlloc(LMEM_MOVEABLE, 0); - ok(gbl != NULL, "local memory not allocated for size 0\n"); - - gbl = LocalReAlloc(gbl, 10, LMEM_MOVEABLE); - ok(gbl != NULL, "Can't realloc local memory\n"); - size = LocalSize(gbl); - ok(size >= 10 && size <= 16, "Memory not resized to size 10, instead size=%ld\n", size); - - gbl = LocalReAlloc(gbl, 0, LMEM_MOVEABLE); - ok(gbl != NULL, "LocalReAlloc should not fail on size 0\n"); - - size = LocalSize(gbl); - ok(size == 0, "Memory not resized to size 0, instead size=%ld\n", size); - ok(LocalFree(gbl) == NULL, "Memory not freed\n"); - size = LocalSize(gbl); - ok(size == 0, "Memory should have been freed, size=%ld\n", size); - - gbl = LocalReAlloc(0, 10, LMEM_MOVEABLE); - ok(gbl == NULL, "local realloc allocated memory\n"); - - /* LocalLock / LocalUnlock with a valid handle */ - gbl = LocalAlloc(LMEM_MOVEABLE, 256); - SetLastError(MAGIC_DEAD); - mem = LocalLock(gbl); /* #1 */ - ok(mem != NULL, "returned %p with %d (expected '!= NULL')\n", mem, GetLastError()); - SetLastError(MAGIC_DEAD); - flags = LocalFlags(gbl); - ok( flags == 1, "returned 0x%04x with %d (expected '0x0001')\n", - flags, GetLastError()); - - SetLastError(MAGIC_DEAD); - msecond = LocalLock(gbl); /* #2 */ - ok( msecond == mem, "returned %p with %d (expected '%p')\n", - msecond, GetLastError(), mem); - SetLastError(MAGIC_DEAD); - flags = LocalFlags(gbl); - ok( flags == 2, "returned 0x%04x with %d (expected '0x0002')\n", - flags, GetLastError()); - SetLastError(MAGIC_DEAD); - - SetLastError(MAGIC_DEAD); - res = LocalUnlock(gbl); /* #1 */ - ok(res, "returned %d with %d (expected '!= 0')\n", res, GetLastError()); - SetLastError(MAGIC_DEAD); - flags = LocalFlags(gbl); - ok( flags , "returned 0x%04x with %d (expected '!= 0')\n", - flags, GetLastError()); - - SetLastError(MAGIC_DEAD); - res = LocalUnlock(gbl); /* #0 */ - /* NT: ERROR_SUCCESS (documented on MSDN), 9x: untouched */ - ok(!res && ((GetLastError() == ERROR_SUCCESS) || (GetLastError() == MAGIC_DEAD)), - "returned %d with %d (expected '0' with: ERROR_SUCCESS or " - "MAGIC_DEAD)\n", res, GetLastError()); - SetLastError(MAGIC_DEAD); - flags = LocalFlags(gbl); - ok( !flags , "returned 0x%04x with %d (expected '0')\n", - flags, GetLastError()); - - /* Unlock an already unlocked Handle */ - SetLastError(MAGIC_DEAD); - res = LocalUnlock(gbl); - /* NT: ERROR_NOT_LOCKED, 9x: untouched */ - ok( !res && - ((GetLastError() == ERROR_NOT_LOCKED) || (GetLastError() == MAGIC_DEAD)), - "returned %d with %d (expected '0' with: ERROR_NOT_LOCKED or " - "MAGIC_DEAD)\n", res, GetLastError()); - - LocalFree(gbl); - /* invalid handles are caught in windows: */ - SetLastError(MAGIC_DEAD); - hsecond = LocalFree(gbl); /* invalid handle: free memory twice */ - ok( (hsecond == gbl) && (GetLastError() == ERROR_INVALID_HANDLE), - "returned %p with 0x%08x (expected %p with ERROR_INVALID_HANDLE)\n", - hsecond, GetLastError(), gbl); - SetLastError(MAGIC_DEAD); - flags = LocalFlags(gbl); - ok( (flags == LMEM_INVALID_HANDLE) && (GetLastError() == ERROR_INVALID_HANDLE), - "returned 0x%04x with 0x%08x (expected LMEM_INVALID_HANDLE with " - "ERROR_INVALID_HANDLE)\n", flags, GetLastError()); - SetLastError(MAGIC_DEAD); - size = LocalSize(gbl); - ok( (size == 0) && (GetLastError() == ERROR_INVALID_HANDLE), - "returned %ld with 0x%08x (expected '0' with ERROR_INVALID_HANDLE)\n", - size, GetLastError()); - - SetLastError(MAGIC_DEAD); - mem = LocalLock(gbl); - ok( (mem == NULL) && (GetLastError() == ERROR_INVALID_HANDLE), - "returned %p with 0x%08x (expected NULL with ERROR_INVALID_HANDLE)\n", - mem, GetLastError()); - - /* This Test works the same on all Systems (GlobalUnlock() is different) */ - SetLastError(MAGIC_DEAD); - res = LocalUnlock(gbl); - ok(!res && (GetLastError() == ERROR_INVALID_HANDLE), - "returned %d with %d (expected '0' with ERROR_INVALID_HANDLE)\n", - res, GetLastError()); - - /* LMEM_FIXED block expands in place only without flags */ - for (size = 1; size <= max_size; size <<= 1) { - gbl = LocalAlloc(LMEM_FIXED, init_size); - SetLastError(MAGIC_DEAD); - hsecond = LocalReAlloc(gbl, size + init_size, 0); - ok(hsecond == gbl || (hsecond == NULL && GetLastError() == ERROR_NOT_ENOUGH_MEMORY), - "got %p with %x (expected %p or NULL) @%ld\n", hsecond, GetLastError(), gbl, size); - LocalFree(gbl); - } - - /* LMEM_FIXED memory can be relocated with LMEM_MOVEABLE */ - for (size = 1; size <= max_size; size <<= 1) { - gbl = LocalAlloc(LMEM_FIXED, init_size); - SetLastError(MAGIC_DEAD); - hsecond = LocalReAlloc(gbl, size + init_size, LMEM_MOVEABLE); - ok(hsecond != NULL, - "got %p with %x (expected non-NULL) @%ld\n", hsecond, GetLastError(), size); - mem = LocalLock(hsecond); - ok(mem == hsecond, "got %p (expected %p) @%ld\n", mem, hsecond, size); - LocalFree(hsecond); - } - - /* trying to unlock pointer from LocalAlloc */ - gbl = LocalAlloc(LMEM_FIXED, 100); - SetLastError(0xdeadbeef); - res = LocalUnlock(gbl); - ok(res == 0, "Expected 0, got %d\n", res); - ok(GetLastError() == ERROR_NOT_LOCKED || - broken(GetLastError() == 0xdeadbeef) /* win9x */, "got %d\n", GetLastError()); - LocalFree(gbl); - - gbl = LocalAlloc( LMEM_FIXED, 0 ); - SetLastError(0xdeadbeef); - size = LocalSize( gbl ); - ok( !size || broken(size == 1), /* vistau64 */ - "wrong size %lu\n", size ); - LocalFree( gbl ); - - /* trying to lock empty memory should give an error */ - gbl = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,0); - ok(gbl != NULL, "returned NULL\n"); - SetLastError(MAGIC_DEAD); - mem = GlobalLock(gbl); - /* NT: ERROR_DISCARDED, 9x: untouched */ - ok( (mem == NULL) && - ((GetLastError() == ERROR_DISCARDED) || (GetLastError() == MAGIC_DEAD)), - "returned %p with 0x%x/%d (expected 'NULL' with: ERROR_DISCARDED or " - "MAGIC_DEAD)\n", mem, GetLastError(), GetLastError()); - - GlobalFree(gbl); - - /* trying to get size from data pointer (GMEM_MOVEABLE) */ - gbl = GlobalAlloc(GMEM_MOVEABLE, 0x123); - ok(gbl != NULL, "returned NULL\n"); - mem = GlobalLock(gbl); - ok(mem != NULL, "returned NULL.\n"); - ok(gbl != mem, "unexpectedly equal.\n"); - - size = GlobalSize(gbl); - size2 = GlobalSize(mem); - ok(size == 0x123, "got %lu\n", size); - ok(size2 == 0x123, "got %lu\n", size2); - - GlobalFree(gbl); - - /* trying to get size from data pointer (GMEM_FIXED) */ - gbl = GlobalAlloc(GMEM_FIXED, 0x123); - ok(gbl != NULL, "returned NULL\n"); - mem = GlobalLock(gbl); - ok(mem != NULL, "returned NULL.\n"); - ok(gbl == mem, "got %p, %p.\n", gbl, mem); - - size = GlobalSize(gbl); - ok(size == 0x123, "got %lu\n", size); - - GlobalFree(gbl); - - size = GlobalSize((void *)0xdeadbee0); - ok(size == 0, "got %lu\n", size); - + return 0; } static void test_HeapCreate(void) { - SYSTEM_INFO sysInfo; - ULONG memchunk; - HANDLE heap; - LPVOID mem1,mem1a,mem3; - UCHAR *mem2,*mem2a; - UINT i; - BOOL error; - DWORD dwSize; + static const BYTE buffer[512] = {0}; + SIZE_T alloc_size = 0x8000 * sizeof(void *), size, i; + struct rtl_heap_entry rtl_entry, rtl_entries[256]; + struct heap_thread_params thread_params = {0}; + PROCESS_HEAP_ENTRY entry, entries[256]; + HANDLE heap, heap1, heaps[8], thread; + BYTE *ptr, *ptr1, *ptrs[128]; + DWORD heap_count, count; + ULONG compat_info; + UINT_PTR align; + DWORD res; + BOOL ret; - /* Retrieve the page size for this system */ - GetSystemInfo(&sysInfo); - ok(sysInfo.dwPageSize>0,"GetSystemInfo should return a valid page size\n"); + thread_params.ready_event = CreateEventW( NULL, FALSE, FALSE, NULL ); + ok( !!thread_params.ready_event, "CreateEventW failed, error %lu\n", GetLastError() ); + thread_params.start_event = CreateEventW( NULL, FALSE, FALSE, NULL ); + ok( !!thread_params.start_event, "CreateEventW failed, error %lu\n", GetLastError() ); + thread = CreateThread( NULL, 0, heap_thread_proc, &thread_params, 0, NULL ); + ok( !!thread, "CreateThread failed, error %lu\n", GetLastError() ); + res = WaitForSingleObject( thread_params.ready_event, INFINITE ); + ok( !res, "WaitForSingleObject returned %#lx, error %lu\n", res, GetLastError() ); - /* Create a Heap with a minimum and maximum size */ - /* Note that Windows and Wine seem to behave a bit differently with respect - to memory allocation. In Windows, you can't access all the memory - specified in the heap (due to overhead), so choosing a reasonable maximum - size for the heap was done mostly by trial-and-error on Win2k. It may need - more tweaking for otherWindows variants. - */ - memchunk=10*sysInfo.dwPageSize; - heap=HeapCreate(0,2*memchunk,5*memchunk); - ok( !((ULONG_PTR)heap & 0xffff), "heap %p not 64K aligned\n", heap ); + heap_count = GetProcessHeaps( 0, NULL ); + ok( heap_count <= 6, "GetProcessHeaps returned %lu\n", heap_count ); - /* Check that HeapCreate allocated the right amount of ram */ - mem1=HeapAlloc(heap,0,5*memchunk+1); - ok(mem1==NULL,"HeapCreate allocated more Ram than it should have\n"); - HeapFree(heap,0,mem1); + /* check heap alignment */ - /* Check that a normal alloc works */ - mem1=HeapAlloc(heap,0,memchunk); - ok(mem1!=NULL,"HeapAlloc failed\n"); - if(mem1) { - ok(HeapSize(heap,0,mem1)>=memchunk, "HeapAlloc should return a big enough memory block\n"); + heap = HeapCreate( 0, 0, 0 ); + ok( !!heap, "HeapCreate failed, error %lu\n", GetLastError() ); + ok( !((ULONG_PTR)heap & 0xffff), "wrong heap alignment\n" ); + count = GetProcessHeaps( 0, NULL ); + ok( count == heap_count + 1, "GetProcessHeaps returned %lu\n", count ); + heap1 = HeapCreate( 0, 0, 0 ); + ok( !!heap, "HeapCreate failed, error %lu\n", GetLastError() ); + ok( !((ULONG_PTR)heap1 & 0xffff), "wrong heap alignment\n" ); + count = GetProcessHeaps( 0, NULL ); + ok( count == heap_count + 2, "GetProcessHeaps returned %lu\n", count ); + count = GetProcessHeaps( ARRAY_SIZE(heaps), heaps ); + ok( count == heap_count + 2, "GetProcessHeaps returned %lu\n", count ); + ok( heaps[0] == GetProcessHeap(), "got wrong heap\n" ); + ok( heaps[heap_count + 0] == heap, "got wrong heap\n" ); + todo_wine + ok( heaps[heap_count + 1] == heap1, "got wrong heap\n" ); + ret = HeapDestroy( heap1 ); + ok( ret, "HeapDestroy failed, error %lu\n", GetLastError() ); + ret = HeapDestroy( heap ); + ok( ret, "HeapDestroy failed, error %lu\n", GetLastError() ); + count = GetProcessHeaps( 0, NULL ); + ok( count == heap_count, "GetProcessHeaps returned %lu\n", count ); + + /* growable heap */ + + heap = HeapCreate( 0, 0, 0 ); + ok( !!heap, "HeapCreate failed, error %lu\n", GetLastError() ); + ok( !((ULONG_PTR)heap & 0xffff), "wrong heap alignment\n" ); + + /* test some border cases */ + + ret = HeapFree( NULL, 0, NULL ); + ok( ret, "HeapFree failed, error %lu\n", GetLastError() ); + ret = HeapFree( heap, 0, NULL ); + ok( ret, "HeapFree failed, error %lu\n", GetLastError() ); + if (0) /* crashes */ + { + SetLastError( 0xdeadbeef ); + ret = HeapFree( heap, 0, (void *)0xdeadbe00 ); + ok( !ret, "HeapFree succeeded\n" ); + ok( GetLastError() == ERROR_NOACCESS, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ptr = (BYTE *)((UINT_PTR)buffer & ~63) + 64; + ret = HeapFree( heap, 0, ptr ); + ok( !ret, "HeapFree succeeded\n" ); + ok( GetLastError() == 0xdeadbeef, "got error %lu\n", GetLastError() ); } - /* Check that a 'zeroing' alloc works */ - mem2=HeapAlloc(heap,HEAP_ZERO_MEMORY,memchunk); - ok(mem2!=NULL,"HeapAlloc failed\n"); - if(mem2) { - ok(HeapSize(heap,0,mem2)>=memchunk,"HeapAlloc should return a big enough memory block\n"); - error=FALSE; - for(i=0;i= _WIN32_WINNT_VISTA) { +#endif + ok( entries[0].wFlags == PROCESS_HEAP_REGION, "got wFlags %#x\n", entries[0].wFlags ); + ok( entries[0].lpData == heap, "got lpData %p\n", entries[0].lpData ); + ok( entries[0].cbData <= 0x1000 /* sizeof(*heap) */, "got cbData %#lx\n", entries[0].cbData ); + ok( entries[0].cbOverhead == 0, "got cbOverhead %#x\n", entries[0].cbOverhead ); + ok( entries[0].iRegionIndex == 0, "got iRegionIndex %d\n", entries[0].iRegionIndex ); + todo_wine + ok( entries[0].Region.dwCommittedSize == 0x400 * sizeof(void *), + "got Region.dwCommittedSize %#lx\n", entries[0].Region.dwCommittedSize ); + ok( entries[0].Region.dwUnCommittedSize == 0x10000 - entries[0].Region.dwCommittedSize || + entries[0].Region.dwUnCommittedSize == 0x10000 * sizeof(void *) - entries[0].Region.dwCommittedSize /* win7 */, + "got Region.dwUnCommittedSize %#lx\n", entries[0].Region.dwUnCommittedSize ); + todo_wine + ok( (BYTE *)entries[0].Region.lpFirstBlock == (BYTE *)entries[0].lpData + entries[0].cbData + 2 * sizeof(void *) || + (BYTE *)entries[0].Region.lpFirstBlock == (BYTE *)entries[0].lpData + entries[0].cbData + 4 * sizeof(void *), + "got Region.lpFirstBlock %p\n", entries[0].Region.lpFirstBlock ); + ok( entries[0].Region.lpLastBlock == (BYTE *)entries[2].lpData + entries[2].cbData, + "got Region.lpLastBlock %p\n", entries[0].Region.lpLastBlock ); - /* Check that HeapReAlloc works */ - mem2a=HeapReAlloc(heap,HEAP_ZERO_MEMORY,mem2,memchunk+5*sysInfo.dwPageSize); - ok(mem2a!=NULL,"HeapReAlloc failed\n"); - if(mem2a) { - ok(HeapSize(heap,0,mem2a)>=memchunk+5*sysInfo.dwPageSize,"HeapReAlloc failed\n"); - error=FALSE; - for(i=0;i<5*sysInfo.dwPageSize;i++) { - if(mem2a[memchunk+i]!=0) { - error=TRUE; + ok( entries[1].wFlags == 0, "got wFlags %#x\n", entries[1].wFlags ); + ok( entries[1].lpData != NULL, "got lpData %p\n", entries[1].lpData ); + ok( entries[1].cbData != 0, "got cbData %#lx\n", entries[1].cbData ); + ok( entries[1].cbOverhead == 4 * sizeof(void *), "got cbOverhead %#x\n", entries[1].cbOverhead ); + ok( entries[1].iRegionIndex == 0, "got iRegionIndex %d\n", entries[1].iRegionIndex ); + + ok( entries[2].wFlags == PROCESS_HEAP_UNCOMMITTED_RANGE, "got wFlags %#x\n", entries[2].wFlags ); + ok( entries[2].lpData == (BYTE *)entries[0].lpData + entries[0].Region.dwCommittedSize, + "got lpData %p\n", entries[2].lpData ); + ok( entries[2].lpData == (BYTE *)entries[1].lpData + entries[1].cbData + 2 * entries[1].cbOverhead, + "got lpData %p\n", entries[2].lpData ); + ok( entries[2].cbData == entries[0].Region.dwUnCommittedSize - 0x1000 || + entries[2].cbData == entries[0].Region.dwUnCommittedSize /* win7 */, + "got cbData %#lx\n", entries[2].cbData ); + ok( entries[2].cbOverhead == 0, "got cbOverhead %#x\n", entries[2].cbOverhead ); + ok( entries[2].iRegionIndex == 0, "got iRegionIndex %d\n", entries[2].iRegionIndex ); +#ifdef __REACTOS__ + } +#endif + + ptr = HeapAlloc( heap, HEAP_ZERO_MEMORY, 5 * alloc_size ); + ok( !!ptr, "HeapAlloc failed, error %lu\n", GetLastError() ); + + count = 0; + memset( &rtl_entries, 0, sizeof(rtl_entries) ); + memset( &rtl_entry, 0xcd, sizeof(rtl_entry) ); + rtl_entry.lpData = NULL; + SetLastError( 0xdeadbeef ); + while (!RtlWalkHeap( heap, &rtl_entry )) rtl_entries[count++] = rtl_entry; +#ifdef __REACTOS__ + ok( count == 4 || broken(count == 5) /* WS03 */, "got count %lu\n", count ); +#else + ok( count == 4, "got count %lu\n", count ); +#endif + + memmove( entries + 16, entries, 3 * sizeof(entry) ); + count = 0; + memset( &entry, 0xcd, sizeof(entry) ); + entry.lpData = NULL; + SetLastError( 0xdeadbeef ); + while ((ret = HeapWalk( heap, &entry ))) entries[count++] = entry; + ok( GetLastError() == ERROR_NO_MORE_ITEMS, "got error %lu\n", GetLastError() ); +#ifdef __REACTOS__ + ok( count == 4 || broken(count == 5) /* WS03 */, "got count %lu\n", count ); +#else + ok( count == 4, "got count %lu\n", count ); +#endif + ok( !memcmp( entries + 16, entries, 3 * sizeof(entry) ), "entries differ\n" ); + + for (i = 0; i < count; ++i) + { + winetest_push_context( "%Iu", i ); + ok( rtl_entries[i].lpData == entries[i].lpData, "got lpData %p\n", rtl_entries[i].lpData ); + ok( rtl_entries[i].cbData == entries[i].cbData, "got cbData %#Ix\n", rtl_entries[i].cbData ); + ok( rtl_entries[i].cbOverhead == entries[i].cbOverhead, "got cbOverhead %#x\n", rtl_entries[i].cbOverhead ); + ok( rtl_entries[i].iRegionIndex == entries[i].iRegionIndex, "got iRegionIndex %#x\n", rtl_entries[i].iRegionIndex ); + if (!entries[i].wFlags) + ok( rtl_entries[i].wFlags == 0, "got wFlags %#x\n", rtl_entries[i].wFlags ); + else if (entries[i].wFlags & PROCESS_HEAP_ENTRY_BUSY) +#ifdef __REACTOS__ + ok( rtl_entries[i].wFlags == (RTL_HEAP_ENTRY_COMMITTED|RTL_HEAP_ENTRY_BLOCK|RTL_HEAP_ENTRY_BUSY) || broken(rtl_entries[i].wFlags == 0x411) /* win7 */ || broken(rtl_entries[i].wFlags == RTL_HEAP_ENTRY_BUSY) /* WS03 */ || broken(rtl_entries[i].wFlags == (RTL_HEAP_ENTRY_BLOCK|0x9)) /* WS03 */, +#else + ok( rtl_entries[i].wFlags == (RTL_HEAP_ENTRY_COMMITTED|RTL_HEAP_ENTRY_BLOCK|RTL_HEAP_ENTRY_BUSY) || broken(rtl_entries[i].wFlags == 0x411) /* win7 */, +#endif + "got wFlags %#x\n", rtl_entries[i].wFlags ); + else if (entries[i].wFlags & PROCESS_HEAP_UNCOMMITTED_RANGE) + ok( rtl_entries[i].wFlags == RTL_HEAP_ENTRY_UNCOMMITTED || broken(rtl_entries[i].wFlags == 0x100) /* win7 */, + "got wFlags %#x\n", rtl_entries[i].wFlags ); + else if (entries[i].wFlags & PROCESS_HEAP_REGION) + { + ok( rtl_entries[i].wFlags == RTL_HEAP_ENTRY_REGION, "got wFlags %#x\n", rtl_entries[i].wFlags ); + ok( rtl_entries[i].Region.dwCommittedSize == entries[i].Region.dwCommittedSize, + "got Region.dwCommittedSize %#lx\n", rtl_entries[i].Region.dwCommittedSize ); + ok( rtl_entries[i].Region.dwUnCommittedSize == entries[i].Region.dwUnCommittedSize, + "got Region.dwUnCommittedSize %#lx\n", rtl_entries[i].Region.dwUnCommittedSize ); + ok( rtl_entries[i].Region.lpFirstBlock == entries[i].Region.lpFirstBlock, + "got Region.lpFirstBlock %p\n", rtl_entries[i].Region.lpFirstBlock ); + ok( rtl_entries[i].Region.lpLastBlock == entries[i].Region.lpLastBlock, + "got Region.lpLastBlock %p\n", rtl_entries[i].Region.lpLastBlock ); } - } - ok(!error,"HeapReAlloc should have zeroed out its allocated memory\n"); + winetest_pop_context(); } - /* Check that HeapReAlloc honours HEAP_REALLOC_IN_PLACE_ONLY */ - error=FALSE; - mem1a=HeapReAlloc(heap,HEAP_REALLOC_IN_PLACE_ONLY,mem1,memchunk+sysInfo.dwPageSize); - if(mem1a!=NULL) { - if(mem1a!=mem1) { - error=TRUE; - } + ok( entries[3].wFlags == PROCESS_HEAP_ENTRY_BUSY || +#ifdef __REACTOS__ + broken(entries[3].wFlags == (PROCESS_HEAP_ENTRY_BUSY | PROCESS_HEAP_ENTRY_DDESHARE)) /* win7 */ || broken(entries[3].wFlags == PROCESS_HEAP_UNCOMMITTED_RANGE) /* WS03 */, +#else + broken(entries[3].wFlags == (PROCESS_HEAP_ENTRY_BUSY | PROCESS_HEAP_ENTRY_DDESHARE)) /* win7 */, +#endif + "got wFlags %#x\n", entries[3].wFlags ); +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) { +#endif + ok( entries[3].lpData == ptr, "got lpData %p\n", entries[3].lpData ); + ok( entries[3].cbData == 5 * alloc_size, "got cbData %#lx\n", entries[3].cbData ); +#ifdef __REACTOS__ } - ok(mem1a==NULL || !error,"HeapReAlloc didn't honour HEAP_REALLOC_IN_PLACE_ONLY\n"); +#endif + ok( entries[3].cbOverhead == 0 || entries[3].cbOverhead == 8 * sizeof(void *) /* win7 */, + "got cbOverhead %#x\n", entries[3].cbOverhead ); +#ifdef __REACTOS__ + ok( entries[3].iRegionIndex == 64 || broken(entries[3].iRegionIndex == 0) /* WS03 */, "got iRegionIndex %d\n", entries[3].iRegionIndex ); +#else + ok( entries[3].iRegionIndex == 64, "got iRegionIndex %d\n", entries[3].iRegionIndex ); +#endif - /* Check that HeapFree works correctly */ - if(mem1a) { - ok(HeapFree(heap,0,mem1a),"HeapFree failed\n"); - } else { - ok(HeapFree(heap,0,mem1),"HeapFree failed\n"); - } - if(mem2a) { - ok(HeapFree(heap,0,mem2a),"HeapFree failed\n"); - } else { - ok(HeapFree(heap,0,mem2),"HeapFree failed\n"); - } + ptr1 = HeapAlloc( heap, HEAP_ZERO_MEMORY, 5 * alloc_size ); + ok( !!ptr1, "HeapAlloc failed, error %lu\n", GetLastError() ); - /* 0-length buffer */ - mem1 = HeapAlloc(heap, 0, 0); - ok(mem1 != NULL, "Reserved memory\n"); + count = 0; + memset( &rtl_entries, 0, sizeof(rtl_entries) ); + memset( &rtl_entry, 0xcd, sizeof(rtl_entry) ); + rtl_entry.lpData = NULL; + SetLastError( 0xdeadbeef ); + while (!RtlWalkHeap( heap, &rtl_entry )) rtl_entries[count++] = rtl_entry; +#ifdef __REACTOS__ + ok( count == 5 || broken(count == 6) /* WS03 */, "got count %lu\n", count ); +#else + ok( count == 5, "got count %lu\n", count ); +#endif - dwSize = HeapSize(heap, 0, mem1); - /* should work with 0-length buffer */ - ok(dwSize < 0xFFFFFFFF, "The size of the 0-length buffer\n"); - ok(HeapFree(heap, 0, mem1), "Freed the 0-length buffer\n"); + memmove( entries + 16, entries, 4 * sizeof(entry) ); + count = 0; + memset( &entry, 0xcd, sizeof(entry) ); + entry.lpData = NULL; + SetLastError( 0xdeadbeef ); + while ((ret = HeapWalk( heap, &entry ))) entries[count++] = entry; + ok( GetLastError() == ERROR_NO_MORE_ITEMS, "got error %lu\n", GetLastError() ); +#ifdef __REACTOS__ + ok( count == 5 || broken(count == 6) /* WS03 */, "got count %lu\n", count ); +#else + ok( count == 5, "got count %lu\n", count ); +#endif + ok( !memcmp( entries + 16, entries, 4 * sizeof(entry) ), "entries differ\n" ); - /* Check that HeapDestroy works */ - ok(HeapDestroy(heap),"HeapDestroy failed\n"); + for (i = 0; i < count; ++i) + { + winetest_push_context( "%Iu", i ); + ok( rtl_entries[i].lpData == entries[i].lpData, "got lpData %p\n", rtl_entries[i].lpData ); + ok( rtl_entries[i].cbData == entries[i].cbData, "got cbData %#Ix\n", rtl_entries[i].cbData ); + ok( rtl_entries[i].cbOverhead == entries[i].cbOverhead, "got cbOverhead %#x\n", rtl_entries[i].cbOverhead ); + ok( rtl_entries[i].iRegionIndex == entries[i].iRegionIndex, "got iRegionIndex %#x\n", rtl_entries[i].iRegionIndex ); + if (!entries[i].wFlags) + ok( rtl_entries[i].wFlags == 0, "got wFlags %#x\n", rtl_entries[i].wFlags ); + else if (entries[i].wFlags & PROCESS_HEAP_ENTRY_BUSY) +#ifdef __REACTOS__ + ok( rtl_entries[i].wFlags == (RTL_HEAP_ENTRY_COMMITTED|RTL_HEAP_ENTRY_BLOCK|RTL_HEAP_ENTRY_BUSY) || broken(rtl_entries[i].wFlags == 0x411) /* win7 */ || broken(rtl_entries[i].wFlags == RTL_HEAP_ENTRY_BUSY) /* WS03 */ || broken(rtl_entries[i].wFlags == (RTL_HEAP_ENTRY_BLOCK|0x9)) /* WS03 */, +#else + ok( rtl_entries[i].wFlags == (RTL_HEAP_ENTRY_COMMITTED|RTL_HEAP_ENTRY_BLOCK|RTL_HEAP_ENTRY_BUSY) || broken(rtl_entries[i].wFlags == 0x411) /* win7 */, +#endif + "got wFlags %#x\n", rtl_entries[i].wFlags ); + else if (entries[i].wFlags & PROCESS_HEAP_UNCOMMITTED_RANGE) + ok( rtl_entries[i].wFlags == RTL_HEAP_ENTRY_UNCOMMITTED || broken(rtl_entries[i].wFlags == 0x100) /* win7 */, + "got wFlags %#x\n", rtl_entries[i].wFlags ); + else if (entries[i].wFlags & PROCESS_HEAP_REGION) + { + ok( rtl_entries[i].wFlags == RTL_HEAP_ENTRY_REGION, "got wFlags %#x\n", rtl_entries[i].wFlags ); + ok( rtl_entries[i].Region.dwCommittedSize == entries[i].Region.dwCommittedSize, + "got Region.dwCommittedSize %#lx\n", rtl_entries[i].Region.dwCommittedSize ); + ok( rtl_entries[i].Region.dwUnCommittedSize == entries[i].Region.dwUnCommittedSize, + "got Region.dwUnCommittedSize %#lx\n", rtl_entries[i].Region.dwUnCommittedSize ); + ok( rtl_entries[i].Region.lpFirstBlock == entries[i].Region.lpFirstBlock, + "got Region.lpFirstBlock %p\n", rtl_entries[i].Region.lpFirstBlock ); + ok( rtl_entries[i].Region.lpLastBlock == entries[i].Region.lpLastBlock, + "got Region.lpLastBlock %p\n", rtl_entries[i].Region.lpLastBlock ); + } + winetest_pop_context(); + } + + ok( entries[4].wFlags == PROCESS_HEAP_ENTRY_BUSY || + broken(entries[4].wFlags == (PROCESS_HEAP_ENTRY_BUSY | PROCESS_HEAP_ENTRY_DDESHARE)) /* win7 */, + "got wFlags %#x\n", entries[4].wFlags ); +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) +#endif + ok( entries[4].lpData == ptr1, "got lpData %p\n", entries[4].lpData ); + ok( entries[4].cbData == 5 * alloc_size, "got cbData %#lx\n", entries[4].cbData ); + ok( entries[4].cbOverhead == 0 || entries[4].cbOverhead == 8 * sizeof(void *) /* win7 */, + "got cbOverhead %#x\n", entries[4].cbOverhead ); + ok( entries[4].iRegionIndex == 64, "got iRegionIndex %d\n", entries[4].iRegionIndex ); + + ret = HeapFree( heap, 0, ptr1 ); + ok( ret, "HeapFree failed, error %lu\n", GetLastError() ); + ret = HeapFree( heap, 0, ptr ); + ok( ret, "HeapFree failed, error %lu\n", GetLastError() ); + + memmove( entries + 16, entries, 3 * sizeof(entry) ); + count = 0; + memset( &entry, 0xcd, sizeof(entry) ); + entry.lpData = NULL; + SetLastError( 0xdeadbeef ); + while ((ret = HeapWalk( heap, &entry ))) entries[count++] = entry; + ok( GetLastError() == ERROR_NO_MORE_ITEMS, "got error %lu\n", GetLastError() ); +#ifdef __REACTOS__ + ok( count == 3 || broken(count == 4) /* WS03 */, "got count %lu\n", count ); +#else + ok( count == 3, "got count %lu\n", count ); +#endif + ok( !memcmp( entries + 16, entries, 3 * sizeof(entry) ), "entries differ\n" ); + + ptr = HeapAlloc( heap, HEAP_ZERO_MEMORY, 123 ); + ok( !!ptr, "HeapAlloc failed, error %lu\n", GetLastError() ); + + memmove( entries + 16, entries, 3 * sizeof(entry) ); + count = 0; + memset( &entry, 0xcd, sizeof(entry) ); + entry.lpData = NULL; + SetLastError( 0xdeadbeef ); + while ((ret = HeapWalk( heap, &entry ))) entries[count++] = entry; + ok( GetLastError() == ERROR_NO_MORE_ITEMS, "got error %lu\n", GetLastError() ); +#ifdef __REACTOS__ + ok( count == 4 || broken(count == 5) /* WS03 */, "got count %lu\n", count ); +#else + ok( count == 4, "got count %lu\n", count ); +#endif + ok( !memcmp( entries + 16, entries, 1 * sizeof(entry) ), "entries differ\n" ); + ok( memcmp( entries + 17, entries + 2, 2 * sizeof(entry) ), "entries differ\n" ); + +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) { +#endif + ok( entries[1].wFlags == PROCESS_HEAP_ENTRY_BUSY, "got wFlags %#x\n", entries[1].wFlags ); + ok( entries[1].lpData == ptr, "got lpData %p\n", entries[1].lpData ); + ok( entries[1].cbData == 123, "got cbData %#lx\n", entries[1].cbData ); + ok( entries[1].cbOverhead != 0, "got cbOverhead %#x\n", entries[1].cbOverhead ); + ok( entries[1].iRegionIndex == 0, "got iRegionIndex %d\n", entries[1].iRegionIndex ); + + ok( entries[2].wFlags == 0, "got wFlags %#x\n", entries[2].wFlags ); + ok( entries[2].lpData == (BYTE *)entries[1].lpData + entries[1].cbData + entries[1].cbOverhead + 2 * sizeof(void *), + "got lpData %p\n", entries[2].lpData ); + ok( entries[2].cbData != 0, "got cbData %#lx\n", entries[2].cbData ); + ok( entries[2].cbOverhead == 4 * sizeof(void *), "got cbOverhead %#x\n", entries[2].cbOverhead ); + ok( entries[2].iRegionIndex == 0, "got iRegionIndex %d\n", entries[2].iRegionIndex ); + + ok( entries[3].wFlags == PROCESS_HEAP_UNCOMMITTED_RANGE, "got wFlags %#x\n", entries[3].wFlags ); + ok( entries[3].lpData == (BYTE *)entries[0].lpData + entries[0].Region.dwCommittedSize, + "got lpData %p\n", entries[3].lpData ); + ok( entries[3].lpData == (BYTE *)entries[2].lpData + entries[2].cbData + 2 * entries[2].cbOverhead, + "got lpData %p\n", entries[3].lpData ); + ok( entries[3].cbData == entries[0].Region.dwUnCommittedSize - 0x1000 || + entries[3].cbData == entries[0].Region.dwUnCommittedSize /* win7 */, + "got cbData %#lx\n", entries[3].cbData ); + ok( entries[3].cbOverhead == 0, "got cbOverhead %#x\n", entries[3].cbOverhead ); + ok( entries[3].iRegionIndex == 0, "got iRegionIndex %d\n", entries[3].iRegionIndex ); +#ifdef __REACTOS__ + } +#endif + + ptr1 = HeapAlloc( heap, HEAP_ZERO_MEMORY, 456 ); + ok( !!ptr1, "HeapAlloc failed, error %lu\n", GetLastError() ); + + memmove( entries + 16, entries, 4 * sizeof(entry) ); + count = 0; + memset( &entry, 0xcd, sizeof(entry) ); + entry.lpData = NULL; + SetLastError( 0xdeadbeef ); + while ((ret = HeapWalk( heap, &entry ))) entries[count++] = entry; + ok( GetLastError() == ERROR_NO_MORE_ITEMS, "got error %lu\n", GetLastError() ); +#ifdef __REACTOS__ + ok( count == 5 || broken(count == 6) /* WS03 */, "got count %lu\n", count ); +#else + ok( count == 5, "got count %lu\n", count ); +#endif + ok( !memcmp( entries + 16, entries, 2 * sizeof(entry) ), "entries differ\n" ); + ok( memcmp( entries + 18, entries + 3, 2 * sizeof(entry) ), "entries differ\n" ); + +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) { +#endif + ok( entries[2].wFlags == PROCESS_HEAP_ENTRY_BUSY, "got wFlags %#x\n", entries[2].wFlags ); + ok( entries[2].lpData == ptr1, "got lpData %p\n", entries[2].lpData ); + ok( entries[2].cbData == 456, "got cbData %#lx\n", entries[2].cbData ); + ok( entries[2].cbOverhead != 0, "got cbOverhead %#x\n", entries[2].cbOverhead ); + ok( entries[2].iRegionIndex == 0, "got iRegionIndex %d\n", entries[2].iRegionIndex ); + + ok( entries[3].wFlags == 0, "got wFlags %#x\n", entries[3].wFlags ); + ok( entries[3].lpData == (BYTE *)entries[2].lpData + entries[2].cbData + entries[2].cbOverhead + 2 * sizeof(void *), + "got lpData %p\n", entries[3].lpData ); + ok( entries[3].cbData != 0, "got cbData %#lx\n", entries[3].cbData ); + ok( entries[3].cbOverhead == 4 * sizeof(void *), "got cbOverhead %#x\n", entries[3].cbOverhead ); + ok( entries[3].iRegionIndex == 0, "got iRegionIndex %d\n", entries[3].iRegionIndex ); + + ok( entries[4].wFlags == PROCESS_HEAP_UNCOMMITTED_RANGE, "got wFlags %#x\n", entries[4].wFlags ); + ok( entries[4].lpData == (BYTE *)entries[0].lpData + entries[0].Region.dwCommittedSize, + "got lpData %p\n", entries[4].lpData ); + ok( entries[4].lpData == (BYTE *)entries[3].lpData + entries[3].cbData + 2 * entries[3].cbOverhead, + "got lpData %p\n", entries[4].lpData ); + ok( entries[4].cbData == entries[0].Region.dwUnCommittedSize - 0x1000 || + entries[4].cbData == entries[0].Region.dwUnCommittedSize /* win7 */, + "got cbData %#lx\n", entries[4].cbData ); + ok( entries[4].cbOverhead == 0, "got cbOverhead %#x\n", entries[4].cbOverhead ); + ok( entries[4].iRegionIndex == 0, "got iRegionIndex %d\n", entries[4].iRegionIndex ); +#ifdef __REACTOS__ + } +#endif + + ret = HeapFree( heap, 0, ptr1 ); + ok( ret, "HeapFree failed, error %lu\n", GetLastError() ); + ret = HeapFree( heap, 0, ptr ); + ok( ret, "HeapFree failed, error %lu\n", GetLastError() ); + +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) { /* NOTE: This crashes on WS03. */ +#endif + size = 0; + SetLastError( 0xdeadbeef ); + ret = pHeapQueryInformation( 0, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); + ok( !ret, "HeapQueryInformation succeeded\n" ); + ok( GetLastError() == ERROR_NOACCESS, "got error %lu\n", GetLastError() ); + ok( size == 0, "got size %Iu\n", size ); +#ifdef __REACTOS__ + } +#endif + + size = 0; + SetLastError( 0xdeadbeef ); + ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, NULL, 0, &size ); + ok( !ret, "HeapQueryInformation succeeded\n" ); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got error %lu\n", GetLastError() ); + ok( size == sizeof(ULONG), "got size %Iu\n", size ); + + SetLastError( 0xdeadbeef ); + ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, NULL, 0, NULL ); + ok( !ret, "HeapQueryInformation succeeded\n" ); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + compat_info = 0xdeadbeef; + ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info) + 1, NULL ); + ok( ret, "HeapQueryInformation failed, error %lu\n", GetLastError() ); + ok( compat_info == 0, "got compat_info %lu\n", compat_info ); + + ret = HeapDestroy( heap ); + ok( ret, "HeapDestroy failed, error %lu\n", GetLastError() ); + + + /* check setting LFH compat info */ + + heap = HeapCreate( 0, 0, 0 ); + ok( !!heap, "HeapCreate failed, error %lu\n", GetLastError() ); + ok( !((ULONG_PTR)heap & 0xffff), "wrong heap alignment\n" ); + + ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); + ok( ret, "HeapQueryInformation failed, error %lu\n", GetLastError() ); +#ifdef __REACTOS__ + ok( compat_info == 0 || broken(compat_info == 1) /* WS03 */, "got HeapCompatibilityInformation %lu\n", compat_info ); +#else + ok( compat_info == 0, "got HeapCompatibilityInformation %lu\n", compat_info ); +#endif + + compat_info = 2; + ret = pHeapSetInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info) ); + ok( ret, "HeapSetInformation failed, error %lu\n", GetLastError() ); + ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); + ok( ret, "HeapQueryInformation failed, error %lu\n", GetLastError() ); + ok( compat_info == 2, "got HeapCompatibilityInformation %lu\n", compat_info ); + + /* cannot be undone */ + + compat_info = 0; + SetLastError( 0xdeadbeef ); + ret = pHeapSetInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info) ); + ok( !ret, "HeapSetInformation succeeded\n" ); + ok( GetLastError() == ERROR_GEN_FAILURE, "got error %lu\n", GetLastError() ); + compat_info = 1; + SetLastError( 0xdeadbeef ); + ret = pHeapSetInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info) ); + ok( !ret, "HeapSetInformation succeeded\n" ); + ok( GetLastError() == ERROR_GEN_FAILURE, "got error %lu\n", GetLastError() ); + ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); + ok( ret, "HeapQueryInformation failed, error %lu\n", GetLastError() ); + ok( compat_info == 2, "got HeapCompatibilityInformation %lu\n", compat_info ); + + ret = HeapDestroy( heap ); + ok( ret, "HeapDestroy failed, error %lu\n", GetLastError() ); + + + /* cannot set LFH with HEAP_NO_SERIALIZE */ + + heap = HeapCreate( HEAP_NO_SERIALIZE, 0, 0 ); + ok( !!heap, "HeapCreate failed, error %lu\n", GetLastError() ); + ok( !((ULONG_PTR)heap & 0xffff), "wrong heap alignment\n" ); + + ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); + ok( ret, "HeapQueryInformation failed, error %lu\n", GetLastError() ); + ok( compat_info == 0, "got HeapCompatibilityInformation %lu\n", compat_info ); + + compat_info = 2; + SetLastError( 0xdeadbeef ); + ret = pHeapSetInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info) ); + ok( !ret, "HeapSetInformation succeeded\n" ); +#ifdef __REACTOS__ + ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == ERROR_GEN_FAILURE) /* WS03 */, "got error %lu\n", GetLastError() ); +#else + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); +#endif + ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); + ok( ret, "HeapQueryInformation failed, error %lu\n", GetLastError() ); + ok( compat_info == 0, "got HeapCompatibilityInformation %lu\n", compat_info ); + + ret = HeapDestroy( heap ); + ok( ret, "HeapDestroy failed, error %lu\n", GetLastError() ); + + + /* some allocation pattern automatically enables LFH */ + + heap = HeapCreate( 0, 0, 0 ); + ok( !!heap, "HeapCreate failed, error %lu\n", GetLastError() ); + ok( !((ULONG_PTR)heap & 0xffff), "wrong heap alignment\n" ); + + ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); + ok( ret, "HeapQueryInformation failed, error %lu\n", GetLastError() ); +#ifdef __REACTOS__ + ok( compat_info == 0 || broken(compat_info == 1) /* WS03 */, "got HeapCompatibilityInformation %lu\n", compat_info ); +#else + ok( compat_info == 0, "got HeapCompatibilityInformation %lu\n", compat_info ); +#endif + + for (i = 0; i < 0x12; i++) ptrs[i] = pHeapAlloc( heap, 0, 0 ); + for (i = 0; i < 0x12; i++) HeapFree( heap, 0, ptrs[i] ); + + ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); + ok( ret, "HeapQueryInformation failed, error %lu\n", GetLastError() ); +#ifdef __REACTOS__ + ok( compat_info == 2 || broken(compat_info == 1) /* WS03 */, "got HeapCompatibilityInformation %lu\n", compat_info ); +#else + ok( compat_info == 2, "got HeapCompatibilityInformation %lu\n", compat_info ); +#endif + + ret = HeapDestroy( heap ); + ok( ret, "HeapDestroy failed, error %lu\n", GetLastError() ); + + + /* LFH actually doesn't enable immediately, the pattern is required */ + + heap = HeapCreate( 0, 0, 0 ); + ok( !!heap, "HeapCreate failed, error %lu\n", GetLastError() ); + ok( !((ULONG_PTR)heap & 0xffff), "wrong heap alignment\n" ); + + compat_info = 2; + ret = pHeapSetInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info) ); + ok( ret, "HeapSetInformation failed, error %lu\n", GetLastError() ); + ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); + ok( ret, "HeapQueryInformation failed, error %lu\n", GetLastError() ); + ok( compat_info == 2, "got HeapCompatibilityInformation %lu\n", compat_info ); + + for (i = 0; i < 0x11; i++) ptrs[i] = pHeapAlloc( heap, 0, 24 + 2 * sizeof(void *) ); + for (i = 0; i < 0x11; i++) HeapFree( heap, 0, ptrs[i] ); + + count = 0; + memset( &entries, 0xcd, sizeof(entries) ); + memset( &entry, 0xcd, sizeof(entry) ); + entry.lpData = NULL; + SetLastError( 0xdeadbeef ); + while ((ret = HeapWalk( heap, &entry ))) entries[count++] = entry; + ok( GetLastError() == ERROR_NO_MORE_ITEMS, "got error %lu\n", GetLastError() ); +#ifdef __REACTOS__ + ok( count == 3 || broken(count == 7) /* WS03 */, "got count %lu\n", count ); +#else + ok( count == 3, "got count %lu\n", count ); +#endif + +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) { +#endif + ok( entries[0].wFlags == PROCESS_HEAP_REGION, "got wFlags %#x\n", entries[0].wFlags ); + ok( entries[0].lpData == heap, "got lpData %p\n", entries[0].lpData ); + ok( entries[0].cbData <= 0x1000 /* sizeof(*heap) */, "got cbData %#lx\n", entries[0].cbData ); + ok( entries[0].cbOverhead == 0, "got cbOverhead %#x\n", entries[0].cbOverhead ); + ok( entries[0].iRegionIndex == 0, "got iRegionIndex %d\n", entries[0].iRegionIndex ); + ok( entries[1].wFlags == 0, "got wFlags %#x\n", entries[1].wFlags ); + ok( entries[2].wFlags == PROCESS_HEAP_UNCOMMITTED_RANGE, "got wFlags %#x\n", entries[2].wFlags ); +#ifdef __REACTOS__ + } +#endif + + for (i = 0; i < 0x12; i++) ptrs[i] = pHeapAlloc( heap, 0, 24 + 2 * sizeof(void *) ); + for (i = 0; i < 0x12; i++) HeapFree( heap, 0, ptrs[i] ); + + count = 0; + memset( &entries, 0xcd, sizeof(entries) ); + memset( &entry, 0xcd, sizeof(entry) ); + entry.lpData = NULL; + SetLastError( 0xdeadbeef ); + while ((ret = HeapWalk( heap, &entry ))) entries[count++] = entry; + ok( GetLastError() == ERROR_NO_MORE_ITEMS, "got error %lu\n", GetLastError() ); + todo_wine +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) +#endif + ok( count > 24, "got count %lu\n", count ); + if (count < 2) count = 2; + +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) { +#endif + ok( entries[0].wFlags == PROCESS_HEAP_REGION, "got wFlags %#x\n", entries[0].wFlags ); + ok( entries[0].lpData == heap, "got lpData %p\n", entries[0].lpData ); + ok( entries[0].cbData <= 0x1000 /* sizeof(*heap) */, "got cbData %#lx\n", entries[0].cbData ); + ok( entries[0].cbOverhead == 0, "got cbOverhead %#x\n", entries[0].cbOverhead ); + ok( entries[0].iRegionIndex == 0, "got iRegionIndex %d\n", entries[0].iRegionIndex ); + todo_wine /* Wine currently reports the LFH group as a single block here */ + ok( entries[1].wFlags == 0, "got wFlags %#x\n", entries[1].wFlags ); + + for (i = 0; i < 0x12; i++) + { + todo_wine + ok( entries[4 + i].wFlags == 0, "got wFlags %#x\n", entries[4 + i].wFlags ); + todo_wine + ok( entries[4 + i].cbData == 0x20, "got cbData %#lx\n", entries[4 + i].cbData ); + todo_wine + ok( entries[4 + i].cbOverhead == 2 * sizeof(void *), "got cbOverhead %#x\n", entries[4 + i].cbOverhead ); + } +#ifdef __REACTOS__ + } +#endif + + if (entries[count - 1].wFlags == PROCESS_HEAP_REGION) /* > win7 */ + ok( entries[count - 2].wFlags == PROCESS_HEAP_UNCOMMITTED_RANGE, "got wFlags %#x\n", entries[count - 2].wFlags ); + else + ok( entries[count - 1].wFlags == PROCESS_HEAP_UNCOMMITTED_RANGE, "got wFlags %#x\n", entries[count - 2].wFlags ); + + count = 0; + memset( &rtl_entries, 0, sizeof(rtl_entries) ); + memset( &rtl_entry, 0xcd, sizeof(rtl_entry) ); + rtl_entry.lpData = NULL; + SetLastError( 0xdeadbeef ); + while (!RtlWalkHeap( heap, &rtl_entry )) rtl_entries[count++] = rtl_entry; + todo_wine +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) +#endif + ok( count > 24, "got count %lu\n", count ); + if (count < 2) count = 2; + + for (i = 3; i < count; ++i) + { + winetest_push_context( "%Iu", i ); + ok( rtl_entries[i].lpData == entries[i].lpData, "got lpData %p\n", rtl_entries[i].lpData ); + ok( rtl_entries[i].cbData == entries[i].cbData, "got cbData %#Ix\n", rtl_entries[i].cbData ); + ok( rtl_entries[i].cbOverhead == entries[i].cbOverhead, "got cbOverhead %#x\n", rtl_entries[i].cbOverhead ); + ok( rtl_entries[i].iRegionIndex == entries[i].iRegionIndex, "got iRegionIndex %#x\n", rtl_entries[i].iRegionIndex ); + if (!entries[i].wFlags) + ok( rtl_entries[i].wFlags == 0 || rtl_entries[i].wFlags == RTL_HEAP_ENTRY_LFH, "got wFlags %#x\n", rtl_entries[i].wFlags ); + else if (entries[i].wFlags & PROCESS_HEAP_ENTRY_BUSY) + ok( rtl_entries[i].wFlags == (RTL_HEAP_ENTRY_LFH|RTL_HEAP_ENTRY_BUSY) || broken(rtl_entries[i].wFlags == 1) /* win7 */, + "got wFlags %#x\n", rtl_entries[i].wFlags ); + else if (entries[i].wFlags & PROCESS_HEAP_UNCOMMITTED_RANGE) + ok( rtl_entries[i].wFlags == RTL_HEAP_ENTRY_UNCOMMITTED || broken(rtl_entries[i].wFlags == 0x100) /* win7 */, + "got wFlags %#x\n", rtl_entries[i].wFlags ); + else if (entries[i].wFlags & PROCESS_HEAP_REGION) + { + ok( rtl_entries[i].wFlags == (RTL_HEAP_ENTRY_LFH|RTL_HEAP_ENTRY_REGION), "got wFlags %#x\n", rtl_entries[i].wFlags ); + ok( rtl_entries[i].Region.dwCommittedSize == entries[i].Region.dwCommittedSize, + "got Region.dwCommittedSize %#lx\n", rtl_entries[i].Region.dwCommittedSize ); + ok( rtl_entries[i].Region.dwUnCommittedSize == entries[i].Region.dwUnCommittedSize, + "got Region.dwUnCommittedSize %#lx\n", rtl_entries[i].Region.dwUnCommittedSize ); + ok( rtl_entries[i].Region.lpFirstBlock == entries[i].Region.lpFirstBlock, + "got Region.lpFirstBlock %p\n", rtl_entries[i].Region.lpFirstBlock ); + ok( rtl_entries[i].Region.lpLastBlock == entries[i].Region.lpLastBlock, + "got Region.lpLastBlock %p\n", rtl_entries[i].Region.lpLastBlock ); + } + winetest_pop_context(); + } + + for (i = 0; i < 0x12; i++) ptrs[i] = pHeapAlloc( heap, 0, 24 + 2 * sizeof(void *) ); + + count = 0; + memset( &entries, 0xcd, sizeof(entries) ); + memset( &entry, 0xcd, sizeof(entry) ); + entry.lpData = NULL; + SetLastError( 0xdeadbeef ); + while ((ret = HeapWalk( heap, &entry ))) entries[count++] = entry; + ok( GetLastError() == ERROR_NO_MORE_ITEMS, "got error %lu\n", GetLastError() ); + todo_wine + ok( count > 24, "got count %lu\n", count ); + if (count < 2) count = 2; + +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) { +#endif + ok( entries[0].wFlags == PROCESS_HEAP_REGION, "got wFlags %#x\n", entries[0].wFlags ); + ok( entries[0].lpData == heap, "got lpData %p\n", entries[0].lpData ); + ok( entries[0].cbData <= 0x1000 /* sizeof(*heap) */, "got cbData %#lx\n", entries[0].cbData ); + ok( entries[0].cbOverhead == 0, "got cbOverhead %#x\n", entries[0].cbOverhead ); + ok( entries[0].iRegionIndex == 0, "got iRegionIndex %d\n", entries[0].iRegionIndex ); + ok( entries[1].wFlags == 0 || entries[1].wFlags == PROCESS_HEAP_ENTRY_BUSY /* win7 */, "got wFlags %#x\n", entries[1].wFlags ); + + for (i = 1; i < count - 2; i++) + { + if (entries[i].wFlags != PROCESS_HEAP_ENTRY_BUSY) continue; + todo_wine /* Wine currently reports the LFH group as a single block */ + ok( entries[i].cbData == 0x18 + 2 * sizeof(void *), "got cbData %#lx\n", entries[i].cbData ); + ok( entries[i].cbOverhead == 0x8, "got cbOverhead %#x\n", entries[i].cbOverhead ); + } +#ifdef __REACTOS__ + } +#endif + + if (entries[count - 1].wFlags == PROCESS_HEAP_REGION) /* > win7 */ + ok( entries[count - 2].wFlags == PROCESS_HEAP_UNCOMMITTED_RANGE, "got wFlags %#x\n", entries[count - 2].wFlags ); + else + ok( entries[count - 1].wFlags == PROCESS_HEAP_UNCOMMITTED_RANGE, "got wFlags %#x\n", entries[count - 2].wFlags ); + + count = 0; + memset( &rtl_entries, 0, sizeof(rtl_entries) ); + memset( &rtl_entry, 0xcd, sizeof(rtl_entry) ); + rtl_entry.lpData = NULL; + SetLastError( 0xdeadbeef ); + while (!RtlWalkHeap( heap, &rtl_entry )) rtl_entries[count++] = rtl_entry; + todo_wine + ok( count > 24, "got count %lu\n", count ); + if (count < 2) count = 2; + + for (i = 3; i < count; ++i) + { + winetest_push_context( "%Iu", i ); + ok( rtl_entries[i].lpData == entries[i].lpData, "got lpData %p\n", rtl_entries[i].lpData ); + ok( rtl_entries[i].cbData == entries[i].cbData, "got cbData %#Ix\n", rtl_entries[i].cbData ); + ok( rtl_entries[i].cbOverhead == entries[i].cbOverhead, "got cbOverhead %#x\n", rtl_entries[i].cbOverhead ); + ok( rtl_entries[i].iRegionIndex == entries[i].iRegionIndex, "got iRegionIndex %#x\n", rtl_entries[i].iRegionIndex ); + if (!entries[i].wFlags) + ok( rtl_entries[i].wFlags == 0 || rtl_entries[i].wFlags == RTL_HEAP_ENTRY_LFH, "got wFlags %#x\n", rtl_entries[i].wFlags ); + else if (entries[i].wFlags & PROCESS_HEAP_ENTRY_BUSY) + { + todo_wine + ok( rtl_entries[i].wFlags == (RTL_HEAP_ENTRY_LFH|RTL_HEAP_ENTRY_BUSY) || broken(rtl_entries[i].wFlags == 1) /* win7 */, + "got wFlags %#x\n", rtl_entries[i].wFlags ); + } + else if (entries[i].wFlags & PROCESS_HEAP_UNCOMMITTED_RANGE) + ok( rtl_entries[i].wFlags == RTL_HEAP_ENTRY_UNCOMMITTED || broken(rtl_entries[i].wFlags == 0x100) /* win7 */, + "got wFlags %#x\n", rtl_entries[i].wFlags ); + else if (entries[i].wFlags & PROCESS_HEAP_REGION) + { + ok( rtl_entries[i].wFlags == (RTL_HEAP_ENTRY_LFH|RTL_HEAP_ENTRY_REGION), "got wFlags %#x\n", rtl_entries[i].wFlags ); + ok( rtl_entries[i].Region.dwCommittedSize == entries[i].Region.dwCommittedSize, + "got Region.dwCommittedSize %#lx\n", rtl_entries[i].Region.dwCommittedSize ); + ok( rtl_entries[i].Region.dwUnCommittedSize == entries[i].Region.dwUnCommittedSize, + "got Region.dwUnCommittedSize %#lx\n", rtl_entries[i].Region.dwUnCommittedSize ); + ok( rtl_entries[i].Region.lpFirstBlock == entries[i].Region.lpFirstBlock, + "got Region.lpFirstBlock %p\n", rtl_entries[i].Region.lpFirstBlock ); + ok( rtl_entries[i].Region.lpLastBlock == entries[i].Region.lpLastBlock, + "got Region.lpLastBlock %p\n", rtl_entries[i].Region.lpLastBlock ); + } + winetest_pop_context(); + } + + for (i = 0; i < 0x12; i++) HeapFree( heap, 0, ptrs[i] ); + + ret = HeapDestroy( heap ); + ok( ret, "HeapDestroy failed, error %lu\n", GetLastError() ); + + + /* check HEAP_NO_SERIALIZE HeapCreate flag effect */ + + heap = HeapCreate( HEAP_NO_SERIALIZE, 0, 0 ); + ok( !!heap, "HeapCreate failed, error %lu\n", GetLastError() ); + ok( !((ULONG_PTR)heap & 0xffff), "wrong heap alignment\n" ); + + ret = HeapLock( heap ); + ok( ret, "HeapLock failed, error %lu\n", GetLastError() ); + thread_params.heap = heap; + thread_params.lock = TRUE; + thread_params.flags = 0; + SetEvent( thread_params.start_event ); + res = WaitForSingleObject( thread_params.ready_event, 100 ); + ok( !res, "WaitForSingleObject returned %#lx, error %lu\n", res, GetLastError() ); + ret = HeapUnlock( heap ); + ok( ret, "HeapUnlock failed, error %lu\n", GetLastError() ); + + ret = HeapLock( heap ); + ok( ret, "HeapLock failed, error %lu\n", GetLastError() ); + thread_params.heap = heap; + thread_params.lock = FALSE; + thread_params.flags = 0; + SetEvent( thread_params.start_event ); + res = WaitForSingleObject( thread_params.ready_event, 100 ); + ok( !res, "WaitForSingleObject returned %#lx, error %lu\n", res, GetLastError() ); + ret = HeapUnlock( heap ); + ok( ret, "HeapUnlock failed, error %lu\n", GetLastError() ); + + ret = HeapDestroy( heap ); + ok( ret, "HeapDestroy failed, error %lu\n", GetLastError() ); + + + /* check HEAP_NO_SERIALIZE HeapAlloc / HeapFree flag effect */ + + heap = HeapCreate( 0, 0, 0 ); + ok( !!heap, "HeapCreate failed, error %lu\n", GetLastError() ); + ok( !((ULONG_PTR)heap & 0xffff), "wrong heap alignment\n" ); + + ret = HeapLock( heap ); + ok( ret, "HeapLock failed, error %lu\n", GetLastError() ); + thread_params.heap = heap; + thread_params.lock = TRUE; + thread_params.flags = 0; + SetEvent( thread_params.start_event ); + res = WaitForSingleObject( thread_params.ready_event, 100 ); + ok( res == WAIT_TIMEOUT, "WaitForSingleObject returned %#lx, error %lu\n", res, GetLastError() ); + ret = HeapUnlock( heap ); + ok( ret, "HeapUnlock failed, error %lu\n", GetLastError() ); + res = WaitForSingleObject( thread_params.ready_event, 100 ); + ok( !res, "WaitForSingleObject returned %#lx, error %lu\n", res, GetLastError() ); + + ret = HeapLock( heap ); + ok( ret, "HeapLock failed, error %lu\n", GetLastError() ); + thread_params.heap = heap; + thread_params.lock = FALSE; + thread_params.flags = 0; + SetEvent( thread_params.start_event ); + res = WaitForSingleObject( thread_params.ready_event, 100 ); + ok( res == WAIT_TIMEOUT, "WaitForSingleObject returned %#lx, error %lu\n", res, GetLastError() ); + ret = HeapUnlock( heap ); + ok( ret, "HeapUnlock failed, error %lu\n", GetLastError() ); + res = WaitForSingleObject( thread_params.ready_event, 100 ); + ok( !res, "WaitForSingleObject returned %#lx, error %lu\n", res, GetLastError() ); + + ret = HeapLock( heap ); + ok( ret, "HeapLock failed, error %lu\n", GetLastError() ); + thread_params.heap = heap; + thread_params.lock = FALSE; + thread_params.flags = HEAP_NO_SERIALIZE; + SetEvent( thread_params.start_event ); + res = WaitForSingleObject( thread_params.ready_event, 100 ); + ok( !res, "WaitForSingleObject returned %#lx, error %lu\n", res, GetLastError() ); + ret = HeapUnlock( heap ); + ok( ret, "HeapUnlock failed, error %lu\n", GetLastError() ); + + ret = HeapDestroy( heap ); + ok( ret, "HeapDestroy failed, error %lu\n", GetLastError() ); + + + /* check LFH heap locking */ + + heap = HeapCreate( 0, 0, 0 ); + ok( !!heap, "HeapCreate failed, error %lu\n", GetLastError() ); + ok( !((ULONG_PTR)heap & 0xffff), "wrong heap alignment\n" ); + + ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); + ok( ret, "HeapQueryInformation failed, error %lu\n", GetLastError() ); +#ifdef __REACTOS__ + ok( compat_info == 0 || broken(compat_info == 1) /* WS03 */, "got HeapCompatibilityInformation %lu\n", compat_info ); +#else + ok( compat_info == 0, "got HeapCompatibilityInformation %lu\n", compat_info ); +#endif + + for (i = 0; i < 0x12; i++) ptrs[i] = pHeapAlloc( heap, 0, 0 ); + for (i = 0; i < 0x12; i++) HeapFree( heap, 0, ptrs[i] ); + + ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); + ok( ret, "HeapQueryInformation failed, error %lu\n", GetLastError() ); +#ifdef __REACTOS__ + ok( compat_info == 2 || broken(compat_info == 1) /* WS03 */, "got HeapCompatibilityInformation %lu\n", compat_info ); +#else + ok( compat_info == 2, "got HeapCompatibilityInformation %lu\n", compat_info ); +#endif + + /* locking is serialized */ + + ret = HeapLock( heap ); + ok( ret, "HeapLock failed, error %lu\n", GetLastError() ); + thread_params.heap = heap; + thread_params.lock = TRUE; + thread_params.flags = 0; + SetEvent( thread_params.start_event ); + res = WaitForSingleObject( thread_params.ready_event, 100 ); + ok( res == WAIT_TIMEOUT, "WaitForSingleObject returned %#lx, error %lu\n", res, GetLastError() ); + ret = HeapUnlock( heap ); + ok( ret, "HeapUnlock failed, error %lu\n", GetLastError() ); + res = WaitForSingleObject( thread_params.ready_event, 100 ); + ok( !res, "WaitForSingleObject returned %#lx, error %lu\n", res, GetLastError() ); + + /* but allocation is not */ + + ret = HeapLock( heap ); + ok( ret, "HeapLock failed, error %lu\n", GetLastError() ); + thread_params.heap = heap; + thread_params.lock = FALSE; + thread_params.flags = 0; + SetEvent( thread_params.start_event ); + res = WaitForSingleObject( thread_params.ready_event, 100 ); +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) +#endif + ok( !res, "WaitForSingleObject returned %#lx, error %lu\n", res, GetLastError() ); + ret = HeapUnlock( heap ); + ok( ret, "HeapUnlock failed, error %lu\n", GetLastError() ); + if (res) res = WaitForSingleObject( thread_params.ready_event, 100 ); + + ret = HeapDestroy( heap ); + ok( ret, "HeapDestroy failed, error %lu\n", GetLastError() ); + + + thread_params.done = TRUE; + SetEvent( thread_params.start_event ); + res = WaitForSingleObject( thread, INFINITE ); + ok( !res, "WaitForSingleObject returned %#lx, error %lu\n", res, GetLastError() ); + CloseHandle( thread_params.start_event ); + CloseHandle( thread_params.ready_event ); + CloseHandle( thread ); } +struct mem_entry +{ + UINT_PTR flags; + void *ptr; +}; + +static struct mem_entry *mem_entry_from_HANDLE( HLOCAL handle ) +{ + return CONTAINING_RECORD( handle, struct mem_entry, ptr ); +} + +static BOOL is_mem_entry( HLOCAL handle ) +{ + return ((UINT_PTR)handle & ((sizeof(void *) << 1) - 1)) == sizeof(void *); +} + static void test_GlobalAlloc(void) { - ULONG memchunk; - HGLOBAL mem1,mem2,mem2a,mem2b; - UCHAR *mem2ptr; - UINT i; - BOOL error; - memchunk=100000; + static const UINT flags_tests[] = + { + GMEM_FIXED | GMEM_NOTIFY, + GMEM_FIXED | GMEM_DISCARDABLE, + GMEM_MOVEABLE | GMEM_NOTIFY, + GMEM_MOVEABLE | GMEM_DDESHARE, + GMEM_MOVEABLE | GMEM_NOT_BANKED, + GMEM_MOVEABLE | GMEM_NODISCARD, + GMEM_MOVEABLE | GMEM_DISCARDABLE, + GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_DISCARDABLE | GMEM_LOWER | GMEM_NOCOMPACT | GMEM_NODISCARD | GMEM_NOT_BANKED | GMEM_NOTIFY, + }; + static const UINT realloc_flags_tests[] = + { + GMEM_FIXED, + GMEM_FIXED | GMEM_MODIFY, + GMEM_MOVEABLE, + GMEM_MOVEABLE | GMEM_MODIFY, + GMEM_MOVEABLE | GMEM_DISCARDABLE, + GMEM_MOVEABLE | GMEM_MODIFY | GMEM_DISCARDABLE, + GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_DISCARDABLE | GMEM_LOWER | GMEM_NOCOMPACT | GMEM_NODISCARD | GMEM_NOT_BANKED | GMEM_NOTIFY, + GMEM_MOVEABLE | GMEM_MODIFY | GMEM_DDESHARE | GMEM_DISCARDABLE | GMEM_LOWER | GMEM_NOCOMPACT | GMEM_NODISCARD | GMEM_NOT_BANKED | GMEM_NOTIFY, + }; + static const char zero_buffer[100000] = {0}; + static const SIZE_T buffer_size = ARRAY_SIZE(zero_buffer); + const HGLOBAL invalid_mem = LongToHandle( 0xdeadbee0 + sizeof(void *) ); + SIZE_T size, alloc_size, small_size = 12, nolfh_size = 0x20000; + void *const invalid_ptr = LongToHandle( 0xdeadbee0 ); + HANDLE heap = GetProcessHeap(); + PROCESS_HEAP_ENTRY walk_entry; + struct mem_entry *entry; + HGLOBAL globals[0x10000]; + HGLOBAL mem, tmp_mem; + BYTE *ptr, *tmp_ptr; + ULONG tmp_flags; + UINT i, flags; + BOOL ret; - SetLastError(NO_ERROR); - /* Check that a normal alloc works */ - mem1=GlobalAlloc(0,memchunk); - ok(mem1!=NULL,"GlobalAlloc failed\n"); - if(mem1) { - ok(GlobalSize(mem1)>=memchunk, "GlobalAlloc should return a big enough memory block\n"); + mem = GlobalFree( 0 ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + mem = GlobalReAlloc( 0, 10, GMEM_MOVEABLE ); + ok( !mem, "GlobalReAlloc succeeded\n" ); + + for (i = 0; i < ARRAY_SIZE(globals); ++i) + { + mem = GlobalAlloc( GMEM_MOVEABLE | GMEM_DISCARDABLE, 0 ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + globals[i] = mem; } - /* Check that a 'zeroing' alloc works */ - mem2=GlobalAlloc(GMEM_ZEROINIT,memchunk); - ok(mem2!=NULL,"GlobalAlloc failed: error=%d\n",GetLastError()); - if(mem2) { - ok(GlobalSize(mem2)>=memchunk,"GlobalAlloc should return a big enough memory block\n"); - mem2ptr=GlobalLock(mem2); - ok(mem2ptr==mem2,"GlobalLock should have returned the same memory as was allocated\n"); - if(mem2ptr) { - error=FALSE; - for(i=0;i= 10 && size <= 16, "GlobalSize returned %Iu\n", size ); + mem = GlobalReAlloc( mem, 0, GMEM_MOVEABLE ); + ok( !!mem, "GlobalReAlloc failed, error %lu\n", GetLastError() ); + size = GlobalSize( mem ); + ok( size == 0, "GlobalSize returned %Iu\n", size ); + mem = GlobalReAlloc( mem, 10, GMEM_MOVEABLE ); + ok( !!mem, "GlobalReAlloc failed, error %lu\n", GetLastError() ); + size = GlobalSize( mem ); + ok( size >= 10 && size <= 16, "GlobalSize returned %Iu\n", size ); + tmp_mem = pGlobalFree( mem ); + ok( !tmp_mem, "GlobalFree failed, error %lu\n", GetLastError() ); + size = GlobalSize( mem ); + ok( size == 0, "GlobalSize returned %Iu\n", size ); + + mem = pGlobalAlloc( GMEM_MOVEABLE | GMEM_DISCARDABLE, 0 ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + entry = mem_entry_from_HANDLE( mem ); + size = GlobalSize( mem ); + ok( size == 0, "GlobalSize returned %Iu\n", size ); + ret = HeapValidate( GetProcessHeap(), 0, entry ); + ok( !ret, "HeapValidate succeeded\n" ); + ok( entry->flags == 0xf, "got unexpected flags %#Ix\n", entry->flags ); + ok( !entry->ptr, "got unexpected ptr %p\n", entry->ptr ); + mem = GlobalFree( mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + mem = pGlobalAlloc( GMEM_MOVEABLE, 0 ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + entry = mem_entry_from_HANDLE( mem ); + size = GlobalSize( mem ); + ok( size == 0, "GlobalSize returned %Iu\n", size ); + ret = HeapValidate( GetProcessHeap(), 0, entry ); + ok( !ret, "HeapValidate succeeded\n" ); + ok( entry->flags == 0xb, "got unexpected flags %#Ix\n", entry->flags ); + ok( !entry->ptr, "got unexpected ptr %p\n", entry->ptr ); + mem = GlobalFree( mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + for (alloc_size = 1; alloc_size < 0x10000000; alloc_size <<= 5) + { + winetest_push_context( "size %#Ix", alloc_size ); + + mem = GlobalAlloc( GMEM_FIXED, alloc_size ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + ok( !((UINT_PTR)mem & sizeof(void *)), "got unexpected ptr align\n" ); + ok( !((UINT_PTR)mem & (sizeof(void *) - 1)), "got unexpected ptr align\n" ); + ret = HeapValidate( GetProcessHeap(), 0, mem ); + ok( ret, "HeapValidate failed, error %lu\n", GetLastError() ); + tmp_mem = GlobalFree( mem ); + ok( !tmp_mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + mem = pGlobalAlloc( GMEM_MOVEABLE, alloc_size ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + ok( ((UINT_PTR)mem & sizeof(void *)), "got unexpected entry align\n" ); + ok( !((UINT_PTR)mem & (sizeof(void *) - 1)), "got unexpected entry align\n" ); + + entry = mem_entry_from_HANDLE( mem ); + ret = HeapValidate( GetProcessHeap(), 0, entry ); + ok( !ret, "HeapValidate succeeded\n" ); + ret = HeapValidate( GetProcessHeap(), 0, entry->ptr ); + ok( ret, "HeapValidate failed, error %lu\n", GetLastError() ); + size = HeapSize( GetProcessHeap(), 0, entry->ptr ); + ok( size == alloc_size, "HeapSize returned %Iu\n", size ); + + tmp_mem = invalid_mem; + tmp_flags = 0xdeadbeef; + ret = pRtlGetUserInfoHeap( GetProcessHeap(), 0, entry->ptr, (void **)&tmp_mem, &tmp_flags ); + ok( ret, "RtlGetUserInfoHeap failed, error %lu\n", GetLastError() ); + ok( tmp_mem == mem, "got user ptr %p\n", tmp_mem ); + ok( tmp_flags == 0x200, "got user flags %#lx\n", tmp_flags ); + + ret = pRtlSetUserValueHeap( GetProcessHeap(), 0, entry->ptr, invalid_mem ); + ok( ret, "RtlSetUserValueHeap failed, error %lu\n", GetLastError() ); + tmp_mem = GlobalHandle( entry->ptr ); + ok( tmp_mem == invalid_mem, "GlobalHandle returned unexpected handle\n" ); + ret = pRtlSetUserValueHeap( GetProcessHeap(), 0, entry->ptr, mem ); + ok( ret, "RtlSetUserValueHeap failed, error %lu\n", GetLastError() ); + + ptr = GlobalLock( mem ); + ok( !!ptr, "GlobalLock failed, error %lu\n", GetLastError() ); + ok( ptr != mem, "got unexpected ptr %p\n", ptr ); + ok( ptr == entry->ptr, "got unexpected ptr %p\n", ptr ); + ok( !((UINT_PTR)ptr & sizeof(void *)), "got unexpected ptr align\n" ); + ok( !((UINT_PTR)ptr & (sizeof(void *) - 1)), "got unexpected ptr align\n" ); + for (i = 1; i < 0xff; ++i) + { + ok( entry->flags == ((i<<16)|3), "got unexpected flags %#Ix\n", entry->flags ); + ptr = GlobalLock( mem ); + ok( !!ptr, "GlobalLock failed, error %lu\n", GetLastError() ); } - ok(!error,"GlobalAlloc should have zeroed out its allocated memory\n"); - } - } - /* Check that GlobalReAlloc works */ - /* Check that we can change GMEM_FIXED to GMEM_MOVEABLE */ - mem2a=GlobalReAlloc(mem2,0,GMEM_MODIFY | GMEM_MOVEABLE); - if(mem2a!=NULL) { - mem2=mem2a; - mem2ptr=GlobalLock(mem2a); - ok(mem2ptr!=NULL && !GlobalUnlock(mem2a)&&GetLastError()==NO_ERROR, - "Converting from FIXED to MOVEABLE didn't REALLY work\n"); + ptr = GlobalLock( mem ); + ok( !!ptr, "GlobalLock failed, error %lu\n", GetLastError() ); + ok( entry->flags == 0xff0003, "got unexpected flags %#Ix\n", entry->flags ); + for (i = 1; i < 0xff; ++i) + { + ret = GlobalUnlock( mem ); + ok( ret, "GlobalUnlock failed, error %lu\n", GetLastError() ); + } + ret = GlobalUnlock( mem ); + ok( !ret, "GlobalUnlock succeeded, error %lu\n", GetLastError() ); + ok( entry->flags == 0x3, "got unexpected flags %#Ix\n", entry->flags ); + + tmp_mem = pGlobalFree( mem ); + ok( !tmp_mem, "GlobalFree failed, error %lu\n", GetLastError() ); + ok( !!entry->flags, "got unexpected flags %#Ix\n", entry->flags ); + ok( !((UINT_PTR)entry->flags & sizeof(void *)), "got unexpected ptr align\n" ); + ok( !((UINT_PTR)entry->flags & (sizeof(void *) - 1)), "got unexpected ptr align\n" ); + ok( !entry->ptr, "got unexpected ptr %p\n", entry->ptr ); + + mem = pGlobalAlloc( GMEM_MOVEABLE | GMEM_DISCARDABLE, 0 ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + entry = mem_entry_from_HANDLE( mem ); + ok( entry->flags == 0xf, "got unexpected flags %#Ix\n", entry->flags ); + ok( !entry->ptr, "got unexpected ptr %p\n", entry->ptr ); + flags = GlobalFlags( mem ); + ok( flags == (GMEM_DISCARDED | GMEM_DISCARDABLE), "GlobalFlags returned %#x, error %lu\n", flags, GetLastError() ); + mem = GlobalFree( mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + mem = pGlobalAlloc( GMEM_MOVEABLE | GMEM_DISCARDABLE, 1 ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + entry = mem_entry_from_HANDLE( mem ); + ok( entry->flags == 0x7, "got unexpected flags %#Ix\n", entry->flags ); + ok( !!entry->ptr, "got unexpected ptr %p\n", entry->ptr ); + flags = GlobalFlags( mem ); + ok( flags == GMEM_DISCARDABLE, "GlobalFlags returned %#x, error %lu\n", flags, GetLastError() ); + mem = GlobalFree( mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + mem = pGlobalAlloc( GMEM_MOVEABLE | GMEM_DISCARDABLE | GMEM_DDESHARE, 1 ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + entry = mem_entry_from_HANDLE( mem ); + ok( entry->flags == 0x8007, "got unexpected flags %#Ix\n", entry->flags ); + ok( !!entry->ptr, "got unexpected ptr %p\n", entry->ptr ); + flags = GlobalFlags( mem ); + ok( flags == (GMEM_DISCARDABLE | GMEM_DDESHARE), "GlobalFlags returned %#x, error %lu\n", flags, GetLastError() ); + mem = GlobalFree( mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + winetest_pop_context(); } - /* Check that ReAllocing memory works as expected */ - mem2a=GlobalReAlloc(mem2,2*memchunk,GMEM_MOVEABLE | GMEM_ZEROINIT); - ok(mem2a!=NULL,"GlobalReAlloc failed\n"); - if(mem2a) { - ok(GlobalSize(mem2a)>=2*memchunk,"GlobalReAlloc failed\n"); - mem2ptr=GlobalLock(mem2a); - ok(mem2ptr!=NULL,"GlobalLock Failed\n"); - if(mem2ptr) { - error=FALSE; - for(i=0;i= _WIN32_WINNT_VISTA) /* crashes on 64-bit, invalid on WS03 */ +#else + if (sizeof(void *) != 8) /* crashes on 64-bit */ +#endif + { + SetLastError( 0xdeadbeef ); + tmp_mem = GlobalHandle( mem ); + ok( !tmp_mem, "GlobalHandle succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); } - if(mem2a) { - ok(GlobalFree(mem2a)==NULL,"GlobalFree failed\n"); + +#ifdef __REACTOS__ + if (is_reactos()) { + ok(FALSE, "FIXME: invalid handle and invalid pointer tests crash on ReactOS!\n"); } else { - ok(GlobalFree(mem2)==NULL,"GlobalFree failed\n"); +#endif + /* invalid handles are caught */ + SetLastError( 0xdeadbeef ); + tmp_mem = pGlobalFree( invalid_mem ); + ok( tmp_mem == invalid_mem, "GlobalFree succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + flags = GlobalFlags( invalid_mem ); + ok( flags == GMEM_INVALID_HANDLE, "GlobalFlags succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + size = GlobalSize( invalid_mem ); + ok( size == 0, "GlobalSize succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ptr = GlobalLock( invalid_mem ); + ok( !ptr, "GlobalLock succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = GlobalUnlock( invalid_mem ); + todo_wine + ok( ret, "GlobalUnlock failed, error %lu\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + tmp_mem = GlobalReAlloc( invalid_mem, 0, GMEM_MOVEABLE ); + ok( !tmp_mem, "GlobalReAlloc succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + if (sizeof(void *) != 8) /* crashes on 64-bit */ + { + SetLastError( 0xdeadbeef ); + tmp_mem = GlobalHandle( invalid_mem ); + ok( !tmp_mem, "GlobalHandle succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = pRtlGetUserInfoHeap( GetProcessHeap(), 0, invalid_mem, (void **)&tmp_ptr, &tmp_flags ); + ok( !ret, "RtlGetUserInfoHeap failed, error %lu\n", GetLastError() ); +#ifdef __REACTOS__ + ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == ERROR_NOACCESS) /* WS03 */, "got error %lu\n", GetLastError() ); +#else + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); +#endif } -} + /* invalid pointers are caught */ + SetLastError( 0xdeadbeef ); + tmp_mem = pGlobalFree( invalid_ptr ); + ok( tmp_mem == invalid_ptr, "GlobalFree succeeded\n" ); + todo_wine +#ifdef __REACTOS__ + ok( GetLastError() == ERROR_NOACCESS || broken(GetLastError() == ERROR_INVALID_HANDLE) /* WS03 */, "got error %lu\n", GetLastError() ); +#else + ok( GetLastError() == ERROR_NOACCESS, "got error %lu\n", GetLastError() ); +#endif + SetLastError( 0xdeadbeef ); + flags = GlobalFlags( invalid_ptr ); + todo_wine + ok( flags == GMEM_INVALID_HANDLE, "GlobalFlags succeeded\n" ); + todo_wine + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + size = GlobalSize( invalid_ptr ); + ok( size == 0, "GlobalSize succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ptr = GlobalLock( invalid_ptr ); + ok( !ptr, "GlobalLock succeeded\n" ); + todo_wine + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = GlobalUnlock( invalid_ptr ); + ok( ret, "GlobalUnlock failed, error %lu\n", GetLastError() ); + ok( GetLastError() == 0xdeadbeef, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + tmp_mem = GlobalReAlloc( invalid_ptr, 0, GMEM_MOVEABLE ); + ok( !tmp_mem, "GlobalReAlloc succeeded\n" ); + todo_wine + ok( GetLastError() == ERROR_NOACCESS, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + tmp_mem = GlobalHandle( invalid_ptr ); + ok( !tmp_mem, "GlobalHandle succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + if (0) /* crashes */ + { + SetLastError( 0xdeadbeef ); + ret = pRtlGetUserInfoHeap( GetProcessHeap(), 0, invalid_ptr, (void **)&tmp_ptr, &tmp_flags ); + ok( ret, "RtlGetUserInfoHeap failed, error %lu\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + } +#ifdef __REACTOS__ + } +#endif + + /* GMEM_FIXED block doesn't allow resize, though it succeeds with GMEM_MODIFY */ + mem = GlobalAlloc( GMEM_FIXED, small_size ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + tmp_mem = GlobalReAlloc( mem, small_size - 1, GMEM_MODIFY ); + ok( !!tmp_mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + ok( tmp_mem == mem, "got ptr %p, expected %p\n", tmp_mem, mem ); + size = GlobalSize( mem ); + ok( size == small_size, "GlobalSize returned %Iu\n", size ); + SetLastError( 0xdeadbeef ); +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) { +#endif + tmp_mem = GlobalReAlloc( mem, small_size, 0 ); + ok( !tmp_mem, "GlobalReAlloc succeeded\n" ); + ok( GetLastError() == ERROR_NOT_ENOUGH_MEMORY, "got error %lu\n", GetLastError() ); +#ifdef __REACTOS__ + } +#endif + if (tmp_mem) mem = tmp_mem; + tmp_mem = GlobalReAlloc( mem, 1024 * 1024, GMEM_MODIFY ); + ok( !!tmp_mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + ok( tmp_mem == mem, "got ptr %p, expected %p\n", tmp_mem, mem ); + size = GlobalSize( mem ); + ok( size == small_size, "GlobalSize returned %Iu\n", size ); + mem = GlobalFree( mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + /* GMEM_FIXED block can be relocated with GMEM_MOVEABLE */ + mem = GlobalAlloc( GMEM_FIXED, small_size ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + tmp_mem = GlobalReAlloc( mem, small_size + 1, GMEM_MOVEABLE ); + ok( !!tmp_mem, "GlobalReAlloc failed, error %lu\n", GetLastError() ); +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) +#endif + ok( tmp_mem != mem, "GlobalReAlloc didn't relocate memory\n" ); + ptr = GlobalLock( tmp_mem ); + ok( !!ptr, "GlobalLock failed, error %lu\n", GetLastError() ); + ok( ptr == tmp_mem, "got ptr %p, expected %p\n", ptr, tmp_mem ); + mem = GlobalFree( tmp_mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + /* test GlobalReAlloc flags / GlobalLock combinations */ +#ifdef __REACTOS__ + if (GetNTVersion() < _WIN32_WINNT_VISTA) { skip("realloc_flags_tests invalid for WS03.\n"); } + else { +#endif + for (i = 0; i < ARRAY_SIZE(realloc_flags_tests); i++) + { + struct mem_entry expect_entry, entry; + BOOL expect_convert; + + flags = realloc_flags_tests[i]; + expect_convert = (flags & (GMEM_MOVEABLE | GMEM_MODIFY)) == (GMEM_MOVEABLE | GMEM_MODIFY); + + winetest_push_context( "flags %#x", flags ); + + mem = pGlobalAlloc( GMEM_FIXED, small_size ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + ok( !is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + + tmp_mem = GlobalReAlloc( mem, 512, flags ); + if (!expect_convert) + { + ok( !is_mem_entry( tmp_mem ), "unexpected moveable %p\n", tmp_mem ); + if (flags == GMEM_MODIFY) ok( tmp_mem == mem, "GlobalReAlloc returned %p\n", tmp_mem ); + else if (flags != GMEM_MOVEABLE) ok( !tmp_mem, "GlobalReAlloc succeeded\n" ); + else ok( tmp_mem != mem, "GlobalReAlloc returned %p\n", tmp_mem ); + } + else + { + ok( is_mem_entry( tmp_mem ), "unexpected moveable %p\n", tmp_mem ); + entry = *mem_entry_from_HANDLE( tmp_mem ); + todo_wine ok( entry.ptr != mem, "got ptr %p was %p\n", entry.ptr, mem ); + if (flags & GMEM_DISCARDABLE) ok( (entry.flags & 0x7fff) == 0x7, "got flags %#Ix\n", entry.flags ); + else ok( (entry.flags & 0x7fff) == 0x3, "got flags %#Ix\n", entry.flags ); + } + if (tmp_mem) mem = tmp_mem; + + size = GlobalSize( mem ); + if (flags == GMEM_MOVEABLE) ok( size == 512, "GlobalSize returned %Iu\n", size ); + else ok( size == small_size, "GlobalSize returned %Iu\n", size ); + + mem = GlobalFree( mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + + mem = pGlobalAlloc( GMEM_FIXED, nolfh_size ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + ok( !is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + + tmp_mem = GlobalReAlloc( mem, nolfh_size + 512, flags ); + if (!expect_convert) + { + ok( !is_mem_entry( tmp_mem ), "unexpected moveable %p\n", tmp_mem ); + if (flags & GMEM_DISCARDABLE) ok( !tmp_mem, "GlobalReAlloc succeeded\n" ); + else ok( tmp_mem == mem, "GlobalReAlloc returned %p\n", tmp_mem ); + } + else + { + ok( is_mem_entry( tmp_mem ), "unexpected moveable %p\n", tmp_mem ); + entry = *mem_entry_from_HANDLE( tmp_mem ); + todo_wine ok( entry.ptr != mem, "got ptr %p was %p\n", entry.ptr, mem ); + if (flags & GMEM_DISCARDABLE) ok( (entry.flags & 0x7fff) == 0x7, "got flags %#Ix\n", entry.flags ); + else ok( (entry.flags & 0x7fff) == 0x3, "got flags %#Ix\n", entry.flags ); + } + if (tmp_mem) mem = tmp_mem; + + size = GlobalSize( mem ); + if (flags & (GMEM_MODIFY | GMEM_DISCARDABLE)) ok( size == nolfh_size, "GlobalSize returned %Iu\n", size ); + else ok( size == nolfh_size + 512, "GlobalSize returned %Iu\n", size ); + + mem = GlobalFree( mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + + mem = pGlobalAlloc( GMEM_FIXED, small_size ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + ok( !is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + + tmp_mem = GlobalReAlloc( mem, 10, flags ); + if (!expect_convert) + { + ok( !is_mem_entry( tmp_mem ), "unexpected moveable %p\n", tmp_mem ); + if (flags == GMEM_MODIFY) ok( tmp_mem == mem, "GlobalReAlloc returned %p\n", tmp_mem ); + else if (flags != GMEM_MOVEABLE) todo_wine_if(!flags) ok( !tmp_mem, "GlobalReAlloc succeeded\n" ); + else todo_wine ok( tmp_mem != mem, "GlobalReAlloc returned %p\n", tmp_mem ); + } + else + { + ok( is_mem_entry( tmp_mem ), "unexpected moveable %p\n", tmp_mem ); + entry = *mem_entry_from_HANDLE( tmp_mem ); + ok( entry.ptr == ptr, "got ptr %p was %p\n", entry.ptr, ptr ); + if (flags & GMEM_DISCARDABLE) ok( (entry.flags & 0x7fff) == 0x7, "got flags %#Ix\n", entry.flags ); + else ok( (entry.flags & 0x7fff) == 0x3, "got flags %#Ix\n", entry.flags ); + } + if (tmp_mem) mem = tmp_mem; + + size = GlobalSize( mem ); + if (flags == GMEM_MOVEABLE) ok( size == 10, "GlobalSize returned %Iu\n", size ); + else todo_wine_if(!flags) ok( size == small_size, "GlobalSize returned %Iu\n", size ); + + mem = GlobalFree( mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + + mem = pGlobalAlloc( GMEM_FIXED, nolfh_size ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + ok( !is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + + tmp_mem = GlobalReAlloc( mem, 10, flags ); + if (!expect_convert) + { + ok( !is_mem_entry( tmp_mem ), "unexpected moveable %p\n", tmp_mem ); + if (flags & GMEM_DISCARDABLE) ok( !tmp_mem, "GlobalReAlloc succeeded\n" ); + else ok( tmp_mem == mem, "GlobalReAlloc returned %p\n", tmp_mem ); + } + else + { + ok( is_mem_entry( tmp_mem ), "unexpected moveable %p\n", tmp_mem ); + entry = *mem_entry_from_HANDLE( tmp_mem ); + ok( entry.ptr != ptr, "got ptr %p was %p\n", entry.ptr, ptr ); + if (flags & GMEM_DISCARDABLE) ok( (entry.flags & 0x7fff) == 0x7, "got flags %#Ix\n", entry.flags ); + else ok( (entry.flags & 0x7fff) == 0x3, "got flags %#Ix\n", entry.flags ); + } + if (tmp_mem) mem = tmp_mem; + + size = GlobalSize( mem ); + if (flags & (GMEM_MODIFY | GMEM_DISCARDABLE)) ok( size == nolfh_size, "GlobalSize returned %Iu\n", size ); + else ok( size == 10, "GlobalSize returned %Iu\n", size ); + + mem = GlobalFree( mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + + mem = pGlobalAlloc( GMEM_FIXED, small_size ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + ok( !is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + + tmp_mem = GlobalReAlloc( mem, 0, flags ); + if (!expect_convert) + { + ok( !is_mem_entry( tmp_mem ), "unexpected moveable %p\n", tmp_mem ); + if (flags == GMEM_MODIFY) ok( tmp_mem == mem, "GlobalReAlloc returned %p\n", tmp_mem ); + else if (flags != GMEM_MOVEABLE) ok( !tmp_mem, "GlobalReAlloc succeeded\n" ); + else ok( tmp_mem != mem, "GlobalReAlloc returned %p\n", tmp_mem ); + } + else + { + ok( is_mem_entry( tmp_mem ), "unexpected moveable %p\n", tmp_mem ); + entry = *mem_entry_from_HANDLE( tmp_mem ); + ok( entry.ptr == ptr, "got ptr %p was %p\n", entry.ptr, ptr ); + if (flags & GMEM_DISCARDABLE) ok( (entry.flags & 0x7fff) == 0x7, "got flags %#Ix\n", entry.flags ); + else ok( (entry.flags & 0x7fff) == 0x3, "got flags %#Ix\n", entry.flags ); + } + if (tmp_mem) mem = tmp_mem; + + size = GlobalSize( mem ); + if (flags == GMEM_MOVEABLE) ok( size == 0 || broken( size == 1 ) /* w7 */, "GlobalSize returned %Iu\n", size ); + else ok( size == small_size, "GlobalSize returned %Iu\n", size ); + + mem = GlobalFree( mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + + mem = pGlobalAlloc( GMEM_FIXED, nolfh_size ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + ok( !is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + + tmp_mem = GlobalReAlloc( mem, 0, flags ); + if (!expect_convert) + { + ok( !is_mem_entry( tmp_mem ), "unexpected moveable %p\n", tmp_mem ); + if (flags & GMEM_DISCARDABLE) ok( !tmp_mem, "GlobalReAlloc succeeded\n" ); + else ok( tmp_mem == mem, "GlobalReAlloc returned %p\n", tmp_mem ); + } + else + { + ok( is_mem_entry( tmp_mem ), "unexpected moveable %p\n", tmp_mem ); + entry = *mem_entry_from_HANDLE( tmp_mem ); + ok( entry.ptr != ptr, "got ptr %p was %p\n", entry.ptr, ptr ); + if (flags & GMEM_DISCARDABLE) ok( (entry.flags & 0x7fff) == 0x7, "got flags %#Ix\n", entry.flags ); + else ok( (entry.flags & 0x7fff) == 0x3, "got flags %#Ix\n", entry.flags ); + } + if (tmp_mem) mem = tmp_mem; + + size = GlobalSize( mem ); + if (flags & (GMEM_MODIFY | GMEM_DISCARDABLE)) ok( size == nolfh_size, "GlobalSize returned %Iu\n", size ); + else ok( size == 0 || broken( size == 1 ) /* w7 */, "GlobalSize returned %Iu\n", size ); + + mem = GlobalFree( mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + + mem = pGlobalAlloc( GMEM_MOVEABLE, small_size ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + ok( is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + ptr = GlobalLock( mem ); + ok( !!ptr, "GlobalLock failed, error %lu\n", GetLastError() ); + expect_entry = *mem_entry_from_HANDLE( mem ); + + tmp_mem = GlobalReAlloc( mem, 512, flags ); + if (flags & GMEM_MODIFY) ok( tmp_mem == mem, "GlobalReAlloc returned %p\n", tmp_mem ); + else if (flags & GMEM_DISCARDABLE) ok( !tmp_mem, "GlobalReAlloc succeeded\n" ); + else if (flags & GMEM_MOVEABLE) ok( tmp_mem == mem, "GlobalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); +#ifdef __REACTOS__ + else ok( !tmp_mem || broken(GetNTVersion() == _WIN32_WINNT_VISTA), "GlobalReAlloc succeeded\n" ); +#else + else ok( !tmp_mem, "GlobalReAlloc succeeded\n" ); +#endif + entry = *mem_entry_from_HANDLE( mem ); + if ((flags & GMEM_DISCARDABLE) && (flags & GMEM_MODIFY)) expect_entry.flags |= 4; +#ifdef __REACTOS__ + if (flags == GMEM_MOVEABLE) ok( entry.ptr != expect_entry.ptr || broken(GetNTVersion() == _WIN32_WINNT_VISTA), "got unexpected ptr %p\n", entry.ptr ); +#else + if (flags == GMEM_MOVEABLE) ok( entry.ptr != expect_entry.ptr, "got unexpected ptr %p\n", entry.ptr ); +#endif + else ok( entry.ptr == expect_entry.ptr, "got ptr %p\n", entry.ptr ); + ok( entry.flags == expect_entry.flags, "got flags %#Ix was %#Ix\n", entry.flags, expect_entry.flags ); + + size = GlobalSize( mem ); + if (flags == GMEM_MOVEABLE) ok( size == 512, "GlobalSize returned %Iu\n", size ); +#ifdef __REACTOS__ + else ok( size == small_size || broken(size == 512) /* Vista */, "GlobalSize returned %Iu\n", size ); +#else + else ok( size == small_size, "GlobalSize returned %Iu\n", size ); +#endif + + ret = GlobalUnlock( mem ); + ok( !ret, "GlobalUnlock succeeded\n" ); + mem = GlobalFree( mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + + mem = pGlobalAlloc( GMEM_MOVEABLE, small_size ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + ok( is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + ptr = GlobalLock( mem ); + ok( !!ptr, "GlobalLock failed, error %lu\n", GetLastError() ); + expect_entry = *mem_entry_from_HANDLE( mem ); + + tmp_mem = GlobalReAlloc( mem, 10, flags ); + if (flags & GMEM_MODIFY) ok( tmp_mem == mem, "GlobalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + else if (flags & GMEM_DISCARDABLE) ok( !tmp_mem, "GlobalReAlloc succeeded\n" ); + else ok( tmp_mem == mem, "GlobalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + entry = *mem_entry_from_HANDLE( mem ); + if ((flags & GMEM_DISCARDABLE) && (flags & GMEM_MODIFY)) expect_entry.flags |= 4; + ok( entry.ptr == expect_entry.ptr, "got ptr %p was %p\n", entry.ptr, expect_entry.ptr ); + ok( entry.flags == expect_entry.flags, "got flags %#Ix was %#Ix\n", entry.flags, expect_entry.flags ); + + size = GlobalSize( mem ); + if (flags & (GMEM_DISCARDABLE | GMEM_MODIFY)) ok( size == small_size, "GlobalSize returned %Iu\n", size ); + else ok( size == 10, "GlobalSize returned %Iu\n", size ); + + ret = GlobalUnlock( mem ); + ok( !ret, "GlobalUnlock succeeded\n" ); + mem = GlobalFree( mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + + mem = pGlobalAlloc( GMEM_MOVEABLE, small_size ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + ok( is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + ptr = GlobalLock( mem ); + ok( !!ptr, "GlobalLock failed, error %lu\n", GetLastError() ); + expect_entry = *mem_entry_from_HANDLE( mem ); + + tmp_mem = GlobalReAlloc( mem, 0, flags ); + if (flags & GMEM_MODIFY) ok( tmp_mem == mem, "GlobalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + else ok( !tmp_mem, "GlobalReAlloc succeeded\n" ); + entry = *mem_entry_from_HANDLE( mem ); + if ((flags & GMEM_DISCARDABLE) && (flags & GMEM_MODIFY)) expect_entry.flags |= 4; + ok( entry.ptr == expect_entry.ptr, "got ptr %p was %p\n", entry.ptr, expect_entry.ptr ); + ok( entry.flags == expect_entry.flags, "got flags %#Ix was %#Ix\n", entry.flags, expect_entry.flags ); + + size = GlobalSize( mem ); + ok( size == small_size, "GlobalSize returned %Iu\n", size ); + + ret = GlobalUnlock( mem ); + ok( !ret, "GlobalUnlock succeeded\n" ); + mem = GlobalFree( mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + + mem = pGlobalAlloc( GMEM_MOVEABLE, small_size ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + ok( is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + expect_entry = *mem_entry_from_HANDLE( mem ); + + tmp_mem = GlobalReAlloc( mem, 512, flags ); + if (flags & GMEM_MODIFY) ok( tmp_mem == mem, "GlobalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + else if (flags & GMEM_DISCARDABLE) ok( !tmp_mem, "GlobalReAlloc succeeded\n" ); + else ok( tmp_mem == mem, "GlobalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + entry = *mem_entry_from_HANDLE( mem ); + if ((flags & GMEM_DISCARDABLE) && (flags & GMEM_MODIFY)) expect_entry.flags |= 4; + if (flags & (GMEM_DISCARDABLE | GMEM_MODIFY)) ok( entry.ptr == expect_entry.ptr, "got ptr %p\n", entry.ptr ); +#ifdef __REACTOS__ + else ok( entry.ptr != expect_entry.ptr || broken(GetNTVersion() == _WIN32_WINNT_VISTA), "got unexpected ptr %p\n", entry.ptr ); +#else + else ok( entry.ptr != expect_entry.ptr, "got unexpected ptr %p\n", entry.ptr ); +#endif + ok( entry.flags == expect_entry.flags, "got flags %#Ix was %#Ix\n", entry.flags, expect_entry.flags ); + + size = GlobalSize( mem ); + if (flags & (GMEM_DISCARDABLE | GMEM_MODIFY)) ok( size == small_size, "GlobalSize returned %Iu\n", size ); + else ok( size == 512, "GlobalSize returned %Iu\n", size ); + + mem = GlobalFree( mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + + mem = pGlobalAlloc( GMEM_MOVEABLE, small_size ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + ok( is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + expect_entry = *mem_entry_from_HANDLE( mem ); + + tmp_mem = GlobalReAlloc( mem, 10, flags ); + if (flags & GMEM_MODIFY) ok( tmp_mem == mem, "GlobalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + else if (flags & GMEM_DISCARDABLE) ok( !tmp_mem, "GlobalReAlloc succeeded\n" ); + else ok( tmp_mem == mem, "GlobalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + entry = *mem_entry_from_HANDLE( mem ); + if ((flags & GMEM_DISCARDABLE) && (flags & GMEM_MODIFY)) expect_entry.flags |= 4; + ok( entry.ptr == expect_entry.ptr, "got ptr %p was %p\n", entry.ptr, expect_entry.ptr ); + ok( entry.flags == expect_entry.flags, "got flags %#Ix was %#Ix\n", entry.flags, expect_entry.flags ); + + size = GlobalSize( mem ); + if (flags & (GMEM_DISCARDABLE | GMEM_MODIFY)) ok( size == small_size, "GlobalSize returned %Iu\n", size ); + else ok( size == 10, "GlobalSize returned %Iu\n", size ); + + mem = GlobalFree( mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + + mem = pGlobalAlloc( GMEM_MOVEABLE, small_size ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + ok( is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + expect_entry = *mem_entry_from_HANDLE( mem ); + + tmp_mem = GlobalReAlloc( mem, 0, flags ); + if (flags & GMEM_MODIFY) ok( tmp_mem == mem, "GlobalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + else if (flags == GMEM_FIXED) ok( !tmp_mem, "GlobalReAlloc succeeded\n" ); + else if (flags & GMEM_DISCARDABLE) ok( !tmp_mem, "GlobalReAlloc succeeded\n" ); + else ok( tmp_mem == mem, "GlobalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + entry = *mem_entry_from_HANDLE( mem ); + if (flags == GMEM_MOVEABLE) + { + expect_entry.flags |= 8; + expect_entry.ptr = NULL; + } + else if ((flags & GMEM_DISCARDABLE) && (flags & GMEM_MODIFY)) expect_entry.flags |= 4; + ok( entry.ptr == expect_entry.ptr, "got ptr %p was %p\n", entry.ptr, expect_entry.ptr ); + ok( entry.flags == expect_entry.flags, "got flags %#Ix was %#Ix\n", entry.flags, expect_entry.flags ); + + size = GlobalSize( mem ); + if (flags == GMEM_MOVEABLE) ok( size == 0, "GlobalSize returned %Iu\n", size ); + else ok( size == small_size, "GlobalSize returned %Iu\n", size ); + + mem = GlobalFree( mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + winetest_pop_context(); + } +#ifdef __REACTOS__ + } +#endif + + mem = GlobalAlloc( GMEM_DDESHARE, 100 ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + ret = GlobalUnlock( mem ); + ok( ret, "GlobalUnlock failed, error %lu\n", GetLastError() ); + ret = GlobalUnlock( mem ); + ok( ret, "GlobalUnlock failed, error %lu\n", GetLastError() ); + + memset( &walk_entry, 0xcd, sizeof(walk_entry) ); + walk_entry.lpData = NULL; + ret = HeapLock( heap ); + ok( ret, "HeapLock failed, error %lu\n", GetLastError() ); + while ((ret = HeapWalk( heap, &walk_entry ))) + { + ok( !(walk_entry.wFlags & PROCESS_HEAP_ENTRY_MOVEABLE), "got PROCESS_HEAP_ENTRY_MOVEABLE\n" ); + ok( !(walk_entry.wFlags & PROCESS_HEAP_ENTRY_DDESHARE), "got PROCESS_HEAP_ENTRY_DDESHARE\n" ); + } + ok( GetLastError() == ERROR_NO_MORE_ITEMS, "got error %lu\n", GetLastError() ); + ret = HeapUnlock( heap ); + ok( ret, "HeapUnlock failed, error %lu\n", GetLastError() ); + + mem = GlobalFree( mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + mem = GlobalAlloc( GMEM_FIXED, 100 ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + ret = GlobalUnlock( mem ); + ok( ret, "GlobalUnlock failed, error %lu\n", GetLastError() ); + tmp_mem = GlobalHandle( mem ); + ok( tmp_mem == mem, "GlobalHandle returned unexpected handle\n" ); + mem = GlobalFree( mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + mem = GlobalAlloc( GMEM_FIXED, 0 ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + size = GlobalSize( mem ); + ok( size == 1, "GlobalSize returned %Iu\n", size ); + mem = GlobalFree( mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + /* trying to lock empty memory should give an error */ + mem = GlobalAlloc( GMEM_MOVEABLE | GMEM_ZEROINIT, 0 ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ptr = GlobalLock( mem ); + ok( !ptr, "GlobalLock succeeded\n" ); + ok( GetLastError() == ERROR_DISCARDED, "got error %lu\n", GetLastError() ); + mem = GlobalFree( mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + mem = GlobalAlloc( 0, buffer_size ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + size = GlobalSize( mem ); + ok( size >= buffer_size, "GlobalSize returned %Iu, error %lu\n", size, GetLastError() ); + mem = GlobalFree( mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + mem = GlobalAlloc( GMEM_ZEROINIT, buffer_size ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + size = GlobalSize( mem ); + ok( size >= buffer_size, "GlobalSize returned %Iu, error %lu\n", size, GetLastError() ); + ptr = GlobalLock( mem ); + ok( !!ptr, "GlobalLock failed, error %lu\n", GetLastError() ); + ok( ptr == mem, "got ptr %p, expected %p\n", ptr, mem ); + ok( !memcmp( ptr, zero_buffer, buffer_size ), "GlobalAlloc didn't clear memory\n" ); + + /* Check that we can change GMEM_FIXED to GMEM_MOVEABLE */ + mem = GlobalReAlloc( mem, 0, GMEM_MODIFY | GMEM_MOVEABLE ); + ok( !!mem, "GlobalReAlloc failed, error %lu\n", GetLastError() ); + ok( mem != ptr, "GlobalReAlloc returned unexpected handle\n" ); + size = GlobalSize( mem ); + ok( size == buffer_size, "GlobalSize returned %Iu, error %lu\n", size, GetLastError() ); + + ptr = GlobalLock( mem ); + ok( !!ptr, "GlobalLock failed, error %lu\n", GetLastError() ); + ok( ptr != mem, "got unexpected ptr %p\n", ptr ); + ret = GlobalUnlock( mem ); + ok( !ret, "GlobalUnlock succeeded, error %lu\n", GetLastError() ); + ok( GetLastError() == NO_ERROR, "got error %lu\n", GetLastError() ); + + tmp_mem = GlobalReAlloc( mem, 2 * buffer_size, GMEM_MOVEABLE | GMEM_ZEROINIT ); + ok( !!tmp_mem, "GlobalReAlloc failed\n" ); + ok( tmp_mem == mem || broken( tmp_mem != mem ) /* happens sometimes?? */, + "GlobalReAlloc returned unexpected handle\n" ); + mem = tmp_mem; + + size = GlobalSize( mem ); + ok( size >= 2 * buffer_size, "GlobalSize returned %Iu, error %lu\n", size, GetLastError() ); + ptr = GlobalLock( mem ); + ok( !!ptr, "GlobalLock failed, error %lu\n", GetLastError() ); + ok( ptr != mem, "got unexpected ptr %p\n", ptr ); + ok( !memcmp( ptr, zero_buffer, buffer_size ), "GlobalReAlloc didn't clear memory\n" ); + ok( !memcmp( ptr + buffer_size, zero_buffer, buffer_size ), + "GlobalReAlloc didn't clear memory\n" ); + + tmp_mem = GlobalHandle( ptr ); + ok( tmp_mem == mem, "GlobalHandle returned unexpected handle\n" ); + /* Check that we can't discard locked memory */ + SetLastError( 0xdeadbeef ); + tmp_mem = GlobalDiscard( mem ); + ok( !tmp_mem, "GlobalDiscard succeeded\n" ); + ret = GlobalUnlock( mem ); + ok( !ret, "GlobalUnlock succeeded, error %lu\n", GetLastError() ); + ok( GetLastError() == NO_ERROR, "got error %lu\n", GetLastError() ); + + tmp_mem = GlobalDiscard( mem ); + ok( tmp_mem == mem, "GlobalDiscard failed, error %lu\n", GetLastError() ); + mem = GlobalFree( mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + + for (i = 0; i < ARRAY_SIZE(flags_tests); i++) + { + mem = GlobalAlloc( flags_tests[i], 4 ); + ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); + flags = GlobalFlags( mem ); + ok( !(flags & ~(GMEM_DDESHARE | GMEM_DISCARDABLE)), "got flags %#x, error %lu\n", flags, GetLastError() ); + mem = GlobalFree( mem ); + ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); + } + + ptr = HeapAlloc( GetProcessHeap(), 0, 16 ); + ok( !!ptr, "HeapAlloc failed, error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + tmp_mem = GlobalHandle( ptr ); + ok( !!tmp_mem, "GlobalHandle failed, error %lu\n", GetLastError() ); + ok( tmp_mem == ptr, "GlobalHandle returned unexpected handle\n" ); + tmp_ptr = (void *)0xdeadbeef; + tmp_flags = 0xdeadbeef; + ret = pRtlGetUserInfoHeap( GetProcessHeap(), 0, ptr, (void **)&tmp_ptr, &tmp_flags ); + ok( ret, "RtlGetUserInfoHeap failed, error %lu\n", GetLastError() ); + ok( tmp_ptr == (void *)0xdeadbeef, "got user value %p\n", tmp_ptr ); + ok( tmp_flags == 0, "got user flags %#lx\n", tmp_flags ); + ret = HeapFree( GetProcessHeap(), 0, ptr ); + ok( ret, "HeapFree failed, error %lu\n", GetLastError() ); +} static void test_LocalAlloc(void) { - ULONG memchunk; - HLOCAL mem1,mem2,mem2a,mem2b; - UCHAR *mem2ptr; - UINT i; - BOOL error; - memchunk=100000; - - /* Check that a normal alloc works */ - mem1=LocalAlloc(0,memchunk); - ok(mem1!=NULL,"LocalAlloc failed: error=%d\n",GetLastError()); - if(mem1) { - ok(LocalSize(mem1)>=memchunk, "LocalAlloc should return a big enough memory block\n"); - } - - /* Check that a 'zeroing' and lock alloc works */ - mem2=LocalAlloc(LMEM_ZEROINIT|LMEM_MOVEABLE,memchunk); - ok(mem2!=NULL,"LocalAlloc failed: error=%d\n",GetLastError()); - if(mem2) { - ok(LocalSize(mem2)>=memchunk,"LocalAlloc should return a big enough memory block\n"); - mem2ptr=LocalLock(mem2); - ok(mem2ptr!=NULL,"LocalLock: error=%d\n",GetLastError()); - if(mem2ptr) { - error=FALSE; - for(i=0;i=2*memchunk,"LocalReAlloc failed\n"); - mem2ptr=LocalLock(mem2a); - ok(mem2ptr!=NULL,"LocalLock Failed\n"); - if(mem2ptr) { - error=FALSE; - for(i=0;i= 10 && size <= 16, "LocalSize returned %Iu\n", size ); + mem = LocalReAlloc( mem, 0, LMEM_MOVEABLE ); + ok( !!mem, "LocalReAlloc failed, error %lu\n", GetLastError() ); + size = LocalSize( mem ); + ok( size == 0, "LocalSize returned %Iu\n", size ); + mem = LocalReAlloc( mem, 10, LMEM_MOVEABLE ); + ok( !!mem, "LocalReAlloc failed, error %lu\n", GetLastError() ); + size = LocalSize( mem ); + ok( size >= 10 && size <= 16, "LocalSize returned %Iu\n", size ); + tmp_mem = pLocalFree( mem ); + ok( !tmp_mem, "LocalFree failed, error %lu\n", GetLastError() ); + size = LocalSize( mem ); + ok( size == 0, "LocalSize returned %Iu\n", size ); + + mem = LocalAlloc( LMEM_MOVEABLE, 256 ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + ptr = LocalLock( mem ); + ok( !!ptr, "LocalLock failed, error %lu\n", GetLastError() ); + ok( ptr != mem, "got unexpected ptr %p\n", ptr ); + tmp_mem = LocalHandle( ptr ); + ok( tmp_mem == mem, "LocalHandle returned unexpected handle\n" ); + flags = LocalFlags( mem ); + ok( flags == 1, "LocalFlags returned %#x, error %lu\n", flags, GetLastError() ); + tmp_ptr = LocalLock( mem ); + ok( !!tmp_ptr, "LocalLock failed, error %lu\n", GetLastError() ); + ok( tmp_ptr == ptr, "got ptr %p, expected %p\n", tmp_ptr, ptr ); + flags = LocalFlags( mem ); + ok( flags == 2, "LocalFlags returned %#x, error %lu\n", flags, GetLastError() ); + ret = LocalUnlock( mem ); + ok( ret, "LocalUnlock failed, error %lu\n", GetLastError() ); + flags = LocalFlags( mem ); + ok( flags == 1, "LocalFlags returned %#x, error %lu\n", flags, GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = LocalUnlock( mem ); + ok( !ret, "LocalUnlock succeeded\n" ); + ok( GetLastError() == ERROR_SUCCESS, "got error %lu\n", GetLastError() ); + flags = LocalFlags( mem ); + ok( !flags, "LocalFlags returned %#x, error %lu\n", flags, GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = LocalUnlock( mem ); + ok( !ret, "LocalUnlock succeeded\n" ); + ok( GetLastError() == ERROR_NOT_LOCKED, "got error %lu\n", GetLastError() ); + tmp_mem = LocalFree( mem ); + ok( !tmp_mem, "LocalFree failed, error %lu\n", GetLastError() ); + + /* freed handles are caught */ + mem = LocalAlloc( LMEM_MOVEABLE, 256 ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + tmp_mem = pLocalFree( mem ); + ok( !tmp_mem, "LocalFree failed, error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + tmp_mem = pLocalFree( mem ); + ok( tmp_mem == mem, "LocalFree succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + flags = LocalFlags( mem ); + ok( flags == LMEM_INVALID_HANDLE, "LocalFlags succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + size = LocalSize( mem ); + ok( size == 0, "LocalSize succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ptr = LocalLock( mem ); + ok( !ptr, "LocalLock succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = LocalUnlock( mem ); + ok( !ret, "LocalUnlock succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + tmp_mem = LocalReAlloc( mem, 0, LMEM_MOVEABLE ); + ok( !tmp_mem, "LocalReAlloc succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + if (sizeof(void *) != 8) /* crashes on 64-bit */ + { + SetLastError( 0xdeadbeef ); + tmp_mem = LocalHandle( mem ); + ok( !tmp_mem, "LocalHandle succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + } + +#ifdef __REACTOS__ + if (is_reactos()) { + ok(FALSE, "FIXME: invalid handle and invalid pointer tests crash on ReactOS!\n"); + } else { +#endif + /* invalid handles are caught */ + SetLastError( 0xdeadbeef ); + tmp_mem = pLocalFree( invalid_mem ); + ok( tmp_mem == invalid_mem, "LocalFree succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + flags = LocalFlags( invalid_mem ); + ok( flags == LMEM_INVALID_HANDLE, "LocalFlags succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + size = LocalSize( invalid_mem ); + ok( size == 0, "LocalSize succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ptr = LocalLock( invalid_mem ); + ok( !ptr, "LocalLock succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = LocalUnlock( invalid_mem ); + ok( !ret, "LocalUnlock succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + tmp_mem = LocalReAlloc( invalid_mem, 0, LMEM_MOVEABLE ); + ok( !tmp_mem, "LocalReAlloc succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + if (sizeof(void *) != 8) /* crashes on 64-bit */ + { + SetLastError( 0xdeadbeef ); + tmp_mem = LocalHandle( invalid_mem ); + ok( !tmp_mem, "LocalHandle succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + } + + /* invalid pointers are caught */ + SetLastError( 0xdeadbeef ); + tmp_mem = pLocalFree( invalid_ptr ); + ok( tmp_mem == invalid_ptr, "LocalFree succeeded\n" ); + todo_wine +#ifdef __REACTOS__ + ok( GetLastError() == ERROR_NOACCESS || broken(GetLastError() == ERROR_INVALID_HANDLE) /* WS03 */, "got error %lu\n", GetLastError() ); +#else + ok( GetLastError() == ERROR_NOACCESS, "got error %lu\n", GetLastError() ); +#endif + SetLastError( 0xdeadbeef ); + flags = LocalFlags( invalid_ptr ); + todo_wine + ok( flags == LMEM_INVALID_HANDLE, "LocalFlags succeeded\n" ); + todo_wine +#ifdef __REACTOS__ + ok( GetLastError() == ERROR_NOACCESS || broken(GetLastError() == ERROR_INVALID_HANDLE) /* WS03 */, "got error %lu\n", GetLastError() ); +#else + ok( GetLastError() == ERROR_NOACCESS, "got error %lu\n", GetLastError() ); +#endif + SetLastError( 0xdeadbeef ); + size = LocalSize( invalid_ptr ); + ok( size == 0, "LocalSize succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ptr = LocalLock( invalid_ptr ); + ok( !ptr, "LocalLock succeeded\n" ); + ok( GetLastError() == 0xdeadbeef, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = LocalUnlock( invalid_ptr ); + ok( !ret, "LocalUnlock succeeded\n" ); + ok( GetLastError() == ERROR_NOT_LOCKED, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + tmp_mem = LocalReAlloc( invalid_ptr, 0, LMEM_MOVEABLE ); + ok( !tmp_mem, "LocalReAlloc succeeded\n" ); + todo_wine + ok( GetLastError() == ERROR_NOACCESS, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + tmp_mem = LocalHandle( invalid_ptr ); + ok( !tmp_mem, "LocalHandle succeeded\n" ); + todo_wine +#ifdef __REACTOS__ + ok( GetLastError() == ERROR_NOACCESS || broken(GetLastError() == ERROR_INVALID_HANDLE) /* WS03 */, "got error %lu\n", GetLastError() ); +#else + ok( GetLastError() == ERROR_NOACCESS, "got error %lu\n", GetLastError() ); +#endif +#ifdef __REACTOS__ + } +#endif + + /* LMEM_FIXED block doesn't allow resize, though it succeeds with LMEM_MODIFY */ + mem = LocalAlloc( LMEM_FIXED, small_size ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + tmp_mem = LocalReAlloc( mem, small_size - 1, LMEM_MODIFY ); + ok( !!tmp_mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + ok( tmp_mem == mem, "got ptr %p, expected %p\n", tmp_mem, mem ); + size = LocalSize( mem ); + ok( size == small_size, "LocalSize returned %Iu\n", size ); + SetLastError( 0xdeadbeef ); +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) { +#endif + tmp_mem = LocalReAlloc( mem, small_size, 0 ); + ok( !tmp_mem, "LocalReAlloc succeeded\n" ); + ok( GetLastError() == ERROR_NOT_ENOUGH_MEMORY, "got error %lu\n", GetLastError() ); +#ifdef __REACTOS__ + } +#endif + if (tmp_mem) mem = tmp_mem; + tmp_mem = LocalReAlloc( mem, 1024 * 1024, LMEM_MODIFY ); + ok( !!tmp_mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + ok( tmp_mem == mem, "got ptr %p, expected %p\n", tmp_mem, mem ); + size = LocalSize( mem ); + ok( size == small_size, "LocalSize returned %Iu\n", size ); + mem = LocalFree( mem ); + ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); + + /* LMEM_FIXED block can be relocated with LMEM_MOVEABLE */ + mem = LocalAlloc( LMEM_FIXED, small_size ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + tmp_mem = LocalReAlloc( mem, small_size + 1, LMEM_MOVEABLE ); + ok( !!tmp_mem, "LocalReAlloc failed, error %lu\n", GetLastError() ); +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) +#endif + ok( tmp_mem != mem, "LocalReAlloc didn't relocate memory\n" ); + ptr = LocalLock( tmp_mem ); + ok( !!ptr, "LocalLock failed, error %lu\n", GetLastError() ); + ok( ptr == tmp_mem, "got ptr %p, expected %p\n", ptr, tmp_mem ); + tmp_mem = LocalFree( tmp_mem ); + ok( !tmp_mem, "LocalFree failed, error %lu\n", GetLastError() ); + + /* test LocalReAlloc flags / LocalLock / size combinations */ + +#ifdef __REACTOS__ + if (GetNTVersion() < _WIN32_WINNT_VISTA) { + skip("realloc_flags_tests invalid for WS03.\n"); + } else { +#endif + for (i = 0; i < ARRAY_SIZE(realloc_flags_tests); i++) + { + struct mem_entry expect_entry, entry; + + flags = realloc_flags_tests[i]; + + winetest_push_context( "flags %#x", flags ); + + mem = pLocalAlloc( LMEM_FIXED, small_size ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + ok( !is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + + tmp_mem = LocalReAlloc( mem, 512, flags ); + ok( !is_mem_entry( tmp_mem ), "unexpected moveable %p\n", tmp_mem ); + if (flags & LMEM_MODIFY) ok( tmp_mem == mem, "LocalReAlloc returned %p\n", tmp_mem ); + else if (flags != LMEM_MOVEABLE) ok( !tmp_mem, "LocalReAlloc succeeded\n" ); + else ok( tmp_mem != mem, "LocalReAlloc returned %p\n", tmp_mem ); + if (tmp_mem) mem = tmp_mem; + + size = LocalSize( mem ); + if (flags == LMEM_MOVEABLE) ok( size == 512, "LocalSize returned %Iu\n", size ); + else ok( size == small_size, "LocalSize returned %Iu\n", size ); + + mem = LocalFree( mem ); + ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); + + + mem = pLocalAlloc( LMEM_FIXED, nolfh_size ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + ok( !is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + tmp_mem = LocalReAlloc( mem, nolfh_size + 512, flags ); + ok( !is_mem_entry( tmp_mem ), "unexpected moveable %p\n", tmp_mem ); + if (flags & LMEM_MODIFY) ok( tmp_mem == mem, "LocalReAlloc returned %p\n", tmp_mem ); + else if (flags & LMEM_DISCARDABLE) ok( !tmp_mem, "LocalReAlloc succeeded\n" ); + else ok( tmp_mem == mem, "LocalReAlloc returned %p\n", tmp_mem ); + size = LocalSize( mem ); + if (flags & (LMEM_DISCARDABLE | LMEM_MODIFY)) ok( size == nolfh_size, "LocalSize returned %Iu\n", size ); + else ok( size == nolfh_size + 512, "LocalSize returned %Iu\n", size ); + mem = LocalFree( mem ); + ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); + + + mem = pLocalAlloc( LMEM_FIXED, small_size ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + ok( !is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + + tmp_mem = LocalReAlloc( mem, 10, flags ); + ok( !is_mem_entry( tmp_mem ), "unexpected moveable %p\n", tmp_mem ); + if (flags & LMEM_MODIFY) ok( tmp_mem == mem, "LocalReAlloc returned %p\n", tmp_mem ); + else if (flags != LMEM_MOVEABLE) todo_wine_if(!flags) ok( !tmp_mem, "LocalReAlloc succeeded\n" ); + else todo_wine ok( tmp_mem != mem, "LocalReAlloc returned %p\n", tmp_mem ); + if (tmp_mem) mem = tmp_mem; + + size = LocalSize( mem ); + if (flags == LMEM_MOVEABLE) ok( size == 10, "LocalSize returned %Iu\n", size ); + else todo_wine_if(!flags) ok( size == small_size, "LocalSize returned %Iu\n", size ); + + mem = LocalFree( mem ); + ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); + + + mem = pLocalAlloc( LMEM_FIXED, nolfh_size ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + ok( !is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + tmp_mem = LocalReAlloc( mem, 10, flags ); + ok( !is_mem_entry( tmp_mem ), "unexpected moveable %p\n", tmp_mem ); + if (flags & LMEM_MODIFY) ok( tmp_mem == mem, "LocalReAlloc returned %p\n", tmp_mem ); + else if (flags & LMEM_DISCARDABLE) ok( !tmp_mem, "LocalReAlloc succeeded\n" ); + else ok( tmp_mem == mem, "LocalReAlloc returned %p\n", tmp_mem ); + size = LocalSize( mem ); + if (flags & (LMEM_DISCARDABLE | LMEM_MODIFY)) ok( size == nolfh_size, "LocalSize returned %Iu\n", size ); + else ok( size == 10, "LocalSize returned %Iu\n", size ); + mem = LocalFree( mem ); + ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); + + + mem = pLocalAlloc( LMEM_FIXED, small_size ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + ok( !is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + + tmp_mem = LocalReAlloc( mem, 0, flags ); + ok( !is_mem_entry( tmp_mem ), "unexpected moveable %p\n", tmp_mem ); + if (flags & LMEM_MODIFY) ok( tmp_mem == mem, "LocalReAlloc returned %p\n", tmp_mem ); + else if (flags != LMEM_MOVEABLE) ok( !tmp_mem, "LocalReAlloc succeeded\n" ); + else ok( tmp_mem != mem, "LocalReAlloc returned %p\n", tmp_mem ); + if (tmp_mem) mem = tmp_mem; + + size = LocalSize( mem ); + if (flags == LMEM_MOVEABLE) ok( size == 0 || broken( size == 1 ) /* w7 */, "LocalSize returned %Iu\n", size ); + else ok( size == small_size, "LocalSize returned %Iu\n", size ); + + mem = LocalFree( mem ); + ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); + + + mem = pLocalAlloc( LMEM_FIXED, nolfh_size ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + ok( !is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + tmp_mem = LocalReAlloc( mem, 0, flags ); + ok( !is_mem_entry( tmp_mem ), "unexpected moveable %p\n", tmp_mem ); + if (flags & LMEM_MODIFY) ok( tmp_mem == mem, "LocalReAlloc returned %p\n", tmp_mem ); + else if (flags & LMEM_DISCARDABLE) ok( !tmp_mem, "LocalReAlloc succeeded\n" ); + else ok( tmp_mem == mem, "LocalReAlloc returned %p\n", tmp_mem ); + size = LocalSize( mem ); + if (flags & (LMEM_DISCARDABLE | LMEM_MODIFY)) ok( size == nolfh_size, "LocalSize returned %Iu\n", size ); + else ok( size == 0 || broken( size == 1 ) /* w7 */, "LocalSize returned %Iu\n", size ); + mem = LocalFree( mem ); + ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); + + + mem = pLocalAlloc( LMEM_MOVEABLE, small_size ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + ok( is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + ptr = LocalLock( mem ); + ok( !!ptr, "LocalLock failed, error %lu\n", GetLastError() ); + expect_entry = *mem_entry_from_HANDLE( mem ); + + tmp_mem = LocalReAlloc( mem, 512, flags ); + if (flags & LMEM_MODIFY) ok( tmp_mem == mem, "LocalReAlloc returned %p\n", tmp_mem ); + else if (flags & LMEM_DISCARDABLE) ok( !tmp_mem, "LocalReAlloc succeeded\n" ); + else if (flags & LMEM_MOVEABLE) ok( tmp_mem == mem, "LocalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); +#ifdef __REACTOS__ + else ok( !tmp_mem || broken(GetNTVersion() == _WIN32_WINNT_VISTA), "LocalReAlloc succeeded\n" ); +#else + else ok( !tmp_mem, "LocalReAlloc succeeded\n" ); +#endif + entry = *mem_entry_from_HANDLE( mem ); + if ((flags & LMEM_DISCARDABLE) && (flags & LMEM_MODIFY)) expect_entry.flags |= 4; +#ifdef __REACTOS__ + if (flags == LMEM_MOVEABLE) ok( entry.ptr != expect_entry.ptr || broken(GetNTVersion() == _WIN32_WINNT_VISTA), "got unexpected ptr %p\n", entry.ptr ); +#else + if (flags == LMEM_MOVEABLE) ok( entry.ptr != expect_entry.ptr, "got unexpected ptr %p\n", entry.ptr ); +#endif + else ok( entry.ptr == expect_entry.ptr, "got ptr %p\n", entry.ptr ); + ok( entry.flags == expect_entry.flags, "got flags %#Ix was %#Ix\n", entry.flags, expect_entry.flags ); + + size = LocalSize( mem ); + if (flags == LMEM_MOVEABLE) ok( size == 512, "LocalSize returned %Iu\n", size ); +#ifdef __REACTOS__ + else ok( size == small_size || broken(size == 512) /* Vista */, "LocalSize returned %Iu\n", size ); +#else + else ok( size == small_size, "LocalSize returned %Iu\n", size ); +#endif + + ret = LocalUnlock( mem ); + ok( !ret, "LocalUnlock succeeded\n" ); + mem = LocalFree( mem ); + ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); + + + mem = pLocalAlloc( LMEM_MOVEABLE, nolfh_size ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + ok( is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + ptr = LocalLock( mem ); + ok( !!ptr, "LocalLock failed, error %lu\n", GetLastError() ); + expect_entry = *mem_entry_from_HANDLE( mem ); + + tmp_mem = LocalReAlloc( mem, nolfh_size + 512, flags ); + if (flags & LMEM_MODIFY) ok( tmp_mem == mem, "LocalReAlloc returned %p\n", tmp_mem ); + else if (flags & LMEM_DISCARDABLE) ok( !tmp_mem, "LocalReAlloc succeeded\n" ); + else ok( tmp_mem == mem, "LocalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + entry = *mem_entry_from_HANDLE( mem ); + if ((flags & LMEM_DISCARDABLE) && (flags & LMEM_MODIFY)) expect_entry.flags |= 4; + ok( entry.ptr == expect_entry.ptr, "got ptr %p\n", entry.ptr ); + ok( entry.flags == expect_entry.flags, "got flags %#Ix was %#Ix\n", entry.flags, expect_entry.flags ); + + size = LocalSize( mem ); + if (flags & (LMEM_DISCARDABLE | LMEM_MODIFY)) ok( size == nolfh_size, "LocalSize returned %Iu\n", size ); + else ok( size == nolfh_size + 512, "LocalSize returned %Iu\n", size ); + + ret = LocalUnlock( mem ); + ok( !ret, "LocalUnlock succeeded\n" ); + mem = LocalFree( mem ); + ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); + + + mem = pLocalAlloc( LMEM_MOVEABLE, small_size ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + ok( is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + ptr = LocalLock( mem ); + ok( !!ptr, "LocalLock failed, error %lu\n", GetLastError() ); + expect_entry = *mem_entry_from_HANDLE( mem ); + + tmp_mem = LocalReAlloc( mem, 10, flags ); + if (flags & LMEM_MODIFY) ok( tmp_mem == mem, "LocalReAlloc returned %p\n", tmp_mem ); + else if (flags & LMEM_DISCARDABLE) ok( !tmp_mem, "LocalReAlloc succeeded\n" ); + else ok( tmp_mem == mem, "LocalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + entry = *mem_entry_from_HANDLE( mem ); + if ((flags & LMEM_DISCARDABLE) && (flags & LMEM_MODIFY)) expect_entry.flags |= 4; + ok( entry.ptr == expect_entry.ptr, "got ptr %p was %p\n", entry.ptr, expect_entry.ptr ); + ok( entry.flags == expect_entry.flags, "got flags %#Ix was %#Ix\n", entry.flags, expect_entry.flags ); + + size = LocalSize( mem ); + if (flags & (LMEM_DISCARDABLE | LMEM_MODIFY)) ok( size == small_size, "LocalSize returned %Iu\n", size ); + else ok( size == 10, "LocalSize returned %Iu\n", size ); + + ret = LocalUnlock( mem ); + ok( !ret, "LocalUnlock succeeded\n" ); + mem = LocalFree( mem ); + ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); + + + mem = pLocalAlloc( LMEM_MOVEABLE, nolfh_size ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + ok( is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + ptr = LocalLock( mem ); + ok( !!ptr, "LocalLock failed, error %lu\n", GetLastError() ); + expect_entry = *mem_entry_from_HANDLE( mem ); + + tmp_mem = LocalReAlloc( mem, 10, flags ); + if (flags & LMEM_MODIFY) ok( tmp_mem == mem, "LocalReAlloc returned %p\n", tmp_mem ); + else if (flags & LMEM_DISCARDABLE) ok( !tmp_mem, "LocalReAlloc succeeded\n" ); + else ok( tmp_mem == mem, "LocalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + entry = *mem_entry_from_HANDLE( mem ); + if ((flags & LMEM_DISCARDABLE) && (flags & LMEM_MODIFY)) expect_entry.flags |= 4; + ok( entry.ptr == expect_entry.ptr, "got ptr %p was %p\n", entry.ptr, expect_entry.ptr ); + ok( entry.flags == expect_entry.flags, "got flags %#Ix was %#Ix\n", entry.flags, expect_entry.flags ); + + size = LocalSize( mem ); + if (flags & (LMEM_DISCARDABLE | LMEM_MODIFY)) ok( size == nolfh_size, "LocalSize returned %Iu\n", size ); + else ok( size == 10, "LocalSize returned %Iu\n", size ); + + ret = LocalUnlock( mem ); + ok( !ret, "LocalUnlock succeeded\n" ); + mem = LocalFree( mem ); + ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); + + + mem = pLocalAlloc( LMEM_MOVEABLE, small_size ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + ok( is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + ptr = LocalLock( mem ); + ok( !!ptr, "LocalLock failed, error %lu\n", GetLastError() ); + expect_entry = *mem_entry_from_HANDLE( mem ); + + tmp_mem = LocalReAlloc( mem, 0, flags ); + if (flags & LMEM_MODIFY) ok( tmp_mem == mem, "LocalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + else ok( !tmp_mem, "LocalReAlloc succeeded\n" ); + entry = *mem_entry_from_HANDLE( mem ); + if ((flags & LMEM_DISCARDABLE) && (flags & LMEM_MODIFY)) expect_entry.flags |= 4; + ok( entry.ptr == expect_entry.ptr, "got ptr %p was %p\n", entry.ptr, expect_entry.ptr ); + ok( entry.flags == expect_entry.flags, "got flags %#Ix was %#Ix\n", entry.flags, expect_entry.flags ); + + size = LocalSize( mem ); + ok( size == small_size, "LocalSize returned %Iu\n", size ); + + ret = LocalUnlock( mem ); + ok( !ret, "LocalUnlock succeeded\n" ); + mem = LocalFree( mem ); + ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); + + + mem = pLocalAlloc( LMEM_MOVEABLE, nolfh_size ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + ok( is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + ptr = LocalLock( mem ); + ok( !!ptr, "LocalLock failed, error %lu\n", GetLastError() ); + expect_entry = *mem_entry_from_HANDLE( mem ); + + tmp_mem = LocalReAlloc( mem, 0, flags ); + if (flags & LMEM_MODIFY) ok( tmp_mem == mem, "LocalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + else ok( !tmp_mem, "LocalReAlloc succeeded\n" ); + entry = *mem_entry_from_HANDLE( mem ); + if ((flags & LMEM_DISCARDABLE) && (flags & LMEM_MODIFY)) expect_entry.flags |= 4; + ok( entry.ptr == expect_entry.ptr, "got ptr %p was %p\n", entry.ptr, expect_entry.ptr ); + ok( entry.flags == expect_entry.flags, "got flags %#Ix was %#Ix\n", entry.flags, expect_entry.flags ); + + size = LocalSize( mem ); + ok( size == nolfh_size, "LocalSize returned %Iu\n", size ); + + ret = LocalUnlock( mem ); + ok( !ret, "LocalUnlock succeeded\n" ); + mem = LocalFree( mem ); + ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); + + + mem = pLocalAlloc( LMEM_MOVEABLE, small_size ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + ok( is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + expect_entry = *mem_entry_from_HANDLE( mem ); + + tmp_mem = LocalReAlloc( mem, 512, flags ); + if (flags & LMEM_MODIFY) ok( tmp_mem == mem, "LocalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + else if (flags & LMEM_DISCARDABLE) ok( !tmp_mem, "LocalReAlloc succeeded\n" ); + else ok( tmp_mem == mem, "LocalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + entry = *mem_entry_from_HANDLE( mem ); + if ((flags & LMEM_DISCARDABLE) && (flags & LMEM_MODIFY)) expect_entry.flags |= 4; + if (flags & (LMEM_DISCARDABLE | LMEM_MODIFY)) ok( entry.ptr == expect_entry.ptr, "got ptr %p\n", entry.ptr ); +#ifdef __REACTOS__ + else ok( entry.ptr != expect_entry.ptr || broken(GetNTVersion() == _WIN32_WINNT_VISTA), "got unexpected ptr %p\n", entry.ptr ); +#else + else ok( entry.ptr != expect_entry.ptr, "got unexpected ptr %p\n", entry.ptr ); +#endif + ok( entry.flags == expect_entry.flags, "got flags %#Ix was %#Ix\n", entry.flags, expect_entry.flags ); + + size = LocalSize( mem ); + if (flags & (LMEM_DISCARDABLE | LMEM_MODIFY)) ok( size == small_size, "LocalSize returned %Iu\n", size ); + else ok( size == 512, "LocalSize returned %Iu\n", size ); + + mem = LocalFree( mem ); + ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); + + + mem = pLocalAlloc( LMEM_MOVEABLE, nolfh_size ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + ok( is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + expect_entry = *mem_entry_from_HANDLE( mem ); + + tmp_mem = LocalReAlloc( mem, nolfh_size + 512, flags ); + if (flags & LMEM_MODIFY) ok( tmp_mem == mem, "LocalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + else if (flags & LMEM_DISCARDABLE) ok( !tmp_mem, "LocalReAlloc succeeded\n" ); + else ok( tmp_mem == mem, "LocalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + entry = *mem_entry_from_HANDLE( mem ); + if ((flags & LMEM_DISCARDABLE) && (flags & LMEM_MODIFY)) expect_entry.flags |= 4; + ok( entry.ptr == expect_entry.ptr, "got unexpected ptr %p\n", entry.ptr ); + ok( entry.flags == expect_entry.flags, "got flags %#Ix was %#Ix\n", entry.flags, expect_entry.flags ); + + size = LocalSize( mem ); + if (flags & (LMEM_DISCARDABLE | LMEM_MODIFY)) ok( size == nolfh_size, "LocalSize returned %Iu\n", size ); + else ok( size == nolfh_size + 512, "LocalSize returned %Iu\n", size ); + + mem = LocalFree( mem ); + ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); + + + mem = pLocalAlloc( LMEM_MOVEABLE, small_size ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + ok( is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + expect_entry = *mem_entry_from_HANDLE( mem ); + + tmp_mem = LocalReAlloc( mem, 10, flags ); + if (flags & LMEM_MODIFY) ok( tmp_mem == mem, "LocalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + else if (flags & LMEM_DISCARDABLE) ok( !tmp_mem, "LocalReAlloc succeeded\n" ); + else ok( tmp_mem == mem, "LocalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + entry = *mem_entry_from_HANDLE( mem ); + if ((flags & LMEM_DISCARDABLE) && (flags & LMEM_MODIFY)) expect_entry.flags |= 4; + ok( entry.ptr == expect_entry.ptr, "got ptr %p was %p\n", entry.ptr, expect_entry.ptr ); + ok( entry.flags == expect_entry.flags, "got flags %#Ix was %#Ix\n", entry.flags, expect_entry.flags ); + + size = LocalSize( mem ); + if (flags & (LMEM_DISCARDABLE | LMEM_MODIFY)) ok( size == small_size, "LocalSize returned %Iu\n", size ); + else ok( size == 10, "LocalSize returned %Iu\n", size ); + + mem = LocalFree( mem ); + ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); + + + mem = pLocalAlloc( LMEM_MOVEABLE, nolfh_size ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + ok( is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + expect_entry = *mem_entry_from_HANDLE( mem ); + + tmp_mem = LocalReAlloc( mem, 10, flags ); + if (flags & LMEM_MODIFY) ok( tmp_mem == mem, "LocalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + else if (flags & LMEM_DISCARDABLE) ok( !tmp_mem, "LocalReAlloc succeeded\n" ); + else ok( tmp_mem == mem, "LocalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + entry = *mem_entry_from_HANDLE( mem ); + if ((flags & LMEM_DISCARDABLE) && (flags & LMEM_MODIFY)) expect_entry.flags |= 4; + ok( entry.ptr == expect_entry.ptr, "got ptr %p was %p\n", entry.ptr, expect_entry.ptr ); + ok( entry.flags == expect_entry.flags, "got flags %#Ix was %#Ix\n", entry.flags, expect_entry.flags ); + + size = LocalSize( mem ); + if (flags & (LMEM_DISCARDABLE | LMEM_MODIFY)) ok( size == nolfh_size, "LocalSize returned %Iu\n", size ); + else ok( size == 10, "LocalSize returned %Iu\n", size ); + + mem = LocalFree( mem ); + ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); + + + mem = pLocalAlloc( LMEM_MOVEABLE, small_size ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + ok( is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + expect_entry = *mem_entry_from_HANDLE( mem ); + + tmp_mem = LocalReAlloc( mem, 0, flags ); + if (flags & LMEM_MODIFY) ok( tmp_mem == mem, "LocalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + else if (flags == LMEM_FIXED) ok( !tmp_mem, "LocalReAlloc succeeded\n" ); + else if (flags & LMEM_DISCARDABLE) ok( !tmp_mem, "LocalReAlloc succeeded\n" ); + else ok( tmp_mem == mem, "LocalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + entry = *mem_entry_from_HANDLE( mem ); + if (flags == LMEM_MOVEABLE) + { + expect_entry.flags |= 8; + expect_entry.ptr = NULL; + } + else if ((flags & LMEM_DISCARDABLE) && (flags & LMEM_MODIFY)) expect_entry.flags |= 4; + ok( entry.ptr == expect_entry.ptr, "got ptr %p was %p\n", entry.ptr, expect_entry.ptr ); + ok( entry.flags == expect_entry.flags, "got flags %#Ix was %#Ix\n", entry.flags, expect_entry.flags ); + + size = LocalSize( mem ); + if (flags == LMEM_MOVEABLE) ok( size == 0, "LocalSize returned %Iu\n", size ); + else ok( size == small_size, "LocalSize returned %Iu\n", size ); + + mem = LocalFree( mem ); + ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); + + + mem = pLocalAlloc( LMEM_MOVEABLE, nolfh_size ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + ok( is_mem_entry( mem ), "unexpected moveable %p\n", mem ); + expect_entry = *mem_entry_from_HANDLE( mem ); + + tmp_mem = LocalReAlloc( mem, 0, flags ); + if (flags & LMEM_MODIFY) ok( tmp_mem == mem, "LocalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + else if (flags == LMEM_FIXED) ok( !tmp_mem, "LocalReAlloc succeeded\n" ); + else if (flags & LMEM_DISCARDABLE) ok( !tmp_mem, "LocalReAlloc succeeded\n" ); + else ok( tmp_mem == mem, "LocalReAlloc returned %p, error %lu\n", tmp_mem, GetLastError() ); + entry = *mem_entry_from_HANDLE( mem ); + if (flags == LMEM_MOVEABLE) + { + expect_entry.flags |= 8; + expect_entry.ptr = NULL; + } + else if ((flags & LMEM_DISCARDABLE) && (flags & LMEM_MODIFY)) expect_entry.flags |= 4; + ok( entry.ptr == expect_entry.ptr, "got ptr %p was %p\n", entry.ptr, expect_entry.ptr ); + ok( entry.flags == expect_entry.flags, "got flags %#Ix was %#Ix\n", entry.flags, expect_entry.flags ); + + size = LocalSize( mem ); + if (flags == LMEM_MOVEABLE) ok( size == 0, "LocalSize returned %Iu\n", size ); + else ok( size == nolfh_size, "LocalSize returned %Iu\n", size ); + + mem = LocalFree( mem ); + ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); + + winetest_pop_context(); + } +#ifdef __REACTOS__ + } +#endif + + mem = LocalAlloc( LMEM_FIXED, 100 ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = LocalUnlock( mem ); + ok( !ret, "LocalUnlock succeeded\n" ); + ok( GetLastError() == ERROR_NOT_LOCKED, "got error %lu\n", GetLastError() ); + tmp_mem = LocalHandle( mem ); + ok( tmp_mem == mem, "LocalHandle returned unexpected handle\n" ); + mem = LocalFree( mem ); + ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); + + mem = LocalAlloc( LMEM_FIXED, 0 ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + size = LocalSize( mem ); +#ifdef __REACTOS__ + ok( size == 0 || broken(size == 1) /* Vista */, "LocalSize returned %Iu\n", size ); +#else + ok( size == 0, "LocalSize returned %Iu\n", size ); +#endif + mem = LocalFree( mem ); + ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); + + /* trying to lock empty memory should give an error */ + mem = LocalAlloc( LMEM_MOVEABLE | LMEM_ZEROINIT, 0 ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ptr = LocalLock( mem ); + ok( !ptr, "LocalLock succeeded\n" ); + ok( GetLastError() == ERROR_DISCARDED, "got error %lu\n", GetLastError() ); + mem = LocalFree( mem ); + ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); + + mem = LocalAlloc( 0, buffer_size ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + size = LocalSize( mem ); + ok( size >= buffer_size, "LocalSize returned %Iu, error %lu\n", size, GetLastError() ); + mem = LocalFree( mem ); + ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); + + mem = LocalAlloc( LMEM_ZEROINIT, buffer_size ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + size = LocalSize( mem ); + ok( size >= buffer_size, "LocalSize returned %Iu, error %lu\n", size, GetLastError() ); + ptr = LocalLock( mem ); + ok( !!ptr, "LocalLock failed, error %lu\n", GetLastError() ); + ok( ptr == mem, "got ptr %p, expected %p\n", ptr, mem ); + ok( !memcmp( ptr, zero_buffer, buffer_size ), "LocalAlloc didn't clear memory\n" ); + + /* Check that we cannot change LMEM_FIXED to LMEM_MOVEABLE */ + mem = LocalReAlloc( mem, 0, LMEM_MODIFY | LMEM_MOVEABLE ); + ok( !!mem, "LocalReAlloc failed, error %lu\n", GetLastError() ); + ok( mem == ptr, "LocalReAlloc returned unexpected handle\n" ); + size = LocalSize( mem ); + ok( size == buffer_size, "LocalSize returned %Iu, error %lu\n", size, GetLastError() ); + + ptr = LocalLock( mem ); + ok( !!ptr, "LocalLock failed, error %lu\n", GetLastError() ); + ok( ptr == mem, "got unexpected ptr %p\n", ptr ); + ret = LocalUnlock( mem ); + ok( !ret, "LocalUnlock succeeded, error %lu\n", GetLastError() ); + ok( GetLastError() == ERROR_NOT_LOCKED, "got error %lu\n", GetLastError() ); + + tmp_mem = LocalReAlloc( mem, 2 * buffer_size, LMEM_MOVEABLE | LMEM_ZEROINIT ); + ok( !!tmp_mem, "LocalReAlloc failed\n" ); + ok( tmp_mem == mem || broken( tmp_mem != mem ) /* happens sometimes?? */, + "LocalReAlloc returned unexpected handle\n" ); + mem = tmp_mem; + + size = LocalSize( mem ); + ok( size >= 2 * buffer_size, "LocalSize returned %Iu, error %lu\n", size, GetLastError() ); + ptr = LocalLock( mem ); + ok( !!ptr, "LocalLock failed, error %lu\n", GetLastError() ); + ok( ptr == mem, "got unexpected ptr %p\n", ptr ); + ok( !memcmp( ptr, zero_buffer, buffer_size ), "LocalReAlloc didn't clear memory\n" ); + ok( !memcmp( ptr + buffer_size, zero_buffer, buffer_size ), + "LocalReAlloc didn't clear memory\n" ); + + tmp_mem = LocalHandle( ptr ); + ok( tmp_mem == mem, "LocalHandle returned unexpected handle\n" ); + tmp_mem = LocalDiscard( mem ); + ok( !!tmp_mem, "LocalDiscard failed, error %lu\n", GetLastError() ); + ok( tmp_mem == mem, "LocalDiscard returned unexpected handle\n" ); + ret = LocalUnlock( mem ); + ok( !ret, "LocalUnlock succeeded, error %lu\n", GetLastError() ); + ok( GetLastError() == ERROR_NOT_LOCKED, "got error %lu\n", GetLastError() ); + + tmp_mem = LocalDiscard( mem ); + ok( tmp_mem == mem, "LocalDiscard failed, error %lu\n", GetLastError() ); + mem = LocalFree( mem ); + ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); + + for (i = 0; i < ARRAY_SIZE(flags_tests); i++) + { + mem = LocalAlloc( flags_tests[i], 4 ); + ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); + flags = LocalFlags( mem ); + ok( !(flags & ~LMEM_DISCARDABLE), "got flags %#x, error %lu\n", flags, GetLastError() ); + mem = LocalFree( mem ); + ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); + } + + ptr = HeapAlloc( GetProcessHeap(), 0, 16 ); + ok( !!ptr, "HeapAlloc failed, error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + tmp_mem = LocalHandle( ptr ); + ok( !!tmp_mem, "LocalHandle failed, error %lu\n", GetLastError() ); + ok( tmp_mem == ptr, "LocalHandle returned unexpected handle\n" ); + tmp_ptr = (void *)0xdeadbeef; + tmp_flags = 0xdeadbeef; + ret = pRtlGetUserInfoHeap( GetProcessHeap(), 0, ptr, (void **)&tmp_ptr, &tmp_flags ); + ok( ret, "RtlGetUserInfoHeap failed, error %lu\n", GetLastError() ); + ok( tmp_ptr == (void *)0xdeadbeef, "got user value %p\n", tmp_ptr ); + ok( tmp_flags == 0, "got user flags %#lx\n", tmp_flags ); + ret = HeapFree( GetProcessHeap(), 0, ptr ); + ok( ret, "HeapFree failed, error %lu\n", GetLastError() ); +} + +static void test_block_layout( HANDLE heap, DWORD global_flags, DWORD heap_flags, DWORD alloc_flags ) +{ + DWORD padd_flags = HEAP_VALIDATE | HEAP_VALIDATE_ALL | HEAP_VALIDATE_PARAMS; + SIZE_T expect_size, diff, alloc_size, extra_size, tail_size = 0; + unsigned char *ptr0, *ptr1, *ptr2, tail; + char tail_buf[64], padd_buf[64]; + void *tmp_ptr, **user_ptr; + ULONG tmp_flags; + UINT_PTR align; + BOOL ret; + + if (global_flags & (FLG_HEAP_DISABLE_COALESCING|FLG_HEAP_PAGE_ALLOCS|FLG_POOL_ENABLE_TAGGING| + FLG_HEAP_ENABLE_TAGGING|FLG_HEAP_ENABLE_TAG_BY_DLL)) + { + skip( "skipping block tests\n" ); return; } - if (0) /* crashes under XP */ + if (!global_flags && !alloc_flags) extra_size = 8; + else extra_size = 2 * sizeof(void *); + if (heap_flags & HEAP_TAIL_CHECKING_ENABLED) extra_size += 2 * sizeof(void *); + if (heap_flags & padd_flags) extra_size += 2 * sizeof(void *); + + if ((heap_flags & HEAP_TAIL_CHECKING_ENABLED)) tail_size = 2 * sizeof(void *); + memset( tail_buf, 0xab, sizeof(tail_buf) ); + memset( padd_buf, 0, sizeof(padd_buf) ); + + for (alloc_size = 0x20000 * sizeof(void *) - 0x3000; alloc_size > 0; alloc_size >>= 1) { - size = 0; - pHeapQueryInformation(0, - HeapCompatibilityInformation, - &info, sizeof(info), &size); - size = 0; - pHeapQueryInformation(GetProcessHeap(), - HeapCompatibilityInformation, - NULL, sizeof(info), &size); + winetest_push_context( "size %#Ix", alloc_size ); + + ptr0 = pHeapAlloc( heap, alloc_flags|HEAP_ZERO_MEMORY, alloc_size ); + ok( !!ptr0, "HeapAlloc failed, error %lu\n", GetLastError() ); + ptr1 = pHeapAlloc( heap, alloc_flags|HEAP_ZERO_MEMORY, alloc_size ); + ok( !!ptr1, "HeapAlloc failed, error %lu\n", GetLastError() ); + ptr2 = pHeapAlloc( heap, alloc_flags|HEAP_ZERO_MEMORY, alloc_size ); + ok( !!ptr2, "HeapAlloc failed, error %lu\n", GetLastError() ); + + align = (UINT_PTR)ptr0 | (UINT_PTR)ptr1 | (UINT_PTR)ptr2; + ok( !(align & (2 * sizeof(void *) - 1)), "wrong align\n" ); + + expect_size = max( alloc_size, 2 * sizeof(void *) ); + expect_size = ALIGN_BLOCK_SIZE( expect_size + extra_size ); + diff = min( llabs( ptr2 - ptr1 ), llabs( ptr1 - ptr0 ) ); + todo_wine_if( (!global_flags && alloc_size < 2 * sizeof(void *)) || + ((heap_flags & HEAP_FREE_CHECKING_ENABLED) && diff >= 0x100000) ) +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) +#endif + ok( diff == expect_size, "got diff %#Ix exp %#Ix\n", diff, expect_size ); + ok( !memcmp( ptr0 + alloc_size, tail_buf, tail_size ), "missing block tail\n" ); + ok( !memcmp( ptr1 + alloc_size, tail_buf, tail_size ), "missing block tail\n" ); + ok( !memcmp( ptr2 + alloc_size, tail_buf, tail_size ), "missing block tail\n" ); + + ret = HeapFree( heap, 0, ptr2 ); + ok( ret, "HeapFree failed, error %lu\n", GetLastError() ); + ret = HeapFree( heap, 0, ptr1 ); + ok( ret, "HeapFree failed, error %lu\n", GetLastError() ); + ret = HeapFree( heap, 0, ptr0 ); + ok( ret, "HeapFree failed, error %lu\n", GetLastError() ); + + winetest_pop_context(); + + if (diff != expect_size) + { + todo_wine + win_skip("skipping sizes\n"); + break; + } } - size = 0; - SetLastError(0xdeadbeef); - ret = pHeapQueryInformation(GetProcessHeap(), - HeapCompatibilityInformation, - NULL, 0, &size); - ok(!ret, "HeapQueryInformation should fail\n"); - ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "expected ERROR_INSUFFICIENT_BUFFER got %u\n", GetLastError()); - ok(size == sizeof(ULONG), "expected 4, got %lu\n", size); - SetLastError(0xdeadbeef); - ret = pHeapQueryInformation(GetProcessHeap(), - HeapCompatibilityInformation, - NULL, 0, NULL); - ok(!ret, "HeapQueryInformation should fail\n"); - ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "expected ERROR_INSUFFICIENT_BUFFER got %u\n", GetLastError()); + /* between the two thresholds, tail may still be set but block position is inconsistent */ - info = 0xdeadbeaf; - SetLastError(0xdeadbeef); - ret = pHeapQueryInformation(GetProcessHeap(), - HeapCompatibilityInformation, - &info, sizeof(info) + 1, NULL); - ok(ret, "HeapQueryInformation error %u\n", GetLastError()); - ok(info == 0 || info == 1 || info == 2, "expected 0, 1 or 2, got %u\n", info); + alloc_size = 0x20000 * sizeof(void *) - 0x2000; + winetest_push_context( "size %#Ix", alloc_size ); + + ptr0 = pHeapAlloc( heap, alloc_flags|HEAP_ZERO_MEMORY, alloc_size ); + ok( !!ptr0, "HeapAlloc failed, error %lu\n", GetLastError() ); + ok( !((UINT_PTR)ptr0 & (2 * sizeof(void *) - 1)), "got unexpected ptr align\n" ); + + ok( !memcmp( ptr0 + alloc_size, tail_buf, tail_size ), "missing block tail\n" ); + + ret = HeapFree( heap, 0, ptr0 ); + ok( ret, "HeapFree failed, error %lu\n", GetLastError() ); + + winetest_pop_context(); + + + for (alloc_size = 0x20000 * sizeof(void *) - 0x1000; alloc_size < 0x800000; alloc_size <<= 1) + { + winetest_push_context( "size %#Ix", alloc_size ); + + ptr0 = pHeapAlloc( heap, alloc_flags|HEAP_ZERO_MEMORY, alloc_size ); + ok( !!ptr0, "HeapAlloc failed, error %lu\n", GetLastError() ); + ptr1 = pHeapAlloc( heap, alloc_flags, alloc_size ); + ok( !!ptr1, "HeapAlloc failed, error %lu\n", GetLastError() ); + ptr2 = pHeapAlloc( heap, alloc_flags, alloc_size ); + ok( !!ptr2, "HeapAlloc failed, error %lu\n", GetLastError() ); + + align = (UINT_PTR)ptr0 | (UINT_PTR)ptr1 | (UINT_PTR)ptr2; + ok( !(align & (8 * sizeof(void *) - 1)), "wrong align\n" ); + + expect_size = max( alloc_size, 2 * sizeof(void *) ); + expect_size = ALIGN_BLOCK_SIZE( expect_size + extra_size ); + diff = min( llabs( ptr2 - ptr1 ), llabs( ptr1 - ptr0 ) ); + todo_wine_if( alloc_size == 0x7efe9 ) + ok( diff > expect_size, "got diff %#Ix\n", diff ); + + tail = ptr0[alloc_size] | ptr1[alloc_size] | ptr2[alloc_size]; + ok( !tail, "got tail\n" ); + + ret = HeapFree( heap, 0, ptr2 ); + ok( ret, "HeapFree failed, error %lu\n", GetLastError() ); + ret = HeapFree( heap, 0, ptr1 ); + ok( ret, "HeapFree failed, error %lu\n", GetLastError() ); + ret = HeapFree( heap, 0, ptr0 ); + ok( ret, "HeapFree failed, error %lu\n", GetLastError() ); + winetest_pop_context(); + + if (diff == expect_size || (align & (8 * sizeof(void *) - 1)) || tail) + { + todo_wine + win_skip("skipping sizes\n"); + break; + } + } + + /* Undocumented HEAP_ADD_USER_INFO flag can be used to force an additional padding + * on small block sizes. Small block use it to store user info, larger blocks + * store them in their block header instead. + * + * RtlGetUserInfoHeap also requires the flag to work consistently, and otherwise + * causes crashes when heap flags are used, or on 32-bit. + */ + if (!(heap_flags & padd_flags)) + { + alloc_size = 0x1000; + winetest_push_context( "size %#Ix", alloc_size ); + ptr0 = pHeapAlloc( heap, 0xc00|HEAP_ADD_USER_INFO, alloc_size ); + ok( !!ptr0, "HeapAlloc failed, error %lu\n", GetLastError() ); + ptr1 = HeapAlloc( heap, 0x200|HEAP_ADD_USER_INFO, alloc_size ); + ok( !!ptr1, "HeapAlloc failed, error %lu\n", GetLastError() ); + ptr2 = HeapAlloc( heap, HEAP_ADD_USER_INFO, alloc_size ); + ok( !!ptr2, "HeapAlloc failed, error %lu\n", GetLastError() ); + + expect_size = max( alloc_size, 2 * sizeof(void *) ); + expect_size = ALIGN_BLOCK_SIZE( expect_size + extra_size + 2 * sizeof(void *) ); + diff = min( llabs( ptr2 - ptr1 ), llabs( ptr1 - ptr0 ) ); + ok( diff == expect_size, "got diff %#Ix\n", diff ); + + ok( !memcmp( ptr0 + alloc_size, tail_buf, tail_size ), "missing block tail\n" ); + ok( !memcmp( ptr1 + alloc_size, tail_buf, tail_size ), "missing block tail\n" ); + ok( !memcmp( ptr2 + alloc_size, tail_buf, tail_size ), "missing block tail\n" ); + + ok( !memcmp( ptr0 + alloc_size + tail_size, padd_buf, 2 * sizeof(void *) ), "unexpected padding\n" ); + + tmp_ptr = (void *)0xdeadbeef; + tmp_flags = 0xdeadbeef; + ret = pRtlGetUserInfoHeap( heap, 0, ptr0, (void **)&tmp_ptr, &tmp_flags ); + ok( ret, "RtlGetUserInfoHeap failed, error %lu\n", GetLastError() ); + ok( tmp_ptr == NULL, "got ptr %p\n", tmp_ptr ); + ok( tmp_flags == 0xc00, "got flags %#lx\n", tmp_flags ); + + tmp_ptr = (void *)0xdeadbeef; + tmp_flags = 0xdeadbeef; + ret = pRtlGetUserInfoHeap( heap, 0, ptr1, (void **)&tmp_ptr, &tmp_flags ); + ok( ret, "RtlGetUserInfoHeap failed, error %lu\n", GetLastError() ); + ok( tmp_ptr == NULL, "got ptr %p\n", tmp_ptr ); + ok( tmp_flags == 0x200, "got flags %#lx\n", tmp_flags ); + + ret = pRtlSetUserValueHeap( heap, 0, ptr0, (void *)0xdeadbeef ); + ok( ret, "RtlSetUserValueHeap failed, error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = pRtlSetUserFlagsHeap( heap, 0, ptr0, 0, 0x1000 ); +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) +#endif + ok( !ret, "RtlSetUserFlagsHeap succeeded\n" ); +#ifdef __REACTOS__ + ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef) /* WS03 */, "got error %lu\n", GetLastError() ); +#else + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); +#endif + SetLastError( 0xdeadbeef ); + ret = pRtlSetUserFlagsHeap( heap, 0, ptr0, 0x100, 0 ); +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) +#endif + ok( !ret, "RtlSetUserFlagsHeap succeeded\n" ); +#ifdef __REACTOS__ + ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef) /* WS03 */, "got error %lu\n", GetLastError() ); +#else + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); +#endif + ret = pRtlSetUserFlagsHeap( heap, 0, ptr0, 0x400, 0x200 ); + ok( ret, "RtlSetUserFlagsHeap failed, error %lu\n", GetLastError() ); + + tmp_ptr = NULL; + tmp_flags = 0; + ret = pRtlGetUserInfoHeap( heap, 0, ptr0, (void **)&tmp_ptr, &tmp_flags ); + ok( ret, "RtlGetUserInfoHeap failed, error %lu\n", GetLastError() ); + ok( tmp_ptr == (void *)0xdeadbeef, "got ptr %p\n", tmp_ptr ); + ok( tmp_flags == 0xa00 || broken(tmp_flags == 0xc00) /* w1064v1507 */, + "got flags %#lx\n", tmp_flags ); + + user_ptr = (void **)(ptr0 + alloc_size + tail_size); + ok( user_ptr[1] == (void *)0xdeadbeef, "unexpected user value\n" ); + user_ptr[0] = (void *)0xdeadbeef; + user_ptr[1] = (void *)0xdeadbee0; + + tmp_ptr = NULL; + tmp_flags = 0; + ret = pRtlGetUserInfoHeap( heap, 0, ptr0, (void **)&tmp_ptr, &tmp_flags ); + ok( ret, "RtlGetUserInfoHeap failed, error %lu\n", GetLastError() ); + ok( tmp_ptr == (void *)0xdeadbee0, "got ptr %p\n", tmp_ptr ); + ok( tmp_flags == 0xa00 || broken(tmp_flags == 0xc00) /* w1064v1507 */, + "got flags %#lx\n", tmp_flags ); + + ret = HeapFree( heap, 0, ptr2 ); + ok( ret, "HeapFree failed, error %lu\n", GetLastError() ); + ret = HeapFree( heap, 0, ptr1 ); + ok( ret, "HeapFree failed, error %lu\n", GetLastError() ); + ret = HeapFree( heap, 0, ptr0 ); + ok( ret, "HeapFree failed, error %lu\n", GetLastError() ); + winetest_pop_context(); + } } static void test_heap_checks( DWORD flags ) @@ -899,16 +3476,15 @@ static void test_heap_checks( DWORD flags ) SIZE_T i, size, large_size = 3000 * 1024 + 37; if (flags & HEAP_PAGE_ALLOCS) return; /* no tests for that case yet */ - trace( "testing heap flags %08x\n", flags ); - p = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 17 ); + p = pHeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 17 ); ok( p != NULL, "HeapAlloc failed\n" ); ret = HeapValidate( GetProcessHeap(), 0, p ); ok( ret, "HeapValidate failed\n" ); size = HeapSize( GetProcessHeap(), 0, p ); - ok( size == 17, "Wrong size %lu\n", size ); + ok( size == 17, "Wrong size %Iu\n", size ); ok( p[14] == 0, "wrong data %x\n", p[14] ); ok( p[15] == 0, "wrong data %x\n", p[15] ); @@ -941,7 +3517,7 @@ static void test_heap_checks( DWORD flags ) ret = HeapFree( GetProcessHeap(), 0, p ); ok( ret, "HeapFree failed\n" ); - p = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 17 ); + p = pHeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 17 ); ok( p != NULL, "HeapAlloc failed\n" ); old = p[17]; p[17] = 0xcc; @@ -955,7 +3531,7 @@ static void test_heap_checks( DWORD flags ) if (flags & HEAP_VALIDATE) { size = HeapSize( GetProcessHeap(), 0, p ); - ok( size == ~(SIZE_T)0 || broken(size == ~0u), "Wrong size %lu\n", size ); + ok( size == ~(SIZE_T)0 || broken(size == ~0u), "Wrong size %Iu\n", size ); p2 = HeapReAlloc( GetProcessHeap(), 0, p, 14 ); ok( p2 == NULL, "HeapReAlloc succeeded\n" ); @@ -967,7 +3543,7 @@ static void test_heap_checks( DWORD flags ) p[17] = old; size = HeapSize( GetProcessHeap(), 0, p ); - ok( size == 17, "Wrong size %lu\n", size ); + ok( size == 17, "Wrong size %Iu\n", size ); p2 = HeapReAlloc( GetProcessHeap(), 0, p, 14 ); ok( p2 != NULL, "HeapReAlloc failed\n" ); @@ -977,11 +3553,40 @@ static void test_heap_checks( DWORD flags ) ret = HeapFree( GetProcessHeap(), 0, p ); ok( ret, "HeapFree failed\n" ); + if (flags & HEAP_FREE_CHECKING_ENABLED) + { + UINT *p32, tmp = 0; + + size = 4 + 3; + p = pHeapAlloc( GetProcessHeap(), 0, size ); + ok( !!p, "HeapAlloc failed\n" ); + p32 = (UINT *)p; + + ok( p32[0] == 0xbaadf00d, "got %#x\n", p32[0] ); + memcpy( &tmp, p + size - 3, 3 ); + ok( tmp != 0xadf00d, "got %#x\n", tmp ); + memset( p, 0xcc, size ); + + size += 2 * 4; + p = pHeapReAlloc( GetProcessHeap(), 0, p, size ); + ok( !!p, "HeapReAlloc failed\n" ); + p32 = (UINT *)p; + + ok( p32[0] == 0xcccccccc, "got %#x\n", p32[0] ); + ok( p32[1] << 8 == 0xcccccc00, "got %#x\n", p32[1] ); + ok( p32[2] == 0xbaadf00d, "got %#x\n", p32[2] ); + memcpy( &tmp, p + size - 3, 3 ); + ok( tmp != 0xadf00d, "got %#x\n", tmp ); + + ret = pHeapFree( GetProcessHeap(), 0, p ); + ok( ret, "failed.\n" ); + } + p = HeapAlloc( GetProcessHeap(), 0, 37 ); ok( p != NULL, "HeapAlloc failed\n" ); memset( p, 0xcc, 37 ); - ret = HeapFree( GetProcessHeap(), 0, p ); + ret = pHeapFree( GetProcessHeap(), 0, p ); ok( ret, "HeapFree failed\n" ); if (flags & HEAP_FREE_CHECKING_ENABLED) @@ -1006,14 +3611,14 @@ static void test_heap_checks( DWORD flags ) /* now test large blocks */ - p = HeapAlloc( GetProcessHeap(), 0, large_size ); + p = pHeapAlloc( GetProcessHeap(), 0, large_size ); ok( p != NULL, "HeapAlloc failed\n" ); ret = HeapValidate( GetProcessHeap(), 0, p ); ok( ret, "HeapValidate failed\n" ); size = HeapSize( GetProcessHeap(), 0, p ); - ok( size == large_size, "Wrong size %lu\n", size ); + ok( size == large_size, "Wrong size %Iu\n", size ); ok( p[large_size - 2] == 0, "wrong data %x\n", p[large_size - 2] ); ok( p[large_size - 1] == 0, "wrong data %x\n", p[large_size - 1] ); @@ -1021,29 +3626,9 @@ static void test_heap_checks( DWORD flags ) if (flags & HEAP_TAIL_CHECKING_ENABLED) { /* Windows doesn't do tail checking on large blocks */ - ok( p[large_size] == 0xab || broken(p[large_size] == 0), "wrong data %x\n", p[large_size] ); - ok( p[large_size+1] == 0xab || broken(p[large_size+1] == 0), "wrong data %x\n", p[large_size+1] ); - ok( p[large_size+2] == 0xab || broken(p[large_size+2] == 0), "wrong data %x\n", p[large_size+2] ); - if (p[large_size] == 0xab) - { - p[large_size] = 0xcc; - ret = HeapValidate( GetProcessHeap(), 0, p ); - ok( !ret, "HeapValidate succeeded\n" ); - - /* other calls only check when HEAP_VALIDATE is set */ - if (flags & HEAP_VALIDATE) - { - size = HeapSize( GetProcessHeap(), 0, p ); - ok( size == ~(SIZE_T)0, "Wrong size %lu\n", size ); - - p2 = HeapReAlloc( GetProcessHeap(), 0, p, large_size - 3 ); - ok( p2 == NULL, "HeapReAlloc succeeded\n" ); - - ret = HeapFree( GetProcessHeap(), 0, p ); - ok( !ret, "HeapFree succeeded\n" ); - } - p[large_size] = 0xab; - } + ok( p[large_size] == 0, "wrong data %x\n", p[large_size] ); + ok( p[large_size + 1] == 0, "wrong data %x\n", p[large_size + 1] ); + ok( p[large_size + 2] == 0, "wrong data %x\n", p[large_size + 2] ); } ret = HeapFree( GetProcessHeap(), 0, p ); @@ -1056,7 +3641,7 @@ static void test_heap_checks( DWORD flags ) { p = HeapAlloc( GetProcessHeap(), 0, size ); for (i = 0; i < 32; i++) if (p[size + i] != 0xab) break; - ok( i >= 8, "only %lu tail bytes for size %lu\n", i, size ); + ok( i >= 8, "only %Iu tail bytes for size %Iu\n", i, size ); HeapFree( GetProcessHeap(), 0, p ); } } @@ -1086,7 +3671,7 @@ static void test_debug_heap( const char *argv0, DWORD flags ) skip("Not authorized to change the image file execution options\n"); return; } - ok( !err, "failed to create '%s' error %u\n", keyname, err ); + ok( !err, "failed to create '%s' error %lu\n", keyname, err ); if (err) return; if (flags == 0xdeadbeef) /* magic value for unsetting it */ @@ -1097,12 +3682,12 @@ static void test_debug_heap( const char *argv0, DWORD flags ) memset( &startup, 0, sizeof(startup) ); startup.cb = sizeof(startup); - sprintf( buffer, "%s heap.c 0x%x", argv0, flags ); + sprintf( buffer, "%s heap.c 0x%lx", argv0, flags ); ret = CreateProcessA( NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info ); - ok( ret, "failed to create child process error %u\n", GetLastError() ); + ok( ret, "failed to create child process error %lu\n", GetLastError() ); if (ret) { - winetest_wait_child_process( info.hProcess ); + wait_child_process( info.hProcess ); CloseHandle( info.hThread ); CloseHandle( info.hProcess ); } @@ -1120,78 +3705,137 @@ static DWORD heap_flags_from_global_flag( DWORD flag ) if (flag & FLG_HEAP_ENABLE_FREE_CHECK) ret |= HEAP_FREE_CHECKING_ENABLED; if (flag & FLG_HEAP_VALIDATE_PARAMETERS) - ret |= HEAP_VALIDATE_PARAMS | HEAP_VALIDATE | HEAP_TAIL_CHECKING_ENABLED | HEAP_FREE_CHECKING_ENABLED; + ret |= HEAP_VALIDATE_PARAMS | HEAP_TAIL_CHECKING_ENABLED | HEAP_FREE_CHECKING_ENABLED; if (flag & FLG_HEAP_VALIDATE_ALL) - ret |= HEAP_VALIDATE_ALL | HEAP_VALIDATE | HEAP_TAIL_CHECKING_ENABLED | HEAP_FREE_CHECKING_ENABLED; + ret |= HEAP_VALIDATE_ALL | HEAP_TAIL_CHECKING_ENABLED | HEAP_FREE_CHECKING_ENABLED; if (flag & FLG_HEAP_DISABLE_COALESCING) ret |= HEAP_DISABLE_COALESCE_ON_FREE; if (flag & FLG_HEAP_PAGE_ALLOCS) - ret |= HEAP_PAGE_ALLOCS | HEAP_GROWABLE; + ret |= HEAP_PAGE_ALLOCS; return ret; } +static void test_heap_layout( HANDLE handle, DWORD global_flag, DWORD heap_flags ) +{ + DWORD force_flags = heap_flags & ~(HEAP_SHARED|HEAP_DISABLE_COALESCE_ON_FREE); + struct heap *heap = handle; + +#ifdef __REACTOS__ + if (GetNTVersion() < _WIN32_WINNT_VISTA) { + skip("test_heap_layout() is invalid on WS03.\n"); + return; + } +#endif + if (global_flag & FLG_HEAP_ENABLE_TAGGING) heap_flags |= HEAP_SHARED; + if (!(global_flag & FLG_HEAP_PAGE_ALLOCS)) force_flags &= ~(HEAP_GROWABLE|HEAP_PRIVATE); + + ok( heap->force_flags == force_flags, "got force_flags %#x\n", heap->force_flags ); + ok( heap->flags == heap_flags, "got flags %#x\n", heap->flags ); + + if (heap->flags & HEAP_PAGE_ALLOCS) + { + struct heap expect_heap; + memset( &expect_heap, 0xee, sizeof(expect_heap) ); + expect_heap.force_flags = heap->force_flags; + expect_heap.flags = heap->flags; + todo_wine + ok( !memcmp( heap, &expect_heap, sizeof(expect_heap) ), "got unexpected data\n" ); + } + else + { + ok( heap->ffeeffee == 0xffeeffee, "got ffeeffee %#x\n", heap->ffeeffee ); + ok( heap->auto_flags == (heap_flags & HEAP_GROWABLE) || !heap->auto_flags, + "got auto_flags %#x\n", heap->auto_flags ); + } +} + static void test_child_heap( const char *arg ) { - struct heap_layout *heap = GetProcessHeap(); - DWORD expected = strtoul( arg, 0, 16 ); - DWORD expect_heap; + char buffer[32]; + DWORD global_flags = strtoul( arg, 0, 16 ), type, size = sizeof(buffer); + DWORD heap_flags; + HANDLE heap; + HKEY hkey; + BOOL ret; - if (expected == 0xdeadbeef) /* expected value comes from Session Manager global flags */ + if (global_flags == 0xdeadbeef) /* global_flags value comes from Session Manager global flags */ { - HKEY hkey; - expected = 0; - if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager", &hkey )) + ret = RegOpenKeyA( HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager", &hkey ); + if (!ret) { - char buffer[32]; - DWORD type, size = sizeof(buffer); - - if (!RegQueryValueExA( hkey, "GlobalFlag", 0, &type, (BYTE *)buffer, &size )) - { - if (type == REG_DWORD) expected = *(DWORD *)buffer; - else if (type == REG_SZ) expected = strtoul( buffer, 0, 16 ); - } - RegCloseKey( hkey ); + skip( "Session Manager flags not set\n" ); + return; } + + ret = RegQueryValueExA( hkey, "GlobalFlag", 0, &type, (BYTE *)buffer, &size ); + ok( ret, "RegQueryValueExA failed, error %lu\n", GetLastError() ); + + if (type == REG_DWORD) global_flags = *(DWORD *)buffer; + else if (type == REG_SZ) global_flags = strtoul( buffer, 0, 16 ); + + ret = RegCloseKey( hkey ); + ok( ret, "RegCloseKey failed, error %lu\n", GetLastError() ); } - if (expected && !pRtlGetNtGlobalFlags()) /* not working on NT4 */ + if (global_flags && !pRtlGetNtGlobalFlags()) /* not working on NT4 */ { win_skip( "global flags not set\n" ); return; } - ok( pRtlGetNtGlobalFlags() == expected, - "%s: got global flags %08x expected %08x\n", arg, pRtlGetNtGlobalFlags(), expected ); + heap_flags = heap_flags_from_global_flag( global_flags ); + trace( "testing global flags %#lx, heap flags %08lx\n", global_flags, heap_flags ); - expect_heap = heap_flags_from_global_flag( expected ); + ok( pRtlGetNtGlobalFlags() == global_flags, "got global flags %#lx\n", pRtlGetNtGlobalFlags() ); - if (!(heap->flags & HEAP_GROWABLE) || heap->pattern == 0xffeeffee) /* vista layout */ - { - ok( (heap->flags & ~HEAP_GROWABLE) == 0, "%s: got heap flags %08x\n", arg, heap->flags ); - } - else if (heap->pattern == 0xeeeeeeee && heap->flags == 0xeeeeeeee) - { - ok( expected & FLG_HEAP_PAGE_ALLOCS, "%s: got heap flags 0xeeeeeeee without page alloc\n", arg ); - } - else - { - ok( heap->flags == (expect_heap | HEAP_GROWABLE), - "%s: got heap flags %08x expected %08x\n", arg, heap->flags, expect_heap ); - ok( heap->force_flags == (expect_heap & ~0x18000080), - "%s: got heap force flags %08x expected %08x\n", arg, heap->force_flags, expect_heap ); - expect_heap = heap->flags; - } + test_heap_layout( GetProcessHeap(), global_flags, heap_flags|HEAP_GROWABLE ); - test_heap_checks( expect_heap ); + heap = HeapCreate( 0, 0, 0 ); + ok( heap != GetProcessHeap(), "got unexpected heap\n" ); + test_heap_layout( heap, global_flags, heap_flags|HEAP_GROWABLE|HEAP_PRIVATE ); + ret = HeapDestroy( heap ); + ok( ret, "HeapDestroy failed, error %lu\n", GetLastError() ); + + heap = HeapCreate( HEAP_NO_SERIALIZE, 0, 0 ); + ok( heap != GetProcessHeap(), "got unexpected heap\n" ); + test_heap_layout( heap, global_flags, heap_flags|HEAP_NO_SERIALIZE|HEAP_GROWABLE|HEAP_PRIVATE ); + test_block_layout( heap, global_flags, heap_flags|HEAP_NO_SERIALIZE|HEAP_GROWABLE|HEAP_PRIVATE, 0 ); + ret = HeapDestroy( heap ); + ok( ret, "HeapDestroy failed, error %lu\n", GetLastError() ); + + heap = HeapCreate( HEAP_TAIL_CHECKING_ENABLED|HEAP_FREE_CHECKING_ENABLED|HEAP_NO_SERIALIZE, 0, 0 ); + ok( heap != GetProcessHeap(), "got unexpected heap\n" ); + test_heap_layout( heap, global_flags, heap_flags|HEAP_NO_SERIALIZE|HEAP_GROWABLE|HEAP_PRIVATE ); + ret = HeapDestroy( heap ); + ok( ret, "HeapDestroy failed, error %lu\n", GetLastError() ); + + heap = HeapCreate( HEAP_NO_SERIALIZE, 0, 0 ); + ok( heap != GetProcessHeap(), "got unexpected heap\n" ); + test_block_layout( heap, global_flags, heap_flags|HEAP_NO_SERIALIZE|HEAP_GROWABLE|HEAP_PRIVATE, + HEAP_TAIL_CHECKING_ENABLED|HEAP_FREE_CHECKING_ENABLED ); + ret = HeapDestroy( heap ); + ok( ret, "HeapDestroy failed, error %lu\n", GetLastError() ); + + heap = HeapCreate( 0, 0x1000, 0x10000 ); + ok( heap != GetProcessHeap(), "got unexpected heap\n" ); + test_heap_layout( heap, global_flags, heap_flags|HEAP_PRIVATE ); + ret = HeapDestroy( heap ); + ok( ret, "HeapDestroy failed, error %lu\n", GetLastError() ); + + heap = HeapCreate( HEAP_SHARED, 0, 0 ); + ok( heap != GetProcessHeap(), "got unexpected heap\n" ); + test_heap_layout( heap, global_flags, heap_flags|HEAP_GROWABLE|HEAP_PRIVATE ); + ret = HeapDestroy( heap ); + ok( ret, "HeapDestroy failed, error %lu\n", GetLastError() ); + + test_heap_checks( heap_flags ); } static void test_GetPhysicallyInstalledSystemMemory(void) { - HMODULE kernel32 = GetModuleHandleA("kernel32.dll"); MEMORYSTATUSEX memstatus; ULONGLONG total_memory; BOOL ret; - pGetPhysicallyInstalledSystemMemory = (void *)GetProcAddress(kernel32, "GetPhysicallyInstalledSystemMemory"); if (!pGetPhysicallyInstalledSystemMemory) { win_skip("GetPhysicallyInstalledSystemMemory is not available\n"); @@ -1202,18 +3846,208 @@ static void test_GetPhysicallyInstalledSystemMemory(void) ret = pGetPhysicallyInstalledSystemMemory(NULL); ok(!ret, "GetPhysicallyInstalledSystemMemory should fail\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); total_memory = 0; ret = pGetPhysicallyInstalledSystemMemory(&total_memory); - ok(ret, "GetPhysicallyInstalledSystemMemory unexpectedly failed\n"); +#ifdef __REACTOS__ + ok(ret || broken(GetLastError() == ERROR_INVALID_FUNCTION) /* Vista x64 ROS testbot */, "GetPhysicallyInstalledSystemMemory unexpectedly failed (%lu)\n", GetLastError()); + if (ret) + ok(total_memory != 0, "expected total_memory != 0\n"); +#else + ok(ret, "GetPhysicallyInstalledSystemMemory unexpectedly failed (%lu)\n", GetLastError()); ok(total_memory != 0, "expected total_memory != 0\n"); +#endif memstatus.dwLength = sizeof(memstatus); ret = GlobalMemoryStatusEx(&memstatus); ok(ret, "GlobalMemoryStatusEx unexpectedly failed\n"); +#ifdef __REACTOS__ + ok(total_memory >= memstatus.ullTotalPhys / 1024 || broken(total_memory == 0) /* Vista x64 ROS testbot */, + "expected total_memory >= memstatus.ullTotalPhys / 1024\n"); +#else ok(total_memory >= memstatus.ullTotalPhys / 1024, "expected total_memory >= memstatus.ullTotalPhys / 1024\n"); +#endif +} + +static void test_GlobalMemoryStatus(void) +{ + char buffer[sizeof(SYSTEM_PERFORMANCE_INFORMATION) + 16]; /* some Win 7 versions need a larger info */ + SYSTEM_PERFORMANCE_INFORMATION *perf_info = (void *)buffer; + SYSTEM_BASIC_INFORMATION basic_info; + MEMORYSTATUSEX memex = {0}, expect; + MEMORYSTATUS mem = {0}; + VM_COUNTERS_EX vmc; + NTSTATUS status; + BOOL ret; + + SetLastError( 0xdeadbeef ); + ret = GlobalMemoryStatusEx( &memex ); + ok( !ret, "GlobalMemoryStatusEx succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + GlobalMemoryStatus( &mem ); + ok( GetLastError() == 0xdeadbeef, "got error %lu\n", GetLastError() ); + + status = NtQuerySystemInformation( SystemBasicInformation, &basic_info, sizeof(basic_info), NULL ); + ok( !status, "NtQuerySystemInformation returned %#lx\n", status ); + status = NtQuerySystemInformation( SystemPerformanceInformation, perf_info, sizeof(buffer), NULL ); + ok( !status, "NtQuerySystemInformation returned %#lx\n", status ); + status = NtQueryInformationProcess( GetCurrentProcess(), ProcessVmCounters, &vmc, sizeof(vmc), NULL ); + ok( !status, "NtQueryInformationProcess returned %#lx\n", status ); + mem.dwLength = sizeof(MEMORYSTATUS); + GlobalMemoryStatus( &mem ); + memex.dwLength = sizeof(MEMORYSTATUSEX); + ret = GlobalMemoryStatusEx( &memex ); + ok( ret, "GlobalMemoryStatusEx succeeded\n" ); + + ok( basic_info.PageSize, "got 0 PageSize\n" ); + ok( basic_info.MmNumberOfPhysicalPages, "got 0 MmNumberOfPhysicalPages\n" ); + ok( !!basic_info.HighestUserAddress, "got 0 HighestUserAddress\n" ); + ok( !!basic_info.LowestUserAddress, "got 0 LowestUserAddress\n" ); + ok( perf_info->TotalCommittedPages, "got 0 TotalCommittedPages\n" ); + ok( perf_info->TotalCommitLimit, "got 0 TotalCommitLimit\n" ); + ok( perf_info->AvailablePages, "got 0 AvailablePages\n" ); + + expect.dwMemoryLoad = (memex.ullTotalPhys - memex.ullAvailPhys) / (memex.ullTotalPhys / 100); + expect.ullTotalPhys = (ULONGLONG)basic_info.MmNumberOfPhysicalPages * basic_info.PageSize; + expect.ullAvailPhys = (ULONGLONG)perf_info->AvailablePages * basic_info.PageSize; + expect.ullTotalPageFile = (ULONGLONG)perf_info->TotalCommitLimit * basic_info.PageSize; + expect.ullAvailPageFile = (ULONGLONG)(perf_info->TotalCommitLimit - perf_info->TotalCommittedPages) * basic_info.PageSize; + expect.ullTotalVirtual = (ULONG_PTR)basic_info.HighestUserAddress - (ULONG_PTR)basic_info.LowestUserAddress + 1; + expect.ullAvailVirtual = expect.ullTotalVirtual - (ULONGLONG)vmc.WorkingSetSize /* approximate */; + expect.ullAvailExtendedVirtual = 0; + +/* allow some variability, info sources are not always in sync */ +#define IS_WITHIN_RANGE(a, b) (((a) - (b) + (256 * basic_info.PageSize)) <= (512 * basic_info.PageSize)) + + ok( memex.dwMemoryLoad == expect.dwMemoryLoad, "got dwMemoryLoad %lu\n", memex.dwMemoryLoad ); + ok( memex.ullTotalPhys == expect.ullTotalPhys, "got ullTotalPhys %#I64x\n", memex.ullTotalPhys ); + ok( IS_WITHIN_RANGE( memex.ullAvailPhys, expect.ullAvailPhys ), "got ullAvailPhys %#I64x\n", memex.ullAvailPhys ); + ok( memex.ullTotalPageFile == expect.ullTotalPageFile, "got ullTotalPageFile %#I64x\n", memex.ullTotalPageFile ); + ok( IS_WITHIN_RANGE( memex.ullAvailPageFile, expect.ullAvailPageFile ), "got ullAvailPageFile %#I64x\n", memex.ullAvailPageFile ); + ok( memex.ullTotalVirtual == expect.ullTotalVirtual, "got ullTotalVirtual %#I64x\n", memex.ullTotalVirtual ); + ok( memex.ullAvailVirtual <= expect.ullAvailVirtual, "got ullAvailVirtual %#I64x\n", memex.ullAvailVirtual ); + ok( memex.ullAvailExtendedVirtual == 0, "got ullAvailExtendedVirtual %#I64x\n", memex.ullAvailExtendedVirtual ); + + ok( mem.dwMemoryLoad == memex.dwMemoryLoad, "got dwMemoryLoad %lu\n", mem.dwMemoryLoad ); + ok( mem.dwTotalPhys == min( ~(SIZE_T)0 >> 1, memex.ullTotalPhys ) || + broken( mem.dwTotalPhys == ~(SIZE_T)0 ) /* Win <= 8.1 with RAM size > 4GB */, + "got dwTotalPhys %#Ix\n", mem.dwTotalPhys ); + ok( IS_WITHIN_RANGE( mem.dwAvailPhys, min( ~(SIZE_T)0 >> 1, memex.ullAvailPhys ) ) || + broken( mem.dwAvailPhys == ~(SIZE_T)0 ) /* Win <= 8.1 with RAM size > 4GB */, + "got dwAvailPhys %#Ix\n", mem.dwAvailPhys ); +#ifndef _WIN64 + todo_wine_if(memex.ullTotalPageFile > 0xfff7ffff) +#endif + ok( mem.dwTotalPageFile == min( ~(SIZE_T)0, memex.ullTotalPageFile ), "got dwTotalPageFile %#Ix\n", mem.dwTotalPageFile ); + ok( IS_WITHIN_RANGE( mem.dwAvailPageFile, min( ~(SIZE_T)0, memex.ullAvailPageFile ) ), "got dwAvailPageFile %#Ix\n", mem.dwAvailPageFile ); + ok( mem.dwTotalVirtual == memex.ullTotalVirtual, "got dwTotalVirtual %#Ix\n", mem.dwTotalVirtual ); + ok( mem.dwAvailVirtual == memex.ullAvailVirtual, "got dwAvailVirtual %#Ix\n", mem.dwAvailVirtual ); + +#undef IS_WITHIN_RANGE +} + +static void get_valloc_info( void *mem, char **base, SIZE_T *alloc_size ) +{ + MEMORY_BASIC_INFORMATION info, info2; + SIZE_T size; + char *p; + + size = VirtualQuery( mem, &info, sizeof(info) ); + ok( size == sizeof(info), "got %Iu.\n", size ); + + info2 = info; + p = info.AllocationBase; + while (1) + { + size = VirtualQuery( p, &info2, sizeof(info2) ); + ok( size == sizeof(info), "got %Iu.\n", size ); + if (info2.AllocationBase != info.AllocationBase) + break; + ok( info2.State == MEM_RESERVE || info2.State == MEM_COMMIT, "got %#lx.\n", info2.State ); + p += info2.RegionSize; + } + + *base = info.AllocationBase; + *alloc_size = p - *base; +} + +static void test_heap_size( SIZE_T initial_size ) +{ + static const SIZE_T default_heap_size = 0x10000, init_grow_size = 0x100000, max_grow_size = 0xfd0000; + + BOOL initial_subheap = TRUE, max_size_reached = FALSE; + SIZE_T alloc_size, current_subheap_size; + char *base, *current_base; + unsigned int i; + HANDLE heap; + void *p; + + winetest_push_context( "init size %#Ix", initial_size ); + heap = HeapCreate( HEAP_NO_SERIALIZE, initial_size, 0 ); + get_valloc_info( heap, ¤t_base, &alloc_size ); + + ok( alloc_size == initial_size + default_heap_size || broken( (initial_size && alloc_size == initial_size) + || (!initial_size && (alloc_size == default_heap_size * sizeof(void*))) ) /* Win7 */, + "got %#Ix.\n", alloc_size ); + + current_subheap_size = alloc_size; + for (i = 0; i < 100; ++i) + { + winetest_push_context( "i %u, current_subheap_size %#Ix", i, current_subheap_size ); + p = HeapAlloc( heap, 0, 0x60000 ); + get_valloc_info( p, &base, &alloc_size ); + if (base != current_base) + { + current_base = base; + if (initial_subheap) + { + current_subheap_size = init_grow_size; + initial_subheap = FALSE; + } + else + { + current_subheap_size = min( current_subheap_size * 2, max_grow_size ); + if (current_subheap_size == max_grow_size) + max_size_reached = TRUE; + } + } + ok( alloc_size == current_subheap_size, "got %#Ix.\n", alloc_size ); + winetest_pop_context(); + } + ok( max_size_reached, "Did not reach maximum subheap size.\n" ); + + HeapDestroy( heap ); + winetest_pop_context(); +} + +static void test_heap_sizes(void) +{ + unsigned int i; + SIZE_T size, round_size = 0x400 * sizeof(void*); + char *base; + +#ifdef __REACTOS__ + if (GetNTVersion() < _WIN32_WINNT_VISTA) { + skip("test_heap_sizes() is invalid for WS03.\n"); + return; + } +#endif + test_heap_size( 0 ); + test_heap_size( 0x80000 ); + test_heap_size( 0x150000 ); + + for (i = 1; i < 0x100; i++) + { + HANDLE heap = HeapCreate( 0, i * 0x100, i * 0x100 ); + ok( heap != NULL, "%x: creation failed\n", i * 0x100 ); + get_valloc_info( heap, &base, &size ); + ok( size == ((i * 0x100 + round_size - 1) & ~(round_size - 1)), + "%x: wrong size %Ix\n", i * 0x100, size ); + HeapDestroy( heap ); + } } START_TEST(heap) @@ -1221,7 +4055,13 @@ START_TEST(heap) int argc; char **argv; - pRtlGetNtGlobalFlags = (void *)GetProcAddress( GetModuleHandleA("ntdll.dll"), "RtlGetNtGlobalFlags" ); +#if defined(__REACTOS__) && defined(SKIPBADHEAP_K32_WINETEST) + if (is_reactos()) { + ok(FALSE, "FIXME: These tests are too rough on ReactOS heap manager on x64. It will eventually finish but it takes over an hour to complete the test suite with it which isn't acceptable.\n"); + return; + } +#endif + load_functions(); argc = winetest_get_mainargs( &argv ); if (argc >= 3) @@ -1230,22 +4070,12 @@ START_TEST(heap) return; } - test_heap(); - test_obsolete_flags(); test_HeapCreate(); test_GlobalAlloc(); test_LocalAlloc(); - /* Test both short and very long blocks */ - test_sized_HeapAlloc(1); - test_sized_HeapAlloc(1 << 20); - test_sized_HeapReAlloc(1, 100); - test_sized_HeapReAlloc(1, (1 << 20)); - test_sized_HeapReAlloc((1 << 20), (2 << 20)); - test_sized_HeapReAlloc((1 << 20), 1); - - test_HeapQueryInformation(); test_GetPhysicallyInstalledSystemMemory(); + test_GlobalMemoryStatus(); if (pRtlGetNtGlobalFlags) { @@ -1262,4 +4092,5 @@ START_TEST(heap) test_debug_heap( argv[0], 0xdeadbeef ); } else win_skip( "RtlGetNtGlobalFlags not found, skipping heap debug tests\n" ); + test_heap_sizes(); } diff --git a/modules/rostests/winetests/kernel32/loader.c b/modules/rostests/winetests/kernel32/loader.c index a61558178da..b0fe86bd703 100644 --- a/modules/rostests/winetests/kernel32/loader.c +++ b/modules/rostests/winetests/kernel32/loader.c @@ -18,8 +18,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#define NONAMELESSUNION -#define NONAMELESSSTRUCT #include #include #include @@ -29,18 +27,21 @@ #include "windef.h" #include "winbase.h" #include "winternl.h" -#include "winuser.h" +#include "winnls.h" #include "wine/test.h" #include "delayloadhandler.h" +#ifdef __REACTOS__ +#include "winehacks.h" +#endif /* PROCESS_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */ #define PROCESS_ALL_ACCESS_NT4 (PROCESS_ALL_ACCESS & ~0xf000) -#define ALIGN_SIZE(size, alignment) (((size) + (alignment - 1)) & ~((alignment - 1))) +#define ALIGN_SIZE(size, alignment) (((size) + ((ULONG_PTR)(alignment) - 1)) & ~(((ULONG_PTR)(alignment) - 1))) struct PROCESS_BASIC_INFORMATION_PRIVATE { - DWORD_PTR ExitStatus; + NTSTATUS ExitStatus; PPEB PebBaseAddress; DWORD_PTR AffinityMask; DWORD_PTR BasePriority; @@ -49,36 +50,47 @@ struct PROCESS_BASIC_INFORMATION_PRIVATE }; static LONG *child_failures; -static WORD cb_count; +static WORD cb_count, cb_count_sys; static DWORD page_size; static BOOL is_win64 = sizeof(void *) > sizeof(int); static BOOL is_wow64; +static char system_dir[MAX_PATH]; +static char syswow_dir[MAX_PATH]; /* only available if is_wow64 */ static NTSTATUS (WINAPI *pNtCreateSection)(HANDLE *, ACCESS_MASK, const OBJECT_ATTRIBUTES *, const LARGE_INTEGER *, ULONG, ULONG, HANDLE ); static NTSTATUS (WINAPI *pNtQuerySection)(HANDLE, SECTION_INFORMATION_CLASS, void *, SIZE_T, SIZE_T *); -static NTSTATUS (WINAPI *pNtMapViewOfSection)(HANDLE, HANDLE, PVOID *, ULONG, SIZE_T, const LARGE_INTEGER *, SIZE_T *, ULONG, ULONG, ULONG); +static NTSTATUS (WINAPI *pNtMapViewOfSection)(HANDLE, HANDLE, PVOID *, ULONG_PTR, SIZE_T, const LARGE_INTEGER *, SIZE_T *, ULONG, ULONG, ULONG); static NTSTATUS (WINAPI *pNtUnmapViewOfSection)(HANDLE, PVOID); static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG); static NTSTATUS (WINAPI *pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG); static NTSTATUS (WINAPI *pNtTerminateProcess)(HANDLE, DWORD); static void (WINAPI *pLdrShutdownProcess)(void); static BOOLEAN (WINAPI *pRtlDllShutdownInProgress)(void); -static NTSTATUS (WINAPI *pNtAllocateVirtualMemory)(HANDLE, PVOID *, ULONG, SIZE_T *, ULONG, ULONG); +static NTSTATUS (WINAPI *pNtAllocateVirtualMemory)(HANDLE, PVOID *, ULONG_PTR, SIZE_T *, ULONG, ULONG); static NTSTATUS (WINAPI *pNtFreeVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG); static NTSTATUS (WINAPI *pLdrLockLoaderLock)(ULONG, ULONG *, ULONG_PTR *); static NTSTATUS (WINAPI *pLdrUnlockLoaderLock)(ULONG, ULONG_PTR); +static NTSTATUS (WINAPI *pLdrLoadDll)(LPCWSTR,DWORD,const UNICODE_STRING *,HMODULE*); +static NTSTATUS (WINAPI *pLdrUnloadDll)(HMODULE); +static void (WINAPI *pRtlInitUnicodeString)(PUNICODE_STRING,LPCWSTR); static void (WINAPI *pRtlAcquirePebLock)(void); static void (WINAPI *pRtlReleasePebLock)(void); static PVOID (WINAPI *pResolveDelayLoadedAPI)(PVOID, PCIMAGE_DELAYLOAD_DESCRIPTOR, - PDELAYLOAD_FAILURE_DLL_CALLBACK, PVOID, + PDELAYLOAD_FAILURE_DLL_CALLBACK, + PDELAYLOAD_FAILURE_SYSTEM_ROUTINE, PIMAGE_THUNK_DATA ThunkAddress,ULONG); static PVOID (WINAPI *pRtlImageDirectoryEntryToData)(HMODULE,BOOL,WORD,ULONG *); +static PIMAGE_NT_HEADERS (WINAPI *pRtlImageNtHeader)(HMODULE); static DWORD (WINAPI *pFlsAlloc)(PFLS_CALLBACK_FUNCTION); static BOOL (WINAPI *pFlsSetValue)(DWORD, PVOID); static PVOID (WINAPI *pFlsGetValue)(DWORD); static BOOL (WINAPI *pFlsFree)(DWORD); static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL); +static BOOL (WINAPI *pWow64DisableWow64FsRedirection)(void **); +static BOOL (WINAPI *pWow64RevertWow64FsRedirection)(void *); +static HMODULE (WINAPI *pLoadPackagedLibrary)(LPCWSTR lpwLibFileName, DWORD Reserved); +static NTSTATUS (WINAPI *pLdrRegisterDllNotification)(ULONG, PLDR_DLL_NOTIFICATION_FUNCTION, void *, void **); static PVOID RVAToAddr(DWORD_PTR rva, HMODULE module) { @@ -97,8 +109,6 @@ static const IMAGE_NT_HEADERS nt_header_template = IMAGE_FILE_MACHINE_I386, /* Machine */ #elif defined __x86_64__ IMAGE_FILE_MACHINE_AMD64, /* Machine */ -#elif defined __powerpc__ - IMAGE_FILE_MACHINE_POWERPC, /* Machine */ #elif defined __arm__ IMAGE_FILE_MACHINE_ARMNT, /* Machine */ #elif defined __aarch64__ @@ -123,8 +133,10 @@ static const IMAGE_NT_HEADERS nt_header_template = 0x10, /* BaseOfCode, also serves as e_lfanew in the truncated MZ header */ #ifndef _WIN64 0, /* BaseOfData */ -#endif 0x10000000, /* ImageBase */ +#else + 0x123450000, /* ImageBase */ +#endif 0, /* SectionAlignment */ 0, /* FileAlignment */ 4, /* MajorOperatingSystemVersion */ @@ -138,13 +150,13 @@ static const IMAGE_NT_HEADERS nt_header_template = sizeof(dos_header) + sizeof(nt_header_template), /* SizeOfHeaders */ 0, /* CheckSum */ IMAGE_SUBSYSTEM_WINDOWS_CUI, /* Subsystem */ - 0, /* DllCharacteristics */ - 0, /* SizeOfStackReserve */ - 0, /* SizeOfStackCommit */ - 0, /* SizeOfHeapReserve */ - 0, /* SizeOfHeapCommit */ + IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLLCHARACTERISTICS_NX_COMPAT, /* DllCharacteristics */ + 0x100000, /* SizeOfStackReserve */ + 0x1000, /* SizeOfStackCommit */ + 0x100000, /* SizeOfHeapReserve */ + 0x1000, /* SizeOfHeapCommit */ 0, /* LoaderFlags */ - 0, /* NumberOfRvaAndSizes */ + IMAGE_NUMBEROF_DIRECTORY_ENTRIES, /* NumberOfRvaAndSizes */ { { 0 } } /* DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] */ } }; @@ -167,6 +179,32 @@ static IMAGE_SECTION_HEADER section = static const char filler[0x1000]; static const char section_data[0x10] = "section data"; +/* return an alternate machine of the same 32/64 bitness */ +static WORD get_alt_machine( WORD orig_machine ) +{ + switch (orig_machine) + { + case IMAGE_FILE_MACHINE_I386: return IMAGE_FILE_MACHINE_ARMNT; + case IMAGE_FILE_MACHINE_AMD64: return IMAGE_FILE_MACHINE_ARM64; + case IMAGE_FILE_MACHINE_ARMNT: return IMAGE_FILE_MACHINE_I386; + case IMAGE_FILE_MACHINE_ARM64: return IMAGE_FILE_MACHINE_AMD64; + } + return 0; +} + +/* return the machine of the alternate 32/64 bitness */ +static WORD get_alt_bitness_machine( WORD orig_machine ) +{ + switch (orig_machine) + { + case IMAGE_FILE_MACHINE_I386: return IMAGE_FILE_MACHINE_AMD64; + case IMAGE_FILE_MACHINE_AMD64: return IMAGE_FILE_MACHINE_I386; + case IMAGE_FILE_MACHINE_ARMNT: return IMAGE_FILE_MACHINE_ARM64; + case IMAGE_FILE_MACHINE_ARM64: return IMAGE_FILE_MACHINE_ARMNT; + } + return 0; +} + static DWORD create_test_dll( const IMAGE_DOS_HEADER *dos_header, UINT dos_size, const IMAGE_NT_HEADERS *nt_header, char dll_name[MAX_PATH] ) { @@ -179,16 +217,16 @@ static DWORD create_test_dll( const IMAGE_DOS_HEADER *dos_header, UINT dos_size, GetTempFileNameA(temp_path, "ldr", 0, dll_name); hfile = CreateFileA(dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0); - ok( hfile != INVALID_HANDLE_VALUE, "failed to create %s err %u\n", dll_name, GetLastError() ); + ok( hfile != INVALID_HANDLE_VALUE, "failed to create %s err %lu\n", dll_name, GetLastError() ); if (hfile == INVALID_HANDLE_VALUE) return 0; SetLastError(0xdeadbeef); ret = WriteFile(hfile, dos_header, dos_size, &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = WriteFile(hfile, nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); if (nt_header->FileHeader.SizeOfOptionalHeader) { @@ -196,14 +234,14 @@ static DWORD create_test_dll( const IMAGE_DOS_HEADER *dos_header, UINT dos_size, ret = WriteFile(hfile, &nt_header->OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); if (nt_header->FileHeader.SizeOfOptionalHeader > sizeof(IMAGE_OPTIONAL_HEADER)) { file_align = nt_header->FileHeader.SizeOfOptionalHeader - sizeof(IMAGE_OPTIONAL_HEADER); assert(file_align < sizeof(filler)); SetLastError(0xdeadbeef); ret = WriteFile(hfile, filler, file_align, &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); } } @@ -229,12 +267,12 @@ static DWORD create_test_dll( const IMAGE_DOS_HEADER *dos_header, UINT dos_size, SetLastError(0xdeadbeef); ret = WriteFile(hfile, §ion, sizeof(section), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); /* section data */ SetLastError(0xdeadbeef); ret = WriteFile(hfile, section_data, sizeof(section_data), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); } /* Minimal PE image that Windows7+ is able to load: 268 bytes */ @@ -244,7 +282,7 @@ static DWORD create_test_dll( const IMAGE_DOS_HEADER *dos_header, UINT dos_size, file_align = 268 - size; SetLastError(0xdeadbeef); ret = WriteFile(hfile, filler, file_align, &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); } size = GetFileSize(hfile, NULL); @@ -265,28 +303,28 @@ static DWORD create_test_dll_sections( const IMAGE_DOS_HEADER *dos_header, const GetTempFileNameA(temp_path, "ldr", 0, dll_name); hfile = CreateFileA(dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0); - ok( hfile != INVALID_HANDLE_VALUE, "failed to create %s err %u\n", dll_name, GetLastError() ); + ok( hfile != INVALID_HANDLE_VALUE, "failed to create %s err %lu\n", dll_name, GetLastError() ); if (hfile == INVALID_HANDLE_VALUE) return 0; SetLastError(0xdeadbeef); ret = WriteFile(hfile, dos_header, sizeof(*dos_header), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = WriteFile(hfile, nt_header, offsetof(IMAGE_NT_HEADERS, OptionalHeader) + nt_header->FileHeader.SizeOfOptionalHeader, &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = WriteFile(hfile, sections, sizeof(*sections) * nt_header->FileHeader.NumberOfSections, &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) { SetFilePointer(hfile, sections[i].PointerToRawData, NULL, FILE_BEGIN); SetLastError(0xdeadbeef); ret = WriteFile(hfile, section_data, sections[i].SizeOfRawData, &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); } size = GetFileSize(hfile, NULL); CloseHandle(hfile); @@ -296,7 +334,6 @@ static DWORD create_test_dll_sections( const IMAGE_DOS_HEADER *dos_header, const static BOOL query_image_section( int id, const char *dll_name, const IMAGE_NT_HEADERS *nt_header, const void *section_data ) { - static BOOL is_winxp; SECTION_BASIC_INFORMATION info; SECTION_IMAGE_INFORMATION image; const IMAGE_COR20_HEADER *cor_header = NULL; @@ -307,26 +344,24 @@ static BOOL query_image_section( int id, const char *dll_name, const IMAGE_NT_HE LARGE_INTEGER map_size; SIZE_T max_stack, commit_stack; void *entry_point; - - /* truncated header is not handled correctly in windows <= w2k3 */ BOOL truncated; file = CreateFileA( dll_name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, 0 ); - ok( file != INVALID_HANDLE_VALUE, "%u: CreateFile error %d\n", id, GetLastError() ); + ok( file != INVALID_HANDLE_VALUE, "%u: CreateFile error %ld\n", id, GetLastError() ); file_size = GetFileSize( file, NULL ); status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY, NULL, NULL, PAGE_READONLY, SEC_IMAGE, file ); - ok( !status, "%u: NtCreateSection failed err %x\n", id, status ); + ok( !status, "%u: NtCreateSection failed err %lx\n", id, status ); if (status) { CloseHandle( file ); return FALSE; } status = pNtQuerySection( mapping, SectionImageInformation, &image, sizeof(image), &info_size ); - ok( !status, "%u: NtQuerySection failed err %x\n", id, status ); - ok( info_size == sizeof(image), "%u: NtQuerySection wrong size %lu\n", id, info_size ); + ok( !status, "%u: NtQuerySection failed err %lx\n", id, status ); + ok( info_size == sizeof(image), "%u: NtQuerySection wrong size %Iu\n", id, info_size ); if (nt_header->OptionalHeader.Magic == (is_win64 ? IMAGE_NT_OPTIONAL_HDR64_MAGIC : IMAGE_NT_OPTIONAL_HDR32_MAGIC)) { @@ -364,40 +399,43 @@ static BOOL query_image_section( int id, const char *dll_name, const IMAGE_NT_HE cor_header = section_data; } ok( (char *)image.TransferAddress == (char *)entry_point || - (S(U(image)).ImageDynamicallyRelocated && LOWORD(image.TransferAddress) == LOWORD(entry_point)), - "%u: TransferAddress wrong %p / %p (%08x)\n", id, + (image.ImageDynamicallyRelocated && LOWORD(image.TransferAddress) == LOWORD(entry_point)), + "%u: TransferAddress wrong %p / %p (%08lx)\n", id, image.TransferAddress, entry_point, nt_header->OptionalHeader.AddressOfEntryPoint ); - ok( image.ZeroBits == 0, "%u: ZeroBits wrong %08x\n", id, image.ZeroBits ); - ok( image.MaximumStackSize == max_stack || broken(truncated), - "%u: MaximumStackSize wrong %lx / %lx\n", id, image.MaximumStackSize, max_stack ); - ok( image.CommittedStackSize == commit_stack || broken(truncated), - "%u: CommittedStackSize wrong %lx / %lx\n", id, image.CommittedStackSize, commit_stack ); - if (truncated) - ok( !image.SubSystemType || broken(truncated), - "%u: SubSystemType wrong %08x / 00000000\n", id, image.SubSystemType ); - else - ok( image.SubSystemType == nt_header->OptionalHeader.Subsystem, - "%u: SubSystemType wrong %08x / %08x\n", id, - image.SubSystemType, nt_header->OptionalHeader.Subsystem ); + ok( image.ZeroBits == 0, "%u: ZeroBits wrong %08lx\n", id, image.ZeroBits ); + ok( image.MaximumStackSize == max_stack, + "%u: MaximumStackSize wrong %Ix / %Ix\n", id, image.MaximumStackSize, max_stack ); + ok( image.CommittedStackSize == commit_stack, + "%u: CommittedStackSize wrong %Ix / %Ix\n", id, image.CommittedStackSize, commit_stack ); + ok( image.SubSystemType == nt_header->OptionalHeader.Subsystem, + "%u: SubSystemType wrong %08lx / %08x\n", id, + image.SubSystemType, nt_header->OptionalHeader.Subsystem ); ok( image.MinorSubsystemVersion == nt_header->OptionalHeader.MinorSubsystemVersion, - "%u: SubsystemVersionLow wrong %04x / %04x\n", id, + "%u: MinorSubsystemVersion wrong %04x / %04x\n", id, image.MinorSubsystemVersion, nt_header->OptionalHeader.MinorSubsystemVersion ); ok( image.MajorSubsystemVersion == nt_header->OptionalHeader.MajorSubsystemVersion, - "%u: SubsystemVersionHigh wrong %04x / %04x\n", id, + "%u: MajorSubsystemVersion wrong %04x / %04x\n", id, image.MajorSubsystemVersion, nt_header->OptionalHeader.MajorSubsystemVersion ); + ok( image.MajorOperatingSystemVersion == nt_header->OptionalHeader.MajorOperatingSystemVersion || + broken( !image.MajorOperatingSystemVersion), /* before win10 */ + "%u: MajorOperatingSystemVersion wrong %04x / %04x\n", id, + image.MajorOperatingSystemVersion, nt_header->OptionalHeader.MajorOperatingSystemVersion ); + ok( image.MinorOperatingSystemVersion == nt_header->OptionalHeader.MinorOperatingSystemVersion, + "%u: MinorOperatingSystemVersion wrong %04x / %04x\n", id, + image.MinorOperatingSystemVersion, nt_header->OptionalHeader.MinorOperatingSystemVersion ); ok( image.ImageCharacteristics == nt_header->FileHeader.Characteristics, "%u: ImageCharacteristics wrong %04x / %04x\n", id, image.ImageCharacteristics, nt_header->FileHeader.Characteristics ); - ok( image.DllCharacteristics == nt_header->OptionalHeader.DllCharacteristics || broken(truncated), + ok( image.DllCharacteristics == nt_header->OptionalHeader.DllCharacteristics, "%u: DllCharacteristics wrong %04x / %04x\n", id, image.DllCharacteristics, nt_header->OptionalHeader.DllCharacteristics ); ok( image.Machine == nt_header->FileHeader.Machine, "%u: Machine wrong %04x / %04x\n", id, image.Machine, nt_header->FileHeader.Machine ); - ok( image.LoaderFlags == (cor_header != NULL), "%u: LoaderFlags wrong %08x\n", id, image.LoaderFlags ); - ok( image.ImageFileSize == file_size || broken(!image.ImageFileSize), /* winxpsp1 */ - "%u: ImageFileSize wrong %08x / %08x\n", id, image.ImageFileSize, file_size ); - ok( image.CheckSum == nt_header->OptionalHeader.CheckSum || broken(truncated), - "%u: CheckSum wrong %08x / %08x\n", id, + ok( image.LoaderFlags == (cor_header != NULL), "%u: LoaderFlags wrong %08lx\n", id, image.LoaderFlags ); + ok( image.ImageFileSize == file_size, + "%u: ImageFileSize wrong %08lx / %08lx\n", id, image.ImageFileSize, file_size ); + ok( image.CheckSum == nt_header->OptionalHeader.CheckSum, + "%u: CheckSum wrong %08lx / %08lx\n", id, image.CheckSum, nt_header->OptionalHeader.CheckSum ); if (nt_header->OptionalHeader.SizeOfCode || nt_header->OptionalHeader.AddressOfEntryPoint) @@ -416,79 +454,97 @@ static BOOL query_image_section( int id, const char *dll_name, const IMAGE_NT_HE (cor_header->MajorRuntimeVersion > 2 || (cor_header->MajorRuntimeVersion == 2 && cor_header->MinorRuntimeVersion >= 5))) { - ok( S(U(image)).ComPlusILOnly || broken(is_winxp), - "%u: wrong ComPlusILOnly flags %02x\n", id, U(image).ImageFlags ); +#ifdef __REACTOS__ + ok( image.ComPlusILOnly || broken(GetNTVersion() < _WIN32_WINNT_VISTA), +#else + ok( image.ComPlusILOnly, +#endif + "%u: wrong ComPlusILOnly flags %02x\n", id, image.ImageFlags ); if (nt_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC && !(cor_header->Flags & COMIMAGE_FLAGS_32BITREQUIRED)) - ok( S(U(image)).ComPlusNativeReady || broken(is_winxp), - "%u: wrong ComPlusNativeReady flags %02x\n", id, U(image).ImageFlags ); +#ifdef __REACTOS__ + ok( image.ComPlusNativeReady || broken(GetNTVersion() < _WIN32_WINNT_VISTA), +#else + ok( image.ComPlusNativeReady, +#endif + "%u: wrong ComPlusNativeReady flags %02x\n", id, image.ImageFlags ); else - ok( !S(U(image)).ComPlusNativeReady, - "%u: wrong ComPlusNativeReady flags %02x\n", id, U(image).ImageFlags ); + ok( !image.ComPlusNativeReady, + "%u: wrong ComPlusNativeReady flags %02x\n", id, image.ImageFlags ); + if (nt_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC && + (cor_header->Flags & COMIMAGE_FLAGS_32BITPREFERRED)) + ok( image.ComPlusPrefer32bit || + broken( !image.MajorOperatingSystemVersion ), /* before win10 */ + "%u: wrong ComPlusPrefer32bit flags %02x\n", id, image.ImageFlags ); + else + ok( !image.ComPlusPrefer32bit, "%u: wrong ComPlusPrefer32bit flags %02x\n", id, image.ImageFlags ); } else { - ok( !S(U(image)).ComPlusILOnly, "%u: wrong ComPlusILOnly flags %02x\n", id, U(image).ImageFlags ); - ok( !S(U(image)).ComPlusNativeReady, "%u: wrong ComPlusNativeReady flags %02x\n", id, U(image).ImageFlags ); + ok( !image.ComPlusILOnly, "%u: wrong ComPlusILOnly flags %02x\n", id, image.ImageFlags ); + ok( !image.ComPlusNativeReady, "%u: wrong ComPlusNativeReady flags %02x\n", id, image.ImageFlags ); + ok( !image.ComPlusPrefer32bit, "%u: wrong ComPlusPrefer32bit flags %02x\n", id, image.ImageFlags ); } if (!(nt_header->OptionalHeader.SectionAlignment % page_size)) - ok( !S(U(image)).ImageMappedFlat, "%u: wrong ImageMappedFlat flags %02x\n", id, U(image).ImageFlags ); + ok( !image.ImageMappedFlat, "%u: wrong ImageMappedFlat flags %02x\n", id, image.ImageFlags ); else - { - /* winxp doesn't support any of the loader flags */ - if (!S(U(image)).ImageMappedFlat) is_winxp = TRUE; - ok( S(U(image)).ImageMappedFlat || broken(is_winxp), - "%u: wrong ImageMappedFlat flags %02x\n", id, U(image).ImageFlags ); - } - if (!(nt_header->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE)) - ok( !S(U(image)).ImageDynamicallyRelocated || broken( S(U(image)).ComPlusILOnly ), /* <= win7 */ - "%u: wrong ImageDynamicallyRelocated flags %02x\n", id, U(image).ImageFlags ); - else if (image.ImageContainsCode && !cor_header) - ok( S(U(image)).ImageDynamicallyRelocated || broken(is_winxp), - "%u: wrong ImageDynamicallyRelocated flags %02x\n", id, U(image).ImageFlags ); - else - ok( !S(U(image)).ImageDynamicallyRelocated || broken(TRUE), /* <= win8 */ - "%u: wrong ImageDynamicallyRelocated flags %02x\n", id, U(image).ImageFlags ); - ok( !S(U(image)).BaseBelow4gb, "%u: wrong BaseBelow4gb flags %02x\n", id, U(image).ImageFlags ); +#ifdef __REACTOS__ + ok( image.ImageMappedFlat || broken(GetNTVersion() < _WIN32_WINNT_VISTA), +#else + ok( image.ImageMappedFlat, +#endif + "%u: wrong ImageMappedFlat flags %02x\n", id, image.ImageFlags ); - /* FIXME: needs more work: */ - /* image.GpValue */ + if (!(nt_header->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE)) + ok( !image.ImageDynamicallyRelocated || broken( image.ComPlusILOnly ), /* <= win7 */ + "%u: wrong ImageDynamicallyRelocated flags %02x\n", id, image.ImageFlags ); + else if (image.ImageContainsCode && !image.ImageMappedFlat && !cor_header) +#ifdef __REACTOS__ + ok( image.ImageDynamicallyRelocated || broken(GetNTVersion() < _WIN32_WINNT_VISTA), +#else + ok( image.ImageDynamicallyRelocated, +#endif + "%u: wrong ImageDynamicallyRelocated flags %02x\n", id, image.ImageFlags ); + else + ok( !image.ImageDynamicallyRelocated || broken(TRUE), /* <= win8 */ + "%u: wrong ImageDynamicallyRelocated flags %02x\n", id, image.ImageFlags ); + ok( !image.BaseBelow4gb, "%u: wrong BaseBelow4gb flags %02x\n", id, image.ImageFlags ); map_size.QuadPart = (nt_header->OptionalHeader.SizeOfImage + page_size - 1) & ~(page_size - 1); status = pNtQuerySection( mapping, SectionBasicInformation, &info, sizeof(info), NULL ); - ok( !status, "NtQuerySection failed err %x\n", status ); - ok( info.Size.QuadPart == map_size.QuadPart, "NtQuerySection wrong size %x%08x / %x%08x\n", + ok( !status, "NtQuerySection failed err %lx\n", status ); + ok( info.Size.QuadPart == map_size.QuadPart, "NtQuerySection wrong size %lx%08lx / %lx%08lx\n", info.Size.u.HighPart, info.Size.u.LowPart, map_size.u.HighPart, map_size.u.LowPart ); CloseHandle( mapping ); map_size.QuadPart = (nt_header->OptionalHeader.SizeOfImage + page_size - 1) & ~(page_size - 1); status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY, NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file ); - ok( !status, "%u: NtCreateSection failed err %x\n", id, status ); + ok( !status, "%u: NtCreateSection failed err %lx\n", id, status ); status = pNtQuerySection( mapping, SectionBasicInformation, &info, sizeof(info), NULL ); - ok( !status, "NtQuerySection failed err %x\n", status ); - ok( info.Size.QuadPart == map_size.QuadPart, "NtQuerySection wrong size %x%08x / %x%08x\n", + ok( !status, "NtQuerySection failed err %lx\n", status ); + ok( info.Size.QuadPart == map_size.QuadPart, "NtQuerySection wrong size %lx%08lx / %lx%08lx\n", info.Size.u.HighPart, info.Size.u.LowPart, map_size.u.HighPart, map_size.u.LowPart ); CloseHandle( mapping ); map_size.QuadPart++; status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY, NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file ); - ok( status == STATUS_SECTION_TOO_BIG, "%u: NtCreateSection failed err %x\n", id, status ); + ok( status == STATUS_SECTION_TOO_BIG, "%u: NtCreateSection failed err %lx\n", id, status ); SetFilePointerEx( file, map_size, NULL, FILE_BEGIN ); SetEndOfFile( file ); status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY, NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file ); - ok( status == STATUS_SECTION_TOO_BIG, "%u: NtCreateSection failed err %x\n", id, status ); + ok( status == STATUS_SECTION_TOO_BIG, "%u: NtCreateSection failed err %lx\n", id, status ); map_size.QuadPart = 1; status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY, NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file ); - ok( !status, "%u: NtCreateSection failed err %x\n", id, status ); + ok( !status, "%u: NtCreateSection failed err %lx\n", id, status ); status = pNtQuerySection( mapping, SectionBasicInformation, &info, sizeof(info), NULL ); - ok( !status, "NtQuerySection failed err %x\n", status ); - ok( info.Size.QuadPart == map_size.QuadPart, "NtQuerySection wrong size %x%08x / %x%08x\n", + ok( !status, "NtQuerySection failed err %lx\n", status ); + ok( info.Size.QuadPart == map_size.QuadPart, "NtQuerySection wrong size %lx%08lx / %lx%08lx\n", info.Size.u.HighPart, info.Size.u.LowPart, map_size.u.HighPart, map_size.u.LowPart ); CloseHandle( mapping ); @@ -496,63 +552,205 @@ static BOOL query_image_section( int id, const char *dll_name, const IMAGE_NT_HE return image.ImageContainsCode && (!cor_header || !(cor_header->Flags & COMIMAGE_FLAGS_ILONLY)); } +static const WCHAR wldr_nameW[] = {'w','l','d','r','t','e','s','t','.','d','l','l',0}; +static WCHAR load_test_name[MAX_PATH], load_fallback_name[MAX_PATH]; +static WCHAR load_path[MAX_PATH]; + +static void init_load_path( const char *fallback_dll ) +{ + static const WCHAR pathW[] = {'P','A','T','H',0}; + static const WCHAR ldrW[] = {'l','d','r',0}; + static const WCHAR sepW[] = {';',0}; + static const WCHAR bsW[] = {'\\',0}; + WCHAR path[MAX_PATH]; + + GetTempPathW( MAX_PATH, path ); + GetTempFileNameW( path, ldrW, 0, load_test_name ); + GetTempFileNameW( path, ldrW, 0, load_fallback_name ); + DeleteFileW( load_test_name ); + ok( CreateDirectoryW( load_test_name, NULL ), "failed to create dir\n" ); + DeleteFileW( load_fallback_name ); + ok( CreateDirectoryW( load_fallback_name, NULL ), "failed to create dir\n" ); + lstrcpyW( load_path, load_test_name ); + lstrcatW( load_path, sepW ); + lstrcatW( load_path, load_fallback_name ); + lstrcatW( load_path, sepW ); + GetEnvironmentVariableW( pathW, load_path + lstrlenW(load_path), + ARRAY_SIZE(load_path) - lstrlenW(load_path) ); + lstrcatW( load_test_name, bsW ); + lstrcatW( load_test_name, wldr_nameW ); + lstrcatW( load_fallback_name, bsW ); + lstrcatW( load_fallback_name, wldr_nameW ); + MultiByteToWideChar( CP_ACP, 0, fallback_dll, -1, path, MAX_PATH ); + MoveFileW( path, load_fallback_name ); +} + +static void delete_load_path(void) +{ + WCHAR *p; + + DeleteFileW( load_test_name ); + for (p = load_test_name + lstrlenW(load_test_name) - 1; *p != '\\'; p--) ; + *p = 0; + RemoveDirectoryW( load_test_name ); + DeleteFileW( load_fallback_name ); + for (p = load_fallback_name + lstrlenW(load_fallback_name) - 1; *p != '\\'; p--) ; + *p = 0; + RemoveDirectoryW( load_fallback_name ); +} + +static UINT get_com_dir_size( const IMAGE_NT_HEADERS *nt ) +{ + if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + return ((const IMAGE_NT_HEADERS32 *)nt)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size; + else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) + return ((const IMAGE_NT_HEADERS64 *)nt)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size; + else + return 0; +} + /* helper to test image section mapping */ static NTSTATUS map_image_section( const IMAGE_NT_HEADERS *nt_header, const IMAGE_SECTION_HEADER *sections, const void *section_data, int line ) { char dll_name[MAX_PATH]; + WCHAR path[MAX_PATH]; + UNICODE_STRING name; LARGE_INTEGER size; HANDLE file, map; - NTSTATUS status; + NTSTATUS status, expect_status, ldr_status; ULONG file_size; - BOOL has_code; - HMODULE mod; + BOOL has_code = FALSE, il_only = FALSE, want_32bit = FALSE, expect_fallback = FALSE, wrong_machine = FALSE; + HMODULE mod = 0, ldr_mod; file_size = create_test_dll_sections( &dos_header, nt_header, sections, section_data, dll_name ); file = CreateFileA(dll_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); - ok(file != INVALID_HANDLE_VALUE, "CreateFile error %d\n", GetLastError()); + ok(file != INVALID_HANDLE_VALUE, "CreateFile error %ld\n", GetLastError()); size.QuadPart = file_size; status = pNtCreateSection(&map, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY, NULL, &size, PAGE_READONLY, SEC_IMAGE, file ); + expect_status = status; + + if (get_com_dir_size( nt_header )) + { + /* invalid COR20 header seems to corrupt internal loader state on Windows */ + if (get_com_dir_size( nt_header ) < sizeof(IMAGE_COR20_HEADER)) goto done; + if (!((const IMAGE_COR20_HEADER *)section_data)->Flags) goto done; + } + if (!status) { SECTION_BASIC_INFORMATION info; SIZE_T info_size = 0xdeadbeef; NTSTATUS ret = pNtQuerySection( map, SectionBasicInformation, &info, sizeof(info), &info_size ); - ok( !ret, "NtQuerySection failed err %x\n", ret ); - ok( info_size == sizeof(info), "NtQuerySection wrong size %lu\n", info_size ); - ok( info.Attributes == (SEC_IMAGE | SEC_FILE), "NtQuerySection wrong attr %x\n", info.Attributes ); + ok( !ret, "NtQuerySection failed err %lx\n", ret ); + ok( info_size == sizeof(info), "NtQuerySection wrong size %Iu\n", info_size ); + ok( info.Attributes == (SEC_IMAGE | SEC_FILE), "NtQuerySection wrong attr %lx\n", info.Attributes ); ok( info.BaseAddress == NULL, "NtQuerySection wrong base %p\n", info.BaseAddress ); - ok( info.Size.QuadPart == file_size, "NtQuerySection wrong size %x%08x / %08x\n", + ok( info.Size.QuadPart == file_size, "NtQuerySection wrong size %lx%08lx / %08lx\n", info.Size.u.HighPart, info.Size.u.LowPart, file_size ); has_code = query_image_section( line, dll_name, nt_header, section_data ); + + if (get_com_dir_size( nt_header )) + { + const IMAGE_COR20_HEADER *cor_header = section_data; + il_only = (cor_header->Flags & COMIMAGE_FLAGS_ILONLY) != 0; + if (il_only) want_32bit = (cor_header->Flags & COMIMAGE_FLAGS_32BITREQUIRED) != 0; + } + + SetLastError( 0xdeadbeef ); + mod = LoadLibraryExA( dll_name, 0, DONT_RESOLVE_DLL_REFERENCES ); /* test loading dll of wrong 32/64 bitness */ if (nt_header->OptionalHeader.Magic == (is_win64 ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC)) { - SetLastError( 0xdeadbeef ); - mod = LoadLibraryExA( dll_name, 0, DONT_RESOLVE_DLL_REFERENCES ); - if (!has_code && nt_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + if (!has_code && is_win64) { - BOOL il_only = FALSE; - if (((const IMAGE_NT_HEADERS32 *)nt_header)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress) - { - const IMAGE_COR20_HEADER *cor_header = section_data; - il_only = (cor_header->Flags & COMIMAGE_FLAGS_ILONLY) != 0; - } - ok( mod != NULL || broken(il_only), /* <= win7 */ - "%u: loading failed err %u\n", line, GetLastError() ); + ok_(__FILE__,line)( mod != NULL || want_32bit || broken(il_only), /* <= win7 */ + "loading failed err %lu\n", GetLastError() ); } else { - ok( !mod, "%u: loading succeeded\n", line ); - ok( GetLastError() == ERROR_BAD_EXE_FORMAT, "%u: wrong error %u\n", line, GetLastError() ); + ok_(__FILE__, line)( !mod, "loading succeeded\n" ); + ok_(__FILE__, line)( GetLastError() == ERROR_BAD_EXE_FORMAT, "wrong error %lu\n", GetLastError() ); + if (nt_header_template.FileHeader.Machine == IMAGE_FILE_MACHINE_ARM64) + { + wrong_machine = TRUE; + expect_status = STATUS_INVALID_IMAGE_FORMAT; + } } - if (mod) FreeLibrary( mod ); } + else + { + wrong_machine = (nt_header->FileHeader.Machine == get_alt_machine( nt_header_template.FileHeader.Machine )); + + ok( mod != NULL || broken(il_only) || /* <= win7 */ + broken( wrong_machine ), /* win8 */ + "%u: loading failed err %lu\n", line, GetLastError() ); + } + if (mod) FreeLibrary( mod ); + expect_fallback = !mod; } + + /* test fallback to another dll further in the load path */ + + MultiByteToWideChar( CP_ACP, 0, dll_name, -1, path, MAX_PATH ); + CopyFileW( path, load_test_name, FALSE ); + pRtlInitUnicodeString( &name, wldr_nameW ); + ldr_status = pLdrLoadDll( load_path, 0, &name, &ldr_mod ); + if (!ldr_status) + { + GetModuleFileNameW( ldr_mod, path, MAX_PATH ); + if (!lstrcmpiW( path, load_test_name )) + { + if (!expect_status) + ok( !expect_fallback, "%u: got test dll but expected fallback\n", line ); + else + ok( !expect_fallback, "%u: got test dll but expected failure %lx\n", line, expect_status ); + } + else if (!lstrcmpiW( path, load_fallback_name )) + { + trace( "%u: loaded fallback\n", line ); +#ifdef __REACTOS__ + ok( !expect_status || broken(is_win64) /* Broken on Vista, 8.1 x64 */, "%u: got fallback but expected failure %lx\n", line, expect_status ); + ok( expect_fallback || broken(is_win64) /* Broken on Vista, 8.1 x64 */ || +#else + ok( !expect_status, "%u: got fallback but expected failure %lx\n", line, expect_status ); + ok( expect_fallback || +#endif + /* win10 also falls back for 32-bit dll without code, even though it could be loaded */ + (is_win64 && !has_code && + nt_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC), + "%u: got fallback but expected test dll\n", line ); + } + else ok( 0, "%u: got unexpected path %s instead of %s\n", line, wine_dbgstr_w(path), wine_dbgstr_w(load_test_name)); + pLdrUnloadDll( ldr_mod ); + } + else if (ldr_status == STATUS_DLL_INIT_FAILED || + ldr_status == STATUS_ACCESS_VIOLATION || + ldr_status == STATUS_ILLEGAL_INSTRUCTION) + { + /* some dlls with invalid entry point will crash, but this means we loaded the test dll */ +#ifdef __REACTOS__ + ok( !expect_fallback || broken(is_win64 && GetNTVersion() == _WIN32_WINNT_WIN8) /* Broken on 8.1 x64 */, "%u: got test dll but expected fallback\n", line ); +#else + ok( !expect_fallback, "%u: got test dll but expected fallback\n", line ); +#endif + } + else + { + ok( ldr_status == expect_status || + (wrong_machine && !expect_status && ldr_status == STATUS_INVALID_IMAGE_FORMAT) || + broken(il_only && !expect_status && ldr_status == STATUS_INVALID_IMAGE_FORMAT) || + broken(nt_header->Signature == IMAGE_OS2_SIGNATURE && ldr_status == STATUS_INVALID_IMAGE_NE_FORMAT), + "%u: wrong status %lx/%lx\n", line, ldr_status, expect_status ); + ok( !expect_fallback || wrong_machine || broken(il_only), + "%u: failed with %lx expected fallback\n", line, ldr_status ); + } + +done: if (map) CloseHandle( map ); CloseHandle( file ); DeleteFileA( dll_name ); @@ -597,7 +795,7 @@ static void test_Loader(void) 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x200, sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x200, sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER), - { ERROR_SUCCESS, ERROR_INVALID_ADDRESS } /* vista is more strict */ + { ERROR_SUCCESS, ERROR_INVALID_ADDRESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */ }, { sizeof(dos_header), 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x1000, @@ -688,7 +886,10 @@ static void test_Loader(void) 0, { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */ }, - /* Minimal PE image that Windows7 is able to load: 268 bytes */ + /* Minimal PE image initially created for Windows 7 and accepted from + * Vista up to Windows 10 1709 with some unexplained exceptions: + * 268 bytes + */ { 0x04, 0, 0xf0, /* optional header size just forces 0xf0 bytes to be written, 0 or another number don't change the behaviour, what really @@ -696,15 +897,15 @@ static void test_Loader(void) 0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04, 0x40, /* minimal image size that Windows7 accepts */ 0, - { ERROR_SUCCESS } + { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* rejected by win10 1809+ */ }, /* the following data mimics the PE image which 8k demos have */ { 0x04, 0, 0x08, 0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04, - 0x200000, + 0x2000, 0x40, - { ERROR_SUCCESS } + { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } } }; int i; @@ -715,15 +916,16 @@ static void test_Loader(void) SIZE_T size; BOOL ret; NTSTATUS status; - WORD alt_machine, orig_machine = nt_header_template.FileHeader.Machine; + WORD orig_machine = nt_header_template.FileHeader.Machine; IMAGE_NT_HEADERS nt_header; IMAGE_COR20_HEADER cor_header; /* prevent displaying of the "Unable to load this DLL" message box */ SetErrorMode(SEM_FAILCRITICALERRORS); - for (i = 0; i < sizeof(td)/sizeof(td[0]); i++) + for (i = 0; i < ARRAY_SIZE(td); i++) { + winetest_push_context("%d", i); nt_header = nt_header_template; nt_header.FileHeader.NumberOfSections = td[i].number_of_sections; nt_header.FileHeader.SizeOfOptionalHeader = td[i].size_of_optional_header; @@ -733,6 +935,7 @@ static void test_Loader(void) nt_header.OptionalHeader.SizeOfImage = td[i].size_of_image; nt_header.OptionalHeader.SizeOfHeaders = td[i].size_of_headers; + section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; file_size = create_test_dll( &dos_header, td[i].size_of_dos_header, &nt_header, dll_name ); SetLastError(0xdeadbeef); @@ -742,56 +945,55 @@ static void test_Loader(void) MEMORY_BASIC_INFORMATION info; void *ptr; - ok( td[i].errors[0] == ERROR_SUCCESS, "%d: should have failed\n", i ); + ok( td[i].errors[0] == ERROR_SUCCESS, "should have failed\n" ); SetLastError(0xdeadbeef); size = VirtualQuery(hlib, &info, sizeof(info)); ok(size == sizeof(info), - "%d: VirtualQuery error %d\n", i, GetLastError()); - ok(info.BaseAddress == hlib, "%d: %p != %p\n", i, info.BaseAddress, hlib); - ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib); - ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect); - ok(info.RegionSize == ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "%d: got %lx != expected %x\n", - i, info.RegionSize, ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size)); - ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State); + "%d: VirtualQuery error %ld\n", i, GetLastError()); + ok(info.BaseAddress == hlib, "%p != %p\n", info.BaseAddress, hlib); + ok(info.AllocationBase == hlib, "%p != %p\n", info.AllocationBase, hlib); + ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%lx != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect); + ok(info.RegionSize == ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "got %Ix != expected %x\n", + info.RegionSize, (UINT)ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size)); + ok(info.State == MEM_COMMIT, "%lx != MEM_COMMIT\n", info.State); if (nt_header.OptionalHeader.SectionAlignment < page_size) - ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect); + ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%lx != PAGE_EXECUTE_WRITECOPY\n", info.Protect); else - ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect); - ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type); + ok(info.Protect == PAGE_READONLY, "%lx != PAGE_READONLY\n", info.Protect); + ok(info.Type == SEC_IMAGE, "%lx != SEC_IMAGE\n", info.Type); SetLastError(0xdeadbeef); ptr = VirtualAlloc(hlib, page_size, MEM_COMMIT, info.Protect); - ok(!ptr, "%d: VirtualAlloc should fail\n", i); - ok(GetLastError() == ERROR_ACCESS_DENIED, "%d: expected ERROR_ACCESS_DENIED, got %d\n", i, GetLastError()); + ok(!ptr, "VirtualAlloc should fail\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); size = VirtualQuery((char *)hlib + info.RegionSize, &info, sizeof(info)); - ok(size == sizeof(info), - "%d: VirtualQuery error %d\n", i, GetLastError()); + ok(size == sizeof(info), "VirtualQuery error %ld\n", GetLastError()); if (nt_header.OptionalHeader.SectionAlignment == page_size || nt_header.OptionalHeader.SectionAlignment == nt_header.OptionalHeader.FileAlignment) { - ok(info.BaseAddress == (char *)hlib + ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "%d: got %p != expected %p\n", - i, info.BaseAddress, (char *)hlib + ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size)); - ok(info.AllocationBase == 0, "%d: %p != 0\n", i, info.AllocationBase); - ok(info.AllocationProtect == 0, "%d: %x != 0\n", i, info.AllocationProtect); + ok(info.BaseAddress == (char *)hlib + ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "got %p != expected %p\n", + info.BaseAddress, (char *)hlib + ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size)); + ok(info.AllocationBase == 0, "%p != 0\n", info.AllocationBase); + ok(info.AllocationProtect == 0, "%lx != 0\n", info.AllocationProtect); /*ok(info.RegionSize == not_practical_value, "%d: %lx != not_practical_value\n", i, info.RegionSize);*/ - ok(info.State == MEM_FREE, "%d: %x != MEM_FREE\n", i, info.State); - ok(info.Type == 0, "%d: %x != 0\n", i, info.Type); - ok(info.Protect == PAGE_NOACCESS, "%d: %x != PAGE_NOACCESS\n", i, info.Protect); + ok(info.State == MEM_FREE, "%lx != MEM_FREE\n", info.State); + ok(info.Type == 0, "%lx != 0\n", info.Type); + ok(info.Protect == PAGE_NOACCESS, "%lx != PAGE_NOACCESS\n", info.Protect); } else { - ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect); - ok(info.BaseAddress == hlib, "%d: got %p != expected %p\n", i, info.BaseAddress, hlib); - ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib); - ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect); - ok(info.RegionSize == ALIGN_SIZE(file_size, page_size), "%d: got %lx != expected %x\n", - i, info.RegionSize, ALIGN_SIZE(file_size, page_size)); - ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State); - ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect); - ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type); + ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%lx != PAGE_EXECUTE_WRITECOPY\n", info.Protect); + ok(info.BaseAddress == hlib, "got %p != expected %p\n", info.BaseAddress, hlib); + ok(info.AllocationBase == hlib, "%p != %p\n", info.AllocationBase, hlib); + ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%lx != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect); + ok(info.RegionSize == ALIGN_SIZE(file_size, page_size), "got %Ix != expected %x\n", + info.RegionSize, (UINT)ALIGN_SIZE(file_size, page_size)); + ok(info.State == MEM_COMMIT, "%lx != MEM_COMMIT\n", info.State); + ok(info.Protect == PAGE_READONLY, "%lx != PAGE_READONLY\n", info.Protect); + ok(info.Type == SEC_IMAGE, "%lx != SEC_IMAGE\n", info.Type); } /* header: check the zeroing of alignment */ @@ -801,7 +1003,7 @@ static void test_Loader(void) start = (const char *)hlib + nt_header.OptionalHeader.SizeOfHeaders; size = ALIGN_SIZE((ULONG_PTR)start, page_size) - (ULONG_PTR)start; - ok(!memcmp(start, filler, size), "%d: header alignment is not cleared\n", i); + ok(!memcmp(start, filler, size), "header alignment is not cleared\n"); } if (nt_header.FileHeader.NumberOfSections) @@ -809,25 +1011,25 @@ static void test_Loader(void) SetLastError(0xdeadbeef); size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info)); ok(size == sizeof(info), - "%d: VirtualQuery error %d\n", i, GetLastError()); + "VirtualQuery error %ld\n", GetLastError()); if (nt_header.OptionalHeader.SectionAlignment < page_size) { - ok(info.BaseAddress == hlib, "%d: got %p != expected %p\n", i, info.BaseAddress, hlib); - ok(info.RegionSize == ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "%d: got %lx != expected %x\n", - i, info.RegionSize, ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size)); - ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect); + ok(info.BaseAddress == hlib, "got %p != expected %p\n", info.BaseAddress, hlib); + ok(info.RegionSize == ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "got %Ix != expected %x\n", + info.RegionSize, (UINT)ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size)); + ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%lx != PAGE_EXECUTE_WRITECOPY\n", info.Protect); } else { - ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress); - ok(info.RegionSize == ALIGN_SIZE(section.Misc.VirtualSize, page_size), "%d: got %lx != expected %x\n", - i, info.RegionSize, ALIGN_SIZE(section.Misc.VirtualSize, page_size)); - ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect); + ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)hlib + section.VirtualAddress); + ok(info.RegionSize == ALIGN_SIZE(section.Misc.VirtualSize, page_size), "got %Ix != expected %x\n", + info.RegionSize, (UINT)ALIGN_SIZE(section.Misc.VirtualSize, page_size)); + ok(info.Protect == PAGE_READONLY, "%lx != PAGE_READONLY\n", info.Protect); } - ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib); - ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect); - ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State); - ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type); + ok(info.AllocationBase == hlib, "%p != %p\n", info.AllocationBase, hlib); + ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%lx != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect); + ok(info.State == MEM_COMMIT, "%lx != MEM_COMMIT\n", info.State); + ok(info.Type == SEC_IMAGE, "%lx != SEC_IMAGE\n", info.Type); if (nt_header.OptionalHeader.SectionAlignment >= page_size) ok(!memcmp((const char *)hlib + section.VirtualAddress + section.PointerToRawData, &nt_header, section.SizeOfRawData), "wrong section data\n"); @@ -841,39 +1043,39 @@ static void test_Loader(void) start = (const char *)hlib + section.VirtualAddress + section.PointerToRawData + section.SizeOfRawData; size = ALIGN_SIZE((ULONG_PTR)start, page_size) - (ULONG_PTR)start; - ok(memcmp(start, filler, size), "%d: alignment should not be cleared\n", i); + ok(memcmp(start, filler, size), "alignment should not be cleared\n"); } SetLastError(0xdeadbeef); ptr = VirtualAlloc((char *)hlib + section.VirtualAddress, page_size, MEM_COMMIT, info.Protect); - ok(!ptr, "%d: VirtualAlloc should fail\n", i); + ok(!ptr, "VirtualAlloc should fail\n"); ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == ERROR_INVALID_ADDRESS, - "%d: expected ERROR_ACCESS_DENIED, got %d\n", i, GetLastError()); + "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError()); } SetLastError(0xdeadbeef); hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE); - ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError()); + ok(hlib_as_data_file != 0, "LoadLibraryEx error %lu\n", GetLastError()); ok(hlib_as_data_file == hlib, "hlib_as_file and hlib are different\n"); SetLastError(0xdeadbeef); ret = FreeLibrary(hlib); - ok(ret, "FreeLibrary error %d\n", GetLastError()); + ok(ret, "FreeLibrary error %ld\n", GetLastError()); SetLastError(0xdeadbeef); hlib = GetModuleHandleA(dll_name); - ok(hlib != 0, "GetModuleHandle error %u\n", GetLastError()); + ok(hlib != 0, "GetModuleHandle error %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = FreeLibrary(hlib_as_data_file); - ok(ret, "FreeLibrary error %d\n", GetLastError()); + ok(ret, "FreeLibrary error %ld\n", GetLastError()); hlib = GetModuleHandleA(dll_name); ok(!hlib, "GetModuleHandle should fail\n"); SetLastError(0xdeadbeef); hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE); - ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError()); + ok(hlib_as_data_file != 0, "LoadLibraryEx error %lu\n", GetLastError()); ok(((ULONG_PTR)hlib_as_data_file & 3) == 1, "hlib_as_data_file got %p\n", hlib_as_data_file); hlib = GetModuleHandleA(dll_name); @@ -881,72 +1083,73 @@ static void test_Loader(void) SetLastError(0xdeadbeef); h = CreateFileA( dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); - ok( h != INVALID_HANDLE_VALUE, "open failed err %u\n", GetLastError() ); + ok( h != INVALID_HANDLE_VALUE, "open failed err %lu\n", GetLastError() ); CloseHandle( h ); SetLastError(0xdeadbeef); ret = FreeLibrary(hlib_as_data_file); - ok(ret, "FreeLibrary error %d\n", GetLastError()); + ok(ret, "FreeLibrary error %ld\n", GetLastError()); SetLastError(0xdeadbeef); hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE); - if (!((ULONG_PTR)hlib_as_data_file & 3) || /* winxp */ - (!hlib_as_data_file && GetLastError() == ERROR_INVALID_PARAMETER)) /* w2k3 */ - { - win_skip( "LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE not supported\n" ); +#ifdef __REACTOS__ + if (!hlib_as_data_file && GetLastError() == ERROR_INVALID_PARAMETER) { + skip("LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE not supported\n"); FreeLibrary(hlib_as_data_file); + } else { +#endif + ok(hlib_as_data_file != 0, "LoadLibraryEx error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + h = CreateFileA( dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); + ok( h == INVALID_HANDLE_VALUE, "open succeeded\n" ); + ok( GetLastError() == ERROR_SHARING_VIOLATION, "wrong error %lu\n", GetLastError() ); + CloseHandle( h ); + + SetLastError(0xdeadbeef); + h = CreateFileA( dll_name, GENERIC_READ | DELETE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); + ok( h != INVALID_HANDLE_VALUE, "open failed err %lu\n", GetLastError() ); + CloseHandle( h ); + + SetLastError(0xdeadbeef); + ret = FreeLibrary(hlib_as_data_file); + ok(ret, "FreeLibrary error %ld\n", GetLastError()); +#ifdef __REACTOS__ } - else - { - ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError()); - - SetLastError(0xdeadbeef); - h = CreateFileA( dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); - ok( h == INVALID_HANDLE_VALUE, "open succeeded\n" ); - ok( GetLastError() == ERROR_SHARING_VIOLATION, "wrong error %u\n", GetLastError() ); - CloseHandle( h ); - - SetLastError(0xdeadbeef); - h = CreateFileA( dll_name, GENERIC_READ | DELETE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); - ok( h != INVALID_HANDLE_VALUE, "open failed err %u\n", GetLastError() ); - CloseHandle( h ); - - SetLastError(0xdeadbeef); - ret = FreeLibrary(hlib_as_data_file); - ok(ret, "FreeLibrary error %d\n", GetLastError()); - } +#endif SetLastError(0xdeadbeef); hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_IMAGE_RESOURCE); - if (!((ULONG_PTR)hlib_as_data_file & 3) || /* winxp */ - (!hlib_as_data_file && GetLastError() == ERROR_INVALID_PARAMETER)) /* w2k3 */ - { - win_skip( "LOAD_LIBRARY_AS_IMAGE_RESOURCE not supported\n" ); +#ifdef __REACTOS__ + if (!hlib_as_data_file && GetLastError() == ERROR_INVALID_PARAMETER) { + skip("LOAD_LIBRARY_AS_IMAGE_RESOURCE not supported\n"); FreeLibrary(hlib_as_data_file); - } - else - { - ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError()); - ok(((ULONG_PTR)hlib_as_data_file & 3) == 2, "hlib_as_data_file got %p\n", - hlib_as_data_file); + } else { +#endif + ok(hlib_as_data_file != 0, "LoadLibraryEx error %lu\n", GetLastError()); + ok(((ULONG_PTR)hlib_as_data_file & 3) == 2, "hlib_as_data_file got %p\n", + hlib_as_data_file); - hlib = GetModuleHandleA(dll_name); - ok(!hlib, "GetModuleHandle should fail\n"); + hlib = GetModuleHandleA(dll_name); + ok(!hlib, "GetModuleHandle should fail\n"); - SetLastError(0xdeadbeef); - ret = FreeLibrary(hlib_as_data_file); - ok(ret, "FreeLibrary error %d\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = FreeLibrary(hlib_as_data_file); + ok(ret, "FreeLibrary error %ld\n", GetLastError()); +#ifdef __REACTOS__ } +#endif SetLastError(0xdeadbeef); ret = DeleteFileA(dll_name); - ok(ret, "DeleteFile error %d\n", GetLastError()); + ok(ret, "DeleteFile error %ld\n", GetLastError()); nt_header.OptionalHeader.AddressOfEntryPoint = 0x12345678; file_size = create_test_dll( &dos_header, td[i].size_of_dos_header, &nt_header, dll_name ); if (!file_size) { ok(0, "could not create %s\n", dll_name); + winetest_pop_context(); break; } @@ -959,17 +1162,18 @@ static void test_Loader(void) error_match = FALSE; for (error_index = 0; - ! error_match && error_index < sizeof(td[i].errors) / sizeof(DWORD); + ! error_match && error_index < ARRAY_SIZE(td[i].errors); error_index++) { error_match = td[i].errors[error_index] == GetLastError(); } - ok(error_match, "%d: unexpected error %d\n", i, GetLastError()); + ok(error_match, "unexpected error %ld\n", GetLastError()); } SetLastError(0xdeadbeef); ret = DeleteFileA(dll_name); - ok(ret, "DeleteFile error %d\n", GetLastError()); + ok(ret, "DeleteFile error %ld\n", GetLastError()); + winetest_pop_context(); } nt_header = nt_header_template; @@ -977,7 +1181,6 @@ static void test_Loader(void) nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER); nt_header.OptionalHeader.SectionAlignment = page_size; - nt_header.OptionalHeader.AddressOfEntryPoint = 0x1234; nt_header.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT; nt_header.OptionalHeader.FileAlignment = page_size; nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER); @@ -988,71 +1191,80 @@ static void test_Loader(void) section.VirtualAddress = page_size; section.Misc.VirtualSize = page_size; + create_test_dll_sections( &dos_header, &nt_header, §ion, section_data, dll_name ); + init_load_path( dll_name ); + + nt_header.OptionalHeader.AddressOfEntryPoint = 0x1234; status = map_image_section( &nt_header, §ion, section_data, __LINE__ ); - ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status ); + ok( status == (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_ARM64 ? STATUS_INVALID_IMAGE_FORMAT : STATUS_SUCCESS), + "NtCreateSection error %08lx\n", status ); nt_header.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE; status = map_image_section( &nt_header, §ion, section_data, __LINE__ ); - ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status ); + ok( status == (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_ARM64 ? STATUS_INVALID_IMAGE_FORMAT : STATUS_SUCCESS), + "NtCreateSection error %08lx\n", status ); nt_header.OptionalHeader.SizeOfCode = 0x1000; status = map_image_section( &nt_header, §ion, section_data, __LINE__ ); - ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status ); + ok( status == (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_ARM64 ? STATUS_INVALID_IMAGE_FORMAT : STATUS_SUCCESS), + "NtCreateSection error %08lx\n", status ); + nt_header.OptionalHeader.SizeOfCode = 0; - nt_header.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT; + nt_header.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE; dos_header.e_magic = 0; status = map_image_section( &nt_header, §ion, section_data, __LINE__ ); - ok( status == STATUS_INVALID_IMAGE_NOT_MZ, "NtCreateSection error %08x\n", status ); + ok( status == STATUS_INVALID_IMAGE_NOT_MZ, "NtCreateSection error %08lx\n", status ); dos_header.e_magic = IMAGE_DOS_SIGNATURE; nt_header.Signature = IMAGE_OS2_SIGNATURE; status = map_image_section( &nt_header, §ion, section_data, __LINE__ ); - ok( status == STATUS_INVALID_IMAGE_NE_FORMAT, "NtCreateSection error %08x\n", status ); + ok( status == STATUS_INVALID_IMAGE_NE_FORMAT, "NtCreateSection error %08lx\n", status ); + for (i = 0; i < 16; i++) + { + ((IMAGE_OS2_HEADER *)&nt_header)->ne_exetyp = i; + status = map_image_section( &nt_header, §ion, section_data, __LINE__ ); + switch (i) + { + case 2: + ok( status == STATUS_INVALID_IMAGE_WIN_16, "NtCreateSection %u error %08lx\n", i, status ); + break; + case 5: + ok( status == STATUS_INVALID_IMAGE_PROTECT, "NtCreateSection %u error %08lx\n", i, status ); + break; + default: + ok( status == STATUS_INVALID_IMAGE_NE_FORMAT, "NtCreateSection %u error %08lx\n", i, status ); + break; + } + } + ((IMAGE_OS2_HEADER *)&nt_header)->ne_exetyp = ((IMAGE_OS2_HEADER *)&nt_header_template)->ne_exetyp; + dos_header.e_lfanew = 0x98760000; + status = map_image_section( &nt_header, §ion, section_data, __LINE__ ); + ok( status == STATUS_INVALID_IMAGE_PROTECT, "NtCreateSection error %08lx\n", status ); + + dos_header.e_lfanew = sizeof(dos_header); nt_header.Signature = 0xdeadbeef; status = map_image_section( &nt_header, §ion, section_data, __LINE__ ); - ok( status == STATUS_INVALID_IMAGE_PROTECT, "NtCreateSection error %08x\n", status ); + ok( status == STATUS_INVALID_IMAGE_PROTECT, "NtCreateSection error %08lx\n", status ); nt_header.Signature = IMAGE_NT_SIGNATURE; nt_header.OptionalHeader.Magic = 0xdead; status = map_image_section( &nt_header, §ion, section_data, __LINE__ ); - ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08x\n", status ); + ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08lx\n", status ); nt_header.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR_MAGIC; nt_header.FileHeader.Machine = 0xdead; status = map_image_section( &nt_header, §ion, section_data, __LINE__ ); - ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(status == STATUS_SUCCESS), /* win2k */ - "NtCreateSection error %08x\n", status ); + ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08lx\n", status ); nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_UNKNOWN; status = map_image_section( &nt_header, §ion, section_data, __LINE__ ); - ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(status == STATUS_SUCCESS), /* win2k */ - "NtCreateSection error %08x\n", status ); + ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08lx\n", status ); - switch (orig_machine) - { - case IMAGE_FILE_MACHINE_I386: alt_machine = IMAGE_FILE_MACHINE_ARMNT; break; - case IMAGE_FILE_MACHINE_AMD64: alt_machine = IMAGE_FILE_MACHINE_ARM64; break; - case IMAGE_FILE_MACHINE_ARMNT: alt_machine = IMAGE_FILE_MACHINE_I386; break; - case IMAGE_FILE_MACHINE_ARM64: alt_machine = IMAGE_FILE_MACHINE_AMD64; break; - } - nt_header.FileHeader.Machine = alt_machine; + nt_header.FileHeader.Machine = get_alt_bitness_machine( orig_machine ); status = map_image_section( &nt_header, §ion, section_data, __LINE__ ); - ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(status == STATUS_SUCCESS), /* win2k */ - "NtCreateSection error %08x\n", status ); - - switch (orig_machine) - { - case IMAGE_FILE_MACHINE_I386: alt_machine = IMAGE_FILE_MACHINE_AMD64; break; - case IMAGE_FILE_MACHINE_AMD64: alt_machine = IMAGE_FILE_MACHINE_I386; break; - case IMAGE_FILE_MACHINE_ARMNT: alt_machine = IMAGE_FILE_MACHINE_ARM64; break; - case IMAGE_FILE_MACHINE_ARM64: alt_machine = IMAGE_FILE_MACHINE_ARMNT; break; - } - nt_header.FileHeader.Machine = alt_machine; - status = map_image_section( &nt_header, §ion, section_data, __LINE__ ); - ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(status == STATUS_SUCCESS), /* win2k */ - "NtCreateSection error %08x\n", status ); + ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08lx\n", status ); nt_header.FileHeader.Machine = orig_machine; nt_header.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES; @@ -1065,35 +1277,35 @@ static void test_Loader(void) cor_header.MajorRuntimeVersion = 2; cor_header.MinorRuntimeVersion = 4; cor_header.Flags = COMIMAGE_FLAGS_ILONLY; - U(cor_header).EntryPointToken = 0xbeef; + cor_header.EntryPointToken = 0xbeef; status = map_image_section( &nt_header, §ion, &cor_header, __LINE__ ); - ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status ); + ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status ); cor_header.MinorRuntimeVersion = 5; status = map_image_section( &nt_header, §ion, &cor_header, __LINE__ ); - ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status ); + ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status ); cor_header.MajorRuntimeVersion = 3; cor_header.MinorRuntimeVersion = 0; status = map_image_section( &nt_header, §ion, &cor_header, __LINE__ ); - ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status ); + ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status ); cor_header.Flags = COMIMAGE_FLAGS_ILONLY | COMIMAGE_FLAGS_32BITREQUIRED; status = map_image_section( &nt_header, §ion, &cor_header, __LINE__ ); - ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status ); + ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status ); cor_header.Flags = COMIMAGE_FLAGS_ILONLY | COMIMAGE_FLAGS_32BITPREFERRED; status = map_image_section( &nt_header, §ion, &cor_header, __LINE__ ); - ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status ); + ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status ); cor_header.Flags = 0; status = map_image_section( &nt_header, §ion, &cor_header, __LINE__ ); - ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status ); + ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status ); nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = 1; nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = 1; status = map_image_section( &nt_header, §ion, &cor_header, __LINE__ ); - ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status ); + ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status ); if (nt_header.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { @@ -1124,7 +1336,7 @@ static void test_Loader(void) status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, section_data, __LINE__ ); ok( status == (is_wow64 ? STATUS_INVALID_IMAGE_FORMAT : STATUS_INVALID_IMAGE_WIN_64), - "NtCreateSection error %08x\n", status ); + "NtCreateSection error %08lx\n", status ); switch (orig_machine) { @@ -1133,26 +1345,26 @@ static void test_Loader(void) } status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, section_data, __LINE__ ); ok( status == (is_wow64 ? STATUS_INVALID_IMAGE_FORMAT : STATUS_INVALID_IMAGE_WIN_64), - "NtCreateSection error %08x\n", status ); + "NtCreateSection error %08lx\n", status ); - nt64.FileHeader.Machine = alt_machine; + nt64.FileHeader.Machine = get_alt_bitness_machine( orig_machine ); status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, section_data, __LINE__ ); ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64), - "NtCreateSection error %08x\n", status ); + "NtCreateSection error %08lx\n", status ); nt64.OptionalHeader.SizeOfCode = 0; nt64.OptionalHeader.AddressOfEntryPoint = 0x1000; section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE; status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, section_data, __LINE__ ); ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64), - "NtCreateSection error %08x\n", status ); + "NtCreateSection error %08lx\n", status ); nt64.OptionalHeader.SizeOfCode = 0; nt64.OptionalHeader.AddressOfEntryPoint = 0; section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE; status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, section_data, __LINE__ ); ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64), - "NtCreateSection error %08x\n", status ); + "NtCreateSection error %08lx\n", status ); nt64.OptionalHeader.SizeOfCode = 0x1000; nt64.OptionalHeader.AddressOfEntryPoint = 0; @@ -1160,14 +1372,14 @@ static void test_Loader(void) section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE; status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, section_data, __LINE__ ); ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64), - "NtCreateSection error %08x\n", status ); + "NtCreateSection error %08lx\n", status ); nt64.OptionalHeader.SizeOfCode = 0; nt64.OptionalHeader.AddressOfEntryPoint = 0; section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE; status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, section_data, __LINE__ ); ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64), - "NtCreateSection error %08x\n", status ); + "NtCreateSection error %08lx\n", status ); nt64.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES; nt64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = page_size; @@ -1177,40 +1389,48 @@ static void test_Loader(void) cor_header.Flags = COMIMAGE_FLAGS_ILONLY; status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, &cor_header, __LINE__ ); ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64), - "NtCreateSection error %08x\n", status ); + "NtCreateSection error %08lx\n", status ); nt64.OptionalHeader.SizeOfCode = 0x1000; status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, &cor_header, __LINE__ ); ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64), - "NtCreateSection error %08x\n", status ); + "NtCreateSection error %08lx\n", status ); cor_header.MinorRuntimeVersion = 5; status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, &cor_header, __LINE__ ); ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64), - "NtCreateSection error %08x\n", status ); + "NtCreateSection error %08lx\n", status ); cor_header.Flags = COMIMAGE_FLAGS_ILONLY | COMIMAGE_FLAGS_32BITREQUIRED; status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, &cor_header, __LINE__ ); ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64), - "NtCreateSection error %08x\n", status ); + "NtCreateSection error %08lx\n", status ); cor_header.Flags = COMIMAGE_FLAGS_ILONLY | COMIMAGE_FLAGS_32BITPREFERRED; status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, &cor_header, __LINE__ ); ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64), - "NtCreateSection error %08x\n", status ); + "NtCreateSection error %08lx\n", status ); cor_header.Flags = 0; status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, &cor_header, __LINE__ ); ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64), - "NtCreateSection error %08x\n", status ); + "NtCreateSection error %08lx\n", status ); nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = 1; nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = 1; status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, &cor_header, __LINE__ ); ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64), - "NtCreateSection error %08x\n", status ); + "NtCreateSection error %08lx\n", status ); + } +#ifdef __REACTOS__ + else if (is_reactos() && orig_machine == IMAGE_FILE_MACHINE_AMD64) + { + ok(FALSE, "FIXME: These tests crash on ReactOS x64!\n"); } else +#else + else +#endif { IMAGE_NT_HEADERS32 nt32; @@ -1238,45 +1458,44 @@ static void test_Loader(void) section.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE; status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, section_data, __LINE__ ); - ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08x\n", status ); + ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08lx\n", status ); - switch (orig_machine) + if (orig_machine == IMAGE_FILE_MACHINE_AMD64) { - case IMAGE_FILE_MACHINE_AMD64: nt32.FileHeader.Machine = IMAGE_FILE_MACHINE_ARMNT; break; - case IMAGE_FILE_MACHINE_ARM64: nt32.FileHeader.Machine = IMAGE_FILE_MACHINE_I386; break; + nt32.FileHeader.Machine = IMAGE_FILE_MACHINE_ARMNT; + status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, section_data, __LINE__ ); + ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(!status) /* win8 */, + "NtCreateSection error %08lx\n", status ); } - status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, section_data, __LINE__ ); - ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(!status) /* win8 */, - "NtCreateSection error %08x\n", status ); - nt32.FileHeader.Machine = alt_machine; + nt32.FileHeader.Machine = IMAGE_FILE_MACHINE_I386; status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, section_data, __LINE__ ); - ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status ); + ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status ); nt32.OptionalHeader.SizeOfCode = 0; nt32.OptionalHeader.AddressOfEntryPoint = 0x1000; section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE; status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, section_data, __LINE__ ); - ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status ); + ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status ); nt32.OptionalHeader.SizeOfCode = 0; nt32.OptionalHeader.AddressOfEntryPoint = 0; section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE; status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, section_data, __LINE__ ); - ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status ); + ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status ); nt32.OptionalHeader.SizeOfCode = 0x1000; nt32.OptionalHeader.AddressOfEntryPoint = 0; nt32.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE; section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE; status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, section_data, __LINE__ ); - ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status ); + ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status ); nt32.OptionalHeader.SizeOfCode = 0; nt32.OptionalHeader.AddressOfEntryPoint = 0; section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE; status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, section_data, __LINE__ ); - ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status ); + ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status ); nt32.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES; nt32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = page_size; @@ -1285,35 +1504,36 @@ static void test_Loader(void) cor_header.MinorRuntimeVersion = 4; cor_header.Flags = COMIMAGE_FLAGS_ILONLY; status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, &cor_header, __LINE__ ); - ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status ); + ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status ); nt32.OptionalHeader.SizeOfCode = 0x1000; status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, &cor_header, __LINE__ ); - ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status ); + ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status ); cor_header.MinorRuntimeVersion = 5; status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, &cor_header, __LINE__ ); - ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status ); + ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status ); cor_header.Flags = COMIMAGE_FLAGS_ILONLY | COMIMAGE_FLAGS_32BITREQUIRED; status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, &cor_header, __LINE__ ); - ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status ); + ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status ); cor_header.Flags = COMIMAGE_FLAGS_ILONLY | COMIMAGE_FLAGS_32BITPREFERRED; status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, &cor_header, __LINE__ ); - ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status ); + ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status ); cor_header.Flags = 0; status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, &cor_header, __LINE__ ); - ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status ); + ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status ); nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = 1; nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = 1; status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, &cor_header, __LINE__ ); - ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status ); + ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status ); } section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; + delete_load_path(); } static void test_filenames(void) @@ -1327,7 +1547,7 @@ static void test_filenames(void) nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER); nt_header.OptionalHeader.SectionAlignment = page_size; - nt_header.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT; + nt_header.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE; nt_header.OptionalHeader.FileAlignment = page_size; nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER); nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + page_size; @@ -1336,11 +1556,11 @@ static void test_filenames(void) strcpy( long_path, dll_name ); strcpy( strrchr( long_path, '\\' ), "\\this-is-a-long-name.dll" ); ret = MoveFileA( dll_name, long_path ); - ok( ret, "MoveFileA failed err %u\n", GetLastError() ); + ok( ret, "MoveFileA failed err %lu\n", GetLastError() ); GetShortPathNameA( long_path, short_path, MAX_PATH ); mod = LoadLibraryA( short_path ); - ok( mod != NULL, "loading failed err %u\n", GetLastError() ); + ok( mod != NULL, "loading failed err %lu\n", GetLastError() ); GetModuleFileNameA( mod, buffer, MAX_PATH ); ok( !lstrcmpiA( buffer, short_path ), "got wrong path %s / %s\n", buffer, short_path ); mod2 = GetModuleHandleA( short_path ); @@ -1348,7 +1568,7 @@ static void test_filenames(void) mod2 = GetModuleHandleA( long_path ); ok( mod == mod2, "wrong module %p for %s\n", mod2, long_path ); mod2 = LoadLibraryA( long_path ); - ok( mod2 != NULL, "loading failed err %u\n", GetLastError() ); + ok( mod2 != NULL, "loading failed err %lu\n", GetLastError() ); ok( mod == mod2, "library loaded twice\n" ); GetModuleFileNameA( mod2, buffer, MAX_PATH ); ok( !lstrcmpiA( buffer, short_path ), "got wrong path %s / %s\n", buffer, short_path ); @@ -1356,7 +1576,7 @@ static void test_filenames(void) FreeLibrary( mod ); mod = LoadLibraryA( long_path ); - ok( mod != NULL, "loading failed err %u\n", GetLastError() ); + ok( mod != NULL, "loading failed err %lu\n", GetLastError() ); GetModuleFileNameA( mod, buffer, MAX_PATH ); ok( !lstrcmpiA( buffer, long_path ), "got wrong path %s / %s\n", buffer, long_path ); mod2 = GetModuleHandleA( short_path ); @@ -1364,7 +1584,7 @@ static void test_filenames(void) mod2 = GetModuleHandleA( long_path ); ok( mod == mod2, "wrong module %p for %s\n", mod2, long_path ); mod2 = LoadLibraryA( short_path ); - ok( mod2 != NULL, "loading failed err %u\n", GetLastError() ); + ok( mod2 != NULL, "loading failed err %lu\n", GetLastError() ); ok( mod == mod2, "library loaded twice\n" ); GetModuleFileNameA( mod2, buffer, MAX_PATH ); ok( !lstrcmpiA( buffer, long_path ), "got wrong path %s / %s\n", buffer, long_path ); @@ -1374,17 +1594,17 @@ static void test_filenames(void) strcpy( dll_name, long_path ); strcpy( strrchr( dll_name, '\\' ), "\\this-is-another-name.dll" ); ret = CreateHardLinkA( dll_name, long_path, NULL ); - ok( ret, "CreateHardLinkA failed err %u\n", GetLastError() ); + ok( ret, "CreateHardLinkA failed err %lu\n", GetLastError() ); if (ret) { mod = LoadLibraryA( dll_name ); - ok( mod != NULL, "loading failed err %u\n", GetLastError() ); + ok( mod != NULL, "loading failed err %lu\n", GetLastError() ); GetModuleFileNameA( mod, buffer, MAX_PATH ); ok( !lstrcmpiA( buffer, dll_name ), "got wrong path %s / %s\n", buffer, dll_name ); mod2 = GetModuleHandleA( long_path ); ok( mod == mod2, "wrong module %p for %s\n", mod2, long_path ); mod2 = LoadLibraryA( long_path ); - ok( mod2 != NULL, "loading failed err %u\n", GetLastError() ); + ok( mod2 != NULL, "loading failed err %lu\n", GetLastError() ); ok( mod == mod2, "library loaded twice\n" ); GetModuleFileNameA( mod2, buffer, MAX_PATH ); ok( !lstrcmpiA( buffer, dll_name ), "got wrong path %s / %s\n", buffer, short_path ); @@ -1395,100 +1615,6 @@ static void test_filenames(void) DeleteFileA( long_path ); } -static void test_FakeDLL(void) -{ -#if defined(__i386__) || defined(__x86_64__) - NTSTATUS (WINAPI *pNtSetEvent)(HANDLE, ULONG *) = NULL; - IMAGE_EXPORT_DIRECTORY *dir; - HMODULE module = GetModuleHandleA("ntdll.dll"); - HANDLE file, map, event; - WCHAR path[MAX_PATH]; - DWORD *names, *funcs; - WORD *ordinals; - ULONG size; - void *ptr; - int i; - - GetModuleFileNameW(module, path, MAX_PATH); - - file = CreateFileW(path, GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); - ok(file != INVALID_HANDLE_VALUE, "Failed to open %s (error %u)\n", wine_dbgstr_w(path), GetLastError()); - - map = CreateFileMappingW(file, NULL, PAGE_EXECUTE_READ | SEC_IMAGE, 0, 0, NULL); - ok(map != NULL, "CreateFileMapping failed with error %u\n", GetLastError()); - ptr = MapViewOfFile(map, FILE_MAP_READ | FILE_MAP_EXECUTE, 0, 0, 0); - ok(ptr != NULL, "MapViewOfFile failed with error %u\n", GetLastError()); - - dir = RtlImageDirectoryEntryToData(ptr, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size); - ok(dir != NULL, "RtlImageDirectoryEntryToData failed\n"); - - names = RVAToAddr(dir->AddressOfNames, ptr); - ordinals = RVAToAddr(dir->AddressOfNameOrdinals, ptr); - funcs = RVAToAddr(dir->AddressOfFunctions, ptr); - ok(dir->NumberOfNames > 0, "Could not find any exported functions\n"); - - for (i = 0; i < dir->NumberOfNames; i++) - { - DWORD map_rva, dll_rva, map_offset, dll_offset; - char *func_name = RVAToAddr(names[i], ptr); - BYTE *dll_func, *map_func; - - /* check only Nt functions for now */ - if (strncmp(func_name, "Zw", 2) && strncmp(func_name, "Nt", 2)) - continue; - - dll_func = (BYTE *)GetProcAddress(module, func_name); - ok(dll_func != NULL, "%s: GetProcAddress returned NULL\n", func_name); -#if defined(__i386__) - if (dll_func[0] == 0x90 && dll_func[1] == 0x90 && - dll_func[2] == 0x90 && dll_func[3] == 0x90) -#elif defined(__x86_64__) - if (dll_func[0] == 0x48 && dll_func[1] == 0x83 && - dll_func[2] == 0xec && dll_func[3] == 0x08) -#endif - { - todo_wine ok(0, "%s: Export is a stub-function, skipping\n", func_name); - continue; - } - - /* check position in memory */ - dll_rva = (DWORD_PTR)dll_func - (DWORD_PTR)module; - map_rva = funcs[ordinals[i]]; - ok(map_rva == dll_rva, "%s: Rva of mapped function (0x%x) does not match dll (0x%x)\n", - func_name, dll_rva, map_rva); - - /* check position in file */ - map_offset = (DWORD_PTR)RtlImageRvaToVa(RtlImageNtHeader(ptr), ptr, map_rva, NULL) - (DWORD_PTR)ptr; - dll_offset = (DWORD_PTR)RtlImageRvaToVa(RtlImageNtHeader(module), module, dll_rva, NULL) - (DWORD_PTR)module; - ok(map_offset == dll_offset, "%s: File offset of mapped function (0x%x) does not match dll (0x%x)\n", - func_name, map_offset, dll_offset); - - /* check function content */ - map_func = RVAToAddr(map_rva, ptr); - ok(!memcmp(map_func, dll_func, 0x20), "%s: Function content does not match!\n", func_name); - - if (!strcmp(func_name, "NtSetEvent")) - pNtSetEvent = (void *)map_func; - } - - ok(pNtSetEvent != NULL, "Could not find NtSetEvent export\n"); - if (pNtSetEvent) - { - event = CreateEventA(NULL, TRUE, FALSE, NULL); - ok(event != NULL, "CreateEvent failed with error %u\n", GetLastError()); - pNtSetEvent(event, 0); - ok(WaitForSingleObject(event, 0) == WAIT_OBJECT_0, "Event was not signaled\n"); - pNtSetEvent(event, 0); - ok(WaitForSingleObject(event, 0) == WAIT_OBJECT_0, "Event was not signaled\n"); - CloseHandle(event); - } - - UnmapViewOfFile(ptr); - CloseHandle(map); - CloseHandle(file); -#endif -} - /* Verify linking style of import descriptors */ static void test_ImportDescriptors(void) { @@ -1532,7 +1658,7 @@ static void test_ImportDescriptors(void) { LPCSTR module_name = RVAToAddr(import_chunk->Name, kernel32_module); PIMAGE_THUNK_DATA name_table = RVAToAddr( - U(*import_chunk).OriginalFirstThunk, kernel32_module); + 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"); @@ -1557,11 +1683,11 @@ static void test_image_mapping(const char *dll_name, DWORD scn_page_access, BOOL SetLastError(0xdeadbeef); hfile = CreateFileA(dll_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); - ok(hfile != INVALID_HANDLE_VALUE, "CreateFile error %d\n", GetLastError()); + ok(hfile != INVALID_HANDLE_VALUE, "CreateFile error %ld\n", GetLastError()); SetLastError(0xdeadbeef); hmap = CreateFileMappingW(hfile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, 0); - ok(hmap != 0, "CreateFileMapping error %d\n", GetLastError()); + ok(hmap != 0, "CreateFileMapping error %ld\n", GetLastError()); offset.u.LowPart = 0; offset.u.HighPart = 0; @@ -1570,41 +1696,41 @@ static void test_image_mapping(const char *dll_name, DWORD scn_page_access, BOOL size = 0; status = pNtMapViewOfSection(hmap, GetCurrentProcess(), &addr1, 0, 0, &offset, &size, 1 /* ViewShare */, 0, PAGE_READONLY); - ok(status == STATUS_SUCCESS, "NtMapViewOfSection error %x\n", status); + ok(NT_SUCCESS(status), "NtMapViewOfSection error %lx\n", status); ok(addr1 != 0, "mapped address should be valid\n"); SetLastError(0xdeadbeef); size = VirtualQuery((char *)addr1 + section.VirtualAddress, &info, sizeof(info)); - ok(size == sizeof(info), "VirtualQuery error %d\n", GetLastError()); + ok(size == sizeof(info), "VirtualQuery error %ld\n", GetLastError()); ok(info.BaseAddress == (char *)addr1 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr1 + section.VirtualAddress); - ok(info.RegionSize == page_size, "got %#lx != expected %#x\n", info.RegionSize, page_size); - ok(info.Protect == scn_page_access, "got %#x != expected %#x\n", info.Protect, scn_page_access); + ok(info.RegionSize == page_size, "got %#Ix != expected %#lx\n", info.RegionSize, page_size); + ok(info.Protect == scn_page_access, "got %#lx != expected %#lx\n", info.Protect, scn_page_access); ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1); - ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#x != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect); - ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State); - ok(info.Type == SEC_IMAGE, "%#x != SEC_IMAGE\n", info.Type); + ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#lx != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect); + ok(info.State == MEM_COMMIT, "%#lx != MEM_COMMIT\n", info.State); + ok(info.Type == SEC_IMAGE, "%#lx != SEC_IMAGE\n", info.Type); addr2 = NULL; size = 0; status = pNtMapViewOfSection(hmap, GetCurrentProcess(), &addr2, 0, 0, &offset, &size, 1 /* ViewShare */, 0, PAGE_READONLY); - ok(status == STATUS_IMAGE_NOT_AT_BASE, "expected STATUS_IMAGE_NOT_AT_BASE, got %x\n", status); + ok(status == STATUS_IMAGE_NOT_AT_BASE, "expected STATUS_IMAGE_NOT_AT_BASE, got %lx\n", status); ok(addr2 != 0, "mapped address should be valid\n"); ok(addr2 != addr1, "mapped addresses should be different\n"); SetLastError(0xdeadbeef); size = VirtualQuery((char *)addr2 + section.VirtualAddress, &info, sizeof(info)); - ok(size == sizeof(info), "VirtualQuery error %d\n", GetLastError()); + ok(size == sizeof(info), "VirtualQuery error %ld\n", GetLastError()); ok(info.BaseAddress == (char *)addr2 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr2 + section.VirtualAddress); - ok(info.RegionSize == page_size, "got %#lx != expected %#x\n", info.RegionSize, page_size); - ok(info.Protect == scn_page_access, "got %#x != expected %#x\n", info.Protect, scn_page_access); + ok(info.RegionSize == page_size, "got %#Ix != expected %#lx\n", info.RegionSize, page_size); + ok(info.Protect == scn_page_access, "got %#lx != expected %#lx\n", info.Protect, scn_page_access); ok(info.AllocationBase == addr2, "%p != %p\n", info.AllocationBase, addr2); - ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#x != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect); - ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State); - ok(info.Type == SEC_IMAGE, "%#x != SEC_IMAGE\n", info.Type); + ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#lx != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect); + ok(info.State == MEM_COMMIT, "%#lx != MEM_COMMIT\n", info.State); + ok(info.Type == SEC_IMAGE, "%#lx != SEC_IMAGE\n", info.Type); status = pNtUnmapViewOfSection(GetCurrentProcess(), addr2); - ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection error %x\n", status); + ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection error %lx\n", status); addr2 = MapViewOfFile(hmap, 0, 0, 0, 0); ok(addr2 != 0, "mapped address should be valid\n"); @@ -1612,37 +1738,37 @@ static void test_image_mapping(const char *dll_name, DWORD scn_page_access, BOOL SetLastError(0xdeadbeef); size = VirtualQuery((char *)addr2 + section.VirtualAddress, &info, sizeof(info)); - ok(size == sizeof(info), "VirtualQuery error %d\n", GetLastError()); + ok(size == sizeof(info), "VirtualQuery error %ld\n", GetLastError()); ok(info.BaseAddress == (char *)addr2 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr2 + section.VirtualAddress); - ok(info.RegionSize == page_size, "got %#lx != expected %#x\n", info.RegionSize, page_size); - ok(info.Protect == scn_page_access, "got %#x != expected %#x\n", info.Protect, scn_page_access); + ok(info.RegionSize == page_size, "got %#Ix != expected %#lx\n", info.RegionSize, page_size); + ok(info.Protect == scn_page_access, "got %#lx != expected %#lx\n", info.Protect, scn_page_access); ok(info.AllocationBase == addr2, "%p != %p\n", info.AllocationBase, addr2); - ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#x != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect); - ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State); - ok(info.Type == SEC_IMAGE, "%#x != SEC_IMAGE\n", info.Type); + ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#lx != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect); + ok(info.State == MEM_COMMIT, "%#lx != MEM_COMMIT\n", info.State); + ok(info.Type == SEC_IMAGE, "%#lx != SEC_IMAGE\n", info.Type); UnmapViewOfFile(addr2); SetLastError(0xdeadbeef); addr2 = LoadLibraryA(dll_name); - if (is_dll) + if (!addr2) { - ok(!addr2, "LoadLibrary should fail, is_dll %d\n", is_dll); - ok(GetLastError() == ERROR_INVALID_ADDRESS, "expected ERROR_INVALID_ADDRESS, got %d\n", GetLastError()); + ok(is_dll, "LoadLibrary should fail, is_dll %d\n", is_dll); + ok(GetLastError() == ERROR_INVALID_ADDRESS, "expected ERROR_INVALID_ADDRESS, got %ld\n", GetLastError()); } else { BOOL ret; - ok(addr2 != 0, "LoadLibrary error %d, is_dll %d\n", GetLastError(), is_dll); + ok(addr2 != 0, "LoadLibrary error %ld, is_dll %d\n", GetLastError(), is_dll); ok(addr2 != addr1, "mapped addresses should be different\n"); SetLastError(0xdeadbeef); ret = FreeLibrary(addr2); - ok(ret, "FreeLibrary error %d\n", GetLastError()); + ok(ret, "FreeLibrary error %ld\n", GetLastError()); } status = pNtUnmapViewOfSection(GetCurrentProcess(), addr1); - ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection error %x\n", status); + ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection error %lx\n", status); CloseHandle(hmap); CloseHandle(hfile); @@ -1708,56 +1834,56 @@ static void test_VirtualProtect(void *base, void *section) SetLastError(0xdeadbeef); ret = VirtualProtect(section, page_size, PAGE_NOACCESS, &old_prot); - ok(ret, "VirtualProtect error %d\n", GetLastError()); + ok(ret, "VirtualProtect error %ld\n", GetLastError()); orig_prot = old_prot; - for (i = 0; i < sizeof(td)/sizeof(td[0]); i++) + for (i = 0; i < ARRAY_SIZE(td); i++) { SetLastError(0xdeadbeef); ret = VirtualQuery(section, &info, sizeof(info)); - ok(ret, "VirtualQuery failed %d\n", GetLastError()); - ok(info.BaseAddress == section, "%d: got %p != expected %p\n", i, info.BaseAddress, section); - ok(info.RegionSize == page_size, "%d: got %#lx != expected %#x\n", i, info.RegionSize, page_size); - ok(info.Protect == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, info.Protect); - ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base); - ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect); - ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State); - ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type); + ok(ret, "VirtualQuery failed %ld\n", GetLastError()); + ok(info.BaseAddress == section, "%ld: got %p != expected %p\n", i, info.BaseAddress, section); + ok(info.RegionSize == page_size, "%ld: got %#Ix != expected %#lx\n", i, info.RegionSize, page_size); + ok(info.Protect == PAGE_NOACCESS, "%ld: got %#lx != expected PAGE_NOACCESS\n", i, info.Protect); + ok(info.AllocationBase == base, "%ld: %p != %p\n", i, info.AllocationBase, base); + ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%ld: %#lx != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect); + ok(info.State == MEM_COMMIT, "%ld: %#lx != MEM_COMMIT\n", i, info.State); + ok(info.Type == SEC_IMAGE, "%ld: %#lx != SEC_IMAGE\n", i, info.Type); old_prot = 0xdeadbeef; SetLastError(0xdeadbeef); ret = VirtualProtect(section, page_size, td[i].prot_set, &old_prot); if (td[i].prot_get) { - ok(ret, "%d: VirtualProtect error %d, requested prot %#x\n", i, GetLastError(), td[i].prot_set); - ok(old_prot == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, old_prot); + ok(ret, "%ld: VirtualProtect error %ld, requested prot %#lx\n", i, GetLastError(), td[i].prot_set); + ok(old_prot == PAGE_NOACCESS, "%ld: got %#lx != expected PAGE_NOACCESS\n", i, old_prot); SetLastError(0xdeadbeef); ret = VirtualQuery(section, &info, sizeof(info)); - ok(ret, "VirtualQuery failed %d\n", GetLastError()); - ok(info.BaseAddress == section, "%d: got %p != expected %p\n", i, info.BaseAddress, section); - ok(info.RegionSize == page_size, "%d: got %#lx != expected %#x\n", i, info.RegionSize, page_size); - ok(info.Protect == td[i].prot_get, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot_get); - ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base); - ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect); - ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State); - ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type); + ok(ret, "VirtualQuery failed %ld\n", GetLastError()); + ok(info.BaseAddress == section, "%ld: got %p != expected %p\n", i, info.BaseAddress, section); + ok(info.RegionSize == page_size, "%ld: got %#Ix != expected %#lx\n", i, info.RegionSize, page_size); + ok(info.Protect == td[i].prot_get, "%ld: got %#lx != expected %#lx\n", i, info.Protect, td[i].prot_get); + ok(info.AllocationBase == base, "%ld: %p != %p\n", i, info.AllocationBase, base); + ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%ld: %#lx != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect); + ok(info.State == MEM_COMMIT, "%ld: %#lx != MEM_COMMIT\n", i, info.State); + ok(info.Type == SEC_IMAGE, "%ld: %#lx != SEC_IMAGE\n", i, info.Type); } else { - ok(!ret, "%d: VirtualProtect should fail\n", i); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError()); + ok(!ret, "%ld: VirtualProtect should fail\n", i); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "%ld: expected ERROR_INVALID_PARAMETER, got %ld\n", i, GetLastError()); } old_prot = 0xdeadbeef; SetLastError(0xdeadbeef); ret = VirtualProtect(section, page_size, PAGE_NOACCESS, &old_prot); - ok(ret, "%d: VirtualProtect error %d\n", i, GetLastError()); + ok(ret, "%ld: VirtualProtect error %ld\n", i, GetLastError()); if (td[i].prot_get) - ok(old_prot == td[i].prot_get, "%d: got %#x != expected %#x\n", i, old_prot, td[i].prot_get); + ok(old_prot == td[i].prot_get, "%ld: got %#lx != expected %#lx\n", i, old_prot, td[i].prot_get); else - ok(old_prot == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, old_prot); + ok(old_prot == PAGE_NOACCESS, "%ld: got %#lx != expected PAGE_NOACCESS\n", i, old_prot); } exec_prot = 0; @@ -1774,11 +1900,11 @@ static void test_VirtualProtect(void *base, void *section) ret = VirtualProtect(section, page_size, prot, &old_prot); if ((rw_prot && exec_prot) || (!rw_prot && !exec_prot)) { - ok(!ret, "VirtualProtect(%02x) should fail\n", prot); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + ok(!ret, "VirtualProtect(%02lx) should fail\n", prot); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); } else - ok(ret, "VirtualProtect(%02x) error %d\n", prot, GetLastError()); + ok(ret, "VirtualProtect(%02lx) error %ld\n", prot, GetLastError()); rw_prot = 1 << j; } @@ -1788,7 +1914,7 @@ static void test_VirtualProtect(void *base, void *section) SetLastError(0xdeadbeef); ret = VirtualProtect(section, page_size, orig_prot, &old_prot); - ok(ret, "VirtualProtect error %d\n", GetLastError()); + ok(ret, "VirtualProtect error %ld\n", GetLastError()); } static void test_section_access(void) @@ -1827,15 +1953,19 @@ static void test_section_access(void) }; char buf[256]; int i; - DWORD dummy, file_align; + DWORD dummy; HANDLE hfile; HMODULE hlib; char temp_path[MAX_PATH]; char dll_name[MAX_PATH]; SIZE_T size; + PEB child_peb; + PROCESS_BASIC_INFORMATION pbi; + SECTION_IMAGE_INFORMATION image_info; MEMORY_BASIC_INFORMATION info; STARTUPINFOA sti; PROCESS_INFORMATION pi; + NTSTATUS status; DWORD ret; /* prevent displaying of the "Unable to load this DLL" message box */ @@ -1843,7 +1973,7 @@ static void test_section_access(void) GetTempPathA(MAX_PATH, temp_path); - for (i = 0; i < sizeof(td)/sizeof(td[0]); i++) + for (i = 0; i < ARRAY_SIZE(td); i++) { IMAGE_NT_HEADERS nt_header; @@ -1859,23 +1989,13 @@ static void test_section_access(void) SetLastError(0xdeadbeef); ret = WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); nt_header = nt_header_template; - nt_header.FileHeader.NumberOfSections = 1; - nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER); - nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL | IMAGE_FILE_RELOCS_STRIPPED; - nt_header.OptionalHeader.SectionAlignment = page_size; nt_header.OptionalHeader.FileAlignment = 0x200; nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + page_size; nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER); - SetLastError(0xdeadbeef); - ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); - SetLastError(0xdeadbeef); - ret = WriteFile(hfile, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); section.SizeOfRawData = sizeof(section_data); section.PointerToRawData = nt_header.OptionalHeader.FileAlignment; @@ -1883,37 +2003,36 @@ static void test_section_access(void) section.Misc.VirtualSize = section.SizeOfRawData; section.Characteristics = td[i].scn_file_access; SetLastError(0xdeadbeef); - ret = WriteFile(hfile, §ion, sizeof(section), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); - file_align = nt_header.OptionalHeader.FileAlignment - nt_header.OptionalHeader.SizeOfHeaders; - assert(file_align < sizeof(filler)); SetLastError(0xdeadbeef); - ret = WriteFile(hfile, filler, file_align, &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ret = WriteFile(hfile, &nt_header, sizeof(nt_header), &dummy, NULL); + ok(ret, "WriteFile error %ld\n", GetLastError()); + + ret = WriteFile(hfile, §ion, sizeof(section), &dummy, NULL); + ok(ret, "WriteFile error %ld\n", GetLastError()); /* section data */ + SetFilePointer( hfile, nt_header.OptionalHeader.FileAlignment, NULL, FILE_BEGIN ); SetLastError(0xdeadbeef); ret = WriteFile(hfile, section_data, sizeof(section_data), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); CloseHandle(hfile); - SetLastError(0xdeadbeef); - hlib = LoadLibraryA(dll_name); - ok(hlib != 0, "LoadLibrary error %d\n", GetLastError()); + hlib = LoadLibraryExA(dll_name, NULL, DONT_RESOLVE_DLL_REFERENCES); + ok(hlib != 0, "LoadLibrary error %ld\n", GetLastError()); SetLastError(0xdeadbeef); size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info)); ok(size == sizeof(info), - "%d: VirtualQuery error %d\n", i, GetLastError()); + "%d: VirtualQuery error %ld\n", i, GetLastError()); ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress); - ok(info.RegionSize == page_size, "%d: got %#lx != expected %#x\n", i, info.RegionSize, page_size); - ok(info.Protect == td[i].scn_page_access, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].scn_page_access); + ok(info.RegionSize == page_size, "%d: got %#Ix != expected %#lx\n", i, info.RegionSize, page_size); + ok(info.Protect == td[i].scn_page_access, "%d: got %#lx != expected %#lx\n", i, info.Protect, td[i].scn_page_access); ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib); - ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect); - ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State); - ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type); + ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#lx != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect); + ok(info.State == MEM_COMMIT, "%d: %#lx != MEM_COMMIT\n", i, info.State); + ok(info.Type == SEC_IMAGE, "%d: %#lx != SEC_IMAGE\n", i, info.Type); if (info.Protect != PAGE_NOACCESS) ok(!memcmp((const char *)info.BaseAddress, section_data, section.SizeOfRawData), "wrong section data\n"); @@ -1926,20 +2045,20 @@ static void test_section_access(void) *p = 0xfe; SetLastError(0xdeadbeef); size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info)); - ok(size == sizeof(info), "%d: VirtualQuery error %d\n", i, GetLastError()); + ok(size == sizeof(info), "%d: VirtualQuery error %ld\n", i, GetLastError()); /* FIXME: remove the condition below once Wine is fixed */ todo_wine_if (info.Protect == PAGE_WRITECOPY || info.Protect == PAGE_EXECUTE_WRITECOPY) - ok(info.Protect == td[i].scn_page_access_after_write, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].scn_page_access_after_write); + ok(info.Protect == td[i].scn_page_access_after_write, "%d: got %#lx != expected %#lx\n", i, info.Protect, td[i].scn_page_access_after_write); } SetLastError(0xdeadbeef); ret = FreeLibrary(hlib); - ok(ret, "FreeLibrary error %d\n", GetLastError()); + ok(ret, "FreeLibrary error %ld\n", GetLastError()); test_image_mapping(dll_name, td[i].scn_page_access, TRUE); /* reset IMAGE_FILE_DLL otherwise CreateProcess fails */ - nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_RELOCS_STRIPPED; + nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE; SetLastError(0xdeadbeef); hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); /* LoadLibrary called on an already memory-mapped file in @@ -1948,67 +2067,130 @@ static void test_section_access(void) * due to sharing violation error. Ignore it and skip the test, * but leave a not deletable temporary file. */ - ok(hfile != INVALID_HANDLE_VALUE || broken(hfile == INVALID_HANDLE_VALUE) /* nt4 */, - "CreateFile error %d\n", GetLastError()); - if (hfile == INVALID_HANDLE_VALUE) goto nt4_is_broken; + ok(hfile != INVALID_HANDLE_VALUE, "CreateFile error %ld\n", GetLastError()); SetFilePointer(hfile, sizeof(dos_header), NULL, FILE_BEGIN); SetLastError(0xdeadbeef); ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); CloseHandle(hfile); memset(&sti, 0, sizeof(sti)); sti.cb = sizeof(sti); SetLastError(0xdeadbeef); ret = CreateProcessA(dll_name, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &sti, &pi); - ok(ret, "CreateProcess() error %d\n", GetLastError()); + ok(ret, "CreateProcess() error %ld\n", GetLastError()); + + status = pNtQueryInformationProcess( pi.hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL ); + ok( !status, "ProcessBasicInformation got %lx\n", status ); + ret = ReadProcessMemory( pi.hProcess, pbi.PebBaseAddress, &child_peb, sizeof(child_peb), NULL ); + ok( ret, "ReadProcessMemory failed err %lu\n", GetLastError() ); + hlib = child_peb.ImageBaseAddress; SetLastError(0xdeadbeef); size = VirtualQueryEx(pi.hProcess, (char *)hlib + section.VirtualAddress, &info, sizeof(info)); ok(size == sizeof(info), - "%d: VirtualQuery error %d\n", i, GetLastError()); + "%d: VirtualQuery error %ld\n", i, GetLastError()); ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress); - ok(info.RegionSize == page_size, "%d: got %#lx != expected %#x\n", i, info.RegionSize, page_size); - ok(info.Protect == td[i].scn_page_access, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].scn_page_access); + ok(info.RegionSize == page_size, "%d: got %#Ix != expected %#lx\n", i, info.RegionSize, page_size); + ok(info.Protect == td[i].scn_page_access, "%d: got %#lx != expected %#lx\n", i, info.Protect, td[i].scn_page_access); ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib); - ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect); - ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State); - ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type); + ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#lx != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect); + ok(info.State == MEM_COMMIT, "%d: %#lx != MEM_COMMIT\n", i, info.State); + ok(info.Type == SEC_IMAGE, "%d: %#lx != SEC_IMAGE\n", i, info.Type); if (info.Protect != PAGE_NOACCESS) { SetLastError(0xdeadbeef); ret = ReadProcessMemory(pi.hProcess, info.BaseAddress, buf, section.SizeOfRawData, NULL); - ok(ret, "ReadProcessMemory() error %d\n", GetLastError()); + ok(ret, "ReadProcessMemory() error %ld\n", GetLastError()); ok(!memcmp(buf, section_data, section.SizeOfRawData), "wrong section data\n"); } +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) { // Crashes on WS03 +#endif + status = NtQueryInformationProcess(pi.hProcess, ProcessImageInformation, + &image_info, sizeof(image_info), NULL ); + ok(!status, "Got unexpected status %#lx.\n", status); + ok(!(image_info.ImageCharacteristics & IMAGE_FILE_DLL), + "Got unexpected characteristics %#x.\n", nt_header.FileHeader.Characteristics); + status = NtUnmapViewOfSection(pi.hProcess, info.BaseAddress); + ok(!status, "Got unexpected status %#lx.\n", status); + status = NtQueryInformationProcess(pi.hProcess, ProcessImageInformation, + &image_info, sizeof(image_info), NULL ); + ok(!status, "Got unexpected status %#lx.\n", status); + ok(!(image_info.ImageCharacteristics & IMAGE_FILE_DLL), + "Got unexpected characteristics %#x.\n", nt_header.FileHeader.Characteristics); +#ifdef __REACTOS__ + } +#endif + SetLastError(0xdeadbeef); ret = TerminateProcess(pi.hProcess, 0); - ok(ret, "TerminateProcess() error %d\n", GetLastError()); + ok(ret, "TerminateProcess() error %ld\n", GetLastError()); ret = WaitForSingleObject(pi.hProcess, 3000); - ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %x\n", ret); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %lx\n", ret); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); test_image_mapping(dll_name, td[i].scn_page_access, FALSE); -nt4_is_broken: - SetLastError(0xdeadbeef); - ret = DeleteFileA(dll_name); - ok(ret || broken(!ret) /* nt4 */, "DeleteFile error %d\n", GetLastError()); + DeleteFileA(dll_name); } } +static void check_tls_index(HANDLE dll, BOOL tls_initialized) +{ + BOOL found_dll = FALSE; + LIST_ENTRY *root = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList; + for (LIST_ENTRY *entry = root->Flink; entry != root; entry = entry->Flink) + { + LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); + if (wcsicmp(L"ntdll.dll", mod->BaseDllName.Buffer) == 0) + { + /* Pick ntdll as a dll that definitely won't have TLS */ + ok(mod->TlsIndex == 0, "ntdll.dll TlsIndex: %d instead of 0\n", mod->TlsIndex); + } + else if (mod->DllBase == dll) + { + SHORT expected = tls_initialized ? -1 : 0; + ok(mod->TlsIndex == expected, "Test exe TlsIndex: %d instead of %d\n", mod->TlsIndex, expected); + found_dll = TRUE; + } + else + { + ok(mod->TlsIndex == 0 || mod->TlsIndex == -1, "%s TlsIndex: %d\n", + debugstr_w(mod->BaseDllName.Buffer), mod->TlsIndex); + } + } + ok(found_dll, "Couldn't find dll %p in module list\n", dll); +} + +static int tls_init_fn_output; + +static DWORD WINAPI tls_thread_fn(void* tlsidx_v) +{ + int tls_index = (int)(DWORD_PTR)(tlsidx_v); + const char* str = ((char **)NtCurrentTeb()->ThreadLocalStoragePointer)[tls_index]; + ok( !strcmp( str, "hello world" ), "wrong tls data '%s' at %p\n", str, str ); + ok( tls_init_fn_output == DLL_THREAD_ATTACH, + "tls init function didn't run or got wrong reason: %d instead of %d\n", tls_init_fn_output, DLL_THREAD_ATTACH ); + tls_init_fn_output = 9999; + return 0; +} + static void test_import_resolution(void) { char temp_path[MAX_PATH]; char dll_name[MAX_PATH]; DWORD dummy; - void *expect; + void *expect, *tmp; char *str; - HANDLE hfile; + SIZE_T size; + HANDLE hfile, mapping; HMODULE mod, mod2; + NTSTATUS status; + LARGE_INTEGER offset; struct imports { IMAGE_IMPORT_DESCRIPTOR descr[2]; @@ -2017,26 +2199,73 @@ static void test_import_resolution(void) char module[16]; struct { WORD hint; char name[32]; } function; IMAGE_TLS_DIRECTORY tls; + UINT_PTR tls_init_fn_list[2]; char tls_data[16]; SHORT tls_index; + SHORT tls_index_hi; + int* tls_init_fn_output; + UCHAR tls_init_fn[64]; /* Note: Uses rip-relative address of tls_init_fn_output, don't separate */ + UCHAR entry_point_fn[16]; + struct + { + IMAGE_BASE_RELOCATION reloc; + USHORT type_off[32]; + } rel; } data, *ptr; - IMAGE_NT_HEADERS nt; + IMAGE_NT_HEADERS nt, *pnt; IMAGE_SECTION_HEADER section; - int test; + SECTION_IMAGE_INFORMATION image; + int test, tls_index_save, nb_rel; +#if defined(__i386__) + static const UCHAR tls_init_code[] = { + 0xE8, 0x00, 0x00, 0x00, 0x00, /* call 1f */ + 0x59, /* 1: pop ecx */ + 0x8B, 0x49, 0xF7, /* mov ecx, [ecx - 9] ; mov ecx, [tls_init_fn_output] */ + 0x8B, 0x54, 0x24, 0x08, /* mov edx, [esp + 8] */ + 0x89, 0x11, /* mov [ecx], edx */ + 0xB8, 0x01, 0x00, 0x00, 0x00, /* mov eax, 1 */ + 0xC2, 0x0C, 0x00, /* ret 12 */ + }; + static const UCHAR entry_point_code[] = { + 0xB8, 0x01, 0x00, 0x00, 0x00, /* mov eax, 1 */ + 0xC2, 0x0C, 0x00, /* ret 12 */ + }; +#elif defined(__x86_64__) + static const UCHAR tls_init_code[] = { + 0x48, 0x8B, 0x0D, 0xF1, 0xFF, 0xFF, 0xFF, /* mov rcx, [rip + tls_init_fn_output] */ + 0x89, 0x11, /* mov [rcx], edx */ + 0xB8, 0x01, 0x00, 0x00, 0x00, /* mov eax, 1 */ + 0xC3, /* ret */ + }; + static const UCHAR entry_point_code[] = { + 0xB8, 0x01, 0x00, 0x00, 0x00, /* mov eax, 1 */ + 0xC3, /* ret */ + }; +#else + static const UCHAR tls_init_code[] = { 0x00 }; + static const UCHAR entry_point_code[] = { 0x00 }; +#endif - for (test = 0; test < 3; test++) + for (test = 0; test < 7; test++) { #define DATA_RVA(ptr) (page_size + ((char *)(ptr) - (char *)&data)) +#ifdef _WIN64 +#define ADD_RELOC(field) data.rel.type_off[nb_rel++] = (IMAGE_REL_BASED_DIR64 << 12) + offsetof( struct imports, field ) +#else +#define ADD_RELOC(field) data.rel.type_off[nb_rel++] = (IMAGE_REL_BASED_HIGHLOW << 12) + offsetof( struct imports, field ) +#endif + winetest_push_context( "%u", test ); nt = nt_header_template; nt.FileHeader.NumberOfSections = 1; nt.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER); - nt.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_RELOCS_STRIPPED; - if (test != 2) nt.FileHeader.Characteristics |= IMAGE_FILE_DLL; + nt.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE; + if (test != 2 && test != 5) nt.FileHeader.Characteristics |= IMAGE_FILE_DLL; nt.OptionalHeader.SectionAlignment = page_size; nt.OptionalHeader.FileAlignment = 0x200; - nt.OptionalHeader.ImageBase = 0x12340000; nt.OptionalHeader.SizeOfImage = 2 * page_size; nt.OptionalHeader.SizeOfHeaders = nt.OptionalHeader.FileAlignment; + nt.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT; + if (test < 6) nt.OptionalHeader.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE; nt.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES; memset( nt.OptionalHeader.DataDirectory, 0, sizeof(nt.OptionalHeader.DataDirectory) ); nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = sizeof(data.descr); @@ -2045,19 +2274,46 @@ static void test_import_resolution(void) nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = DATA_RVA(&data.tls); memset( &data, 0, sizeof(data) ); - U(data.descr[0]).OriginalFirstThunk = DATA_RVA( data.original_thunks ); + data.descr[0].OriginalFirstThunk = DATA_RVA( data.original_thunks ); data.descr[0].FirstThunk = DATA_RVA( data.thunks ); data.descr[0].Name = DATA_RVA( data.module ); strcpy( data.module, "kernel32.dll" ); strcpy( data.function.name, "CreateEventA" ); data.original_thunks[0].u1.AddressOfData = DATA_RVA( &data.function ); data.thunks[0].u1.AddressOfData = 0xdeadbeef; + nb_rel = 0; data.tls.StartAddressOfRawData = nt.OptionalHeader.ImageBase + DATA_RVA( data.tls_data ); + ADD_RELOC( tls.StartAddressOfRawData ); data.tls.EndAddressOfRawData = data.tls.StartAddressOfRawData + sizeof(data.tls_data); + ADD_RELOC( tls.EndAddressOfRawData ); data.tls.AddressOfIndex = nt.OptionalHeader.ImageBase + DATA_RVA( &data.tls_index ); + ADD_RELOC( tls.AddressOfIndex ); strcpy( data.tls_data, "hello world" ); data.tls_index = 9999; + data.tls_index_hi = 9999; + + if (test == 3 && sizeof(tls_init_code) > 1) + { + /* Windows doesn't consistently call tls init functions on dlls without entry points */ + assert(sizeof(tls_init_code) <= sizeof(data.tls_init_fn)); + assert(sizeof(entry_point_code) <= sizeof(data.entry_point_fn)); + memcpy(data.tls_init_fn, tls_init_code, sizeof(tls_init_code)); + memcpy(data.entry_point_fn, entry_point_code, sizeof(entry_point_code)); + tls_init_fn_output = 9999; + data.tls_init_fn_output = &tls_init_fn_output; + data.tls_init_fn_list[0] = nt.OptionalHeader.ImageBase + DATA_RVA(&data.tls_init_fn); + ADD_RELOC( tls_init_fn_list[0] ); + data.tls.AddressOfCallBacks = nt.OptionalHeader.ImageBase + DATA_RVA(&data.tls_init_fn_list); + ADD_RELOC( tls.AddressOfCallBacks ); + nt.OptionalHeader.AddressOfEntryPoint = DATA_RVA(&data.entry_point_fn); + } + + if (nb_rel % 2) nb_rel++; + data.rel.reloc.VirtualAddress = nt.OptionalHeader.SectionAlignment; + data.rel.reloc.SizeOfBlock = (char *)&data.rel.type_off[nb_rel] - (char *)&data.rel.reloc; + nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = data.rel.reloc.SizeOfBlock; + nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = DATA_RVA(&data.rel); GetTempPathA(MAX_PATH, temp_path); GetTempFileNameA(temp_path, "ldr", 0, dll_name); @@ -2072,6 +2328,7 @@ static void test_import_resolution(void) section.Misc.VirtualSize = sizeof(data); section.SizeOfRawData = sizeof(data); section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; + if (test == 3) section.Characteristics |= IMAGE_SCN_MEM_EXECUTE; WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL); WriteFile(hfile, &nt, sizeof(nt), &dummy, NULL); @@ -2086,24 +2343,30 @@ static void test_import_resolution(void) { case 0: /* normal load */ mod = LoadLibraryA( dll_name ); - ok( mod != NULL, "failed to load err %u\n", GetLastError() ); + ok( mod != NULL, "failed to load err %lu\n", GetLastError() ); if (!mod) break; ptr = (struct imports *)((char *)mod + page_size); expect = GetProcAddress( GetModuleHandleA( data.module ), data.function.name ); ok( (void *)ptr->thunks[0].u1.Function == expect, "thunk %p instead of %p for %s.%s\n", (void *)ptr->thunks[0].u1.Function, expect, data.module, data.function.name ); - ok( ptr->tls_index < 32 || broken(ptr->tls_index == 9999), /* before vista */ - "wrong tls index %d\n", ptr->tls_index ); - if (ptr->tls_index != 9999) - { - str = ((char **)NtCurrentTeb()->ThreadLocalStoragePointer)[ptr->tls_index]; - ok( !strcmp( str, "hello world" ), "wrong tls data '%s' at %p\n", str, str ); +#ifdef __REACTOS__ + ok( ptr->tls_index < 32 || broken(ptr->tls_index == 9999) /* WS03 */, "wrong tls index %d\n", ptr->tls_index ); + if (ptr->tls_index != 9999) { +#else + ok( ptr->tls_index < 32, "wrong tls index %d\n", ptr->tls_index ); +#endif + str = ((char **)NtCurrentTeb()->ThreadLocalStoragePointer)[ptr->tls_index]; + ok( !strcmp( str, "hello world" ), "wrong tls data '%s' at %p\n", str, str ); + ok(ptr->tls_index_hi == 0, "TLS Index written as a short, high half: %d\n", ptr->tls_index_hi); +#ifdef __REACTOS__ } +#endif + check_tls_index(mod, ptr->tls_index != 9999); FreeLibrary( mod ); break; case 1: /* load with DONT_RESOLVE_DLL_REFERENCES doesn't resolve imports */ mod = LoadLibraryExA( dll_name, 0, DONT_RESOLVE_DLL_REFERENCES ); - ok( mod != NULL, "failed to load err %u\n", GetLastError() ); + ok( mod != NULL, "failed to load err %lu\n", GetLastError() ); if (!mod) break; ptr = (struct imports *)((char *)mod + page_size); ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n", @@ -2115,39 +2378,585 @@ static void test_import_resolution(void) ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n", (void *)ptr->thunks[0].u1.Function, data.module, data.function.name ); ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index ); + check_tls_index(mod, ptr->tls_index != 9999); FreeLibrary( mod2 ); FreeLibrary( mod ); break; case 2: /* load without IMAGE_FILE_DLL doesn't resolve imports */ mod = LoadLibraryA( dll_name ); - ok( mod != NULL, "failed to load err %u\n", GetLastError() ); + ok( mod != NULL, "failed to load err %lu\n", GetLastError() ); if (!mod) break; ptr = (struct imports *)((char *)mod + page_size); ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n", (void *)ptr->thunks[0].u1.Function, data.module, data.function.name ); ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index ); + check_tls_index(mod, ptr->tls_index != 9999); FreeLibrary( mod ); break; + case 3: /* load with tls init function */ + mod = LoadLibraryA( dll_name ); + ok( mod != NULL, "failed to load err %lu\n", GetLastError() ); + if (!mod) break; + ptr = (struct imports *)((char *)mod + page_size); + tls_index_save = ptr->tls_index; +#ifdef __REACTOS__ + ok( ptr->tls_index < 32 || broken(ptr->tls_index == 9999) /* WS03 */, "wrong tls index %d\n", ptr->tls_index ); + if (sizeof(tls_init_code) > 1 && ptr->tls_index != 9999) +#else + ok( ptr->tls_index < 32, "wrong tls index %d\n", ptr->tls_index ); + if (sizeof(tls_init_code) > 1) +#endif + { + str = ((char **)NtCurrentTeb()->ThreadLocalStoragePointer)[ptr->tls_index]; + ok( !strcmp( str, "hello world" ), "wrong tls data '%s' at %p\n", str, str ); + /* tls init function will write the reason to *tls_init_fn_output */ + ok( tls_init_fn_output == DLL_PROCESS_ATTACH, + "tls init function didn't run or got wrong reason: %d instead of %d\n", tls_init_fn_output, DLL_PROCESS_ATTACH ); + tls_init_fn_output = 9999; + WaitForSingleObject(CreateThread(NULL, 0, tls_thread_fn, (void*)(DWORD_PTR)ptr->tls_index, 0, NULL), INFINITE); + ok( tls_init_fn_output == DLL_THREAD_DETACH, + "tls init function didn't run or got wrong reason: %d instead of %d\n", tls_init_fn_output, DLL_THREAD_DETACH ); + } + check_tls_index(mod, ptr->tls_index != 9999); + tls_init_fn_output = 9999; + FreeLibrary( mod ); + if (tls_index_save != 9999 && sizeof(tls_init_code) > 1) + ok( tls_init_fn_output == DLL_PROCESS_DETACH, + "tls init function didn't run or got wrong reason: %d instead of %d\n", tls_init_fn_output, DLL_PROCESS_DETACH ); + break; + case 4: /* map with ntdll */ + case 5: /* map with ntdll, without IMAGE_FILE_DLL */ + case 6: /* map with ntdll, without IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE */ + hfile = CreateFileA(dll_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); + ok( hfile != INVALID_HANDLE_VALUE, "CreateFile failed err %lu\n", GetLastError() ); + mapping = CreateFileMappingA( hfile, NULL, SEC_IMAGE | PAGE_READONLY, 0, 0, NULL ); + CloseHandle( hfile ); + if (test == 6 && + (nt_header_template.FileHeader.Machine == IMAGE_FILE_MACHINE_ARMNT || + nt_header_template.FileHeader.Machine == IMAGE_FILE_MACHINE_ARM64)) + { + ok( !mapping, "CreateFileMappingA succeeded\n" ); + ok( GetLastError() == ERROR_BAD_EXE_FORMAT, "wrong error %lu\n", GetLastError() ); + break; + } + status = pNtQuerySection( mapping, SectionImageInformation, &image, sizeof(image), &size ); + ok( !status, "NtQuerySection failed %lx\n", status ); +#ifdef __REACTOS__ + ok( test == 6 ? !image.ImageDynamicallyRelocated : image.ImageDynamicallyRelocated || broken(GetNTVersion() < _WIN32_WINNT_VISTA), +#else + ok( test == 6 ? !image.ImageDynamicallyRelocated : image.ImageDynamicallyRelocated, +#endif + "image flags %x\n", image.ImageFlags); + ok( !image.ImageContainsCode, "contains code %x\n", image.ImageContainsCode); + ok( mapping != 0, "CreateFileMappingA failed err %lu\n", GetLastError() ); + /* make sure that the address is not available */ + tmp = VirtualAlloc( (void *)nt.OptionalHeader.ImageBase, 0x10000, + MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE ); + mod = NULL; + size = 0; + offset.QuadPart = 0; + status = pNtMapViewOfSection( mapping, GetCurrentProcess(), (void **)&mod, 0, 0, &offset, + &size, 1 /* ViewShare */, 0, PAGE_READONLY ); + todo_wine_if (test == 5) +#ifdef __REACTOS__ + ok( status == (test == 6 ? STATUS_IMAGE_NOT_AT_BASE : STATUS_SUCCESS) || broken(GetNTVersion() < _WIN32_WINNT_VISTA), +#else + ok( status == (test == 6 ? STATUS_IMAGE_NOT_AT_BASE : STATUS_SUCCESS), +#endif + "NtMapViewOfSection failed %lx\n", status ); + ok( mod != (void *)nt.OptionalHeader.ImageBase, "loaded at image base %p\n", mod ); + pnt = pRtlImageNtHeader( mod ); + ptr = (void *)((char *)mod + page_size); + if (test == 6) + { + ok( (void *)pnt->OptionalHeader.ImageBase != mod, "not relocated from %p\n", mod ); + ok( (char *)ptr->tls.StartAddressOfRawData == (char *)nt.OptionalHeader.ImageBase + DATA_RVA( data.tls_data ), + "tls relocated %p / %p\n", (void *)ptr->tls.StartAddressOfRawData, + (char *)nt.OptionalHeader.ImageBase + DATA_RVA( data.tls_data )); + } + else todo_wine_if (test == 5) + { +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) { +#endif + ok( (void *)pnt->OptionalHeader.ImageBase == mod, "not at base %p / %p\n", + (void *)pnt->OptionalHeader.ImageBase, mod ); + ok( (char *)ptr->tls.StartAddressOfRawData == (char *)mod + DATA_RVA( data.tls_data ), + "tls not relocated %p / %p\n", (void *)ptr->tls.StartAddressOfRawData, + (char *)mod + DATA_RVA( data.tls_data )); +#ifdef __REACTOS__ + } +#endif + } + UnmapViewOfFile( mod ); + CloseHandle( mapping ); + if (tmp) VirtualFree( tmp, 0, MEM_RELEASE ); + break; } DeleteFileA( dll_name ); + winetest_pop_context(); #undef DATA_RVA } } +static HANDLE gen_forward_chain_testdll( char testdll_path[MAX_PATH], + const char source_dll[MAX_PATH], + BOOL is_export, BOOL is_import, + DWORD *exp_func_base_rva, + DWORD *imp_thunk_base_rva ) +{ + DWORD text_rva = page_size; /* assumes that the PE/COFF headers fit in a page */ + DWORD text_size = page_size; + DWORD edata_rva = text_rva + text_size; + DWORD edata_size = page_size; + DWORD idata_rva = edata_rva + text_size; + DWORD idata_size = page_size; + DWORD eof_rva = idata_rva + edata_size; + const IMAGE_SECTION_HEADER sections[3] = { + { + .Name = ".text", + .Misc = { .VirtualSize = text_size }, + .VirtualAddress = text_rva, + .SizeOfRawData = text_size, + .PointerToRawData = text_rva, + .Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, + }, + { + .Name = ".edata", + .Misc = { .VirtualSize = edata_size }, + .VirtualAddress = edata_rva, + .SizeOfRawData = edata_size, + .PointerToRawData = edata_rva, + .Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, + }, + { + .Name = ".idata", + .Misc = { .VirtualSize = edata_size }, + .VirtualAddress = idata_rva, + .SizeOfRawData = idata_size, + .PointerToRawData = idata_rva, + .Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, + }, + }; + struct expdesc + { + const IMAGE_EXPORT_DIRECTORY dir; + + DWORD functions[2]; + + const DWORD names[2]; + const WORD name_ords[2]; + const char str_forward_test_func[32]; + const char str_forward_test_func2[32]; + + char dll_name[MAX_PATH]; /* dynamically populated */ + char strpool[2][MAX_PATH + 16]; /* for names of export forwarders */ + } expdesc = { + .dir = { + .Characteristics = 0, + .TimeDateStamp = 0x12345678, + .Name = edata_rva + offsetof(struct expdesc, dll_name), + .Base = 1, + .NumberOfFunctions = ARRAY_SIZE(expdesc.functions), + .NumberOfNames = ARRAY_SIZE(expdesc.names), + .AddressOfFunctions = edata_rva + offsetof(struct expdesc, functions), + .AddressOfNames = edata_rva + offsetof(struct expdesc, names), + .AddressOfNameOrdinals = edata_rva + offsetof(struct expdesc, name_ords), + }, + .functions = { + text_rva + 0x4, /* may be overwritten */ + text_rva + 0x8, /* may be overwritten */ + }, + .names = { + edata_rva + offsetof(struct expdesc, str_forward_test_func), + edata_rva + offsetof(struct expdesc, str_forward_test_func2), + }, + .name_ords = { + 0, + 1, + }, + .str_forward_test_func = "forward_test_func", + .str_forward_test_func2 = "forward_test_func2", + }; + struct impdesc + { + const IMAGE_IMPORT_DESCRIPTOR descr[2]; + const IMAGE_THUNK_DATA original_thunks[3]; + const IMAGE_THUNK_DATA thunks[3]; + const struct { WORD hint; char name[32]; } impname_forward_test_func; + + char module[MAX_PATH]; /* dynamically populated */ + } impdesc = { + .descr = { + { + .OriginalFirstThunk = idata_rva + offsetof(struct impdesc, original_thunks), + .TimeDateStamp = 0, + .ForwarderChain = -1, + .Name = idata_rva + offsetof(struct impdesc, module), + .FirstThunk = idata_rva + offsetof(struct impdesc, thunks), + }, + {{ 0 }}, + }, + .original_thunks = { + {{ idata_rva + offsetof(struct impdesc, impname_forward_test_func) }}, + {{ IMAGE_ORDINAL_FLAG | 2 }}, + {{ 0 }}, + }, + .thunks = { + {{ idata_rva + offsetof(struct impdesc, impname_forward_test_func) }}, + {{ IMAGE_ORDINAL_FLAG | 2 }}, + {{ 0 }}, + }, + .impname_forward_test_func = { 0, "forward_test_func" }, + }; + IMAGE_NT_HEADERS nt_header; + char temp_path[MAX_PATH]; + HANDLE file, file_w; + LARGE_INTEGER qpc; + DWORD outlen; + BOOL ret; + int res; + + QueryPerformanceCounter( &qpc ); + res = snprintf( expdesc.dll_name, ARRAY_SIZE(expdesc.dll_name), + "ldr%05lx.dll", qpc.LowPart & 0xfffffUL ); + ok( res > 0 && res < ARRAY_SIZE(expdesc.dll_name), "snprintf failed\n" ); + + if (source_dll) + { + const char *export_names[2] = { + "forward_test_func", + "#2", + }; + const char *backslash = strrchr( source_dll, '\\' ); + const char *dllname = backslash ? backslash + 1 : source_dll; + const char *dot = strrchr( dllname, '.' ); + size_t ext_start = dot ? dot - dllname : strlen(dllname); + size_t i; + + res = snprintf( impdesc.module, ARRAY_SIZE(impdesc.module), "%s", dllname ); + ok( res > 0 && res < ARRAY_SIZE(impdesc.module), "snprintf() failed\n" ); + + for (i = 0; i < ARRAY_SIZE(export_names); i++) + { + char *buf; + size_t buf_size; + + assert( i < ARRAY_SIZE(expdesc.strpool) ); + buf = expdesc.strpool[i]; + buf_size = ARRAY_SIZE(expdesc.strpool[i]); + + assert( ext_start < buf_size ); + memcpy( buf, dllname, ext_start ); + buf += ext_start; + buf_size -= ext_start; + + res = snprintf( buf, buf_size, ".%s", export_names[i] ); + ok( res > 0 && res < buf_size, "snprintf() failed\n" ); + + assert( i < ARRAY_SIZE(expdesc.functions) ); + expdesc.functions[i] = edata_rva + (expdesc.strpool[i] - (char *)&expdesc); + } + } + + nt_header = nt_header_template; + nt_header.FileHeader.TimeDateStamp = 0x12345678; + nt_header.FileHeader.NumberOfSections = ARRAY_SIZE(sections); + nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER); + + nt_header.OptionalHeader.SizeOfCode = text_size; + nt_header.OptionalHeader.SectionAlignment = page_size; + nt_header.OptionalHeader.FileAlignment = page_size; + nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(sections); + nt_header.OptionalHeader.SizeOfImage = eof_rva; + if (is_export) + { + nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = edata_rva; + nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sizeof(expdesc); + } + /* Always have an import descriptor (even if empty) just like a real DLL */ + nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = idata_rva; + nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = is_import ? sizeof(impdesc) : sizeof(IMAGE_IMPORT_DESCRIPTOR); + + ok( nt_header.OptionalHeader.SizeOfHeaders <= text_rva, + "headers (size %#lx) should not overlap with text area (RVA %#lx)\n", + nt_header.OptionalHeader.SizeOfHeaders, text_rva ); + + outlen = GetTempPathA( ARRAY_SIZE(temp_path), temp_path ); + ok( outlen > 0 && outlen < ARRAY_SIZE(temp_path), "GetTempPathA() err=%lu\n", GetLastError() ); + + res = snprintf( testdll_path, MAX_PATH, "%s\\%s", temp_path, expdesc.dll_name ); + ok( res > 0 && res < MAX_PATH, "snprintf failed\n" ); + + /* Open file handle that will be deleted on close or process termination */ + file = CreateFileA( testdll_path, + DELETE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + CREATE_NEW, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, + NULL ); + ok( file != INVALID_HANDLE_VALUE, "CreateFile(%s) for delete returned error %lu\n", + wine_dbgstr_a( testdll_path ), GetLastError() ); + + /* Open file again with write access */ + file_w = CreateFileA( testdll_path, + GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL ); + ok( file_w != INVALID_HANDLE_VALUE, "CreateFile(%s) for write returned error %lu\n", + wine_dbgstr_a( testdll_path ), GetLastError() ); + + ret = WriteFile( file_w, &dos_header, sizeof(dos_header), &outlen, NULL ); + ok( ret && outlen == sizeof(dos_header), "write dos_header: err=%lu outlen=%lu\n", GetLastError(), outlen ); + + ret = WriteFile( file_w, &nt_header, sizeof(nt_header), &outlen, NULL ); + ok( ret && outlen == sizeof(nt_header), "write nt_header: err=%lu outlen=%lu\n", GetLastError(), outlen ); + + ret = WriteFile( file_w, sections, sizeof(sections), &outlen, NULL ); + ok( ret && outlen == sizeof(sections), "write sections: err=%lu outlen=%lu\n", GetLastError(), outlen ); + + if (is_export) + { + SetFilePointer( file_w, edata_rva, NULL, FILE_BEGIN ); + ret = WriteFile( file_w, &expdesc, sizeof(expdesc), &outlen, NULL ); + ok( ret && outlen == sizeof(expdesc), "write expdesc: err=%lu outlen=%lu\n", GetLastError(), outlen ); + } + + if (is_import) + { + SetFilePointer( file_w, idata_rva, NULL, FILE_BEGIN ); + ret = WriteFile( file_w, &impdesc, sizeof(impdesc), &outlen, NULL ); + ok( ret && outlen == sizeof(impdesc), "write impdesc: err=%lu outlen=%lu\n", GetLastError(), outlen ); + } + + ret = SetFilePointer( file_w, eof_rva, NULL, FILE_BEGIN ); + ok( ret, "%lu\n", GetLastError() ); + ret = SetEndOfFile( file_w ); + ok( ret, "%lu\n", GetLastError() ); + + ret = CloseHandle( file_w ); + ok( ret, "%lu\n", GetLastError() ); + + if (exp_func_base_rva) + { + *exp_func_base_rva = is_export ? edata_rva + ((char *)&expdesc.functions - (char *)&expdesc) : 0; + } + + if (imp_thunk_base_rva) + { + *imp_thunk_base_rva = is_import ? idata_rva + ((char *)&impdesc.thunks - (char *)&impdesc) : 0; + } + + return file; +} + +static void subtest_export_forwarder_dep_chain( size_t num_chained_export_modules, + size_t exporter_index, + BOOL test_static_import ) +{ + size_t num_modules = num_chained_export_modules + !!test_static_import; + size_t importer_index = test_static_import ? num_modules - 1 : 0; + DWORD imp_thunk_base_rva, exp_func_base_rva; + size_t ultimate_depender_index = 0; /* latest module depending on modules earlier in chain */ + char temp_paths[4][MAX_PATH]; + HANDLE temp_files[4]; + UINT_PTR exports[2]; + HMODULE modules[4]; + BOOL res; + size_t i; + + assert(exporter_index < num_chained_export_modules); + assert(num_modules > 1); + assert(num_modules <= ARRAY_SIZE(temp_paths)); + assert(num_modules <= ARRAY_SIZE(temp_files)); + assert(num_modules <= ARRAY_SIZE(modules)); + + if (winetest_debug > 1) + trace( "Generate a chain of test DLL fixtures\n" ); + + for (i = 0; i < num_modules; i++) + { + temp_files[i] = gen_forward_chain_testdll( temp_paths[i], + i >= 1 ? temp_paths[i - 1] : NULL, + i < num_chained_export_modules, + importer_index && i == importer_index, + i == 0 ? &exp_func_base_rva : NULL, + i == importer_index ? &imp_thunk_base_rva : NULL ); + } + + if (winetest_debug > 1) + trace( "Load the entire test DLL chain\n" ); + + for (i = 0; i < num_modules; i++) + { + HMODULE module; + + ok( !GetModuleHandleA( temp_paths[i] ), "%s already loaded\n", + wine_dbgstr_a( temp_paths[i] ) ); + + modules[i] = LoadLibraryA( temp_paths[i] ); + ok( !!modules[i], "LoadLibraryA(temp_paths[%Iu] = %s) err=%lu\n", + i, wine_dbgstr_a( temp_paths[i] ), GetLastError() ); + + if (i == importer_index) + { + /* Statically importing export forwarder introduces a load-time dependency */ + ultimate_depender_index = max( ultimate_depender_index, importer_index ); + } + + module = GetModuleHandleA( temp_paths[i] ); + ok( module == modules[i], "modules[%Iu] expected %p, got %p err=%lu\n", + i, modules[i], module, GetLastError() ); + } + + if (winetest_debug > 1) + trace( "Get address of exported functions from the source module\n" ); + + for (i = 0; i < ARRAY_SIZE(exports); i++) + { + char *mod_base = (char *)modules[0]; /* source (non-forward) DLL */ + exports[i] = (UINT_PTR)(mod_base + ((DWORD *)(mod_base + exp_func_base_rva))[i]); + } + + if (winetest_debug > 1) + trace( "Check import address table of the importer DLL, if any\n" ); + + if (importer_index) + { + UINT_PTR *imp_thunk_base = (UINT_PTR *)((char *)modules[importer_index] + imp_thunk_base_rva); + for (i = 0; i < ARRAY_SIZE(exports); i++) + { + ok( imp_thunk_base[i] == exports[i], "import thunk mismatch [%Iu]: (%#Ix, %#Ix)\n", + i, imp_thunk_base[i], exports[i] ); + } + } + + if (winetest_debug > 1) + trace( "Call GetProcAddress() on the exporter DLL, if any\n" ); + + if (exporter_index) + { + UINT_PTR proc; + + proc = (UINT_PTR)GetProcAddress( modules[exporter_index], "forward_test_func" ); + ok( proc == exports[0], "GetProcAddress mismatch [0]: (%#Ix, %#Ix)\n", proc, exports[0] ); + + proc = (UINT_PTR)GetProcAddress( modules[exporter_index], (LPSTR)2 ); + ok( proc == exports[1], "GetProcAddress mismatch [1]: (%#Ix, %#Ix)\n", proc, exports[1] ); + + /* Dynamically importing export forwarder introduces a runtime dependency */ + ultimate_depender_index = max( ultimate_depender_index, exporter_index ); + } + + if (winetest_debug > 1) + trace( "Unreference modules except the ultimate dependant DLL\n" ); + + for (i = 0; i < ultimate_depender_index; i++) + { + HMODULE module; + + res = FreeLibrary( modules[i] ); + ok( res, "FreeLibrary(modules[%Iu]) err=%lu\n", i, GetLastError() ); + + /* FreeLibrary() should *not* unload the DLL immediately */ + module = GetModuleHandleA( temp_paths[i] ); + todo_wine_if(i < ultimate_depender_index && i + 1 != importer_index) + ok( module == modules[i], "modules[%Iu] expected %p, got %p (unloaded?) err=%lu\n", + i, modules[i], module, GetLastError() ); + } + + if (winetest_debug > 1) + trace( "The ultimate dependant DLL should keep other DLLs from being unloaded\n" ); + + for (i = 0; i < num_modules; i++) + { + HMODULE module = GetModuleHandleA( temp_paths[i] ); + + todo_wine_if(i < ultimate_depender_index && i + 1 != importer_index) + ok( module == modules[i], "modules[%Iu] expected %p, got %p (unloaded?) err=%lu\n", + i, modules[i], module, GetLastError() ); + } + + if (winetest_debug > 1) + trace( "Unreference the remaining modules (including the dependant DLL)\n" ); + + for (i = ultimate_depender_index; i < num_modules; i++) + { + res = FreeLibrary( modules[i] ); + ok( res, "FreeLibrary(modules[%Iu]) err=%lu\n", i, GetLastError() ); + + /* FreeLibrary() should unload the DLL immediately */ + ok( !GetModuleHandleA( temp_paths[i] ), "modules[%Iu] should not be kept loaded (2)\n", i ); + } + + if (winetest_debug > 1) + trace( "All modules should be unloaded; the unloading process should not reload any DLL\n" ); + +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) { +#endif + for (i = 0; i < num_modules; i++) + { + ok( !GetModuleHandleA( temp_paths[i] ), "modules[%Iu] should not be kept loaded (3)\n", i ); + } +#ifdef __REACTOS__ + } +#endif + + if (winetest_debug > 1) + trace( "Close and delete temp files\n" ); + + for (i = 0; i < num_modules; i++) + { + /* handles should be delete-on-close */ + CloseHandle( temp_files[i] ); + } +} + +static void test_export_forwarder_dep_chain(void) +{ + winetest_push_context( "no import" ); + /* export forwarder does not introduce a dependency on its own */ + subtest_export_forwarder_dep_chain( 2, 0, FALSE ); + winetest_pop_context(); + + winetest_push_context( "static import of export forwarder" ); + subtest_export_forwarder_dep_chain( 2, 0, TRUE ); + winetest_pop_context(); + + winetest_push_context( "static import of chained export forwarder" ); + subtest_export_forwarder_dep_chain( 3, 0, TRUE ); + winetest_pop_context(); + + winetest_push_context( "dynamic import of export forwarder" ); + subtest_export_forwarder_dep_chain( 2, 1, FALSE ); + winetest_pop_context(); + + winetest_push_context( "dynamic import of chained export forwarder" ); + subtest_export_forwarder_dep_chain( 3, 2, FALSE ); + winetest_pop_context(); +} + #define MAX_COUNT 10 static HANDLE attached_thread[MAX_COUNT]; static DWORD attached_thread_count; -HANDLE stop_event, event, mutex, semaphore, loader_lock_event, peb_lock_event, heap_lock_event, ack_event; -static int test_dll_phase, inside_loader_lock, inside_peb_lock, inside_heap_lock; +static HANDLE event, mutex, semaphore; +static HANDLE stop_event, loader_lock_event, peb_lock_event, heap_lock_event, cs_lock_event, ack_event; +static CRITICAL_SECTION cs_lock; +static int test_dll_phase, inside_loader_lock, inside_peb_lock, inside_heap_lock, inside_cs_lock; static LONG fls_callback_count; static DWORD WINAPI mutex_thread_proc(void *param) { - HANDLE wait_list[4]; + HANDLE wait_list[5]; DWORD ret; ret = WaitForSingleObject(mutex, 0); - ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret); + ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#lx\n", ret); SetEvent(param); @@ -2155,38 +2964,46 @@ static DWORD WINAPI mutex_thread_proc(void *param) wait_list[1] = loader_lock_event; wait_list[2] = peb_lock_event; wait_list[3] = heap_lock_event; + wait_list[4] = cs_lock_event; - trace("%04x: mutex_thread_proc: starting\n", GetCurrentThreadId()); + trace("%04lx: mutex_thread_proc: starting\n", GetCurrentThreadId()); while (1) { - ret = WaitForMultipleObjects(sizeof(wait_list)/sizeof(wait_list[0]), wait_list, FALSE, 50); + ret = WaitForMultipleObjects(ARRAY_SIZE(wait_list), wait_list, FALSE, 50); if (ret == WAIT_OBJECT_0) break; else if (ret == WAIT_OBJECT_0 + 1) { ULONG_PTR loader_lock_magic; - trace("%04x: mutex_thread_proc: Entering loader lock\n", GetCurrentThreadId()); + trace("%04lx: mutex_thread_proc: Entering loader lock\n", GetCurrentThreadId()); ret = pLdrLockLoaderLock(0, NULL, &loader_lock_magic); - ok(!ret, "LdrLockLoaderLock error %#x\n", ret); + ok(!ret, "LdrLockLoaderLock error %#lx\n", ret); inside_loader_lock++; SetEvent(ack_event); } else if (ret == WAIT_OBJECT_0 + 2) { - trace("%04x: mutex_thread_proc: Entering PEB lock\n", GetCurrentThreadId()); + trace("%04lx: mutex_thread_proc: Entering PEB lock\n", GetCurrentThreadId()); pRtlAcquirePebLock(); inside_peb_lock++; SetEvent(ack_event); } else if (ret == WAIT_OBJECT_0 + 3) { - trace("%04x: mutex_thread_proc: Entering heap lock\n", GetCurrentThreadId()); + trace("%04lx: mutex_thread_proc: Entering heap lock\n", GetCurrentThreadId()); HeapLock(GetProcessHeap()); inside_heap_lock++; SetEvent(ack_event); } + else if (ret == WAIT_OBJECT_0 + 4) + { + trace("%04lx: mutex_thread_proc: Entering CS lock\n", GetCurrentThreadId()); + EnterCriticalSection(&cs_lock); + inside_cs_lock++; + SetEvent(ack_event); + } } - trace("%04x: mutex_thread_proc: exiting\n", GetCurrentThreadId()); + trace("%04lx: mutex_thread_proc: exiting\n", GetCurrentThreadId()); return 196; } @@ -2195,18 +3012,18 @@ static DWORD WINAPI semaphore_thread_proc(void *param) DWORD ret; ret = WaitForSingleObject(semaphore, 0); - ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret); + ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#lx\n", ret); SetEvent(param); while (1) { if (winetest_debug > 1) - trace("%04x: semaphore_thread_proc: still alive\n", GetCurrentThreadId()); + trace("%04lx: semaphore_thread_proc: still alive\n", GetCurrentThreadId()); if (WaitForSingleObject(stop_event, 50) != WAIT_TIMEOUT) break; } - trace("%04x: semaphore_thread_proc: exiting\n", GetCurrentThreadId()); + trace("%04lx: semaphore_thread_proc: exiting\n", GetCurrentThreadId()); return 196; } @@ -2218,7 +3035,7 @@ static DWORD WINAPI noop_thread_proc(void *param) InterlockedIncrement(noop_thread_started); } - trace("%04x: noop_thread_proc: exiting\n", GetCurrentThreadId()); + trace("%04lx: noop_thread_proc: exiting\n", GetCurrentThreadId()); return 195; } @@ -2228,12 +3045,34 @@ static VOID WINAPI fls_callback(PVOID lpFlsData) InterlockedIncrement(&fls_callback_count); } +static LIST_ENTRY *fls_list_head; + +static unsigned int check_linked_list(const LIST_ENTRY *le, const LIST_ENTRY *search_entry, unsigned int *index_found) +{ + unsigned int count = 0; + LIST_ENTRY *entry; + + *index_found = ~0; + + for (entry = le->Flink; entry != le; entry = entry->Flink) + { + if (entry == search_entry) + { + ok(*index_found == ~0, "Duplicate list entry.\n"); + *index_found = count; + } + ++count; + } + return count; +} + static BOOL WINAPI dll_entry_point(HINSTANCE hinst, DWORD reason, LPVOID param) { static LONG noop_thread_started; - static DWORD fls_index = FLS_OUT_OF_INDEXES; + static DWORD fls_index = FLS_OUT_OF_INDEXES, fls_index2 = FLS_OUT_OF_INDEXES; static int fls_count = 0; static int thread_detach_count = 0; + static int thread_count; DWORD ret; ok(!inside_loader_lock, "inside_loader_lock should not be set\n"); @@ -2245,7 +3084,7 @@ static BOOL WINAPI dll_entry_point(HINSTANCE hinst, DWORD reason, LPVOID param) trace("dll: %p, DLL_PROCESS_ATTACH, %p\n", hinst, param); ret = pRtlDllShutdownInProgress(); - ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret); + ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret); /* Set up the FLS slot, if FLS is available */ if (pFlsGetValue) @@ -2253,17 +3092,20 @@ static BOOL WINAPI dll_entry_point(HINSTANCE hinst, DWORD reason, LPVOID param) void* value; BOOL bret; ret = pFlsAlloc(&fls_callback); - ok(ret != FLS_OUT_OF_INDEXES, "FlsAlloc returned %d\n", ret); + ok(ret != FLS_OUT_OF_INDEXES, "FlsAlloc returned %ld\n", ret); fls_index = ret; SetLastError(0xdeadbeef); value = pFlsGetValue(fls_index); ok(!value, "FlsGetValue returned %p, expected NULL\n", value); - ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError()); + ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %lu\n", GetLastError()); bret = pFlsSetValue(fls_index, (void*) 0x31415); ok(bret, "FlsSetValue failed\n"); fls_count++; - } + fls_index2 = pFlsAlloc(&fls_callback); + ok(fls_index2 != FLS_OUT_OF_INDEXES, "FlsAlloc returned %ld\n", ret); + } + ++thread_count; break; case DLL_PROCESS_DETACH: { @@ -2290,68 +3132,75 @@ static BOOL WINAPI dll_entry_point(HINSTANCE hinst, DWORD reason, LPVOID param) * doesn't call the DLL entry point on process detach either. */ HeapLock(GetProcessHeap()); + todo_wine ok(0, "dll_entry_point: process should already deadlock\n"); break; } + else if (test_dll_phase == 7) + { + EnterCriticalSection(&cs_lock); + } - if (test_dll_phase == 0 || test_dll_phase == 1 || test_dll_phase == 3) + if (test_dll_phase == 0 || test_dll_phase == 1 || test_dll_phase == 3 || test_dll_phase == 7) ok(param != NULL, "dll: param %p\n", param); else ok(!param, "dll: param %p\n", param); if (test_dll_phase == 0 || test_dll_phase == 1) expected_code = 195; else if (test_dll_phase == 3) expected_code = 196; + else if (test_dll_phase == 7) expected_code = 199; else expected_code = STILL_ACTIVE; - if (test_dll_phase == 3) + ret = pRtlDllShutdownInProgress(); + if (test_dll_phase == 0 || test_dll_phase == 1 || test_dll_phase == 3) { - ret = pRtlDllShutdownInProgress(); - ok(ret, "RtlDllShutdownInProgress returned %d\n", ret); + ok(ret, "RtlDllShutdownInProgress returned %ld\n", ret); } else { - ret = pRtlDllShutdownInProgress(); - /* FIXME: remove once Wine is fixed */ todo_wine_if (!(expected_code == STILL_ACTIVE || expected_code == 196)) - ok(!ret || broken(ret) /* before Vista */, "RtlDllShutdownInProgress returned %d\n", ret); +#ifdef __REACTOS__ + ok(!ret || broken(GetNTVersion() < _WIN32_WINNT_VISTA), "RtlDllShutdownInProgress returned %ld\n", ret); +#else + ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret); +#endif } /* In the case that the process is terminating, FLS slots should still be accessible, but * the callback should be already run for this thread and the contents already NULL. - * Note that this is broken for Win2k3, which runs the callbacks *after* the DLL entry - * point has already run. */ if (param && pFlsGetValue) { void* value; SetLastError(0xdeadbeef); value = pFlsGetValue(fls_index); - todo_wine - { - ok(broken(value == (void*) 0x31415) || /* Win2k3 */ - value == NULL, "FlsGetValue returned %p, expected NULL\n", value); - } - ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError()); - todo_wine - { - ok(broken(fls_callback_count == thread_detach_count) || /* Win2k3 */ - fls_callback_count == thread_detach_count + 1, - "wrong FLS callback count %d, expected %d\n", fls_callback_count, thread_detach_count + 1); - } +#ifdef __REACTOS__ + ok(value == NULL || broken(value == (void*)0x31415) /* WS03 */, "FlsGetValue returned %p, expected NULL\n", value); +#else + ok(value == NULL, "FlsGetValue returned %p, expected NULL\n", value); +#endif + ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %lu\n", GetLastError()); +#ifdef __REACTOS__ + ok(fls_callback_count == thread_detach_count + 1 || broken(GetNTVersion() < _WIN32_WINNT_VISTA), + "wrong FLS callback count %ld, expected %d\n", fls_callback_count, thread_detach_count + 1); +#else + ok(fls_callback_count == thread_detach_count + 1, + "wrong FLS callback count %ld, expected %d\n", fls_callback_count, thread_detach_count + 1); +#endif } if (pFlsFree) { BOOL ret; /* Call FlsFree now and run the remaining callbacks from uncleanly terminated threads */ ret = pFlsFree(fls_index); - ok(ret, "FlsFree failed with error %u\n", GetLastError()); + ok(ret, "FlsFree failed with error %lu\n", GetLastError()); fls_index = FLS_OUT_OF_INDEXES; - todo_wine - { - ok(fls_callback_count == fls_count, - "wrong FLS callback count %d, expected %d\n", fls_callback_count, fls_count); - } +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) +#endif + ok(fls_callback_count == fls_count, + "wrong FLS callback count %ld, expected %d\n", fls_callback_count, fls_count); } ok(attached_thread_count >= 2, "attached thread count should be >= 2\n"); @@ -2364,40 +3213,40 @@ static BOOL WINAPI dll_entry_point(HINSTANCE hinst, DWORD reason, LPVOID param) if (expected_code != STILL_ACTIVE) { ret = WaitForSingleObject(attached_thread[i], 1000); - ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret); + ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#lx\n", ret); } ret = GetExitCodeThread(attached_thread[i], &code); - trace("dll: GetExitCodeThread(%u) => %d,%u\n", i, ret, code); - ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret); - ok(code == expected_code, "expected thread exit code %u, got %u\n", expected_code, code); + trace("dll: GetExitCodeThread(%lu) => %ld,%lu\n", i, ret, code); + ok(ret == 1, "GetExitCodeThread returned %ld, expected 1\n", ret); + ok(code == expected_code, "expected thread exit code %lu, got %lu\n", expected_code, code); } ret = WaitForSingleObject(event, 0); - ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret); + ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret); ret = WaitForSingleObject(mutex, 0); if (expected_code == STILL_ACTIVE) - ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret); + ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret); else - ok(ret == WAIT_ABANDONED, "expected WAIT_ABANDONED, got %#x\n", ret); + ok(ret == WAIT_ABANDONED, "expected WAIT_ABANDONED, got %#lx\n", ret); /* semaphore is not abandoned on thread termination */ ret = WaitForSingleObject(semaphore, 0); - ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret); + ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret); if (expected_code == STILL_ACTIVE) { ret = WaitForSingleObject(attached_thread[0], 0); - ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret); + ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret); ret = WaitForSingleObject(attached_thread[1], 0); - ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret); + ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret); } else { ret = WaitForSingleObject(attached_thread[0], 0); - ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret); + ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#lx\n", ret); ret = WaitForSingleObject(attached_thread[1], 0); - ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret); + ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#lx\n", ret); } /* win7 doesn't allow creating a thread during process shutdown but @@ -2408,56 +3257,68 @@ static BOOL WINAPI dll_entry_point(HINSTANCE hinst, DWORD reason, LPVOID param) handle = CreateThread(NULL, 0, noop_thread_proc, &noop_thread_started, 0, &ret); if (param) { - ok(!handle || broken(handle != 0) /* before win7 */, "CreateThread should fail\n"); +#ifdef __REACTOS__ + ok(!handle || broken(handle != 0) /* Pre-Win7 */, "CreateThread should fail\n"); + if (!handle) - ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError()); else { ret = WaitForSingleObject(handle, 1000); ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret); CloseHandle(handle); } +#else + ok(!handle, "CreateThread should fail\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError()); +#endif } else { - ok(handle != 0, "CreateThread error %d\n", GetLastError()); + ok(handle != 0, "CreateThread error %ld\n", GetLastError()); ret = WaitForSingleObject(handle, 1000); - ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret); - ok(!noop_thread_started || broken(noop_thread_started) /* XP64 */, "thread shouldn't start yet\n"); + ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret); + ok(!noop_thread_started, "thread shouldn't start yet\n"); CloseHandle(handle); } SetLastError(0xdeadbeef); process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, GetCurrentProcessId()); - ok(process != NULL, "OpenProcess error %d\n", GetLastError()); + ok(process != NULL, "OpenProcess error %ld\n", GetLastError()); noop_thread_started = 0; SetLastError(0xdeadbeef); handle = CreateRemoteThread(process, NULL, 0, noop_thread_proc, &noop_thread_started, 0, &ret); if (param) { - ok(!handle || broken(handle != 0) /* before win7 */, "CreateRemoteThread should fail\n"); +#ifdef __REACTOS__ + ok(!handle || broken(handle != 0) /* Pre-Win7 */, "CreateRemoteThread should fail\n"); + if (!handle) - ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError()); else { ret = WaitForSingleObject(handle, 1000); ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret); CloseHandle(handle); } +#else + ok(!handle, "CreateRemoteThread should fail\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError()); +#endif } else { - ok(handle != 0, "CreateRemoteThread error %d\n", GetLastError()); + ok(handle != 0, "CreateRemoteThread error %ld\n", GetLastError()); ret = WaitForSingleObject(handle, 1000); - ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret); - ok(!noop_thread_started || broken(noop_thread_started) /* XP64 */, "thread shouldn't start yet\n"); + ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret); + ok(!noop_thread_started, "thread shouldn't start yet\n"); CloseHandle(handle); } SetLastError(0xdeadbeef); handle = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, NULL); - ok(handle != 0, "CreateFileMapping error %d\n", GetLastError()); + ok(handle != 0, "CreateFileMapping error %ld\n", GetLastError()); offset.u.LowPart = 0; offset.u.HighPart = 0; @@ -2465,9 +3326,9 @@ static BOOL WINAPI dll_entry_point(HINSTANCE hinst, DWORD reason, LPVOID param) size = 0; ret = pNtMapViewOfSection(handle, process, &addr, 0, 0, &offset, &size, 1 /* ViewShare */, 0, PAGE_READONLY); - ok(ret == STATUS_SUCCESS, "NtMapViewOfSection error %#x\n", ret); + ok(ret == STATUS_SUCCESS, "NtMapViewOfSection error %#lx\n", ret); ret = pNtUnmapViewOfSection(process, addr); - ok(ret == STATUS_SUCCESS, "NtUnmapViewOfSection error %#x\n", ret); + ok(ret == STATUS_SUCCESS, "NtUnmapViewOfSection error %#lx\n", ret); CloseHandle(handle); CloseHandle(process); @@ -2476,32 +3337,31 @@ static BOOL WINAPI dll_entry_point(HINSTANCE hinst, DWORD reason, LPVOID param) ok(!handle, "winver.exe shouldn't be loaded yet\n"); SetLastError(0xdeadbeef); handle = LoadLibraryA("winver.exe"); - ok(handle != 0, "LoadLibrary error %d\n", GetLastError()); + ok(handle != 0, "LoadLibrary error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = FreeLibrary(handle); - ok(ret, "FreeLibrary error %d\n", GetLastError()); + ok(ret, "FreeLibrary error %ld\n", GetLastError()); handle = GetModuleHandleA("winver.exe"); if (param) ok(handle != 0, "winver.exe should not be unloaded\n"); else todo_wine - ok(!handle || broken(handle != 0) /* before win7 */, "winver.exe should be unloaded\n"); + ok(!handle, "winver.exe should be unloaded\n"); SetLastError(0xdeadbeef); ret = WaitForDebugEvent(&de, 0); ok(!ret, "WaitForDebugEvent should fail\n"); -todo_wine - ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = DebugActiveProcess(GetCurrentProcessId()); ok(!ret, "DebugActiveProcess should fail\n"); - ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = WaitForDebugEvent(&de, 0); ok(!ret, "WaitForDebugEvent should fail\n"); - ok(GetLastError() == ERROR_SEM_TIMEOUT, "expected ERROR_SEM_TIMEOUT, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_SEM_TIMEOUT, "expected ERROR_SEM_TIMEOUT, got %ld\n", GetLastError()); if (test_dll_phase == 2) { @@ -2515,8 +3375,10 @@ todo_wine case DLL_THREAD_ATTACH: trace("dll: %p, DLL_THREAD_ATTACH, %p\n", hinst, param); + ++thread_count; + ret = pRtlDllShutdownInProgress(); - ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret); + ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret); if (attached_thread_count < MAX_COUNT) { @@ -2533,8 +3395,7 @@ todo_wine SetLastError(0xdeadbeef); value = pFlsGetValue(fls_index); ok(!value, "FlsGetValue returned %p, expected NULL\n", value); - todo_wine - ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError()); + ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %lu\n", GetLastError()); ret = pFlsSetValue(fls_index, (void*) 0x31415); ok(ret, "FlsSetValue failed\n"); fls_count++; @@ -2543,6 +3404,7 @@ todo_wine break; case DLL_THREAD_DETACH: trace("dll: %p, DLL_THREAD_DETACH, %p\n", hinst, param); + --thread_count; thread_detach_count++; ret = pRtlDllShutdownInProgress(); @@ -2551,30 +3413,47 @@ todo_wine * sent on thread exit, but DLL_THREAD_ATTACH is never received. */ if (noop_thread_started) - ok(ret, "RtlDllShutdownInProgress returned %d\n", ret); + ok(ret, "RtlDllShutdownInProgress returned %ld\n", ret); else - ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret); + ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret); /* FLS data should already be destroyed, if FLS is available. - * Note that this is broken for Win2k3, which runs the callbacks *after* the DLL entry - * point has already run. */ if (pFlsGetValue && fls_index != FLS_OUT_OF_INDEXES) { + unsigned int index, count; void* value; + BOOL bret; + SetLastError(0xdeadbeef); value = pFlsGetValue(fls_index); - todo_wine +#ifdef __REACTOS__ + ok(!value || broken(value == (void*)0x31415) /* WS03 */, "FlsGetValue returned %p, expected NULL\n", value); +#else + ok(!value, "FlsGetValue returned %p, expected NULL\n", value); +#endif + ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %lu\n", GetLastError()); + + bret = pFlsSetValue(fls_index2, (void*) 0x31415); + ok(bret, "FlsSetValue failed\n"); + + if (fls_list_head) { - ok(broken(value == (void*) 0x31415) || /* Win2k3 */ - !value, "FlsGetValue returned %p, expected NULL\n", value); + count = check_linked_list(fls_list_head, &NtCurrentTeb()->FlsSlots->fls_list_entry, &index); +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) { +#endif + ok(count <= thread_count, "Got unexpected count %u, thread_count %u.\n", count, thread_count); + ok(index == ~0, "Got unexpected index %u.\n", index); +#ifdef __REACTOS__ + } +#endif } - ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError()); } break; default: - trace("dll: %p, %d, %p\n", hinst, reason, param); + trace("dll: %p, %ld, %p\n", hinst, reason, param); break; } @@ -2583,6 +3462,13 @@ todo_wine return TRUE; } +static void CALLBACK ldr_notify_callback(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context) +{ + /* If some DLL happens to be loaded during process shutdown load notification is called but never unload + * notification. */ + ok(reason == LDR_DLL_NOTIFICATION_REASON_LOADED, "got reason %lu.\n", reason); +} + static void child_process(const char *dll_name, DWORD target_offset) { void *target; @@ -2591,36 +3477,48 @@ static void child_process(const char *dll_name, DWORD target_offset) HMODULE hmod; struct PROCESS_BASIC_INFORMATION_PRIVATE pbi; DWORD_PTR affinity; + void *cookie; - trace("phase %d: writing %p at %#x\n", test_dll_phase, dll_entry_point, target_offset); + trace("phase %d: writing %p at %#lx\n", test_dll_phase, dll_entry_point, target_offset); + + if (pFlsAlloc) + { + fls_list_head = NtCurrentTeb()->Peb->FlsListHead.Flink ? &NtCurrentTeb()->Peb->FlsListHead + : NtCurrentTeb()->FlsSlots->fls_list_entry.Flink; + } SetLastError(0xdeadbeef); mutex = CreateMutexW(NULL, FALSE, NULL); - ok(mutex != 0, "CreateMutex error %d\n", GetLastError()); + ok(mutex != 0, "CreateMutex error %ld\n", GetLastError()); SetLastError(0xdeadbeef); semaphore = CreateSemaphoreW(NULL, 1, 1, NULL); - ok(semaphore != 0, "CreateSemaphore error %d\n", GetLastError()); + ok(semaphore != 0, "CreateSemaphore error %ld\n", GetLastError()); SetLastError(0xdeadbeef); event = CreateEventW(NULL, TRUE, FALSE, NULL); - ok(event != 0, "CreateEvent error %d\n", GetLastError()); + ok(event != 0, "CreateEvent error %ld\n", GetLastError()); SetLastError(0xdeadbeef); loader_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL); - ok(loader_lock_event != 0, "CreateEvent error %d\n", GetLastError()); + ok(loader_lock_event != 0, "CreateEvent error %ld\n", GetLastError()); SetLastError(0xdeadbeef); peb_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL); - ok(peb_lock_event != 0, "CreateEvent error %d\n", GetLastError()); + ok(peb_lock_event != 0, "CreateEvent error %ld\n", GetLastError()); SetLastError(0xdeadbeef); heap_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL); - ok(heap_lock_event != 0, "CreateEvent error %d\n", GetLastError()); + ok(heap_lock_event != 0, "CreateEvent error %ld\n", GetLastError()); + + InitializeCriticalSection(&cs_lock); + SetLastError(0xdeadbeef); + cs_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(cs_lock_event != 0, "CreateEvent error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ack_event = CreateEventW(NULL, FALSE, FALSE, NULL); - ok(ack_event != 0, "CreateEvent error %d\n", GetLastError()); + ok(ack_event != 0, "CreateEvent error %ld\n", GetLastError()); file = CreateFileA(dll_name, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); if (file == INVALID_HANDLE_VALUE) @@ -2632,20 +3530,20 @@ static void child_process(const char *dll_name, DWORD target_offset) SetLastError(0xdeadbeef); target = dll_entry_point; ret = WriteFile(file, &target, sizeof(target), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); CloseHandle(file); SetLastError(0xdeadbeef); hmod = LoadLibraryA(dll_name); - ok(hmod != 0, "LoadLibrary error %d\n", GetLastError()); + ok(hmod != 0, "LoadLibrary error %ld\n", GetLastError()); SetLastError(0xdeadbeef); stop_event = CreateEventW(NULL, TRUE, FALSE, NULL); - ok(stop_event != 0, "CreateEvent error %d\n", GetLastError()); + ok(stop_event != 0, "CreateEvent error %ld\n", GetLastError()); SetLastError(0xdeadbeef); thread = CreateThread(NULL, 0, mutex_thread_proc, event, 0, &dummy); - ok(thread != 0, "CreateThread error %d\n", GetLastError()); + ok(thread != 0, "CreateThread error %ld\n", GetLastError()); WaitForSingleObject(event, 3000); CloseHandle(thread); @@ -2653,7 +3551,7 @@ static void child_process(const char *dll_name, DWORD target_offset) SetLastError(0xdeadbeef); thread = CreateThread(NULL, 0, semaphore_thread_proc, event, 0, &dummy); - ok(thread != 0, "CreateThread error %d\n", GetLastError()); + ok(thread != 0, "CreateThread error %ld\n", GetLastError()); WaitForSingleObject(event, 3000); CloseHandle(thread); @@ -2664,110 +3562,110 @@ static void child_process(const char *dll_name, DWORD target_offset) for (i = 0; i < attached_thread_count; i++) { ret = GetExitCodeThread(attached_thread[i], &code); - trace("child: GetExitCodeThread(%u) => %d,%u\n", i, ret, code); - ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret); - ok(code == STILL_ACTIVE, "expected thread exit code STILL_ACTIVE, got %u\n", code); + trace("child: GetExitCodeThread(%lu) => %ld,%lu\n", i, ret, code); + ok(ret == 1, "GetExitCodeThread returned %ld, expected 1\n", ret); + ok(code == STILL_ACTIVE, "expected thread exit code STILL_ACTIVE, got %lu\n", code); } ret = WaitForSingleObject(attached_thread[0], 0); - ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret); + ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret); ret = WaitForSingleObject(attached_thread[1], 0); - ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret); + ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret); ret = WaitForSingleObject(event, 0); - ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret); + ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret); ret = WaitForSingleObject(mutex, 0); - ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret); + ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret); ret = WaitForSingleObject(semaphore, 0); - ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret); + ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret); ret = pRtlDllShutdownInProgress(); - ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret); + ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret); SetLastError(0xdeadbeef); process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, GetCurrentProcessId()); - ok(process != NULL, "OpenProcess error %d\n", GetLastError()); + ok(process != NULL, "OpenProcess error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = TerminateProcess(0, 195); ok(!ret, "TerminateProcess(0) should fail\n"); - ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError()); Sleep(100); affinity = 1; ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity)); - ok(!ret, "NtSetInformationProcess error %#x\n", ret); + ok(!ret, "NtSetInformationProcess error %#lx\n", ret); switch (test_dll_phase) { case 0: ret = pRtlDllShutdownInProgress(); - ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret); + ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret); trace("call NtTerminateProcess(0, 195)\n"); ret = pNtTerminateProcess(0, 195); - ok(!ret, "NtTerminateProcess error %#x\n", ret); + ok(!ret, "NtTerminateProcess error %#lx\n", ret); memset(&pbi, 0, sizeof(pbi)); ret = pNtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL); - ok(!ret, "NtQueryInformationProcess error %#x\n", ret); + ok(!ret, "NtQueryInformationProcess error %#lx\n", ret); ok(pbi.ExitStatus == STILL_ACTIVE || pbi.ExitStatus == 195, "expected STILL_ACTIVE, got %lu\n", pbi.ExitStatus); affinity = 1; ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity)); - ok(!ret, "NtSetInformationProcess error %#x\n", ret); + ok(!ret, "NtSetInformationProcess error %#lx\n", ret); ret = pRtlDllShutdownInProgress(); - ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret); + ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret); hmod = GetModuleHandleA(dll_name); ok(hmod != 0, "DLL should not be unloaded\n"); +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) { +#endif SetLastError(0xdeadbeef); thread = CreateThread(NULL, 0, noop_thread_proc, &dummy, 0, &ret); - ok(!thread || broken(thread != 0) /* before win7 */, "CreateThread should fail\n"); - if (!thread) - ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); - else - { - ret = WaitForSingleObject(thread, 1000); - ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret); - CloseHandle(thread); + ok(!thread, "CreateThread should fail\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError()); +#ifdef __REACTOS__ } +#endif trace("call LdrShutdownProcess()\n"); + pLdrRegisterDllNotification(0, ldr_notify_callback, NULL, &cookie); pLdrShutdownProcess(); ret = pRtlDllShutdownInProgress(); - ok(ret, "RtlDllShutdownInProgress returned %d\n", ret); + ok(ret, "RtlDllShutdownInProgress returned %ld\n", ret); hmod = GetModuleHandleA(dll_name); ok(hmod != 0, "DLL should not be unloaded\n"); memset(&pbi, 0, sizeof(pbi)); ret = pNtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL); - ok(!ret, "NtQueryInformationProcess error %#x\n", ret); + ok(!ret, "NtQueryInformationProcess error %#lx\n", ret); ok(pbi.ExitStatus == STILL_ACTIVE || pbi.ExitStatus == 195, "expected STILL_ACTIVE, got %lu\n", pbi.ExitStatus); affinity = 1; ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity)); - ok(!ret, "NtSetInformationProcess error %#x\n", ret); + ok(!ret, "NtSetInformationProcess error %#lx\n", ret); break; case 1: /* normal ExitProcess */ ret = pRtlDllShutdownInProgress(); - ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret); + ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret); break; case 2: /* ExitProcess will be called by the PROCESS_DETACH handler */ ret = pRtlDllShutdownInProgress(); - ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret); + ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret); trace("call FreeLibrary(%p)\n", hmod); SetLastError(0xdeadbeef); ret = FreeLibrary(hmod); - ok(ret, "FreeLibrary error %d\n", GetLastError()); + ok(ret, "FreeLibrary error %ld\n", GetLastError()); hmod = GetModuleHandleA(dll_name); ok(!hmod, "DLL should be unloaded\n"); @@ -2775,7 +3673,7 @@ static void child_process(const char *dll_name, DWORD target_offset) ok(0, "FreeLibrary+ExitProcess should never return\n"); ret = pRtlDllShutdownInProgress(); - ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret); + ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret); break; @@ -2793,7 +3691,7 @@ static void child_process(const char *dll_name, DWORD target_offset) /* calling NtTerminateProcess should not cause a deadlock */ trace("call NtTerminateProcess(0, 198)\n"); ret = pNtTerminateProcess(0, 198); - ok(!ret, "NtTerminateProcess error %#x\n", ret); + ok(!ret, "NtTerminateProcess error %#lx\n", ret); *child_failures = winetest_get_failures(); @@ -2834,6 +3732,20 @@ static void child_process(const char *dll_name, DWORD target_offset) ok(0, "ExitProcess should not return\n"); break; + case 7: + trace("setting cs_lock_event\n"); + SetEvent(cs_lock_event); + WaitForSingleObject(ack_event, 1000); + ok(inside_cs_lock != 0, "inside_cs_lock is not set\n"); + + *child_failures = winetest_get_failures(); + + /* calling ExitProcess should not cause a deadlock */ + trace("call ExitProcess(199)\n"); + ExitProcess(199); + ok(0, "ExitProcess should not return\n"); + break; + default: assert(0); break; @@ -2847,24 +3759,24 @@ static void child_process(const char *dll_name, DWORD target_offset) if (expected_code == STILL_ACTIVE) { ret = WaitForSingleObject(attached_thread[0], 100); - ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret); + ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret); ret = WaitForSingleObject(attached_thread[1], 100); - ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret); + ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret); } else { ret = WaitForSingleObject(attached_thread[0], 2000); - ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret); + ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#lx\n", ret); ret = WaitForSingleObject(attached_thread[1], 2000); - ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret); + ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#lx\n", ret); } for (i = 0; i < attached_thread_count; i++) { ret = GetExitCodeThread(attached_thread[i], &code); - trace("child: GetExitCodeThread(%u) => %d,%u\n", i, ret, code); - ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret); - ok(code == expected_code, "expected thread exit code %u, got %u\n", expected_code, code); + trace("child: GetExitCodeThread(%lu) => %ld,%lu\n", i, ret, code); + ok(ret == 1, "GetExitCodeThread returned %ld, expected 1\n", ret); + ok(code == expected_code, "expected thread exit code %lu, got %lu\n", expected_code, code); } *child_failures = winetest_get_failures(); @@ -2875,6 +3787,7 @@ static void child_process(const char *dll_name, DWORD target_offset) static void test_ExitProcess(void) { +#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) #include "pshpack1.h" #ifdef __x86_64__ static struct section_data @@ -2883,13 +3796,20 @@ static void test_ExitProcess(void) void *target; BYTE jmp_rax[2]; } section_data = { { 0x48,0xb8 }, dll_entry_point, { 0xff,0xe0 } }; -#else +#elif defined(__i386__) static struct section_data { BYTE mov_eax; void *target; BYTE jmp_eax[2]; } section_data = { 0xb8, dll_entry_point, { 0xff,0xe0 } }; +#elif defined(__aarch64__) + static struct section_data + { + DWORD ldr; /* ldr x0,target */ + DWORD br; /* br x0 */ + void *target; + } section_data = { 0x58000040, 0xd61f0000, dll_entry_point }; #endif #include "poppack.h" DWORD dummy, file_align; @@ -2908,11 +3828,6 @@ static void test_ExitProcess(void) SIZE_T size; IMAGE_NT_HEADERS nt_header; -#if !defined(__i386__) && !defined(__x86_64__) - skip("x86 specific ExitProcess test\n"); - return; -#endif - if (!pRtlDllShutdownInProgress) { win_skip("RtlDllShutdownInProgress is not available on this platform (XP+)\n"); @@ -2945,13 +3860,9 @@ static void test_ExitProcess(void) SetLastError(0xdeadbeef); ret = WriteFile(file, &dos_header, sizeof(dos_header), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); nt_header = nt_header_template; - nt_header.FileHeader.NumberOfSections = 1; - nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER); - nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL | IMAGE_FILE_RELOCS_STRIPPED; - nt_header.OptionalHeader.AddressOfEntryPoint = 0x1000; nt_header.OptionalHeader.SectionAlignment = 0x1000; nt_header.OptionalHeader.FileAlignment = 0x200; @@ -2959,10 +3870,10 @@ static void test_ExitProcess(void) nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER); SetLastError(0xdeadbeef); ret = WriteFile(file, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = WriteFile(file, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); section.SizeOfRawData = sizeof(section_data); section.PointerToRawData = nt_header.OptionalHeader.FileAlignment; @@ -2971,20 +3882,20 @@ static void test_ExitProcess(void) section.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE; SetLastError(0xdeadbeef); ret = WriteFile(file, §ion, sizeof(section), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); file_align = nt_header.OptionalHeader.FileAlignment - nt_header.OptionalHeader.SizeOfHeaders; assert(file_align < sizeof(filler)); SetLastError(0xdeadbeef); ret = WriteFile(file, filler, file_align, &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); target_offset = SetFilePointer(file, 0, NULL, FILE_CURRENT) + FIELD_OFFSET(struct section_data, target); /* section data */ SetLastError(0xdeadbeef); ret = WriteFile(file, §ion_data, sizeof(section_data), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); CloseHandle(file); @@ -2992,17 +3903,21 @@ static void test_ExitProcess(void) /* phase 0 */ *child_failures = -1; - sprintf(cmdline, "\"%s\" loader %s %u 0", argv[0], dll_name, target_offset); + sprintf(cmdline, "\"%s\" loader %s %lu 0", argv[0], dll_name, target_offset); ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); - ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError()); + ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError()); ret = WaitForSingleObject(pi.hProcess, 10000); ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n"); if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0); GetExitCodeProcess(pi.hProcess, &ret); - ok(ret == 195, "expected exit code 195, got %u\n", ret); +#ifdef __REACTOS__ + ok(ret == 195 || broken(ret == 0xc0000005) /* WS03 */, "expected exit code 195, got %lu\n", ret); +#else + ok(ret == 195, "expected exit code 195, got %lu\n", ret); +#endif if (*child_failures) { - trace("%d failures in child process\n", *child_failures); + trace("%ld failures in child process\n", *child_failures); winetest_add_failures(*child_failures); } CloseHandle(pi.hThread); @@ -3010,17 +3925,17 @@ static void test_ExitProcess(void) /* phase 1 */ *child_failures = -1; - sprintf(cmdline, "\"%s\" loader %s %u 1", argv[0], dll_name, target_offset); + sprintf(cmdline, "\"%s\" loader %s %lu 1", argv[0], dll_name, target_offset); ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); - ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError()); + ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError()); ret = WaitForSingleObject(pi.hProcess, 10000); ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n"); if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0); GetExitCodeProcess(pi.hProcess, &ret); - ok(ret == 195, "expected exit code 195, got %u\n", ret); + ok(ret == 195, "expected exit code 195, got %lu\n", ret); if (*child_failures) { - trace("%d failures in child process\n", *child_failures); + trace("%ld failures in child process\n", *child_failures); winetest_add_failures(*child_failures); } CloseHandle(pi.hThread); @@ -3028,17 +3943,17 @@ static void test_ExitProcess(void) /* phase 2 */ *child_failures = -1; - sprintf(cmdline, "\"%s\" loader %s %u 2", argv[0], dll_name, target_offset); + sprintf(cmdline, "\"%s\" loader %s %lu 2", argv[0], dll_name, target_offset); ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); - ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError()); + ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError()); ret = WaitForSingleObject(pi.hProcess, 10000); ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n"); if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0); GetExitCodeProcess(pi.hProcess, &ret); - ok(ret == 197, "expected exit code 197, got %u\n", ret); + ok(ret == 197, "expected exit code 197, got %lu\n", ret); if (*child_failures) { - trace("%d failures in child process\n", *child_failures); + trace("%ld failures in child process\n", *child_failures); winetest_add_failures(*child_failures); } CloseHandle(pi.hThread); @@ -3046,17 +3961,17 @@ static void test_ExitProcess(void) /* phase 3 */ *child_failures = -1; - sprintf(cmdline, "\"%s\" loader %s %u 3", argv[0], dll_name, target_offset); + sprintf(cmdline, "\"%s\" loader %s %lu 3", argv[0], dll_name, target_offset); ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); - ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError()); + ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError()); ret = WaitForSingleObject(pi.hProcess, 10000); ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n"); if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0); GetExitCodeProcess(pi.hProcess, &ret); - ok(ret == 195, "expected exit code 195, got %u\n", ret); + ok(ret == 195, "expected exit code 195, got %lu\n", ret); if (*child_failures) { - trace("%d failures in child process\n", *child_failures); + trace("%ld failures in child process\n", *child_failures); winetest_add_failures(*child_failures); } CloseHandle(pi.hThread); @@ -3066,17 +3981,17 @@ static void test_ExitProcess(void) if (pLdrLockLoaderLock && pLdrUnlockLoaderLock) { *child_failures = -1; - sprintf(cmdline, "\"%s\" loader %s %u 4", argv[0], dll_name, target_offset); + sprintf(cmdline, "\"%s\" loader %s %lu 4", argv[0], dll_name, target_offset); ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); - ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError()); + ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError()); ret = WaitForSingleObject(pi.hProcess, 10000); ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n"); if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0); GetExitCodeProcess(pi.hProcess, &ret); - ok(ret == 198, "expected exit code 198, got %u\n", ret); + ok(ret == 198, "expected exit code 198, got %lu\n", ret); if (*child_failures) { - trace("%d failures in child process\n", *child_failures); + trace("%ld failures in child process\n", *child_failures); winetest_add_failures(*child_failures); } CloseHandle(pi.hThread); @@ -3089,9 +4004,9 @@ static void test_ExitProcess(void) if (pRtlAcquirePebLock && pRtlReleasePebLock) { *child_failures = -1; - sprintf(cmdline, "\"%s\" loader %s %u 5", argv[0], dll_name, target_offset); + sprintf(cmdline, "\"%s\" loader %s %lu 5", argv[0], dll_name, target_offset); ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); - ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError()); + ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError()); ret = WaitForSingleObject(pi.hProcess, 5000); ok(ret == WAIT_TIMEOUT, "child process should fail to terminate\n"); if (ret != WAIT_OBJECT_0) @@ -3102,10 +4017,10 @@ static void test_ExitProcess(void) ret = WaitForSingleObject(pi.hProcess, 1000); ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n"); GetExitCodeProcess(pi.hProcess, &ret); - ok(ret == 199, "expected exit code 199, got %u\n", ret); + ok(ret == 199, "expected exit code 199, got %lu\n", ret); if (*child_failures) { - trace("%d failures in child process\n", *child_failures); + trace("%ld failures in child process\n", *child_failures); winetest_add_failures(*child_failures); } CloseHandle(pi.hThread); @@ -3116,11 +4031,16 @@ static void test_ExitProcess(void) /* phase 6 */ *child_failures = -1; - sprintf(cmdline, "\"%s\" loader %s %u 6", argv[0], dll_name, target_offset); + sprintf(cmdline, "\"%s\" loader %s %lu 6", argv[0], dll_name, target_offset); ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); - ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError()); + ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError()); ret = WaitForSingleObject(pi.hProcess, 5000); - ok(ret == WAIT_TIMEOUT || broken(ret == WAIT_OBJECT_0) /* XP */, "child process should fail to terminate\n"); + todo_wine +#ifdef __REACTOS__ + ok(ret == WAIT_TIMEOUT || broken(ret == WAIT_OBJECT_0) /* WS03 */, "child process should fail to terminate\n"); +#else + ok(ret == WAIT_TIMEOUT, "child process should fail to terminate\n"); +#endif if (ret != WAIT_OBJECT_0) { trace("terminating child process\n"); @@ -3129,10 +4049,39 @@ static void test_ExitProcess(void) ret = WaitForSingleObject(pi.hProcess, 1000); ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n"); GetExitCodeProcess(pi.hProcess, &ret); - ok(ret == 201 || broken(ret == 1) /* XP */, "expected exit code 201, got %u\n", ret); + todo_wine +#ifdef __REACTOS__ + ok(ret == 201 || broken(ret == 1) /* WS03 */, "expected exit code 201, got %lu\n", ret); +#else + ok(ret == 201, "expected exit code 201, got %lu\n", ret); +#endif if (*child_failures) { - trace("%d failures in child process\n", *child_failures); + trace("%ld failures in child process\n", *child_failures); + winetest_add_failures(*child_failures); + } + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + + /* phase 7 */ + *child_failures = -1; + sprintf(cmdline, "\"%s\" loader %s %lu 7", argv[0], dll_name, target_offset); + ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError()); + ret = WaitForSingleObject(pi.hProcess, 5000); + ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n"); + if (ret != WAIT_OBJECT_0) + { + trace("terminating child process\n"); + TerminateProcess(pi.hProcess, 199); + } + ret = WaitForSingleObject(pi.hProcess, 1000); + ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n"); + GetExitCodeProcess(pi.hProcess, &ret); + ok(ret == 199, "expected exit code 199, got %lu\n", ret); + if (*child_failures) + { + trace("%ld failures in child process\n", *child_failures); winetest_add_failures(*child_failures); } CloseHandle(pi.hThread); @@ -3141,32 +4090,32 @@ static void test_ExitProcess(void) /* test remote process termination */ SetLastError(0xdeadbeef); ret = CreateProcessA(argv[0], NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi); - ok(ret, "CreateProcess(%s) error %d\n", argv[0], GetLastError()); + ok(ret, "CreateProcess(%s) error %ld\n", argv[0], GetLastError()); SetLastError(0xdeadbeef); addr = VirtualAllocEx(pi.hProcess, NULL, 4096, MEM_COMMIT, PAGE_READWRITE); - ok(addr != NULL, "VirtualAllocEx error %d\n", GetLastError()); + ok(addr != NULL, "VirtualAllocEx error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = VirtualProtectEx(pi.hProcess, addr, 4096, PAGE_READONLY, &old_prot); - ok(ret, "VirtualProtectEx error %d\n", GetLastError()); - ok(old_prot == PAGE_READWRITE, "expected PAGE_READWRITE, got %#x\n", old_prot); + ok(ret, "VirtualProtectEx error %ld\n", GetLastError()); + ok(old_prot == PAGE_READWRITE, "expected PAGE_READWRITE, got %#lx\n", old_prot); SetLastError(0xdeadbeef); size = VirtualQueryEx(pi.hProcess, NULL, &mbi, sizeof(mbi)); - ok(size == sizeof(mbi), "VirtualQueryEx error %d\n", GetLastError()); + ok(size == sizeof(mbi), "VirtualQueryEx error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = ReadProcessMemory(pi.hProcess, addr, buf, 4, &size); - ok(ret, "ReadProcessMemory error %d\n", GetLastError()); - ok(size == 4, "expected 4, got %lu\n", size); + ok(ret, "ReadProcessMemory error %ld\n", GetLastError()); + ok(size == 4, "expected 4, got %Iu\n", size); SetLastError(0xdeadbeef); hmap = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, NULL); - ok(hmap != 0, "CreateFileMapping error %d\n", GetLastError()); + ok(hmap != 0, "CreateFileMapping error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = DuplicateHandle(GetCurrentProcess(), hmap, pi.hProcess, &hmap_dup, 0, FALSE, DUPLICATE_SAME_ACCESS); - ok(ret, "DuplicateHandle error %d\n", GetLastError()); + ok(ret, "DuplicateHandle error %ld\n", GetLastError()); offset.u.LowPart = 0; offset.u.HighPart = 0; @@ -3174,122 +4123,122 @@ static void test_ExitProcess(void) size = 0; ret = pNtMapViewOfSection(hmap, pi.hProcess, &addr, 0, 0, &offset, &size, 1 /* ViewShare */, 0, PAGE_READONLY); - ok(!ret, "NtMapViewOfSection error %#x\n", ret); + ok(!ret, "NtMapViewOfSection error %#lx\n", ret); ret = pNtUnmapViewOfSection(pi.hProcess, addr); - ok(!ret, "NtUnmapViewOfSection error %#x\n", ret); + ok(!ret, "NtUnmapViewOfSection error %#lx\n", ret); SetLastError(0xdeadbeef); thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret); - ok(thread != 0, "CreateRemoteThread error %d\n", GetLastError()); + ok(thread != 0, "CreateRemoteThread error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ctx.ContextFlags = CONTEXT_INTEGER; ret = GetThreadContext(thread, &ctx); - ok(ret, "GetThreadContext error %d\n", GetLastError()); + ok(ret, "GetThreadContext error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ctx.ContextFlags = CONTEXT_INTEGER; ret = SetThreadContext(thread, &ctx); - ok(ret, "SetThreadContext error %d\n", GetLastError()); + ok(ret, "SetThreadContext error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = SetThreadPriority(thread, 0); - ok(ret, "SetThreadPriority error %d\n", GetLastError()); + ok(ret, "SetThreadPriority error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = TerminateThread(thread, 199); - ok(ret, "TerminateThread error %d\n", GetLastError()); + ok(ret, "TerminateThread error %ld\n", GetLastError()); /* Calling GetExitCodeThread() without waiting for thread termination * leads to different results due to a race condition. */ ret = WaitForSingleObject(thread, 1000); - ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %x\n", ret); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %lx\n", ret); GetExitCodeThread(thread, &ret); - ok(ret == 199, "expected exit code 199, got %u\n", ret); + ok(ret == 199, "expected exit code 199, got %lu\n", ret); SetLastError(0xdeadbeef); ret = TerminateProcess(pi.hProcess, 198); - ok(ret, "TerminateProcess error %d\n", GetLastError()); + ok(ret, "TerminateProcess error %ld\n", GetLastError()); /* Checking process state without waiting for process termination * leads to different results due to a race condition. */ ret = WaitForSingleObject(pi.hProcess, 1000); - ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %x\n", ret); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %lx\n", ret); SetLastError(0xdeadbeef); process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, pi.dwProcessId); - ok(process != NULL, "OpenProcess error %d\n", GetLastError()); + ok(process != NULL, "OpenProcess error %ld\n", GetLastError()); CloseHandle(process); memset(&pbi, 0, sizeof(pbi)); ret = pNtQueryInformationProcess(pi.hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL); - ok(!ret, "NtQueryInformationProcess error %#x\n", ret); + ok(!ret, "NtQueryInformationProcess error %#lx\n", ret); ok(pbi.ExitStatus == 198, "expected 198, got %lu\n", pbi.ExitStatus); affinity = 1; ret = pNtSetInformationProcess(pi.hProcess, ProcessAffinityMask, &affinity, sizeof(affinity)); - ok(ret == STATUS_PROCESS_IS_TERMINATING, "expected STATUS_PROCESS_IS_TERMINATING, got %#x\n", ret); + ok(ret == STATUS_PROCESS_IS_TERMINATING, "expected STATUS_PROCESS_IS_TERMINATING, got %#lx\n", ret); SetLastError(0xdeadbeef); ctx.ContextFlags = CONTEXT_INTEGER; ret = GetThreadContext(thread, &ctx); - ok(!ret || broken(ret) /* XP 64-bit */, "GetThreadContext should fail\n"); - if (!ret) - ok(GetLastError() == ERROR_INVALID_PARAMETER || - GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ || - GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */, - "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + ok(!ret, "GetThreadContext should fail\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER || + GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ || + GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */ || + GetLastError() == ERROR_ACCESS_DENIED /* Win10 32-bit */, + "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ctx.ContextFlags = CONTEXT_INTEGER; ret = SetThreadContext(thread, &ctx); - ok(!ret || broken(ret) /* XP 64-bit */, "SetThreadContext should fail\n"); - if (!ret) - ok(GetLastError() == ERROR_ACCESS_DENIED || - GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ || - GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */, - "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + ok(!ret, "SetThreadContext should fail\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED || + GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ || + GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */, + "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = SetThreadPriority(thread, 0); - ok(ret, "SetThreadPriority error %d\n", GetLastError()); + ok(ret, "SetThreadPriority error %ld\n", GetLastError()); CloseHandle(thread); + ret = WaitForSingleObject(pi.hThread, 1000); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %lx\n", ret); SetLastError(0xdeadbeef); ctx.ContextFlags = CONTEXT_INTEGER; ret = GetThreadContext(pi.hThread, &ctx); - ok(!ret || broken(ret) /* XP 64-bit */, "GetThreadContext should fail\n"); - if (!ret) - ok(GetLastError() == ERROR_INVALID_PARAMETER || - GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ || - GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */, - "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + ok(!ret, "GetThreadContext should fail\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER || + GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ || + GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */ || + GetLastError() == ERROR_ACCESS_DENIED /* Win10 32-bit */, + "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ctx.ContextFlags = CONTEXT_INTEGER; ret = SetThreadContext(pi.hThread, &ctx); - ok(!ret || broken(ret) /* XP 64-bit */, "SetThreadContext should fail\n"); - if (!ret) - ok(GetLastError() == ERROR_ACCESS_DENIED || - GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ || - GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */, - "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + ok(!ret, "SetThreadContext should fail\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED || + GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ || + GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */, + "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = VirtualProtectEx(pi.hProcess, addr, 4096, PAGE_READWRITE, &old_prot); ok(!ret, "VirtualProtectEx should fail\n"); - ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); size = 0; ret = ReadProcessMemory(pi.hProcess, addr, buf, 4, &size); ok(!ret, "ReadProcessMemory should fail\n"); ok(GetLastError() == ERROR_PARTIAL_COPY || GetLastError() == ERROR_ACCESS_DENIED, - "expected ERROR_PARTIAL_COPY, got %d\n", GetLastError()); - ok(!size, "expected 0, got %lu\n", size); + "expected ERROR_PARTIAL_COPY, got %ld\n", GetLastError()); + ok(!size, "expected 0, got %Iu\n", size); SetLastError(0xdeadbeef); ret = VirtualFreeEx(pi.hProcess, addr, 0, MEM_RELEASE); ok(!ret, "VirtualFreeEx should fail\n"); - ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); addr = VirtualAllocEx(pi.hProcess, NULL, 4096, MEM_COMMIT, PAGE_READWRITE); ok(!addr, "VirtualAllocEx should fail\n"); - ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); size = VirtualQueryEx(pi.hProcess, NULL, &mbi, sizeof(mbi)); ok(!size, "VirtualQueryEx should fail\n"); - ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError()); /* CloseHandle() call below leads to premature process termination * under some Windows versions. @@ -3305,7 +4254,7 @@ if (0) ret = DuplicateHandle(GetCurrentProcess(), hmap, pi.hProcess, &hmap_dup, 0, FALSE, DUPLICATE_SAME_ACCESS); ok(!ret, "DuplicateHandle should fail\n"); - ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError()); offset.u.LowPart = 0; offset.u.HighPart = 0; @@ -3313,57 +4262,59 @@ if (0) size = 0; ret = pNtMapViewOfSection(hmap, pi.hProcess, &addr, 0, 0, &offset, &size, 1 /* ViewShare */, 0, PAGE_READONLY); - ok(ret == STATUS_PROCESS_IS_TERMINATING, "expected STATUS_PROCESS_IS_TERMINATING, got %#x\n", ret); + ok(ret == STATUS_PROCESS_IS_TERMINATING, "expected STATUS_PROCESS_IS_TERMINATING, got %#lx\n", ret); SetLastError(0xdeadbeef); thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret); ok(!thread, "CreateRemoteThread should fail\n"); - ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = DebugActiveProcess(pi.dwProcessId); ok(!ret, "DebugActiveProcess should fail\n"); ok(GetLastError() == ERROR_ACCESS_DENIED /* 64-bit */ || GetLastError() == ERROR_NOT_SUPPORTED /* 32-bit */, - "ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + "ERROR_ACCESS_DENIED, got %ld\n", GetLastError()); GetExitCodeProcess(pi.hProcess, &ret); - ok(ret == 198 || broken(ret != 198) /* some 32-bit XP version in a VM returns random exit code */, - "expected exit code 198, got %u\n", ret); + ok(ret == 198, "expected exit code 198, got %lu\n", ret); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); ret = DeleteFileA(dll_name); - ok(ret, "DeleteFile error %d\n", GetLastError()); + ok(ret, "DeleteFile error %ld\n", GetLastError()); +#else + skip("x86 specific ExitProcess test\n"); +#endif } static PVOID WINAPI failuredllhook(ULONG ul, DELAYLOAD_INFO* pd) { - ok(ul == 4, "expected 4, got %u\n", ul); + ok(ul == 4, "expected 4, got %lu\n", ul); ok(!!pd, "no delayload info supplied\n"); if (pd) { - ok(pd->Size == sizeof(*pd), "got %u\n", pd->Size); + ok(pd->Size == sizeof(*pd), "got %lu\n", pd->Size); ok(!!pd->DelayloadDescriptor, "no DelayloadDescriptor supplied\n"); if (pd->DelayloadDescriptor) { ok(pd->DelayloadDescriptor->Attributes.AllAttributes == 1, - "expected 1, got %u\n", pd->DelayloadDescriptor->Attributes.AllAttributes); + "expected 1, got %lu\n", pd->DelayloadDescriptor->Attributes.AllAttributes); ok(pd->DelayloadDescriptor->DllNameRVA == 0x2000, - "expected 0x2000, got %x\n", pd->DelayloadDescriptor->DllNameRVA); + "expected 0x2000, got %lx\n", pd->DelayloadDescriptor->DllNameRVA); ok(pd->DelayloadDescriptor->ModuleHandleRVA == 0x201a, - "expected 0x201a, got %x\n", pd->DelayloadDescriptor->ModuleHandleRVA); + "expected 0x201a, got %lx\n", pd->DelayloadDescriptor->ModuleHandleRVA); ok(pd->DelayloadDescriptor->ImportAddressTableRVA > pd->DelayloadDescriptor->ModuleHandleRVA, - "expected %x > %x\n", pd->DelayloadDescriptor->ImportAddressTableRVA, + "expected %lx > %lx\n", pd->DelayloadDescriptor->ImportAddressTableRVA, pd->DelayloadDescriptor->ModuleHandleRVA); ok(pd->DelayloadDescriptor->ImportNameTableRVA > pd->DelayloadDescriptor->ImportAddressTableRVA, - "expected %x > %x\n", pd->DelayloadDescriptor->ImportNameTableRVA, + "expected %lx > %lx\n", pd->DelayloadDescriptor->ImportNameTableRVA, pd->DelayloadDescriptor->ImportAddressTableRVA); ok(pd->DelayloadDescriptor->BoundImportAddressTableRVA == 0, - "expected 0, got %x\n", pd->DelayloadDescriptor->BoundImportAddressTableRVA); + "expected 0, got %lx\n", pd->DelayloadDescriptor->BoundImportAddressTableRVA); ok(pd->DelayloadDescriptor->UnloadInformationTableRVA == 0, - "expected 0, got %x\n", pd->DelayloadDescriptor->UnloadInformationTableRVA); + "expected 0, got %lx\n", pd->DelayloadDescriptor->UnloadInformationTableRVA); ok(pd->DelayloadDescriptor->TimeDateStamp == 0, - "expected 0, got %x\n", pd->DelayloadDescriptor->TimeDateStamp); + "expected 0, got %lx\n", pd->DelayloadDescriptor->TimeDateStamp); } ok(!!pd->ThunkAddress, "no ThunkAddress supplied\n"); @@ -3376,10 +4327,10 @@ static PVOID WINAPI failuredllhook(ULONG ul, DELAYLOAD_INFO* pd) "expected \"secur32.dll\", got \"%s\"\n", pd->TargetDllName); ok(pd->TargetApiDescriptor.ImportDescribedByName == 0, - "expected 0, got %x\n", pd->TargetApiDescriptor.ImportDescribedByName); + "expected 0, got %lx\n", pd->TargetApiDescriptor.ImportDescribedByName); ok(pd->TargetApiDescriptor.Description.Ordinal == 0 || pd->TargetApiDescriptor.Description.Ordinal == 999, - "expected 0, got %x\n", pd->TargetApiDescriptor.Description.Ordinal); + "expected 0, got %lx\n", pd->TargetApiDescriptor.Description.Ordinal); ok(!!pd->TargetModuleBase, "no TargetModuleBase supplied\n"); ok(pd->Unused == NULL, "expected NULL, got %p\n", pd->Unused); @@ -3389,6 +4340,14 @@ static PVOID WINAPI failuredllhook(ULONG ul, DELAYLOAD_INFO* pd) return (void*)0xdeadbeef; } +static PVOID WINAPI failuresyshook(const char *dll, const char *function) +{ + ok(!strcmp(dll, "secur32.dll"), "wrong dll: %s\n", dll); + ok(!((ULONG_PTR)function >> 16), "expected ordinal, got %p\n", function); + cb_count_sys++; + return (void*)0x12345678; +} + static void test_ResolveDelayLoadedAPI(void) { static const char test_dll[] = "secur32.dll"; @@ -3439,13 +4398,13 @@ static void test_ResolveDelayLoadedAPI(void) SetLastError(0xdeadbeef); ok(!pResolveDelayLoadedAPI(NULL, NULL, NULL, NULL, NULL, 0), "ResolveDelayLoadedAPI succeeded\n"); - ok(GetLastError() == 0xdeadbeef, "GetLastError changed to %x\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "GetLastError changed to %lx\n", GetLastError()); cb_count = 0; SetLastError(0xdeadbeef); ok(!pResolveDelayLoadedAPI(NULL, NULL, failuredllhook, NULL, NULL, 0), "ResolveDelayLoadedAPI succeeded\n"); - ok(GetLastError() == 0xdeadbeef, "GetLastError changed to %x\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "GetLastError changed to %lx\n", GetLastError()); ok(cb_count == 1, "Wrong callback count: %d\n", cb_count); } @@ -3461,7 +4420,7 @@ static void test_ResolveDelayLoadedAPI(void) SetLastError(0xdeadbeef); ret = WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); nt_header = nt_header_template; nt_header.FileHeader.NumberOfSections = 2; @@ -3473,37 +4432,37 @@ static void test_ResolveDelayLoadedAPI(void) nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + 2 * sizeof(IMAGE_SECTION_HEADER); nt_header.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES; nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress = 0x1000; - nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size = 0x100; + nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size = 2 * sizeof(idd); SetLastError(0xdeadbeef); ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = WriteFile(hfile, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); /* sections */ section.PointerToRawData = nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress; section.VirtualAddress = nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress; - section.Misc.VirtualSize = 2 * sizeof(idd); - section.SizeOfRawData = section.Misc.VirtualSize; + section.Misc.VirtualSize = 0x1000; + section.SizeOfRawData = 2 * sizeof(idd); section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; SetLastError(0xdeadbeef); ret = WriteFile(hfile, §ion, sizeof(section), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); section.PointerToRawData = 0x2000; section.VirtualAddress = 0x2000; - i = sizeof(td)/sizeof(td[0]); - section.Misc.VirtualSize = sizeof(test_dll) + sizeof(hint) + sizeof(test_func) + sizeof(HMODULE) + + i = ARRAY_SIZE(td); + section.SizeOfRawData = sizeof(test_dll) + sizeof(hint) + sizeof(test_func) + sizeof(HMODULE) + 2 * (i + 1) * sizeof(IMAGE_THUNK_DATA); - ok(section.Misc.VirtualSize <= 0x1000, "Too much tests, add a new section!\n"); - section.SizeOfRawData = section.Misc.VirtualSize; + ok(section.SizeOfRawData <= 0x1000, "Too much tests, add a new section!\n"); + section.Misc.VirtualSize = 0x1000; section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; SetLastError(0xdeadbeef); ret = WriteFile(hfile, §ion, sizeof(section), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); /* fill up to delay data */ SetFilePointer( hfile, nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress, NULL, SEEK_SET ); @@ -3520,11 +4479,11 @@ static void test_ResolveDelayLoadedAPI(void) SetLastError(0xdeadbeef); ret = WriteFile(hfile, &idd, sizeof(idd), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = WriteFile(hfile, filler, sizeof(idd), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); /* fill up to extended delay data */ SetFilePointer( hfile, idd.DllNameRVA, NULL, SEEK_SET ); @@ -3532,33 +4491,33 @@ static void test_ResolveDelayLoadedAPI(void) /* extended delay data */ SetLastError(0xdeadbeef); ret = WriteFile(hfile, test_dll, sizeof(test_dll), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = WriteFile(hfile, &hint, sizeof(hint), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = WriteFile(hfile, test_func, sizeof(test_func), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); SetFilePointer( hfile, idd.ImportAddressTableRVA, NULL, SEEK_SET ); - for (i = 0; i < sizeof(td)/sizeof(td[0]); i++) + for (i = 0; i < ARRAY_SIZE(td); i++) { /* 0x1a00 is an empty space between delay data and extended delay data, real thunks are not necessary */ itd32.u1.Function = nt_header.OptionalHeader.ImageBase + 0x1a00 + i * 0x20; SetLastError(0xdeadbeef); ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); } itd32.u1.Function = 0; SetLastError(0xdeadbeef); ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); - for (i = 0; i < sizeof(td)/sizeof(td[0]); i++) + for (i = 0; i < ARRAY_SIZE(td); i++) { if (td[i].func) itd32.u1.AddressOfData = idd.DllNameRVA + sizeof(test_dll); @@ -3566,13 +4525,13 @@ static void test_ResolveDelayLoadedAPI(void) itd32.u1.Ordinal = td[i].ordinal; SetLastError(0xdeadbeef); ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); } itd32.u1.Ordinal = 0; SetLastError(0xdeadbeef); ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL); - ok(ret, "WriteFile error %d\n", GetLastError()); + ok(ret, "WriteFile error %ld\n", GetLastError()); /* fill up to eof */ SetFilePointer( hfile, section.VirtualAddress + section.Misc.VirtualSize, NULL, SEEK_SET ); @@ -3581,7 +4540,7 @@ static void test_ResolveDelayLoadedAPI(void) SetLastError(0xdeadbeef); hlib = LoadLibraryA(dll_name); - ok(hlib != NULL, "LoadLibrary error %u\n", GetLastError()); + ok(hlib != NULL, "LoadLibrary error %lu\n", GetLastError()); if (!hlib) { skip("couldn't load %s.\n", dll_name); @@ -3611,10 +4570,13 @@ static void test_ResolveDelayLoadedAPI(void) itda = RVAToAddr(delaydir->ImportAddressTableRVA, hlib); htarget = LoadLibraryA(RVAToAddr(delaydir->DllNameRVA, hlib)); - for (i = 0; i < sizeof(td)/sizeof(td[0]); i++) + for (i = 0; i < ARRAY_SIZE(td); i++) { void *ret, *load; + /* relocate thunk address by hand since we don't generate reloc records */ + itda[i].u1.AddressOfData += (char *)hlib - (char *)nt_header.OptionalHeader.ImageBase; + if (IMAGE_SNAP_BY_ORDINAL(itdn[i].u1.Ordinal)) load = (void *)GetProcAddress(htarget, (LPSTR)IMAGE_ORDINAL(itdn[i].u1.Ordinal)); else @@ -3623,20 +4585,52 @@ static void test_ResolveDelayLoadedAPI(void) load = (void *)GetProcAddress(htarget, (char*)iibn->Name); } - cb_count = 0; - ret = pResolveDelayLoadedAPI(hlib, delaydir, failuredllhook, NULL, &itda[i], 0); + /* test without failure dll callback */ + cb_count = cb_count_sys = 0; + ret = pResolveDelayLoadedAPI(hlib, delaydir, NULL, failuresyshook, &itda[i], 0); if (td[i].succeeds) { - ok(ret != NULL, "Test %u: ResolveDelayLoadedAPI failed\n", i); - ok(ret == load, "Test %u: expected %p, got %p\n", i, load, ret); - ok(ret == (void*)itda[i].u1.AddressOfData, "Test %u: expected %p, got %p\n", + ok(ret != NULL, "Test %lu: ResolveDelayLoadedAPI failed\n", i); + ok(ret == load, "Test %lu: expected %p, got %p\n", i, load, ret); + ok(ret == (void*)itda[i].u1.AddressOfData, "Test %lu: expected %p, got %p\n", i, ret, (void*)itda[i].u1.AddressOfData); - ok(!cb_count, "Test %u: Wrong callback count: %d\n", i, cb_count); + ok(!cb_count, "Test %lu: Wrong callback count: %d\n", i, cb_count); + ok(!cb_count_sys, "Test %lu: Wrong sys callback count: %d\n", i, cb_count_sys); } else { - ok(ret == (void*)0xdeadbeef, "Test %u: ResolveDelayLoadedAPI succeeded with %p\n", i, ret); - ok(cb_count, "Test %u: Wrong callback count: %d\n", i, cb_count); + ok(ret == (void*)0x12345678, "Test %lu: ResolveDelayLoadedAPI succeeded with %p\n", i, ret); + ok(!cb_count, "Test %lu: Wrong callback count: %d\n", i, cb_count); + ok(cb_count_sys == 1, "Test %lu: Wrong sys callback count: %d\n", i, cb_count_sys); + } + + /* test with failure dll callback */ + cb_count = cb_count_sys = 0; + ret = pResolveDelayLoadedAPI(hlib, delaydir, failuredllhook, failuresyshook, &itda[i], 0); + if (td[i].succeeds) + { + ok(ret != NULL, "Test %lu: ResolveDelayLoadedAPI failed\n", i); + ok(ret == load, "Test %lu: expected %p, got %p\n", i, load, ret); + ok(ret == (void*)itda[i].u1.AddressOfData, "Test %lu: expected %p, got %p\n", + i, ret, (void*)itda[i].u1.AddressOfData); + ok(!cb_count, "Test %lu: Wrong callback count: %d\n", i, cb_count); + ok(!cb_count_sys, "Test %lu: Wrong sys callback count: %d\n", i, cb_count_sys); + } + else + { + if (ret == (void*)0x12345678) + { + /* Win10+ sometimes buffers the address of the stub function */ + ok(!cb_count, "Test %lu: Wrong callback count: %d\n", i, cb_count); + ok(!cb_count_sys, "Test %lu: Wrong sys callback count: %d\n", i, cb_count_sys); + } + else if (ret == (void*)0xdeadbeef) + { + ok(cb_count == 1, "Test %lu: Wrong callback count: %d\n", i, cb_count); + ok(!cb_count_sys, "Test %lu: Wrong sys callback count: %d\n", i, cb_count_sys); + } + else + ok(0, "Test %lu: ResolveDelayLoadedAPI succeeded with %p\n", i, ret); } } delaydir++; @@ -3668,77 +4662,158 @@ static void test_InMemoryOrderModuleList(void) ok(entry2 == mark2, "expected entry2 == mark2, got %p and %p\n", entry2, mark2); } -static inline WCHAR toupperW(WCHAR c) +static BOOL is_path_made_of(const char *filename, const char *pfx, const char *sfx) { - WCHAR tmp = c; - CharUpperBuffW(&tmp, 1); - return tmp; + const size_t len = strlen(pfx); + return !strncasecmp(filename, pfx, len) && filename[len] == '\\' && + !strcasecmp(filename + len + 1, sfx); } -static ULONG hash_basename(const WCHAR *basename) +static void test_wow64_redirection_for_dll(const char *libname, BOOL will_fail) { - WORD version = MAKEWORD(NtCurrentTeb()->Peb->OSMinorVersion, - NtCurrentTeb()->Peb->OSMajorVersion); - ULONG hash = 0; + HMODULE lib; + char buf[256]; + const char *modname; - if (version >= 0x0602) + if (!GetModuleHandleA(libname)) { - for (; *basename; basename++) - hash = hash * 65599 + toupperW(*basename); - } - else if (version == 0x0601) - { - for (; *basename; basename++) - hash = hash + 65599 * toupperW(*basename); + lib = LoadLibraryExA(libname, NULL, 0); + ok(lib != NULL, "Loading %s should succeed with WOW64 redirection disabled\n", libname); + /* Win 7/2008R2 return the un-redirected path (i.e. c:\windows\system32\dwrite.dll), test loading it. */ + GetModuleFileNameA(lib, buf, sizeof(buf)); + FreeLibrary(lib); + lib = LoadLibraryExA(buf, NULL, 0); + ok(lib != NULL, "Loading %s from full path should succeed with WOW64 redirection disabled\n", libname); + if (lib) + FreeLibrary(lib); + modname = strrchr(libname, '\\'); + modname = modname ? modname + 1 : libname; + todo_wine_if(will_fail) + ok(is_path_made_of(buf, system_dir, modname) || + /* Win7 report from syswow64 */ broken(is_path_made_of(buf, syswow_dir, modname)), + "Unexpected loaded DLL name %s for %s\n", buf, libname); } else - hash = toupperW(basename[0]) - 'A'; - - return hash & 31; + { + skip("%s was already loaded in the process\n", libname); + } } -static void test_HashLinks(void) +static void test_wow64_redirection(void) { - static WCHAR ntdllW[] = {'n','t','d','l','l','.','d','l','l',0}; - static WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0}; + void *OldValue; + char buffer[MAX_PATH]; + static const char *dlls[] = {"wlanapi.dll", "dxgi.dll", "dwrite.dll"}; + unsigned i; - LIST_ENTRY *hash_map, *entry, *mark; - LDR_DATA_TABLE_ENTRY *module; - BOOL found; + if (!is_wow64) + return; - entry = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList; - entry = entry->Flink; - - module = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); - entry = module->HashLinks.Blink; - - hash_map = entry - hash_basename(module->BaseDllName.Buffer); - - mark = &hash_map[hash_basename(ntdllW)]; - found = FALSE; - for (entry = mark->Flink; entry != mark; entry = entry->Flink) + /* Disable FS redirection, then test loading system libraries (pick ones that shouldn't + * already be loaded in this process). + */ + ok(pWow64DisableWow64FsRedirection(&OldValue), "Disabling FS redirection failed\n"); + for (i = 0; i < ARRAY_SIZE(dlls); i++) { - module = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, HashLinks); - if (!lstrcmpiW(module->BaseDllName.Buffer, ntdllW)) - { - found = TRUE; - break; - } + test_wow64_redirection_for_dll(dlls[i], FALSE); + /* even absolute paths to syswow64 are loaded with path to system32 */ + snprintf(buffer, ARRAY_SIZE(buffer), "%s\\%s", syswow_dir, dlls[i]); + test_wow64_redirection_for_dll(buffer, TRUE); } - ok(found, "Could not find ntdll\n"); - mark = &hash_map[hash_basename(kernel32W)]; - found = FALSE; - for (entry = mark->Flink; entry != mark; entry = entry->Flink) + ok(pWow64RevertWow64FsRedirection(OldValue), "Re-enabling FS redirection failed\n"); + /* and results don't depend whether redirection is enabled or not */ + for (i = 0; i < ARRAY_SIZE(dlls); i++) { - module = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, HashLinks); - if (!lstrcmpiW(module->BaseDllName.Buffer, kernel32W)) - { - found = TRUE; - break; - } + test_wow64_redirection_for_dll(dlls[i], FALSE); + snprintf(buffer, ARRAY_SIZE(buffer), "%s\\%s", syswow_dir, dlls[i]); + test_wow64_redirection_for_dll(buffer, TRUE); } - ok(found, "Could not find kernel32\n"); +} + +static void test_dll_file( const char *name ) +{ + HMODULE module = GetModuleHandleA( name ); + IMAGE_NT_HEADERS *nt, *nt_file; + IMAGE_SECTION_HEADER *sec, *sec_file; + char path[MAX_PATH]; + HANDLE file, mapping; + int i = 0; + void *ptr; + + GetModuleFileNameA( module, path, MAX_PATH ); + file = CreateFileA( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); + ok( file != INVALID_HANDLE_VALUE, "can't open '%s': %lu\n", path, GetLastError() ); + + mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 0, NULL ); + ok( mapping != NULL, "%s: CreateFileMappingW failed err %lu\n", name, GetLastError() ); + ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 ); + ok( ptr != NULL, "%s: MapViewOfFile failed err %lu\n", name, GetLastError() ); + CloseHandle( mapping ); + CloseHandle( file ); + + nt = pRtlImageNtHeader( module ); + nt_file = pRtlImageNtHeader( ptr ); + ok( nt_file != NULL, "%s: invalid header\n", path ); +#define OK_FIELD(x, f) ok( nt->x == nt_file->x, "%s:%u: wrong " #x " " f " / " f "\n", name, i, nt->x, nt_file->x ) + OK_FIELD( FileHeader.NumberOfSections, "%x" ); + OK_FIELD( OptionalHeader.AddressOfEntryPoint, "%lx" ); + OK_FIELD( OptionalHeader.NumberOfRvaAndSizes, "%lx" ); + for (i = 0; i < nt->OptionalHeader.NumberOfRvaAndSizes; i++) + { + OK_FIELD( OptionalHeader.DataDirectory[i].VirtualAddress, "%lx" ); + OK_FIELD( OptionalHeader.DataDirectory[i].Size, "%lx" ); + } + sec = IMAGE_FIRST_SECTION( nt ); + sec_file = IMAGE_FIRST_SECTION( nt_file ); + for (i = 0; i < nt->FileHeader.NumberOfSections; i++) + ok( !memcmp( sec + i, sec_file + i, sizeof(*sec) ), "%s: wrong section %d\n", name, i ); + UnmapViewOfFile( ptr ); +#undef OK_FIELD +} + +static void test_LoadPackagedLibrary(void) +{ + HMODULE h; + + if (!pLoadPackagedLibrary) + { + win_skip("LoadPackagedLibrary is not available.\n"); + return; + } + + SetLastError( 0xdeadbeef ); + h = pLoadPackagedLibrary(L"kernel32.dll", 0); + ok(!h && GetLastError() == APPMODEL_ERROR_NO_PACKAGE, "Got unexpected handle %p, GetLastError() %lu.\n", + h, GetLastError()); +} + +static void test_Wow64Transition(void) +{ + char buffer[400]; + MEMORY_SECTION_NAME *name = (MEMORY_SECTION_NAME *)buffer; + const WCHAR *filepart; + void **pWow64Transition; + NTSTATUS status; + + if (!(pWow64Transition = (void *)GetProcAddress(GetModuleHandleA("ntdll"), "Wow64Transition"))) + { + skip("Wow64Transition is not present\n"); + return; + } + if (!is_wow64) + { + skip("Wow64Transition is not patched\n"); + return; + } + + status = NtQueryVirtualMemory(GetCurrentProcess(), *pWow64Transition, + MemoryMappedFilenameInformation, name, sizeof(buffer), NULL); + ok(!status, "got %#lx\n", status); + filepart = name->SectionFileName.Buffer + name->SectionFileName.Length / sizeof(WCHAR); + while (*filepart != '\\') --filepart; + ok(!wcsnicmp(filepart, L"\\wow64cpu.dll", wcslen(L"\\wow64cpu.dll")), "got file name %s\n", + debugstr_wn(name->SectionFileName.Buffer, name->SectionFileName.Length / sizeof(WCHAR))); } START_TEST(loader) @@ -3747,6 +4822,7 @@ START_TEST(loader) char **argv; HANDLE ntdll, mapping, kernel32; SYSTEM_INFO si; + DWORD len; ntdll = GetModuleHandleA("ntdll.dll"); kernel32 = GetModuleHandleA("kernel32.dll"); @@ -3763,15 +4839,23 @@ START_TEST(loader) pNtFreeVirtualMemory = (void *)GetProcAddress(ntdll, "NtFreeVirtualMemory"); pLdrLockLoaderLock = (void *)GetProcAddress(ntdll, "LdrLockLoaderLock"); pLdrUnlockLoaderLock = (void *)GetProcAddress(ntdll, "LdrUnlockLoaderLock"); + pLdrLoadDll = (void *)GetProcAddress(ntdll, "LdrLoadDll"); + pLdrUnloadDll = (void *)GetProcAddress(ntdll, "LdrUnloadDll"); + pRtlInitUnicodeString = (void *)GetProcAddress(ntdll, "RtlInitUnicodeString"); pRtlAcquirePebLock = (void *)GetProcAddress(ntdll, "RtlAcquirePebLock"); pRtlReleasePebLock = (void *)GetProcAddress(ntdll, "RtlReleasePebLock"); pRtlImageDirectoryEntryToData = (void *)GetProcAddress(ntdll, "RtlImageDirectoryEntryToData"); + pRtlImageNtHeader = (void *)GetProcAddress(ntdll, "RtlImageNtHeader"); + pLdrRegisterDllNotification = (void *)GetProcAddress(ntdll, "LdrRegisterDllNotification"); pFlsAlloc = (void *)GetProcAddress(kernel32, "FlsAlloc"); pFlsSetValue = (void *)GetProcAddress(kernel32, "FlsSetValue"); pFlsGetValue = (void *)GetProcAddress(kernel32, "FlsGetValue"); pFlsFree = (void *)GetProcAddress(kernel32, "FlsFree"); pIsWow64Process = (void *)GetProcAddress(kernel32, "IsWow64Process"); + pWow64DisableWow64FsRedirection = (void *)GetProcAddress(kernel32, "Wow64DisableWow64FsRedirection"); + pWow64RevertWow64FsRedirection = (void *)GetProcAddress(kernel32, "Wow64RevertWow64FsRedirection"); pResolveDelayLoadedAPI = (void *)GetProcAddress(kernel32, "ResolveDelayLoadedAPI"); + pLoadPackagedLibrary = (void *)GetProcAddress(kernel32, "LoadPackagedLibrary"); if (pIsWow64Process) pIsWow64Process( GetCurrentProcess(), &is_wow64 ); GetSystemInfo( &si ); @@ -3797,14 +4881,29 @@ START_TEST(loader) return; } - test_Loader(); - test_FakeDLL(); + len = GetSystemDirectoryA(system_dir, ARRAY_SIZE(system_dir)); + ok(len && len < ARRAY_SIZE(system_dir), "Couldn't get system directory: %lu\n", GetLastError()); + if (is_wow64) + { + len = GetSystemWow64DirectoryA(syswow_dir, ARRAY_SIZE(syswow_dir)); + ok(len && len < ARRAY_SIZE(syswow_dir), "Couldn't get wow directory: %lu\n", GetLastError()); + } + test_filenames(); test_ResolveDelayLoadedAPI(); test_ImportDescriptors(); test_section_access(); test_import_resolution(); + test_export_forwarder_dep_chain(); test_ExitProcess(); test_InMemoryOrderModuleList(); - test_HashLinks(); + test_LoadPackagedLibrary(); + test_wow64_redirection(); + test_dll_file( "ntdll.dll" ); + test_dll_file( "kernel32.dll" ); + test_dll_file( "advapi32.dll" ); + test_dll_file( "user32.dll" ); + test_Wow64Transition(); + /* loader test must be last, it can corrupt the internal loader state on Windows */ + test_Loader(); } diff --git a/modules/rostests/winetests/kernel32/locale.c b/modules/rostests/winetests/kernel32/locale.c index 959fa965a4b..716ed813f08 100644 --- a/modules/rostests/winetests/kernel32/locale.c +++ b/modules/rostests/winetests/kernel32/locale.c @@ -25,16 +25,22 @@ * the control panel i8n page), we will still get the expected results. */ +#define _CRT_NON_CONFORMING_WCSTOK + #include #include #include #include -#include "wine/test.h" +#include "ntstatus.h" +#define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" #include "winerror.h" #include "winnls.h" +#include "winternl.h" +#include "winreg.h" +#include "wine/test.h" static const WCHAR upper_case[] = {'\t','J','U','S','T','!',' ','A',',',' ','T','E','S','T',';',' ','S','T','R','I','N','G',' ','1','/','*','+','-','.','\r','\n',0}; static const WCHAR lower_case[] = {'\t','j','u','s','t','!',' ','a',',',' ','t','e','s','t',';',' ','s','t','r','i','n','g',' ','1','/','*','+','-','.','\r','\n',0}; @@ -45,33 +51,6 @@ static const WCHAR fooW[] = {'f','o','o',0}; static const WCHAR emptyW[] = {0}; static const WCHAR invalidW[] = {'i','n','v','a','l','i','d',0}; -static inline unsigned int strlenW( const WCHAR *str ) -{ - const WCHAR *s = str; - while (*s) s++; - return s - str; -} - -static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n ) -{ - if (n <= 0) return 0; - while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; } - return *str1 - *str2; -} - -static inline WCHAR *strchrW( const WCHAR *str, WCHAR ch ) -{ - do { if (*str == ch) return (WCHAR *)str; } while (*str++); - return NULL; -} - -static inline BOOL isdigitW( WCHAR wc ) -{ - WORD type; - GetStringTypeW( CT_CTYPE1, &wc, 1, &type ); - return type & C1_DIGIT; -} - /* Some functions are only in later versions of kernel32.dll */ static WORD enumCount; @@ -80,29 +59,56 @@ static INT (WINAPI *pGetDateFormatEx)(LPCWSTR, DWORD, const SYSTEMTIME *, LPCWST static BOOL (WINAPI *pEnumSystemLanguageGroupsA)(LANGUAGEGROUP_ENUMPROCA, DWORD, LONG_PTR); static BOOL (WINAPI *pEnumLanguageGroupLocalesA)(LANGGROUPLOCALE_ENUMPROCA, LGRPID, DWORD, LONG_PTR); static BOOL (WINAPI *pEnumUILanguagesA)(UILANGUAGE_ENUMPROCA, DWORD, LONG_PTR); +static BOOL (WINAPI *pEnumSystemLocalesA)(LOCALE_ENUMPROCA, DWORD); +static BOOL (WINAPI *pEnumSystemLocalesW)(LOCALE_ENUMPROCW, DWORD); static BOOL (WINAPI *pEnumSystemLocalesEx)(LOCALE_ENUMPROCEX, DWORD, LPARAM, LPVOID); static INT (WINAPI *pLCMapStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPWSTR, INT, LPNLSVERSIONINFO, LPVOID, LPARAM); static LCID (WINAPI *pLocaleNameToLCID)(LPCWSTR, DWORD); +static NTSTATUS (WINAPI *pRtlLocaleNameToLcid)(LPCWSTR, LCID *, DWORD); +static BOOLEAN (WINAPI *pRtlIsValidLocaleName)(const WCHAR *,ULONG); +static NTSTATUS (WINAPI *pRtlLcidToLocaleName)(LCID, UNICODE_STRING *,DWORD,BYTE); static INT (WINAPI *pLCIDToLocaleName)(LCID, LPWSTR, INT, DWORD); -static INT (WINAPI *pFoldStringA)(DWORD, LPCSTR, INT, LPSTR, INT); -static INT (WINAPI *pFoldStringW)(DWORD, LPCWSTR, INT, LPWSTR, INT); static BOOL (WINAPI *pIsValidLanguageGroup)(LGRPID, DWORD); static INT (WINAPI *pIdnToNameprepUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT); static INT (WINAPI *pIdnToAscii)(DWORD, LPCWSTR, INT, LPWSTR, INT); static INT (WINAPI *pIdnToUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT); static INT (WINAPI *pGetLocaleInfoEx)(LPCWSTR, LCTYPE, LPWSTR, INT); static BOOL (WINAPI *pIsValidLocaleName)(LPCWSTR); +static INT (WINAPI *pResolveLocaleName)(LPCWSTR,LPWSTR,INT); static INT (WINAPI *pCompareStringOrdinal)(const WCHAR *, INT, const WCHAR *, INT, BOOL); static INT (WINAPI *pCompareStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPCWSTR, INT, LPNLSVERSIONINFO, LPVOID, LPARAM); static INT (WINAPI *pGetGeoInfoA)(GEOID, GEOTYPE, LPSTR, INT, LANGID); static INT (WINAPI *pGetGeoInfoW)(GEOID, GEOTYPE, LPWSTR, INT, LANGID); +static INT (WINAPI *pGetGeoInfoEx)(const WCHAR *, GEOTYPE, PWSTR, INT); +static INT (WINAPI *pGetUserDefaultGeoName)(LPWSTR, int); +static BOOL (WINAPI *pSetUserGeoName)(PWSTR); static BOOL (WINAPI *pEnumSystemGeoID)(GEOCLASS, GEOID, GEO_ENUMPROC); static BOOL (WINAPI *pGetSystemPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*); static BOOL (WINAPI *pGetThreadPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*); static BOOL (WINAPI *pGetUserPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*); static WCHAR (WINAPI *pRtlUpcaseUnicodeChar)(WCHAR); static INT (WINAPI *pGetNumberFormatEx)(LPCWSTR, DWORD, LPCWSTR, const NUMBERFMTW *, LPWSTR, int); +static INT (WINAPI *pFindNLSStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPCWSTR, INT, LPINT, LPNLSVERSIONINFO, LPVOID, LPARAM); +static void * (WINAPI *pNlsValidateLocale)(LCID*,ULONG); +static LANGID (WINAPI *pSetThreadUILanguage)(LANGID); +static LANGID (WINAPI *pGetThreadUILanguage)(VOID); +static INT (WINAPI *pNormalizeString)(NORM_FORM, LPCWSTR, INT, LPWSTR, INT); +static INT (WINAPI *pFindStringOrdinal)(DWORD, LPCWSTR lpStringSource, INT, LPCWSTR, INT, BOOL); +static BOOL (WINAPI *pGetNLSVersion)(NLS_FUNCTION,LCID,NLSVERSIONINFO*); +static BOOL (WINAPI *pGetNLSVersionEx)(NLS_FUNCTION,LPCWSTR,NLSVERSIONINFOEX*); +static DWORD (WINAPI *pIsValidNLSVersion)(NLS_FUNCTION,LPCWSTR,NLSVERSIONINFOEX*); +static BOOL (WINAPI *pIsNLSDefinedString)(NLS_FUNCTION,DWORD,NLSVERSIONINFO*,const WCHAR *,int); +static NTSTATUS (WINAPI *pRtlNormalizeString)(ULONG, LPCWSTR, INT, LPWSTR, INT*); +static NTSTATUS (WINAPI *pRtlIsNormalizedString)(ULONG, LPCWSTR, INT, BOOLEAN*); +static NTSTATUS (WINAPI *pNtGetNlsSectionPtr)(ULONG,ULONG,void*,void**,SIZE_T*); +static NTSTATUS (WINAPI *pNtInitializeNlsFiles)(void**,LCID*,LARGE_INTEGER*); +static NTSTATUS (WINAPI *pRtlGetLocaleFileMappingAddress)(void**,LCID*,LARGE_INTEGER*); +static void (WINAPI *pRtlInitCodePageTable)(USHORT*,CPTABLEINFO*); +static NTSTATUS (WINAPI *pRtlCustomCPToUnicodeN)(CPTABLEINFO*,WCHAR*,DWORD,DWORD*,const char*,DWORD); +static NTSTATUS (WINAPI *pRtlGetSystemPreferredUILanguages)(DWORD,ULONG,ULONG*,WCHAR*,ULONG*); +static NTSTATUS (WINAPI *pRtlGetThreadPreferredUILanguages)(DWORD,ULONG*,WCHAR*,ULONG*); +static NTSTATUS (WINAPI *pRtlGetUserPreferredUILanguages)(DWORD,ULONG,ULONG*,WCHAR*,ULONG*); static void InitFunctionPointers(void) { @@ -116,28 +122,57 @@ static void InitFunctionPointers(void) X(LocaleNameToLCID); X(LCIDToLocaleName); X(LCMapStringEx); - X(FoldStringA); - X(FoldStringW); X(IsValidLanguageGroup); X(EnumUILanguagesA); + X(EnumSystemLocalesA); + X(EnumSystemLocalesW); X(EnumSystemLocalesEx); X(IdnToNameprepUnicode); X(IdnToAscii); X(IdnToUnicode); X(GetLocaleInfoEx); X(IsValidLocaleName); + X(ResolveLocaleName); X(CompareStringOrdinal); X(CompareStringEx); X(GetGeoInfoA); X(GetGeoInfoW); + X(GetGeoInfoEx); + X(GetUserDefaultGeoName); + X(SetUserGeoName); X(EnumSystemGeoID); X(GetSystemPreferredUILanguages); X(GetThreadPreferredUILanguages); X(GetUserPreferredUILanguages); X(GetNumberFormatEx); + X(FindNLSStringEx); + X(SetThreadUILanguage); + X(GetThreadUILanguage); + X(NormalizeString); + X(FindStringOrdinal); + X(GetNLSVersion); + X(GetNLSVersionEx); + X(IsValidNLSVersion); + X(IsNLSDefinedString); + + mod = GetModuleHandleA("kernelbase"); + X(NlsValidateLocale); mod = GetModuleHandleA("ntdll"); X(RtlUpcaseUnicodeChar); + X(RtlLocaleNameToLcid); + X(RtlIsValidLocaleName); + X(RtlLcidToLocaleName); + X(RtlNormalizeString); + X(RtlIsNormalizedString); + X(NtGetNlsSectionPtr); + X(NtInitializeNlsFiles); + X(RtlInitCodePageTable); + X(RtlCustomCPToUnicodeN); + X(RtlGetLocaleFileMappingAddress); + X(RtlGetSystemPreferredUILanguages); + X(RtlGetThreadPreferredUILanguages); + X(RtlGetUserPreferredUILanguages); #undef X } @@ -146,18 +181,79 @@ static void InitFunctionPointers(void) (label), (received), (expected)) #define BUFFER_SIZE 128 -#define COUNTOF(x) (sizeof(x)/sizeof(x)[0]) -#define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0xdeadbeef); buffer[0] = '\0' -#define EXPECT_LENA ok(ret == lstrlenA(Expected)+1, "Expected len %d, got %d\n", lstrlenA(Expected)+1, ret) -#define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \ - "Expected '%s', got '%s'\n", Expected, buffer) +#define expect_str(r,s,e) expect_str_(__LINE__, r, s, e) +static void expect_str_(int line, int ret, const char *str, const char *expected) +{ + if (ret) + { + ok_(__FILE__, line)(GetLastError() == 0xdeadbeef, "unexpected gle %lu\n", GetLastError()); + ok_(__FILE__, line)(ret == strlen(expected) + 1, "Expected ret %Id, got %d\n", strlen(expected) + 1, ret); + if (str) + ok_(__FILE__, line)(strcmp(str, expected) == 0, "Expected '%s', got '%s'\n", expected, str); + } + else + ok_(__FILE__, line)(0, "expected success, got error %ld\n", GetLastError()); +} -#define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \ - MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \ - 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_err(r,s,e) expect_err_(__LINE__, r, s, e, #e) +static void expect_err_(int line, int ret, const char *str, DWORD err, const char* err_name) +{ + ok_(__FILE__, line)(!ret && GetLastError() == err, + "Expected %s, got %ld and ret=%d\n", err_name, GetLastError(), ret); + if (str) + ok_(__FILE__, line)(strcmp(str, "pristine") == 0, "Expected a pristine buffer, got '%s'\n", str); +} + +#define expect_wstr(r,s,e) expect_wstr_(__LINE__, r, s, e) +static void expect_wstr_(int line, int ret, const WCHAR *str, const WCHAR *expected) +{ + if (ret) + { + ok_(__FILE__, line)(GetLastError() == 0xdeadbeef, "unexpected gle %lu\n", GetLastError()); + ok_(__FILE__, line)(ret == wcslen(expected) + 1, "Expected ret %Id, got %d\n", wcslen(expected) + 1, ret); + if (str) + ok_(__FILE__, line)(wcscmp(str, expected) == 0, "Expected %s, got %s\n", wine_dbgstr_w(expected), wine_dbgstr_w(str)); + } + else + ok_(__FILE__, line)(0, "expected success, got error %ld\n", GetLastError()); +} + +#define expect_werr(r,s,e) expect_werr_(__LINE__, r, s, e, #e) +static void expect_werr_(int line, int ret, const WCHAR *str, DWORD err, const char* err_name) +{ + ok_(__FILE__, line)(!ret && GetLastError() == err, + "Expected %s, got %ld and ret=%d\n", err_name, GetLastError(), ret); + if (str) + ok_(__FILE__, line)(wcscmp(str, L"pristine") == 0, "Expected a pristine buffer, got %s\n", wine_dbgstr_w(str)); +} + +static int get_utf16( const WCHAR *src, unsigned int srclen, unsigned int *ch ) +{ + if (IS_HIGH_SURROGATE( src[0] )) + { + if (srclen <= 1) return 0; + if (!IS_LOW_SURROGATE( src[1] )) return 0; + *ch = 0x10000 + ((src[0] & 0x3ff) << 10) + (src[1] & 0x3ff); + return 2; + } + if (IS_LOW_SURROGATE( src[0] )) return 0; + *ch = src[0]; + return 1; +} + +static int put_utf16( WCHAR *str, unsigned int c ) +{ + if (c < 0x10000) + { + *str = c; + return 1; + } + c -= 0x10000; + str[0] = 0xd800 | (c >> 10); + str[1] = 0xdc00 | (c & 0x3ff); + return 2; +} #define NUO LOCALE_NOUSEROVERRIDE @@ -170,30 +266,30 @@ static void test_GetLocaleInfoA(void) char expected[BUFFER_SIZE]; DWORD val; - ok(lcid == 0x409, "wrong LCID calculated - %d\n", lcid); + ok(lcid == 0x409, "wrong LCID calculated - %ld\n", lcid); ret = GetLocaleInfoA(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (char*)&val, sizeof(val)); ok(ret, "got %d\n", ret); - ok(val == lcid, "got 0x%08x\n", val); + ok(val == lcid, "got 0x%08lx\n", val); /* en and ar use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT Same is true for zh on pre-Vista, but on Vista and higher GetLocaleInfo assumes SUBLANG_NEUTRAL for zh */ - memset(expected, 0, COUNTOF(expected)); - len = GetLocaleInfoA(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected)); + memset(expected, 0, ARRAY_SIZE(expected)); + len = GetLocaleInfoA(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, ARRAY_SIZE(expected)); SetLastError(0xdeadbeef); - memset(buffer, 0, COUNTOF(buffer)); - ret = GetLocaleInfoA(LANG_ENGLISH, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer)); + memset(buffer, 0, ARRAY_SIZE(buffer)); + ret = GetLocaleInfoA(LANG_ENGLISH, LOCALE_SLANGUAGE, buffer, ARRAY_SIZE(buffer)); ok((ret == len) && !lstrcmpA(buffer, expected), "got %d with '%s' (expected %d with '%s')\n", ret, buffer, len, expected); - memset(expected, 0, COUNTOF(expected)); - len = GetLocaleInfoA(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected)); + memset(expected, 0, ARRAY_SIZE(expected)); + len = GetLocaleInfoA(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, ARRAY_SIZE(expected)); if (len) { SetLastError(0xdeadbeef); - memset(buffer, 0, COUNTOF(buffer)); - ret = GetLocaleInfoA(LANG_ARABIC, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer)); + memset(buffer, 0, ARRAY_SIZE(buffer)); + ret = GetLocaleInfoA(LANG_ARABIC, LOCALE_SLANGUAGE, buffer, ARRAY_SIZE(buffer)); ok((ret == len) && !lstrcmpA(buffer, expected), "got %d with '%s' (expected %d with '%s')\n", ret, buffer, len, expected); @@ -202,35 +298,54 @@ static void test_GetLocaleInfoA(void) win_skip("LANG_ARABIC not installed\n"); /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */ - memset(expected, 0, COUNTOF(expected)); - len = GetLocaleInfoA(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected)); + memset(expected, 0, ARRAY_SIZE(expected)); + len = GetLocaleInfoA(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, ARRAY_SIZE(expected)); SetLastError(0xdeadbeef); - memset(buffer, 0, COUNTOF(buffer)); - ret = GetLocaleInfoA(LANG_GERMAN, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer)); + memset(buffer, 0, ARRAY_SIZE(buffer)); + ret = GetLocaleInfoA(LANG_GERMAN, LOCALE_SLANGUAGE, buffer, ARRAY_SIZE(buffer)); ok((ret == len) && !lstrcmpA(buffer, expected), "got %d with '%s' (expected %d with '%s')\n", ret, buffer, len, expected); + len = GetLocaleInfoA(GetUserDefaultLCID(), LOCALE_SLANGUAGE, expected, ARRAY_SIZE(expected)); + ret = GetLocaleInfoA(LOCALE_NEUTRAL, LOCALE_SLANGUAGE, buffer, ARRAY_SIZE(buffer)); + ok( (ret == len) && !lstrcmpA(buffer, expected), "got %d with '%s' (expected %d with '%s')\n", + ret, buffer, len, expected); + ret = GetLocaleInfoA(LOCALE_CUSTOM_DEFAULT, LOCALE_SLANGUAGE, buffer, ARRAY_SIZE(buffer)); +#ifdef __REACTOS__ + ok( ((ret == len) && !lstrcmpA(buffer, expected)) || broken(!ret) /* WS03 */, "got %d with '%s' (expected %d with '%s')\n", + ret, buffer, len, expected); +#else + ok( (ret == len) && !lstrcmpA(buffer, expected), "got %d with '%s' (expected %d with '%s')\n", + ret, buffer, len, expected); +#endif + ret = GetLocaleInfoA(LOCALE_CUSTOM_UNSPECIFIED, LOCALE_SLANGUAGE, buffer, ARRAY_SIZE(buffer)); + ok( (ret == len && !lstrcmpA(buffer, expected)) || broken(!ret), /* <= win8 */ + "got %d with '%s' (expected %d with '%s')\n", ret, buffer, len, expected); + len = GetLocaleInfoA(GetUserDefaultUILanguage(), LOCALE_SLANGUAGE, expected, ARRAY_SIZE(expected)); + ret = GetLocaleInfoA(LOCALE_CUSTOM_UI_DEFAULT, LOCALE_SLANGUAGE, buffer, ARRAY_SIZE(buffer)); + if (ret) ok( (ret == len && !lstrcmpA(buffer, expected)), + "got %d with '%s' (expected %d with '%s')\n", ret, buffer, len, expected); /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to * partially fill the buffer even if it is too short. See bug 637. */ SetLastError(0xdeadbeef); - memset(buffer, 0, COUNTOF(buffer)); + memset(buffer, 0, ARRAY_SIZE(buffer)); ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0); ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret); SetLastError(0xdeadbeef); - memset(buffer, 0, COUNTOF(buffer)); + memset(buffer, 0, ARRAY_SIZE(buffer)); ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3); ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); + "Expected ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError()); ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer); SetLastError(0xdeadbeef); - memset(buffer, 0, COUNTOF(buffer)); + memset(buffer, 0, ARRAY_SIZE(buffer)); ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10); - ok(ret == 7, "Expected ret == 7, got %d, error %d\n", ret, GetLastError()); + ok(ret == 7, "Expected ret == 7, got %d, error %ld\n", ret, GetLastError()); ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer); } @@ -240,7 +355,6 @@ struct neutralsublang_name2_t { LCID lcid; LCID lcid_broken; WCHAR sname_broken[15]; - int todo; }; static const struct neutralsublang_name2_t neutralsublang_names2[] = { @@ -257,7 +371,7 @@ static const struct neutralsublang_name2_t neutralsublang_names2[] = { MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH), SORT_DEFAULT) /* vista */, {'e','s','-','E','S','_','t','r','a','d','n','l',0} }, { {'g','a',0}, {'g','a','-','I','E',0}, - MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT), 0, {0}, 0x3 }, + MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT), 0, {0} }, { {'i','t',0}, {'i','t','-','I','T',0}, MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) }, { {'m','s',0}, {'m','s','-','M','Y',0}, @@ -288,17 +402,17 @@ static void test_GetLocaleInfoW(void) DWORD ret; INT i; - ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW)); + ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1, bufferW, ARRAY_SIZE(bufferW)); if (!ret) { win_skip("GetLocaleInfoW() isn't implemented\n"); return; } ret = GetLocaleInfoW(lcid_en, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR)); - ok(ret, "got %d\n", ret); - ok(val == lcid_en, "got 0x%08x\n", val); + ok(ret, "got %ld\n", ret); + ok(val == lcid_en, "got 0x%08lx\n", val); - ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SNAME, bufferW, COUNTOF(bufferW)); + ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SNAME, bufferW, ARRAY_SIZE(bufferW)); if (ret) { static const WCHAR slangW[] = {'E','n','g','l','i','s','h',' ','(','U','n','i','t','e','d',' ', @@ -309,8 +423,8 @@ static void test_GetLocaleInfoW(void) ok(!lstrcmpW(bufferW, enW), "got wrong name %s\n", wine_dbgstr_w(bufferW)); - ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SCOUNTRY, bufferW, COUNTOF(bufferW)); - ok(ret, "got %d\n", ret); + ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SCOUNTRY, bufferW, ARRAY_SIZE(bufferW)); + ok(ret, "got %ld\n", ret); if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) || (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH)) { @@ -319,8 +433,8 @@ static void test_GetLocaleInfoW(void) else ok(!lstrcmpW(statesW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW)); - ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SLANGUAGE, bufferW, COUNTOF(bufferW)); - ok(ret, "got %d\n", ret); + ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SLANGUAGE, bufferW, ARRAY_SIZE(bufferW)); + ok(ret, "got %ld\n", ret); if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) || (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH)) { @@ -340,29 +454,27 @@ static void test_GetLocaleInfoW(void) val = 0; GetLocaleInfoW(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR)); - todo_wine_if (ptr->todo & 0x1) - ok(val == ptr->lcid || (val && broken(val == ptr->lcid_broken)), "%s: got wrong lcid 0x%04x, expected 0x%04x\n", - wine_dbgstr_w(ptr->name), val, ptr->lcid); + ok(val == ptr->lcid || (val && broken(val == ptr->lcid_broken)), "%s: got wrong lcid 0x%04lx, expected 0x%04lx\n", + wine_dbgstr_w(ptr->name), val, ptr->lcid); /* now check LOCALE_SNAME */ - GetLocaleInfoW(lcid, LOCALE_SNAME, bufferW, COUNTOF(bufferW)); - todo_wine_if (ptr->todo & 0x2) - ok(!lstrcmpW(bufferW, ptr->sname) || - (*ptr->sname_broken && broken(!lstrcmpW(bufferW, ptr->sname_broken))), - "%s: got %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW)); + GetLocaleInfoW(lcid, LOCALE_SNAME, bufferW, ARRAY_SIZE(bufferW)); + ok(!lstrcmpW(bufferW, ptr->sname) || + (*ptr->sname_broken && broken(!lstrcmpW(bufferW, ptr->sname_broken))), + "%s: got %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW)); ptr++; } } else win_skip("English neutral locale not supported\n"); - ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW)); + ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, ARRAY_SIZE(bufferW)); if (!ret) { win_skip("LANG_RUSSIAN locale data unavailable\n"); return; } ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES, - bufferW, COUNTOF(bufferW)); + bufferW, ARRAY_SIZE(bufferW)); if (!ret) { win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n"); return; @@ -372,35 +484,33 @@ static void test_GetLocaleInfoW(void) bufferA[0] = 'a'; SetLastError(0xdeadbeef); ret = GetLocaleInfoA(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES, - bufferA, COUNTOF(bufferA)); + bufferA, ARRAY_SIZE(bufferA)); ok(ret == 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n"); ok(bufferA[0] == 'a', "Expected buffer to be untouched\n"); ok(GetLastError() == ERROR_INVALID_FLAGS, - "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError()); + "Expected ERROR_INVALID_FLAGS, got %lx\n", GetLastError()); bufferW[0] = 'a'; SetLastError(0xdeadbeef); - ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES, - bufferW, COUNTOF(bufferW)); + ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES, bufferW, ARRAY_SIZE(bufferW)); ok(ret == 0, - "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %d\n", ret); + "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %ld\n", ret); ok(bufferW[0] == 'a', "Expected buffer to be untouched\n"); ok(GetLastError() == ERROR_INVALID_FLAGS, - "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError()); + "Expected ERROR_INVALID_FLAGS, got %lx\n", GetLastError()); /* yes, test empty 13 month entry too */ for (i = 0; i < 12; i++) { bufferW[0] = 0; ret = GetLocaleInfoW(lcid_ru, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES, - bufferW, COUNTOF(bufferW)); + bufferW, ARRAY_SIZE(bufferW)); ok(ret, "Expected non zero result\n"); - ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n", + ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %ld, length %d\n", ret, lstrlenW(bufferW)); buffer2W[0] = 0; - ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i, - buffer2W, COUNTOF(buffer2W)); + ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i, buffer2W, ARRAY_SIZE(buffer2W)); ok(ret, "Expected non zero result\n"); - ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n", + ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %ld, length %d\n", ret, lstrlenW(buffer2W)); ok(lstrcmpW(bufferW, buffer2W) != 0, @@ -409,15 +519,14 @@ static void test_GetLocaleInfoW(void) /* for locale without genitive names nominative returned in both cases */ bufferW[0] = 0; ret = GetLocaleInfoW(lcid_en, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES, - bufferW, COUNTOF(bufferW)); + bufferW, ARRAY_SIZE(bufferW)); ok(ret, "Expected non zero result\n"); - ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n", + ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %ld, length %d\n", ret, lstrlenW(bufferW)); buffer2W[0] = 0; - ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i, - buffer2W, COUNTOF(buffer2W)); + ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i, buffer2W, ARRAY_SIZE(buffer2W)); ok(ret, "Expected non zero result\n"); - ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n", + ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %ld, length %d\n", ret, lstrlenW(buffer2W)); ok(lstrcmpW(bufferW, buffer2W) == 0, @@ -430,120 +539,104 @@ static void test_GetTimeFormatA(void) int ret; SYSTEMTIME curtime; LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); - char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE]; + char buffer[BUFFER_SIZE]; - memset(&curtime, 2, sizeof(SYSTEMTIME)); - STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */ SetLastError(0xdeadbeef); - ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer)); - ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + /* Invalid time */ + memset(&curtime, 2, sizeof(SYSTEMTIME)); + strcpy(buffer, "pristine"); + ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, "tt HH':'mm'@'ss", buffer, ARRAY_SIZE(buffer)); + expect_err(ret, buffer, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); + + /* Valid time */ curtime.wHour = 8; curtime.wMinute = 56; curtime.wSecond = 13; curtime.wMilliseconds = 22; - STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */ - SetLastError(0xdeadbeef); - ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, "tt HH':'mm'@'ss", buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "AM 08:56@13"); /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */ + strcpy(buffer, "pristine"); + ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, "HH", buffer, ARRAY_SIZE(buffer)); + expect_err(ret, buffer, ERROR_INVALID_FLAGS); SetLastError(0xdeadbeef); - ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer)); - ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, - "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); - STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */ + /* Insufficient buffer */ + ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, " HH", buffer, 2); + /* The content of the buffer depends on implementation details: + * it may be " ristine" or " 0ristine" or unchanged and cannot be relied on. + */ + expect_err(ret, NULL, ERROR_INSUFFICIENT_BUFFER); SetLastError(0xdeadbeef); - ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2); - 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); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; + /* Calculate length only */ + ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, "tt HH':'mm'@'ss", NULL, 0); + expect_str(ret, NULL, "AM 08:56@13"); - STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */ - ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + /* TIME_NOMINUTESORSECONDS, default format */ + ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "8 AM"); - STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */ - ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer)); - 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 ); + /* TIME_NOMINUTESORSECONDS/complex format */ + ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, "m1s2m3s4", buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, ""); - STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */ - ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + /* TIME_NOSECONDS/Default format */ + ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "8:56 AM"); - 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)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + /* TIME_NOSECONDS */ + strcpy(buffer, "pristine"); /* clear previous identical result */ + ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, "h:m:s tt", buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "8:56 AM"); - STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */ - ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer)); - 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 ); + /* Multiple delimiters */ + ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, "h.@:m.@:s.@:tt", buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "8.@:56AM"); - STRINGSA("s1s2s3", ""); /* Duplicate tokens */ - ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer)); - 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 ); + /* Duplicate tokens */ + ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, "s1s2s3", buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, ""); - STRINGSA("t/tt", "A/AM"); /* AM time marker */ - ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + /* AM time marker */ + ret = GetTimeFormatA(lcid, 0, &curtime, "t/tt", buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "A/AM"); + /* PM time marker */ curtime.wHour = 13; - STRINGSA("t/tt", "P/PM"); /* PM time marker */ - ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + ret = GetTimeFormatA(lcid, 0, &curtime, "t/tt", buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "P/PM"); - STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */ - ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + /* TIME_NOTIMEMARKER: removes text around time marker token */ + ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, "h1t2tt3m", buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "156"); - STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */ - ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + /* TIME_FORCE24HOURFORMAT */ + ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, "h:m:s tt", buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "13:56:13 PM"); - STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */ - ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + /* TIME_FORCE24HOURFORMAT doesn't add time marker */ + ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, "h:m:s", buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "13:56:13"); + /* 24 hrs, leading 0 */ 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)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + ret = GetTimeFormatA(lcid, 0, &curtime, "h hh H HH m mm s ss t tt", buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "2 02 14 14 5 05 3 03 P PM"); + /* "hh" and "HH" */ curtime.wHour = 0; - STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */ - ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + ret = GetTimeFormatA(lcid, 0, &curtime, "h/H/hh/HH", buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "12/0/12/00"); - 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)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + /* non-zero flags should fail with format, doesn't */ + ret = GetTimeFormatA(lcid, 0, &curtime, "h:m:s tt", buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "12:5:3 AM"); /* 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" @@ -555,76 +648,85 @@ static void test_GetTimeFormatA(void) curtime.wMinute = 56; curtime.wSecond = 13; curtime.wMilliseconds = 22; - 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)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + ret = GetTimeFormatA(lcid, 0, &curtime, "h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS", buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS"); - STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */ - strcpy(buffer, "text"); - ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0); - ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); - EXPECT_EQA; + /* Don't write to buffer if len is 0 */ + strcpy(buffer, "pristine"); + ret = GetTimeFormatA(lcid, 0, &curtime, "h:mm", buffer, 0); + expect_str(ret, NULL, "8:56"); + ok(strcmp(buffer, "pristine") == 0, "Expected a pristine buffer, got '%s'\n", buffer); - 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)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + /* "'" preserves tokens */ + ret = GetTimeFormatA(lcid, 0, &curtime, "h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'", buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "8 h 8 H 08 HH 56 m 13 s A t AM tt"); - STRINGSA("'''", "'"); /* invalid quoted string */ - ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + /* invalid quoted string */ + ret = GetTimeFormatA(lcid, 0, &curtime, "'''", buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "'"); - /* test that msdn suggested single quotation usage works as expected */ - STRINGSA("''''", "'"); /* single quote mark */ - ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + /* check that MSDN's suggested single quotation usage works as expected */ + strcpy(buffer, "pristine"); /* clear previous identical result */ + ret = GetTimeFormatA(lcid, 0, &curtime, "''''", buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "'"); - STRINGSA("''HHHHHH", "08"); /* Normal use */ - ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + /* Normal use */ + ret = GetTimeFormatA(lcid, 0, &curtime, "''HHHHHH", buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "08"); /* and test for normal use of the single quotation mark */ - STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */ - ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + ret = GetTimeFormatA(lcid, 0, &curtime, "'''HHHHHH'", buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "'HHHHHH"); - STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */ - ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + /* Odd use */ + strcpy(buffer, "pristine"); /* clear previous identical result */ + ret = GetTimeFormatA(lcid, 0, &curtime, "'''HHHHHH", buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "'HHHHHH"); - STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */ - ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + /* TIME_NOTIMEMARKER drops literals too */ + ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, "'123'tt", buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, ""); + /* Invalid time */ curtime.wHour = 25; - STRINGSA("'123'tt", ""); /* Invalid time */ + strcpy(buffer, "pristine"); + ret = GetTimeFormatA(lcid, 0, &curtime, "'123'tt", buffer, ARRAY_SIZE(buffer)); + expect_err(ret, buffer, ERROR_INVALID_PARAMETER); SetLastError(0xdeadbeef); - ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + /* Invalid date */ 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)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + curtime.wMonth = 60; + ret = GetTimeFormatA(lcid, 0, &curtime, "h:m:s", buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "12:56:13"); + + /* The ANSI string may be longer than the Unicode one. + * In particular, in the Japanese code page, "\x93\xfa" = L"\x65e5". + */ + + lcid = MAKELCID(MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN), SORT_DEFAULT); + + ret = GetTimeFormatA(lcid, 0, &curtime, "h\x93\xfa", buffer, 5); + expect_str(ret, buffer, "12\x93\xfa"); /* only 3+1 WCHARs */ + + ret = GetTimeFormatA(lcid, 0, &curtime, "h\x93\xfa", buffer, 4); + expect_err(ret, NULL, ERROR_INSUFFICIENT_BUFFER); + SetLastError(0xdeadbeef); + + ret = GetTimeFormatA(lcid, 0, &curtime, "h\x93\xfa", NULL, 0); + expect_str(ret, NULL, "12\x93\xfa"); + + strcpy(buffer, "pristine"); /* clear previous identical result */ + ret = GetTimeFormatA(lcid, 0, &curtime, "h\x93\xfa", buffer, 0); + expect_str(ret, NULL, "12\x93\xfa"); + ok(strcmp(buffer, "pristine") == 0, "Expected a pristine buffer, got '%s'\n", buffer); } static void test_GetTimeFormatEx(void) { int ret; SYSTEMTIME curtime; - WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE]; + WCHAR buffer[BUFFER_SIZE]; if (!pGetTimeFormatEx) { @@ -632,114 +734,102 @@ static void test_GetTimeFormatEx(void) return; } - memset(&curtime, 2, sizeof(SYSTEMTIME)); - STRINGSW("tt HH':'mm'@'ss", ""); /* Invalid time */ SetLastError(0xdeadbeef); - ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer)); - ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + /* Invalid time */ + memset(&curtime, 2, sizeof(SYSTEMTIME)); + wcscpy(buffer, L"pristine"); + ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, L"tt HH':'mm'@'ss", buffer, ARRAY_SIZE(buffer)); + expect_werr(ret, buffer, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); + + /* Valid time */ curtime.wHour = 8; curtime.wMinute = 56; curtime.wSecond = 13; curtime.wMilliseconds = 22; - STRINGSW("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */ - SetLastError(0xdeadbeef); - ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, L"tt HH':'mm'@'ss", buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"AM 08:56@13"); /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */ + wcscpy(buffer, L"pristine"); + ret = pGetTimeFormatEx(localeW, NUO|TIME_FORCE24HOURFORMAT, &curtime, L"HH", buffer, ARRAY_SIZE(buffer)); + expect_werr(ret, buffer, ERROR_INVALID_FLAGS); SetLastError(0xdeadbeef); - ret = pGetTimeFormatEx(localeW, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer)); - ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, - "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); - STRINGSW("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */ + /* Insufficient buffer */ + ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, L" tt", buffer, 2); + /* there is no guarantee on the buffer content, see GetTimeFormatA() */ + expect_werr(ret, NULL, ERROR_INSUFFICIENT_BUFFER); SetLastError(0xdeadbeef); - ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2); - ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); - STRINGSW("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */ - ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; + /* Calculate length only */ + ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, L"tt HH':'mm'@'ss", NULL, 0); + expect_wstr(ret, NULL, L"AM 08:56@13"); - STRINGSW("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */ - ret = pGetTimeFormatEx(localeW, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* TIME_NOMINUTESORSECONDS, default format */ + ret = pGetTimeFormatEx(localeW, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"8 AM"); - STRINGSW("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */ - ret = pGetTimeFormatEx(localeW, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret == strlenW(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* TIME_NOMINUTESORSECONDS/complex format */ + wcscpy(buffer, L"pristine"); + ret = pGetTimeFormatEx(localeW, TIME_NOMINUTESORSECONDS, &curtime, L"m1s2m3s4", buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L""); - STRINGSW("", "8:56 AM"); /* TIME_NOSECONDS/Default format */ - ret = pGetTimeFormatEx(localeW, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* TIME_NOSECONDS/Default format */ + ret = pGetTimeFormatEx(localeW, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"8:56 AM"); - STRINGSW("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */ - ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* TIME_NOSECONDS */ + wcscpy(buffer, L"pristine"); /* clear previous identical result */ + ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, L"h:m:s tt", buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"8:56 AM"); - STRINGSW("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */ - ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* Multiple delimiters */ + ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, L"h.@:m.@:s.@:tt", buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"8.@:56AM"); - STRINGSW("s1s2s3", ""); /* Duplicate tokens */ - ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret == strlenW(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* Duplicate tokens */ + wcscpy(buffer, L"pristine"); + ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, L"s1s2s3", buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L""); - STRINGSW("t/tt", "A/AM"); /* AM time marker */ - ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* AM time marker */ + ret = pGetTimeFormatEx(localeW, 0, &curtime, L"t/tt", buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"A/AM"); + /* PM time marker */ curtime.wHour = 13; - STRINGSW("t/tt", "P/PM"); /* PM time marker */ - ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + ret = pGetTimeFormatEx(localeW, 0, &curtime, L"t/tt", buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"P/PM"); - STRINGSW("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */ - ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* TIME_NOTIMEMARKER: removes text around time marker token */ + ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &curtime, L"h1t2tt3m", buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"156"); - STRINGSW("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */ - ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* TIME_FORCE24HOURFORMAT */ + ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, L"h:m:s tt", buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"13:56:13 PM"); - STRINGSW("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */ - ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* TIME_FORCE24HOURFORMAT doesn't add time marker */ + ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, L"h:m:s", buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"13:56:13"); + /* 24 hrs, leading 0 */ curtime.wHour = 14; /* change this to 14 or 2pm */ curtime.wMinute = 5; curtime.wSecond = 3; - STRINGSW("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 = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + ret = pGetTimeFormatEx(localeW, 0, &curtime, L"h hh H HH m mm s ss t tt", buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"2 02 14 14 5 05 3 03 P PM"); + /* "hh" and "HH" */ curtime.wHour = 0; - STRINGSW("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */ - ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + ret = pGetTimeFormatEx(localeW, 0, &curtime, L"h/H/hh/HH", buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"12/0/12/00"); - STRINGSW("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */ - ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* non-zero flags should fail with format, doesn't */ + ret = pGetTimeFormatEx(localeW, 0, &curtime, L"h:m:s tt", buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"12:5:3 AM"); /* 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" @@ -751,69 +841,57 @@ static void test_GetTimeFormatEx(void) curtime.wMinute = 56; curtime.wSecond = 13; curtime.wMilliseconds = 22; - STRINGSW("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 = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + ret = pGetTimeFormatEx(localeW, 0, &curtime, L"h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS", buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS"); - STRINGSW("h", "text"); /* Don't write to buffer if len is 0 */ - lstrcpyW(buffer, Expected); - ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, 0); - ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); - EXPECT_EQW; + /* Don't write to buffer if len is 0 */ + wcscpy(buffer, L"pristine"); + ret = pGetTimeFormatEx(localeW, 0, &curtime, L"h:mm", buffer, 0); + expect_wstr(ret, NULL, L"8:56"); + ok(wcscmp(buffer, L"pristine") == 0, "Expected a pristine buffer, got %s\n", wine_dbgstr_w(buffer)); - STRINGSW("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 = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* "'" preserves tokens */ + ret = pGetTimeFormatEx(localeW, 0, &curtime, L"h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'", buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"8 h 8 H 08 HH 56 m 13 s A t AM tt"); - STRINGSW("'''", "'"); /* invalid quoted string */ - ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* invalid quoted string */ + ret = pGetTimeFormatEx(localeW, 0, &curtime, L"'''", buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"'"); - /* test that msdn suggested single quotation usage works as expected */ - STRINGSW("''''", "'"); /* single quote mark */ - ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* check that MSDN's suggested single quotation usage works as expected */ + wcscpy(buffer, L"pristine"); /* clear previous identical result */ + ret = pGetTimeFormatEx(localeW, 0, &curtime, L"''''", buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"'"); - STRINGSW("''HHHHHH", "08"); /* Normal use */ - ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* Normal use */ + ret = pGetTimeFormatEx(localeW, 0, &curtime, L"''HHHHHH", buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"08"); /* and test for normal use of the single quotation mark */ - STRINGSW("'''HHHHHH'", "'HHHHHH"); /* Normal use */ - ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + ret = pGetTimeFormatEx(localeW, 0, &curtime, L"'''HHHHHH'", buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"'HHHHHH"); - STRINGSW("'''HHHHHH", "'HHHHHH"); /* Odd use */ - ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* Odd use */ + wcscpy(buffer, L"pristine"); /* clear previous identical result */ + ret = pGetTimeFormatEx(localeW, 0, &curtime, L"'''HHHHHH", buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"'HHHHHH"); - STRINGSW("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */ - ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* TIME_NOTIMEMARKER drops literals too */ + ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &curtime, L"'123'tt", buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L""); + /* Invalid time */ curtime.wHour = 25; - STRINGSW("'123'tt", ""); /* Invalid time */ + wcscpy(buffer, L"pristine"); + ret = pGetTimeFormatEx(localeW, 0, &curtime, L"'123'tt", buffer, ARRAY_SIZE(buffer)); + expect_werr(ret, buffer, ERROR_INVALID_PARAMETER); SetLastError(0xdeadbeef); - ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + /* Invalid date */ curtime.wHour = 12; - curtime.wMonth = 60; /* Invalid */ - STRINGSW("h:m:s", "12:56:13"); /* Invalid date */ - ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + curtime.wMonth = 60; + ret = pGetTimeFormatEx(localeW, 0, &curtime, L"h:m:s", buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"12:56:13"); } static void test_GetDateFormatA(void) @@ -822,88 +900,78 @@ static void test_GetDateFormatA(void) SYSTEMTIME curtime; LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT); - char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE]; - char Broken[BUFFER_SIZE]; + LCID lcid_ja = MAKELCID(MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN), SORT_DEFAULT); + char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE]; char short_day[10], month[10], genitive_month[10]; - memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */ - STRINGSA("ddd',' MMM dd yy",""); SetLastError(0xdeadbeef); - ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + /* Invalid time */ + memset(&curtime, 2, sizeof(SYSTEMTIME)); + strcpy(buffer, "pristine"); + ret = GetDateFormatA(lcid, 0, &curtime, "ddd',' MMM dd yy", buffer, ARRAY_SIZE(buffer)); + expect_err(ret, buffer, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); + + /* Simple case */ curtime.wYear = 2002; curtime.wMonth = 5; curtime.wDay = 4; curtime.wDayOfWeek = 3; - STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */ - ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + ret = GetDateFormatA(lcid, 0, &curtime, "ddd',' MMM dd yy", buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "Sat, May 04 02"); /* Same as above but with LOCALE_NOUSEROVERRIDE */ - STRINGSA("ddd',' MMM dd yy",""); /* Simple case */ + strcpy(buffer, "pristine"); + ret = GetDateFormatA(lcid, NUO, &curtime, "ddd',' MMM dd yy", buffer, ARRAY_SIZE(buffer)); + expect_err(ret, buffer, ERROR_INVALID_FLAGS); SetLastError(0xdeadbeef); - ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer)); - 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)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + /* Format containing "'" */ + ret = GetDateFormatA(lcid, 0, &curtime, "ddd',' MMM dd yy", buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "Sat, May 04 02"); - curtime.wHour = 36; /* Invalid */ - STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */ - ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + /* Invalid time */ + curtime.wHour = 36; + ret = GetDateFormatA(lcid, 0, &curtime, "ddd',' MMM dd ''''yy", buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "Sat, May 04 '02"); - STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */ - ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0); - ok(ret == 16, "Expected ret == 16, got %d, error %d\n", ret, GetLastError()); - EXPECT_EQA; + /* Get size only */ + ret = GetDateFormatA(lcid, 0, &curtime, "ddd',' MMM dd ''''yy", NULL, 0); + expect_str(ret, NULL, "Sat, May 04 '02"); - STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */ + /* Buffer too small */ + strcpy(buffer, "pristine"); + ret = GetDateFormatA(lcid, 0, &curtime, "ddd", buffer, 2); + /* there is no guarantee on the buffer content, see GetTimeFormatA() */ + expect_err(ret, NULL, ERROR_INSUFFICIENT_BUFFER); SetLastError(0xdeadbeef); - ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2); - 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 = GetDateFormatA(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer)); - 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); + /* Default to DATE_SHORTDATE */ + ret = GetDateFormatA(lcid, NUO, &curtime, NULL, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "5/4/2002"); - SetLastError(0xdeadbeef); buffer[0] = '\0'; /* DATE_LONGDATE */ - ret = GetDateFormatA(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + /* DATE_LONGDATE */ + ret = GetDateFormatA(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, ARRAY_SIZE(buffer)); + ok(ret, "Expected ret != 0, got %d, error %ld\n", ret, GetLastError()); ok(strcmp(buffer, "Saturday, May 04, 2002") == 0 || strcmp(buffer, "Saturday, May 4, 2002") == 0 /* Win 8 */, "got an unexpected date string '%s'\n", buffer); /* test for expected DATE_YEARMONTH behavior with null format */ /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */ - STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */ + strcpy(buffer, "pristine"); + ret = GetDateFormatA(lcid, NUO|DATE_YEARMONTH, &curtime, "ddd',' MMM dd ''''yy", buffer, ARRAY_SIZE(buffer)); + expect_err(ret, buffer, ERROR_INVALID_FLAGS); SetLastError(0xdeadbeef); - ret = GetDateFormatA(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer)); - 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 */ - STRINGSA("m/d/y", ""); /* Invalid flags */ + ret = GetDateFormatA(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE, &curtime, "m/d/y", buffer, ARRAY_SIZE(buffer)); + expect_err(ret, NULL, ERROR_INVALID_FLAGS); SetLastError(0xdeadbeef); - ret = GetDateFormatA(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE, - &curtime, input, buffer, COUNTOF(buffer)); - ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, - "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); - ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddMMMM", buffer, COUNTOF(buffer)); + ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddMMMM", buffer, ARRAY_SIZE(buffer)); if (!ret) { win_skip("LANG_RUSSIAN locale data unavailable\n"); @@ -912,82 +980,70 @@ static void test_GetDateFormatA(void) /* month part should be in genitive form */ strcpy(genitive_month, buffer + 2); - ret = GetDateFormatA(lcid_ru, 0, &curtime, "MMMM", buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + ret = GetDateFormatA(lcid_ru, 0, &curtime, "MMMM", buffer, ARRAY_SIZE(buffer)); + ok(ret, "Expected ret != 0, got %d, error %ld\n", ret, GetLastError()); strcpy(month, buffer); ok(strcmp(genitive_month, month) != 0, "Expected different month forms\n"); - ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddd", buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddd", buffer, ARRAY_SIZE(buffer)); + ok(ret, "Expected ret != 0, got %d, error %ld\n", ret, GetLastError()); strcpy(short_day, buffer); - STRINGSA("dd MMMMddd dd", ""); + ret = GetDateFormatA(lcid_ru, 0, &curtime, "dd MMMMddd dd", buffer, ARRAY_SIZE(buffer)); sprintf(Expected, "04 %s%s 04", genitive_month, short_day); - ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_EQA; + expect_str(ret, buffer, Expected); - STRINGSA("MMMMddd dd", ""); + ret = GetDateFormatA(lcid_ru, 0, &curtime, "MMMMddd dd", buffer, ARRAY_SIZE(buffer)); sprintf(Expected, "%s%s 04", month, short_day); - ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_EQA; + expect_str(ret, buffer, Expected); - STRINGSA("MMMMddd", ""); + ret = GetDateFormatA(lcid_ru, 0, &curtime, "MMMMddd", buffer, ARRAY_SIZE(buffer)); sprintf(Expected, "%s%s", month, short_day); - ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_EQA; + expect_str(ret, buffer, Expected); - STRINGSA("MMMMdd", ""); + ret = GetDateFormatA(lcid_ru, 0, &curtime, "MMMMdd", buffer, ARRAY_SIZE(buffer)); sprintf(Expected, "%s04", genitive_month); - sprintf(Broken, "%s04", month); - ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - ok(strncmp(buffer, Expected, strlen(Expected)) == 0 || - broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */, - "Expected '%s', got '%s'\n", Expected, buffer); + expect_str(ret, buffer, Expected); - STRINGSA("MMMMdd ddd", ""); + ret = GetDateFormatA(lcid_ru, 0, &curtime, "MMMMdd ddd", buffer, ARRAY_SIZE(buffer)); sprintf(Expected, "%s04 %s", genitive_month, short_day); - sprintf(Broken, "%s04 %s", month, short_day); - ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - ok(strncmp(buffer, Expected, strlen(Expected)) == 0 || - broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */, - "Expected '%s', got '%s'\n", Expected, buffer); + expect_str(ret, buffer, Expected); - STRINGSA("dd dddMMMM", ""); + ret = GetDateFormatA(lcid_ru, 0, &curtime, "dd dddMMMM", buffer, ARRAY_SIZE(buffer)); sprintf(Expected, "04 %s%s", short_day, month); - ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_EQA; + expect_str(ret, buffer, Expected); - STRINGSA("dd dddMMMM ddd MMMMdd", ""); + ret = GetDateFormatA(lcid_ru, 0, &curtime, "dd dddMMMM ddd MMMMdd", buffer, ARRAY_SIZE(buffer)); sprintf(Expected, "04 %s%s %s %s04", short_day, month, short_day, genitive_month); - sprintf(Broken, "04 %s%s %s %s04", short_day, month, short_day, month); - ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - ok(strncmp(buffer, Expected, strlen(Expected)) == 0 || - broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */, - "Expected '%s', got '%s'\n", Expected, buffer); + expect_str(ret, buffer, Expected); /* with literal part */ - STRINGSA("ddd',' MMMM dd", ""); + ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddd',' MMMM dd", buffer, ARRAY_SIZE(buffer)); sprintf(Expected, "%s, %s 04", short_day, genitive_month); - sprintf(Broken, "%s, %s 04", short_day, month); - ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - ok(strncmp(buffer, Expected, strlen(Expected)) == 0 || - broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */, - "Expected '%s', got '%s'\n", Expected, buffer); + expect_str(ret, buffer, Expected); + + /* The ANSI string may be longer than the Unicode one. + * In particular, in the Japanese code page, "\x93\xfa" = L"\x65e5". + * See the corresponding GetDateFormatW() test. + */ + + ret = GetDateFormatA(lcid_ja, 0, &curtime, "d\x93\xfa", buffer, 4); + expect_str(ret, buffer, "4\x93\xfa"); /* only 2+1 WCHARs */ + + ret = GetDateFormatA(lcid_ja, 0, &curtime, "d\x93\xfa", buffer, 3); + expect_err(ret, NULL, ERROR_INSUFFICIENT_BUFFER); + SetLastError(0xdeadbeef); + + strcpy(buffer, "pristine"); /* clear previous identical result */ + ret = GetDateFormatA(lcid_ja, 0, &curtime, "d\x93\xfa", NULL, 0); + expect_str(ret, NULL, "4\x93\xfa"); } static void test_GetDateFormatEx(void) { int ret; SYSTEMTIME curtime; - WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE]; + WCHAR buffer[BUFFER_SIZE]; if (!pGetDateFormatEx) { @@ -995,32 +1051,42 @@ static void test_GetDateFormatEx(void) return; } - STRINGSW("",""); /* If flags are set, then format must be NULL */ SetLastError(0xdeadbeef); - ret = pGetDateFormatEx(localeW, DATE_LONGDATE, NULL, - input, buffer, COUNTOF(buffer), NULL); - ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, - "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); - EXPECT_EQW; - STRINGSW("",""); /* NULL buffer, len > 0 */ + /* If flags are set, then format must be NULL */ + wcscpy(buffer, L"pristine"); + ret = pGetDateFormatEx(localeW, DATE_LONGDATE, NULL, L"", buffer, ARRAY_SIZE(buffer), NULL); + expect_werr(ret, buffer, ERROR_INVALID_FLAGS); SetLastError(0xdeadbeef); - ret = pGetDateFormatEx(localeW, 0, NULL, input, NULL, COUNTOF(buffer), NULL); - ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); - STRINGSW("",""); /* NULL buffer, len == 0 */ - ret = pGetDateFormatEx(localeW, 0, NULL, input, NULL, 0, NULL); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; - - STRINGSW("",""); /* Invalid flag combination */ + /* NULL buffer, len > 0 */ + wcscpy(buffer, L"pristine"); + ret = pGetDateFormatEx(localeW, 0, NULL, L"", NULL, ARRAY_SIZE(buffer), NULL); + expect_werr(ret, buffer, ERROR_INVALID_PARAMETER); SetLastError(0xdeadbeef); + + /* NULL buffer, len == 0 */ + ret = pGetDateFormatEx(localeW, 0, NULL, L"", NULL, 0, NULL); + expect_wstr(ret, NULL, L""); + + /* Invalid flag combination */ + wcscpy(buffer, L"pristine"); ret = pGetDateFormatEx(localeW, DATE_LONGDATE|DATE_SHORTDATE, NULL, - input, NULL, 0, NULL); - ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, - "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); - EXPECT_EQW; + L"", NULL, 0, NULL); + expect_werr(ret, buffer, ERROR_INVALID_FLAGS); + SetLastError(0xdeadbeef); + + /* Incorrect DOW and time */ + curtime.wYear = 2002; + curtime.wMonth = 10; + curtime.wDay = 23; + curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */ + curtime.wHour = 65432; /* Invalid */ + curtime.wMinute = 34512; /* Invalid */ + curtime.wSecond = 65535; /* Invalid */ + curtime.wMilliseconds = 12345; + ret = pGetDateFormatEx(localeW, 0, &curtime, L"dddd d MMMM yyyy", buffer, ARRAY_SIZE(buffer), NULL); + expect_wstr(ret, buffer, L"Wednesday 23 October 2002"); curtime.wYear = 2002; curtime.wMonth = 10; @@ -1030,23 +1096,10 @@ static void test_GetDateFormatEx(void) curtime.wMinute = 34512; /* Invalid */ curtime.wSecond = 65535; /* Invalid */ curtime.wMilliseconds = 12345; - STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */ - ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; - - curtime.wYear = 2002; - curtime.wMonth = 10; - curtime.wDay = 23; - curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */ - curtime.wHour = 65432; /* Invalid */ - curtime.wMinute = 34512; /* Invalid */ - curtime.wSecond = 65535; /* Invalid */ - curtime.wMilliseconds = 12345; - STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); - ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), emptyW); /* Use reserved arg */ - ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + wcscpy(buffer, L"pristine"); + ret = pGetDateFormatEx(localeW, 0, &curtime, L"dddd d MMMM yyyy", buffer, ARRAY_SIZE(buffer), emptyW); /* Use reserved arg */ + expect_werr(ret, buffer, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); /* Limit tests */ @@ -1058,11 +1111,8 @@ static void test_GetDateFormatEx(void) curtime.wMinute = 0; curtime.wSecond = 0; curtime.wMilliseconds = 0; - STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601"); - SetLastError(0xdeadbeef); - ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + ret = pGetDateFormatEx(localeW, 0, &curtime, L"dddd d MMMM yyyy", buffer, ARRAY_SIZE(buffer), NULL); + expect_wstr(ret, buffer, L"Monday 1 January 1601"); curtime.wYear = 1600; curtime.wMonth = 12; @@ -1072,43 +1122,42 @@ static void test_GetDateFormatEx(void) curtime.wMinute = 59; curtime.wSecond = 59; curtime.wMilliseconds = 999; - STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600"); - SetLastError(0xdeadbeef); - ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL); - ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + wcscpy(buffer, L"pristine"); + ret = pGetDateFormatEx(localeW, 0, &curtime, L"dddd d MMMM yyyy", buffer, ARRAY_SIZE(buffer), NULL); + expect_werr(ret, buffer, ERROR_INVALID_PARAMETER); } static void test_GetDateFormatW(void) { int ret; SYSTEMTIME curtime; - WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE]; + WCHAR buffer[BUFFER_SIZE]; LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); - STRINGSW("",""); /* If flags is not zero then format must be NULL */ - ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL, - input, buffer, COUNTOF(buffer)); + SetLastError(0xdeadbeef); + + /* If flags is not zero then format must be NULL */ + wcscpy(buffer, L"pristine"); + ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL, L"", buffer, ARRAY_SIZE(buffer)); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { win_skip("GetDateFormatW is not implemented\n"); return; } - ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, - "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); - EXPECT_EQW; - - STRINGSW("",""); /* NULL buffer, len > 0 */ + expect_werr(ret, buffer, ERROR_INVALID_FLAGS); SetLastError(0xdeadbeef); - ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer)); - 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); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* NULL buffer, len > 0 */ + wcscpy(buffer, L"pristine"); + ret = GetDateFormatW (lcid, 0, NULL, L"", NULL, ARRAY_SIZE(buffer)); + expect_werr(ret, buffer, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); + /* NULL buffer, len == 0 */ + ret = GetDateFormatW (lcid, 0, NULL, L"", NULL, 0); + expect_wstr(ret, NULL, L""); + + /* Incorrect DOW and time */ curtime.wYear = 2002; curtime.wMonth = 10; curtime.wDay = 23; @@ -1117,10 +1166,8 @@ static void test_GetDateFormatW(void) curtime.wMinute = 34512; /* Invalid */ curtime.wSecond = 65535; /* Invalid */ 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)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + ret = GetDateFormatW (lcid, 0, &curtime, L"dddd d MMMM yyyy", buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"Wednesday 23 October 2002"); /* Limit tests */ @@ -1132,11 +1179,8 @@ static void test_GetDateFormatW(void) curtime.wMinute = 0; curtime.wSecond = 0; curtime.wMilliseconds = 0; - STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601"); - SetLastError(0xdeadbeef); - ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + ret = GetDateFormatW (lcid, 0, &curtime, L"dddd d MMMM yyyy", buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"Monday 1 January 1601"); curtime.wYear = 1600; curtime.wMonth = 12; @@ -1146,11 +1190,23 @@ static void test_GetDateFormatW(void) curtime.wMinute = 59; curtime.wSecond = 59; curtime.wMilliseconds = 999; - STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600"); + wcscpy(buffer, L"pristine"); + ret = GetDateFormatW (lcid, 0, &curtime, L"dddd d MMMM yyyy", buffer, ARRAY_SIZE(buffer)); + expect_werr(ret, buffer, ERROR_INVALID_PARAMETER); SetLastError(0xdeadbeef); - ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + + /* See the corresponding GetDateFormatA() test */ + + lcid = MAKELCID(MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN), SORT_DEFAULT); + + curtime.wYear = 2002; + curtime.wMonth = 5; + curtime.wDay = 4; + ret = GetDateFormatW(lcid, 0, &curtime, L"d\x65e5", buffer, 3); + expect_wstr(ret, buffer, L"4\x65e5"); + + ret = GetDateFormatW(lcid, 0, &curtime, L"d\x65e5", NULL, 0); + expect_wstr(ret, NULL, L"4\x65e5"); } @@ -1164,92 +1220,104 @@ static void test_GetCurrencyFormatA(void) static char szDot[] = { '.', '\0' }; static char szComma[] = { ',', '\0' }; static char szDollar[] = { '$', '\0' }; - int ret; + static const char* const negative_order[] = + {"($1.0)", /* 0 */ + "-$1.0", + "$-1.0", + "$1.0-", + "(1.0$)", + "-1.0$", /* 5 */ + "1.0-$", + "1.0$-", + "-1.0 $", + "-$ 1.0", + "1.0 $-", /* 10 */ + "$ 1.0-", + "$ -1.0", + "1.0- $", + "($ 1.0)", + "(1.0 $)", /* 15 */ + }; + int ret, o; LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); - char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE]; + char buffer[BUFFER_SIZE]; CURRENCYFMTA format; + SetLastError(0xdeadbeef); + + /* NULL output, length > 0 --> Error */ + ret = GetCurrencyFormatA(lcid, 0, "23", NULL, NULL, ARRAY_SIZE(buffer)); + expect_err(ret, NULL, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); + + /* Invalid character --> Error */ + strcpy(buffer, "pristine"); + ret = GetCurrencyFormatA(lcid, 0, "23,53", NULL, buffer, ARRAY_SIZE(buffer)); + expect_err(ret, buffer, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); + + /* Double '-' --> Error */ + strcpy(buffer, "pristine"); + ret = GetCurrencyFormatA(lcid, 0, "--", NULL, buffer, ARRAY_SIZE(buffer)); + expect_err(ret, buffer, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); + + /* Trailing '-' --> Error */ + strcpy(buffer, "pristine"); + ret = GetCurrencyFormatA(lcid, 0, "0-", NULL, buffer, ARRAY_SIZE(buffer)); + expect_err(ret, buffer, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); + + /* Double '.' --> Error */ + strcpy(buffer, "pristine"); + ret = GetCurrencyFormatA(lcid, 0, "0..", NULL, buffer, ARRAY_SIZE(buffer)); + expect_err(ret, buffer, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); + + /* Leading space --> Error */ + ret = GetCurrencyFormatA(lcid, 0, " 0.1", NULL, buffer, ARRAY_SIZE(buffer)); + expect_err(ret, buffer, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); + + /* Length too small --> Write up to length chars */ + strcpy(buffer, "pristine"); + ret = GetCurrencyFormatA(lcid, NUO, "1234", NULL, buffer, 2); + /* there is no guarantee on the buffer content, see GetTimeFormatA() */ + expect_err(ret, NULL, ERROR_INSUFFICIENT_BUFFER); + SetLastError(0xdeadbeef); + + /* Valid number */ + ret = GetCurrencyFormatA(lcid, NUO, "2353", NULL, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "$2,353.00"); + + /* Valid negative number */ + ret = GetCurrencyFormatA(lcid, NUO, "-2353", NULL, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "($2,353.00)"); + + /* Valid real number */ + ret = GetCurrencyFormatA(lcid, NUO, "2353.1", NULL, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "$2,353.10"); + + /* Too many DP --> Truncated */ + ret = GetCurrencyFormatA(lcid, NUO, "2353.111", NULL, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "$2,353.11"); + + /* Too many DP --> Rounded */ + ret = GetCurrencyFormatA(lcid, NUO, "2353.119", NULL, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "$2,353.12"); + + /* Format and flags given --> Error */ memset(&format, 0, sizeof(format)); - - STRINGSA("23",""); /* NULL output, length > 0 --> Error */ + strcpy(buffer, "pristine"); + ret = GetCurrencyFormatA(lcid, NUO, "2353", &format, buffer, ARRAY_SIZE(buffer)); + expect_err(ret, buffer, ERROR_INVALID_FLAGS); SetLastError(0xdeadbeef); - ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer)); - ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); - STRINGSA("23,53",""); /* Invalid character --> Error */ + /* Invalid format --> Error */ + strcpy(buffer, "pristine"); + ret = GetCurrencyFormatA(lcid, 0, "2353", &format, buffer, ARRAY_SIZE(buffer)); + expect_err(ret, buffer, ERROR_INVALID_PARAMETER); SetLastError(0xdeadbeef); - ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer)); - 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)); - 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)); - 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)); - 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)); - 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); - 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)); - 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)); - 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)); - 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)); - 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)); - 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)); - 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)); - 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; @@ -1260,154 +1328,77 @@ static void test_GetCurrencyFormatA(void) format.lpThousandSep = szComma; format.lpCurrencySymbol = szDollar; - STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */ - ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + /* No decimal or grouping chars expected */ + ret = GetCurrencyFormatA(lcid, 0, "2353", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "$2353"); - format.NumDigits = 1; /* 1 DP --> Expect decimal separator */ - STRINGSA("2353","$2353.0"); - ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + /* 1 DP --> Expect decimal separator */ + format.NumDigits = 1; + ret = GetCurrencyFormatA(lcid, 0, "2353", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "$2353.0"); - format.Grouping = 2; /* Group by 100's */ - STRINGSA("2353","$23,53.0"); - ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + /* Group by 100's */ + format.Grouping = 2; + ret = GetCurrencyFormatA(lcid, 0, "2353", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "$23,53.0"); - STRINGSA("235","$235.0"); /* Grouping of a positive number */ + /* Grouping of a positive number */ format.Grouping = 3; - ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + ret = GetCurrencyFormatA(lcid, 0, "235", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "$235.0"); - STRINGSA("-235","$-235.0"); /* Grouping of a negative number */ + format.Grouping = 31; + ret = GetCurrencyFormatA(lcid, 0, "1234567890", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "$1,2,3,4,5,6,7,890.0"); + + format.Grouping = 312; + ret = GetCurrencyFormatA(lcid, 0, "1234567890", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "$12,34,56,7,890.0"); + + format.Grouping = 310; + ret = GetCurrencyFormatA(lcid, 0, "1234567890", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "$123456,7,890.0"); + + /* Grouping of a negative number */ format.NegativeOrder = 2; - ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + ret = GetCurrencyFormatA(lcid, 0, "-235", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "$-235.0"); - format.LeadingZero = 1; /* Always provide leading zero */ - STRINGSA(".5","$0.5"); - ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + /* Always provide leading zero */ + format.LeadingZero = 1; + ret = GetCurrencyFormatA(lcid, 0, ".5", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "$0.5"); + ret = GetCurrencyFormatA(lcid, 0, "0.5", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "$0.5"); + + format.LeadingZero = 0; + ret = GetCurrencyFormatA(lcid, 0, "0.5", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "$.5"); + ret = GetCurrencyFormatA(lcid, 0, "0.5", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "$.5"); format.PositiveOrder = CY_POS_RIGHT; - STRINGSA("1","1.0$"); - ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + ret = GetCurrencyFormatA(lcid, 0, "1", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "1.0$"); format.PositiveOrder = CY_POS_LEFT_SPACE; - STRINGSA("1","$ 1.0"); - ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + ret = GetCurrencyFormatA(lcid, 0, "1", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "$ 1.0"); format.PositiveOrder = CY_POS_RIGHT_SPACE; - STRINGSA("1","1.0 $"); - ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + ret = GetCurrencyFormatA(lcid, 0, "1", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "1.0 $"); - format.NegativeOrder = 0; - STRINGSA("-1","($1.0)"); - ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - 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)); - 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)); - 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)); - 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)); - 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)); - 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)); - 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)); - 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)); - 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)); - 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)); - 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)); - 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)); - 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)); - 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)); - 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)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + for (o = 0; o <= 15; o++) + { + winetest_push_context("%d", o); + format.NegativeOrder = o; + strcpy(buffer, "pristine"); + ret = GetCurrencyFormatA(lcid, 0, "-1", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, negative_order[o]); + winetest_pop_context(); + } } #define NEG_PARENS 0 /* "(1.1)" */ @@ -1422,95 +1413,90 @@ static void test_GetNumberFormatA(void) static char szComma[] = { ',', '\0' }; int ret; LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); - char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE]; + WCHAR grouping[32], t1000[8], dec[8], frac[8], lzero[8]; + char buffer[BUFFER_SIZE]; NUMBERFMTA format; + SetLastError(0xdeadbeef); + + /* NULL output, length > 0 --> Error */ + strcpy(buffer, "pristine"); + ret = GetNumberFormatA(lcid, 0, "23", NULL, NULL, ARRAY_SIZE(buffer)); + expect_err(ret, buffer, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); + + /* Invalid character --> Error */ + strcpy(buffer, "pristine"); + ret = GetNumberFormatA(lcid, 0, "23,53", NULL, buffer, ARRAY_SIZE(buffer)); + expect_err(ret, buffer, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); + + /* Double '-' --> Error */ + strcpy(buffer, "pristine"); + ret = GetNumberFormatA(lcid, 0, "--", NULL, buffer, ARRAY_SIZE(buffer)); + expect_err(ret, buffer, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); + + /* Trailing '-' --> Error */ + strcpy(buffer, "pristine"); + ret = GetNumberFormatA(lcid, 0, "0-", NULL, buffer, ARRAY_SIZE(buffer)); + expect_err(ret, buffer, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); + + /* Double '.' --> Error */ + strcpy(buffer, "pristine"); + ret = GetNumberFormatA(lcid, 0, "0..", NULL, buffer, ARRAY_SIZE(buffer)); + expect_err(ret, buffer, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); + + /* Leading space --> Error */ + strcpy(buffer, "pristine"); + ret = GetNumberFormatA(lcid, 0, " 0.1", NULL, buffer, ARRAY_SIZE(buffer)); + expect_err(ret, buffer, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); + + /* Length too small --> Write up to length chars */ + ret = GetNumberFormatA(lcid, NUO, "1234", NULL, buffer, 2); + /* there is no guarantee on the buffer content, see GetTimeFormatA() */ + expect_err(ret, NULL, ERROR_INSUFFICIENT_BUFFER); + SetLastError(0xdeadbeef); + + /* Valid number */ + ret = GetNumberFormatA(lcid, NUO, "2353", NULL, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "2,353.00"); + + /* Valid negative number */ + ret = GetNumberFormatA(lcid, NUO, "-2353", NULL, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "-2,353.00"); + + /* test for off by one error in grouping */ + ret = GetNumberFormatA(lcid, NUO, "-353", NULL, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "-353.00"); + + /* Valid real number */ + ret = GetNumberFormatA(lcid, NUO, "2353.1", NULL, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "2,353.10"); + + /* Too many DP --> Truncated */ + ret = GetNumberFormatA(lcid, NUO, "2353.111", NULL, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "2,353.11"); + + /* Too many DP --> Rounded */ + ret = GetNumberFormatA(lcid, NUO, "2353.119", NULL, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "2,353.12"); + + /* Format and flags given --> Error */ memset(&format, 0, sizeof(format)); - - STRINGSA("23",""); /* NULL output, length > 0 --> Error */ + strcpy(buffer, "pristine"); + ret = GetNumberFormatA(lcid, NUO, "2353", &format, buffer, ARRAY_SIZE(buffer)); + expect_err(ret, buffer, ERROR_INVALID_FLAGS); SetLastError(0xdeadbeef); - ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer)); - ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); - STRINGSA("23,53",""); /* Invalid character --> Error */ + /* Invalid format --> Error */ + strcpy(buffer, "pristine"); + ret = GetNumberFormatA(lcid, 0, "2353", &format, buffer, ARRAY_SIZE(buffer)); + expect_err(ret, buffer, ERROR_INVALID_PARAMETER); SetLastError(0xdeadbeef); - ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer)); - 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)); - 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)); - 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)); - 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)); - 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); - 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)); - 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)); - 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)); - 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)); - 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)); - 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)); - 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)); - 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)); - 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; @@ -1519,80 +1505,155 @@ static void test_GetNumberFormatA(void) format.lpDecimalSep = szDot; format.lpThousandSep = szComma; - STRINGSA("2353","2353"); /* No decimal or grouping chars expected */ - ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + /* No decimal or grouping chars expected */ + ret = GetNumberFormatA(lcid, 0, "2353", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "2353"); format.NumDigits = 1; /* 1 DP --> Expect decimal separator */ - STRINGSA("2353","2353.0"); - ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + ret = GetNumberFormatA(lcid, 0, "2353", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "2353.0"); format.Grouping = 2; /* Group by 100's */ - STRINGSA("2353","23,53.0"); - ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + ret = GetNumberFormatA(lcid, 0, "2353", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "23,53.0"); - STRINGSA("235","235.0"); /* Grouping of a positive number */ + /* Grouping of a positive number */ format.Grouping = 3; - ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + ret = GetNumberFormatA(lcid, 0, "235", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "235.0"); + ret = GetNumberFormatA(lcid, 0, "000235", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "235.0"); - STRINGSA("-235","-235.0"); /* Grouping of a negative number */ + format.Grouping = 23; + ret = GetNumberFormatA(lcid, 0, "123456789", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "1,234,567,89.0"); + + format.Grouping = 230; + ret = GetNumberFormatA(lcid, 0, "123456789", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "1234,567,89.0"); + + format.Grouping = 203; + ret = GetNumberFormatA(lcid, 0, "123456789", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "1,234,567,,89.0"); + + format.Grouping = 2030; + ret = GetNumberFormatA(lcid, 0, "123456789", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "1234,567,,89.0"); + + format.Grouping = 2003; + ret = GetNumberFormatA(lcid, 0, "123456789", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "1,234,567,,,89.0"); + + format.Grouping = 1200; + ret = GetNumberFormatA(lcid, 0, "123456789", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "123456,,78,9.0"); + + /* Grouping of a negative number */ format.NegativeOrder = NEG_LEFT; - ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + format.Grouping = 3; + ret = GetNumberFormatA(lcid, 0, "-235", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "-235.0"); + ret = GetNumberFormatA(lcid, 0, "-000235", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "-235.0"); format.LeadingZero = 1; /* Always provide leading zero */ - STRINGSA(".5","0.5"); - ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + ret = GetNumberFormatA(lcid, 0, ".5", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "0.5"); + ret = GetNumberFormatA(lcid, 0, "0000.5", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "0.5"); format.NegativeOrder = NEG_PARENS; - STRINGSA("-1","(1.0)"); - ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + ret = GetNumberFormatA(lcid, 0, "-1", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "(1.0)"); format.NegativeOrder = NEG_LEFT; - STRINGSA("-1","-1.0"); - ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + ret = GetNumberFormatA(lcid, 0, "-1", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "-1.0"); format.NegativeOrder = NEG_LEFT_SPACE; - STRINGSA("-1","- 1.0"); - ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + ret = GetNumberFormatA(lcid, 0, "-1", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "- 1.0"); format.NegativeOrder = NEG_RIGHT; - STRINGSA("-1","1.0-"); - ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + ret = GetNumberFormatA(lcid, 0, "-1", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "1.0-"); format.NegativeOrder = NEG_RIGHT_SPACE; - STRINGSA("-1","1.0 -"); - ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + ret = GetNumberFormatA(lcid, 0, "-1", &format, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "1.0 -"); + /* Test French formatting */ lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT); - if (IsValidLocale(lcid, 0)) { - STRINGSA("-12345","-12 345,00"); /* Try French formatting */ - Expected[3] = 160; /* Non breaking space */ - ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENA; EXPECT_EQA; + ret = GetNumberFormatA(lcid, NUO, "-12345", NULL, buffer, ARRAY_SIZE(buffer)); + expect_str(ret, buffer, "-12\xa0\x33\x34\x35,00"); /* Non breaking space */ + } + + /* Test the actual LOCALE_SGROUPING string, the rules for repeats are opposite */ + if (GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, grouping, ARRAY_SIZE(grouping)) && + GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, t1000, ARRAY_SIZE(t1000)) && + GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, dec, ARRAY_SIZE(dec)) && + GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDIGITS, frac, ARRAY_SIZE(frac)) && + GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_ILZERO, lzero, ARRAY_SIZE(lzero))) + { + static const struct + { + const char *grouping; + const char *expected; + } tests[] = { + { "3;0", "1,234,567,890.54321" }, + { "2;3", "12345,678,90.54321" }, + { "1", "123456789,0.54321" }, + { "1;0", "1,2,3,4,5,6,7,8,9,0.54321" }, + { "1;0;3", "123456,789,,0.54321" }, + { "0", "1234567890.54321" }, + { "0;0", "1234567890.54321" }, + { "0;1", "123456789,0.54321" }, + { "0;0;0", "1234567890.54321" }, + { "0;1;0", "1,2,3,4,5,6,7,8,9,0.54321" }, + { "2;0;0", "12345678,90.54321" }, + { "2;0;0;0", "12345678,,90.54321" }, + { "2;0;0;0;0", "12345678,,,90.54321" }, + { "2;0;0;1;0", "1,2,3,4,5,6,7,8,,,90.54321" }, + { "1;3;2", "1234,56,789,0.54321" }, + { "1;3;2;0", "12,34,56,789,0.54321" }, + { "3;1;1;2;0", "1,23,45,6,7,890.54321" }, + { "6;1", "123,4,567890.54321" }, + }; + unsigned i; + + SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, ","); + SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, "."); + SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_IDIGITS, "5"); + SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ILZERO, "0"); + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { +#ifdef __REACTOS__ + /* Skip tests[4, 10-13] on WS03 */ + if (GetNTVersion() < _WIN32_WINNT_VISTA && (i == 4 || (i >= 10 && i <= 13))) + continue; +#endif + SetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, tests[i].grouping); + SetLastError(0xdeadbeef); + ret = GetNumberFormatA(LOCALE_USER_DEFAULT, 0, "1234567890.54321", NULL, buffer, ARRAY_SIZE(buffer)); + if (ret) + { + ok(GetLastError() == 0xdeadbeef, "[%u] unexpected error %lu\n", i, GetLastError()); + ok(ret == strlen(tests[i].expected) + 1, "[%u] unexpected ret %d\n", i, ret); + ok(!strcmp(buffer, tests[i].expected), "[%u] unexpected string %s\n", i, buffer); + } + else + ok(0, "[%u] expected success, got error %ld\n", i, GetLastError()); + } + + /* Restore */ + ok(SetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, grouping), "Restoring SGROUPING failed\n"); + ok(SetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, t1000), "Restoring STHOUSAND failed\n"); + ok(SetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, dec), "Restoring SDECIMAL failed\n"); + ok(SetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDIGITS, frac), "Restoring IDIGITS failed\n"); + ok(SetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_ILZERO, lzero), "Restoring ILZERO failed\n"); } } @@ -1605,7 +1666,7 @@ static void test_GetNumberFormatEx(void) static const WCHAR enW[] = {'e','n','-','U','S',0}; static const WCHAR frW[] = {'f','r','-','F','R',0}; static const WCHAR bogusW[] = {'b','o','g','u','s',0}; - WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE]; + WCHAR buffer[BUFFER_SIZE]; if (!pGetNumberFormatEx) { @@ -1613,88 +1674,94 @@ static void test_GetNumberFormatEx(void) return; } - STRINGSW("23",""); /* NULL output, length > 0 --> Error */ - ret = pGetNumberFormatEx(enW, 0, input, NULL, NULL, COUNTOF(buffer)); - ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + SetLastError(0xdeadbeef); - STRINGSW("23,53",""); /* Invalid character --> Error */ - ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer)); - ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + /* NULL output, length > 0 --> Error */ + wcscpy(buffer, L"pristine"); + ret = pGetNumberFormatEx(enW, 0, L"23", NULL, NULL, ARRAY_SIZE(buffer)); + expect_werr(ret, buffer, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); - STRINGSW("--",""); /* Double '-' --> Error */ - ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer)); - ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + /* Invalid character --> Error */ + wcscpy(buffer, L"pristine"); + ret = pGetNumberFormatEx(enW, 0, L"23,53", NULL, buffer, ARRAY_SIZE(buffer)); + expect_werr(ret, buffer, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); - STRINGSW("0-",""); /* Trailing '-' --> Error */ - ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer)); - ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + /* Double '-' --> Error */ + wcscpy(buffer, L"pristine"); + ret = pGetNumberFormatEx(enW, 0, L"--", NULL, buffer, ARRAY_SIZE(buffer)); + expect_werr(ret, buffer, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); - STRINGSW("0..",""); /* Double '.' --> Error */ - ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer)); - ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + /* Trailing '-' --> Error */ + wcscpy(buffer, L"pristine"); + ret = pGetNumberFormatEx(enW, 0, L"0-", NULL, buffer, ARRAY_SIZE(buffer)); + expect_werr(ret, buffer, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); - STRINGSW(" 0.1",""); /* Leading space --> Error */ - ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer)); - ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + /* Double '.' --> Error */ + wcscpy(buffer, L"pristine"); + ret = pGetNumberFormatEx(enW, 0, L"0..", NULL, buffer, ARRAY_SIZE(buffer)); + expect_werr(ret, buffer, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); - STRINGSW("1234","1"); /* Length too small --> Write up to length chars */ - ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, 2); - ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); + /* Leading space --> Error */ + wcscpy(buffer, L"pristine"); + ret = pGetNumberFormatEx(enW, 0, L" 0.1", NULL, buffer, ARRAY_SIZE(buffer)); + expect_werr(ret, buffer, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); - STRINGSW("23",""); /* Bogus locale --> Error */ - ret = pGetNumberFormatEx(bogusW, NUO, input, NULL, buffer, COUNTOF(buffer)); - ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + /* Length too small --> Write up to length chars */ + wcscpy(buffer, L"pristine"); + ret = pGetNumberFormatEx(enW, NUO, L"1234", NULL, buffer, 2); + /* there is no guarantee on the buffer content, see GetTimeFormatA() */ + expect_werr(ret, NULL, ERROR_INSUFFICIENT_BUFFER); + SetLastError(0xdeadbeef); + + /* Bogus locale --> Error */ + wcscpy(buffer, L"pristine"); + ret = pGetNumberFormatEx(bogusW, NUO, L"23", NULL, buffer, ARRAY_SIZE(buffer)); + expect_werr(ret, buffer, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); memset(&format, 0, sizeof(format)); - STRINGSW("2353",""); /* Format and flags given --> Error */ - ret = pGetNumberFormatEx(enW, NUO, input, &format, buffer, COUNTOF(buffer)); - 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()); + /* Format and flags given --> Error */ + wcscpy(buffer, L"pristine"); + ret = pGetNumberFormatEx(enW, NUO, L"2353", &format, buffer, ARRAY_SIZE(buffer)); + expect_werr(ret, buffer, ERROR_INVALID_FLAGS); + SetLastError(0xdeadbeef); - STRINGSW("2353",""); /* Invalid format --> Error */ - ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer)); - ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + /* Invalid format --> Error */ + wcscpy(buffer, L"pristine"); + ret = pGetNumberFormatEx(enW, 0, L"2353", &format, buffer, ARRAY_SIZE(buffer)); + expect_werr(ret, buffer, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); - STRINGSW("2353","2,353.00"); /* Valid number */ - ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* Valid number */ + ret = pGetNumberFormatEx(enW, NUO, L"2353", NULL, buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"2,353.00"); - STRINGSW("-2353","-2,353.00"); /* Valid negative number */ - ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* Valid negative number */ + ret = pGetNumberFormatEx(enW, NUO, L"-2353", NULL, buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"-2,353.00"); - STRINGSW("-353","-353.00"); /* test for off by one error in grouping */ - ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* test for off by one error in grouping */ + ret = pGetNumberFormatEx(enW, NUO, L"-353", NULL, buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"-353.00"); - STRINGSW("2353.1","2,353.10"); /* Valid real number */ - ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* Valid real number */ + ret = pGetNumberFormatEx(enW, NUO, L"2353.1", NULL, buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"2,353.10"); - STRINGSW("2353.111","2,353.11"); /* Too many DP --> Truncated */ - ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* Too many DP --> Truncated */ + ret = pGetNumberFormatEx(enW, NUO, L"2353.111", NULL, buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"2,353.11"); - STRINGSW("2353.119","2,353.12"); /* Too many DP --> Rounded */ - ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* Too many DP --> Rounded */ + ret = pGetNumberFormatEx(enW, NUO, L"2353.119", NULL, buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"2,353.12"); format.NumDigits = 0; /* No decimal separator */ format.LeadingZero = 0; @@ -1703,78 +1770,72 @@ static void test_GetNumberFormatEx(void) format.lpDecimalSep = dotW; format.lpThousandSep = commaW; - STRINGSW("2353","2353"); /* No decimal or grouping chars expected */ - ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* No decimal or grouping chars expected */ + ret = pGetNumberFormatEx(enW, 0, L"2353", &format, buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"2353"); - format.NumDigits = 1; /* 1 DP --> Expect decimal separator */ - STRINGSW("2353","2353.0"); - ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* 1 DP --> Expect decimal separator */ + format.NumDigits = 1; + ret = pGetNumberFormatEx(enW, 0, L"2353", &format, buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"2353.0"); - format.Grouping = 2; /* Group by 100's */ - STRINGSW("2353","23,53.0"); - ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* Group by 100's */ + format.Grouping = 2; + ret = pGetNumberFormatEx(enW, 0, L"2353", &format, buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"23,53.0"); - STRINGSW("235","235.0"); /* Grouping of a positive number */ + /* Grouping of a positive number */ format.Grouping = 3; - ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + ret = pGetNumberFormatEx(enW, 0, L"235", &format, buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"235.0"); - STRINGSW("-235","-235.0"); /* Grouping of a negative number */ + /* Grouping of a negative number */ format.NegativeOrder = NEG_LEFT; - ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + ret = pGetNumberFormatEx(enW, 0, L"-235", &format, buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"-235.0"); - format.LeadingZero = 1; /* Always provide leading zero */ - STRINGSW(".5","0.5"); - ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + /* Always provide leading zero */ + format.LeadingZero = 1; + ret = pGetNumberFormatEx(enW, 0, L".5", &format, buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"0.5"); + ret = pGetNumberFormatEx(enW, 0, L"0.5", &format, buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"0.5"); + + format.LeadingZero = 0; + ret = pGetNumberFormatEx(enW, 0, L".5", &format, buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L".5"); + ret = pGetNumberFormatEx(enW, 0, L"0.5", &format, buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L".5"); format.NegativeOrder = NEG_PARENS; - STRINGSW("-1","(1.0)"); - ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + ret = pGetNumberFormatEx(enW, 0, L"-1", &format, buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"(1.0)"); format.NegativeOrder = NEG_LEFT; - STRINGSW("-1","-1.0"); - ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + ret = pGetNumberFormatEx(enW, 0, L"-1", &format, buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"-1.0"); format.NegativeOrder = NEG_LEFT_SPACE; - STRINGSW("-1","- 1.0"); - ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + ret = pGetNumberFormatEx(enW, 0, L"-1", &format, buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"- 1.0"); format.NegativeOrder = NEG_RIGHT; - STRINGSW("-1","1.0-"); - ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + ret = pGetNumberFormatEx(enW, 0, L"-1", &format, buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"1.0-"); format.NegativeOrder = NEG_RIGHT_SPACE; - STRINGSW("-1","1.0 -"); - ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + ret = pGetNumberFormatEx(enW, 0, L"-1", &format, buffer, ARRAY_SIZE(buffer)); + expect_wstr(ret, buffer, L"1.0 -"); + /* Test French formatting */ if (pIsValidLocaleName(frW)) { - STRINGSW("-12345","-12 345,00"); /* Try French formatting */ - Expected[3] = 160; /* Non breaking space */ - ret = pGetNumberFormatEx(frW, NUO, input, NULL, buffer, COUNTOF(buffer)); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); - EXPECT_LENW; EXPECT_EQW; + const WCHAR *expected; + ret = pGetNumberFormatEx(frW, NUO, L"-12345", NULL, buffer, ARRAY_SIZE(buffer)); + expected = (ret && wcschr(buffer, 0x202f)) ? + L"-12\x202f\x33\x34\x35,00" : /* Same but narrow (win11) */ + L"-12\xa0\x33\x34\x35,00"; /* Non breaking space */ + expect_wstr(ret, buffer, expected); } } @@ -1786,6 +1847,7 @@ struct comparestringa_entry { const char *second; int second_len; int ret; + DWORD le; }; static const struct comparestringa_entry comparestringa_data[] = { @@ -1833,21 +1895,45 @@ static const struct comparestringa_entry comparestringa_data[] = { { LOCALE_SYSTEM_DEFAULT, 0, "a", 2, "a\0x", 4, CSTR_LESS_THAN }, { LOCALE_SYSTEM_DEFAULT, 0, "a\0x", 4, "a", 1, CSTR_GREATER_THAN }, { LOCALE_SYSTEM_DEFAULT, 0, "a\0x", 4, "a", 2, CSTR_GREATER_THAN }, + /* flag tests */ + { LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1, CSTR_EQUAL }, + { LOCALE_SYSTEM_DEFAULT, LINGUISTIC_IGNORECASE, "NULL", -1, "NULL", -1, CSTR_EQUAL }, + { LOCALE_SYSTEM_DEFAULT, LINGUISTIC_IGNOREDIACRITIC, "NULL", -1, "NULL", -1, CSTR_EQUAL }, + { LOCALE_SYSTEM_DEFAULT, NORM_IGNOREKANATYPE, "NULL", -1, "NULL", -1, CSTR_EQUAL }, + { LOCALE_SYSTEM_DEFAULT, NORM_IGNORENONSPACE, "NULL", -1, "NULL", -1, CSTR_EQUAL }, + { LOCALE_SYSTEM_DEFAULT, NORM_IGNOREWIDTH, "NULL", -1, "NULL", -1, CSTR_EQUAL }, + { LOCALE_SYSTEM_DEFAULT, NORM_LINGUISTIC_CASING, "NULL", -1, "NULL", -1, CSTR_EQUAL }, + { LOCALE_SYSTEM_DEFAULT, SORT_DIGITSASNUMBERS, "NULL", -1, "NULL", -1, 0, ERROR_INVALID_FLAGS } }; static void test_CompareStringA(void) { + static const char ABC_EE[] = {'A','B','C',0,0xEE}; + static const char ABC_FF[] = {'A','B','C',0,0xFF}; int ret, i; char a[256]; + BOOL is_utf8; + CPINFOEXA cpinfo; LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT); - for (i = 0; i < sizeof(comparestringa_data)/sizeof(struct comparestringa_entry); i++) + GetCPInfoExA( CP_ACP, 0, &cpinfo ); + is_utf8 = cpinfo.CodePage == CP_UTF8; + + for (i = 0; i < ARRAY_SIZE(comparestringa_data); i++) { +#ifdef __REACTOS__ + /* Skip comparestringa_data[44, 45, 49] on WS03 */ + if (GetNTVersion() < _WIN32_WINNT_VISTA && (i == 44 || i == 45 || i == 49)) + continue; +#endif const struct comparestringa_entry *entry = &comparestringa_data[i]; + SetLastError(0xdeadbeef); ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len, entry->second, entry->second_len); ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret); + ok(GetLastError() == (ret ? 0xdeadbeef : entry->le), "%d: got last error %ld, expected %ld\n", + i, GetLastError(), (ret ? 0xdeadbeef : entry->le)); } ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1); @@ -1873,19 +1959,6 @@ static void test_CompareStringA(void) ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1); ok (ret == CSTR_EQUAL, "(Salut/saLuT) Expected CSTR_EQUAL, got %d\n", ret); - /* test for CompareStringA flags */ - SetLastError(0xdeadbeef); - 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"); - - SetLastError(0xdeadbeef); - ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1); - ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError()); - ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret); - /* end of test for CompareStringA flags */ - ret = lstrcmpA("", ""); ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret); @@ -1897,9 +1970,7 @@ static void test_CompareStringA(void) ret = lstrcmpA(NULL, ""); ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret); - - if (0) { /* this requires collation table patch to make it MS compatible */ ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 ); ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret); @@ -1935,8 +2006,6 @@ static void test_CompareStringA(void) ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 ); ok(ret == CSTR_LESS_THAN, "-m vs `o expected CSTR_LESS_THAN, got %d\n", ret); - } - /* WinXP handles embedded NULLs differently than earlier versions */ ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10); @@ -1954,7 +2023,7 @@ static void test_CompareStringA(void) "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret); ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2); - todo_wine ok(ret != CSTR_EQUAL, "\\2 vs \\1 expected unequal\n"); + ok(ret != CSTR_EQUAL, "\\2 vs \\1 expected unequal\n"); ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1); ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret); @@ -1969,7 +2038,7 @@ static void test_CompareStringA(void) /* \xB9 character lies between a and b */ ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1); - todo_wine ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n"); + ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n"); ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1); ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n"); @@ -1977,11 +2046,27 @@ static void test_CompareStringA(void) SetLastError(0xdeadbeef); ret = CompareStringA(lcid, 0, a, sizeof(a), a, sizeof(a)); ok (GetLastError() == 0xdeadbeef && ret == CSTR_EQUAL, - "ret %d, error %d, expected value %d\n", ret, GetLastError(), CSTR_EQUAL); + "ret %d, error %ld, expected value %d\n", ret, GetLastError(), CSTR_EQUAL); + + ret = CompareStringA(LOCALE_USER_DEFAULT, 0, ABC_EE, 3, ABC_FF, 3); + ok(ret == CSTR_EQUAL, "expected CSTR_EQUAL, got %d\n", ret); + ret = CompareStringA(LOCALE_USER_DEFAULT, 0, ABC_EE, 5, ABC_FF, 3); + ok(ret == CSTR_GREATER_THAN || (is_utf8 && ret == CSTR_EQUAL), "expected CSTR_GREATER_THAN, got %d\n", ret); + ret = CompareStringA(LOCALE_USER_DEFAULT, 0, ABC_EE, 3, ABC_FF, 5); + ok(ret == CSTR_LESS_THAN || (is_utf8 && ret == CSTR_EQUAL), "expected CSTR_LESS_THAN, got %d\n", ret); + ret = CompareStringA(LOCALE_USER_DEFAULT, 0, ABC_EE, 5, ABC_FF, 5); + ok(ret == CSTR_LESS_THAN || (is_utf8 && ret == CSTR_EQUAL), "expected CSTR_LESS_THAN, got %d\n", ret); + ret = CompareStringA(LOCALE_USER_DEFAULT, 0, ABC_FF, 5, ABC_EE, 5); + ok(ret == CSTR_GREATER_THAN || (is_utf8 && ret == CSTR_EQUAL), "expected CSTR_GREATER_THAN, got %d\n", ret); } static void test_CompareStringW(void) { + static const WCHAR ABC_EE[] = {'A','B','C',0,0xEE}; + static const WCHAR ABC_FF[] = {'A','B','C',0,0xFF}; + static const WCHAR A_ACUTE_BC[] = {0xc1,'B','C',0}; + static const WCHAR A_ACUTE_BC_DECOMP[] = {'A',0x301,'B','C',0}; + static const WCHAR A_NULL_BC[] = {'A',0,'B','C',0}; WCHAR *str1, *str2; SYSTEM_INFO si; DWORD old_prot; @@ -1991,11 +2076,11 @@ static void test_CompareStringW(void) GetSystemInfo(&si); buf = VirtualAlloc(NULL, si.dwPageSize * 4, MEM_COMMIT, PAGE_READWRITE); - ok(buf != NULL, "VirtualAlloc failed with %u\n", GetLastError()); + ok(buf != NULL, "VirtualAlloc failed with %lu\n", GetLastError()); success = VirtualProtect(buf + si.dwPageSize, si.dwPageSize, PAGE_NOACCESS, &old_prot); - ok(success, "VirtualProtect failed with %u\n", GetLastError()); + ok(success, "VirtualProtect failed with %lu\n", GetLastError()); success = VirtualProtect(buf + 3 * si.dwPageSize, si.dwPageSize, PAGE_NOACCESS, &old_prot); - ok(success, "VirtualProtect failed with %u\n", GetLastError()); + ok(success, "VirtualProtect failed with %lu\n", GetLastError()); str1 = (WCHAR *)(buf + si.dwPageSize - sizeof(WCHAR)); str2 = (WCHAR *)(buf + 3 * si.dwPageSize - sizeof(WCHAR)); @@ -2003,11 +2088,57 @@ static void test_CompareStringW(void) *str2 = 'B'; /* CompareStringW should abort on the first non-matching character */ - ret = CompareStringW(CP_ACP, 0, str1, 100, str2, 100); + ret = CompareStringW(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), + 0, str1, 100, str2, 100); ok(ret == CSTR_LESS_THAN, "expected CSTR_LESS_THAN, got %d\n", ret); success = VirtualFree(buf, 0, MEM_RELEASE); - ok(success, "VirtualFree failed with %u\n", GetLastError()); + ok(success, "VirtualFree failed with %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = CompareStringW(LOCALE_USER_DEFAULT, SORT_DIGITSASNUMBERS, L"NULL", -1, L"NULL", -1); + ok(ret == CSTR_EQUAL || broken(!ret && GetLastError() == ERROR_INVALID_FLAGS) /* locale, -1, locale, sizeof(locale)/sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, e->locale, -1, locale, ARRAY_SIZE(locale)); ret = pCompareStringEx(locale, e->flags, e->first, -1, e->second, -1, NULL, NULL, 0); - todo_wine_if (e->todo) - ok(ret == e->ret || broken(ret == e->broken), - "%d: got %s, expected %s\n", i, op[ret], op[e->ret]); + ok(ret == e->ret || broken(ret == e->broken), + "%d: got %s, expected %s\n", i, op[ret], op[e->ret]); } } @@ -2239,7 +2368,7 @@ static void test_LCMapStringA(void) ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE, lower_case, -1, buf, sizeof(buf)); ok(ret == lstrlenA(lower_case) + 1, - "ret %d, error %d, expected value %d\n", + "ret %d, error %ld, expected value %d\n", ret, GetLastError(), lstrlenA(lower_case) + 1); ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf); @@ -2247,18 +2376,18 @@ static void test_LCMapStringA(void) upper_case, -1, buf, sizeof(buf)); ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n"); ok(GetLastError() == ERROR_INVALID_FLAGS, - "unexpected error code %d\n", GetLastError()); + "unexpected error code %ld\n", GetLastError()); /* test invalid flag combinations */ - for (i = 0; i < sizeof(lcmap_invalid_flags)/sizeof(lcmap_invalid_flags[0]); i++) { + for (i = 0; i < ARRAY_SIZE(lcmap_invalid_flags); i++) { lstrcpyA(buf, "foo"); SetLastError(0xdeadbeef); ret = LCMapStringA(LOCALE_USER_DEFAULT, lcmap_invalid_flags[i], lower_case, -1, buf, sizeof(buf)); ok(GetLastError() == ERROR_INVALID_FLAGS, - "LCMapStringA (flag %08x) unexpected error code %d\n", + "LCMapStringA (flag %08lx) unexpected error code %ld\n", lcmap_invalid_flags[i], GetLastError()); - ok(!ret, "LCMapStringA (flag %08x) should return 0, got %d\n", + ok(!ret, "LCMapStringA (flag %08lx) should return 0, got %d\n", lcmap_invalid_flags[i], ret); } @@ -2266,7 +2395,7 @@ static void test_LCMapStringA(void) ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, upper_case, -1, buf, sizeof(buf)); ok(ret == lstrlenA(upper_case) + 1, - "ret %d, error %d, expected value %d\n", + "ret %d, error %ld, expected value %d\n", ret, GetLastError(), lstrlenA(upper_case) + 1); ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf); @@ -2274,7 +2403,7 @@ static void test_LCMapStringA(void) ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE, lower_case, -1, buf, sizeof(buf)); ok(ret == lstrlenA(lower_case) + 1, - "ret %d, error %d, expected value %d\n", + "ret %d, error %ld, expected value %d\n", ret, GetLastError(), lstrlenA(lower_case) + 1); ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf); @@ -2294,7 +2423,7 @@ static void test_LCMapStringA(void) else { ok(ret == lstrlenA(lower_case) + 1, - "ret %d, error %d, expected value %d\n", + "ret %d, error %ld, expected value %d\n", ret, GetLastError(), lstrlenA(lower_case) + 1); ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf); } @@ -2306,7 +2435,7 @@ static void test_LCMapStringA(void) else { ok(ret == lstrlenA(upper_case) + 1, - "ret %d, error %d, expected value %d\n", + "ret %d, error %ld, expected value %d\n", ret, GetLastError(), lstrlenA(lower_case) + 1); ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf); } @@ -2317,10 +2446,11 @@ static void test_LCMapStringA(void) buf, 10, buf, sizeof(buf)); ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ || GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */, - "unexpected error code %d\n", GetLastError()); + "unexpected error code %ld\n", GetLastError()); ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n"); /* test whether '\0' is always appended */ + memset(buf, 0xff, sizeof(buf)); ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY, upper_case, -1, buf, sizeof(buf)); ok(ret, "LCMapStringA must succeed\n"); @@ -2330,7 +2460,13 @@ static void test_LCMapStringA(void) ok(ret2, "LCMapStringA must succeed\n"); ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" ); ok(ret == ret2, "lengths of sort keys must be equal\n"); - ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n"); + ok(!memcmp(buf, buf2, ret), "sort keys must be equal\n"); + + /* test we get the same length when no dest buffer is provided */ + ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY, + upper_case, lstrlenA(upper_case), NULL, 0); + ok(ret2, "LCMapStringA must succeed\n"); + ok(ret == ret2, "lengths of sort keys must be equal (%d vs %d)\n", ret, ret2); /* test LCMAP_SORTKEY | NORM_IGNORECASE */ ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE, @@ -2340,7 +2476,7 @@ static void test_LCMapStringA(void) lower_case, -1, buf2, sizeof(buf2)); ok(ret2, "LCMapStringA must succeed\n"); ok(ret == ret2, "lengths of sort keys must be equal\n"); - ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n"); + ok(!memcmp(buf, buf2, ret), "sort keys must be equal\n"); /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different results from plain LCMAP_SORTKEY on Vista */ @@ -2353,7 +2489,7 @@ static void test_LCMapStringA(void) symbols_stripped, -1, buf2, sizeof(buf2)); ok(ret2, "LCMapStringA must succeed\n"); ok(ret == ret2, "lengths of sort keys must be equal\n"); - ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n"); + ok(!memcmp(buf, buf2, ret), "sort keys must be equal\n"); /* test NORM_IGNORENONSPACE */ lstrcpyA(buf, "foo"); @@ -2384,122 +2520,194 @@ static void test_LCMapStringA(void) ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf)); ok(!ret, "LCMapStringA should fail with srclen = 0\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "unexpected error code %d\n", GetLastError()); + "unexpected error code %ld\n", GetLastError()); } typedef INT (*lcmapstring_wrapper)(DWORD, LPCWSTR, INT, LPWSTR, INT); static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *func_name) { - static const WCHAR japanese_text[] = { - 0x3044, 0x309d, 0x3084, 0x3001, 0x30a4, 0x30fc, 0x30cf, - 0x30c8, 0x30fc, 0x30f4, 0x30a9, 0x306e, 0x2026, 0 + const static WCHAR japanese_text[] = { + 0x3044, 0x309d, 0x3084, 0x3001, 0x30a4, 0x30fc, 0x30cf, 0x30c8, + 0x30fc, 0x30f4, 0x30a9, 0x306e, 0x91ce, 0x539f, 0x306f, 0x5e83, + 0x3044, 0x3093, 0x3060, 0x3088, 0x3002, 0 }; - static const WCHAR hiragana_text[] = { - 0x3044, 0x309d, 0x3084, 0x3001, 0x3044, 0x30fc, 0x306f, - 0x3068, 0x30fc, 0x3094, 0x3049, 0x306e, 0x2026, 0 + const static WCHAR hiragana_text[] = { + 0x3044, 0x309d, 0x3084, 0x3001, 0x3044, 0x30fc, 0x306f, 0x3068, + 0x30fc, 0x3094, 0x3049, 0x306e, 0x91ce, 0x539f, 0x306f, 0x5e83, + 0x3044, 0x3093, 0x3060, 0x3088, 0x3002, 0 }; - static const WCHAR katakana_text[] = { - 0x30a4, 0x30fd, 0x30e4, 0x3001, 0x30a4, 0x30fc, 0x30cf, - 0x30c8, 0x30fc, 0x30f4, 0x30a9, 0x30ce, 0x2026, 0 + const static WCHAR katakana_text[] = { + 0x30a4, 0x30fd, 0x30e4, 0x3001, 0x30a4, 0x30fc, 0x30cf, 0x30c8, + 0x30fc, 0x30f4, 0x30a9, 0x30ce, 0x91ce, 0x539f, 0x30cf, 0x5e83, + 0x30a4, 0x30f3, 0x30c0, 0x30e8, 0x3002, 0 }; - static const WCHAR halfwidth_text[] = { - 0x3044, 0x309d, 0x3084, 0xff64, 0xff72, 0xff70, 0xff8a, - 0xff84, 0xff70, 0xff73, 0xff9e, 0xff6b, 0x306e, 0x2026, 0 + const static WCHAR halfwidth_text[] = { + 0x3044, 0x309d, 0x3084, 0xff64, 0xff72, 0xff70, 0xff8a, 0xff84, + 0xff70, 0xff73, 0xff9e, 0xff6b, 0x306e, 0x91ce, 0x539f, 0x306f, + 0x5e83, 0x3044, 0x3093, 0x3060, 0x3088, 0xff61, 0 }; + const static WCHAR halfwidth_text2[] = { + 0xff72, 0x30fd, 0xff94, 0xff64, 0xff72, 0xff70, 0xff8a, 0xff84, + 0xff70, 0xff73, 0xff9e, 0xff6b, 0xff89, 0x91ce, 0x539f, 0xff8a, + 0x5e83, 0xff72, 0xff9d, 0xff80, 0xff9e, 0xff96, 0xff61, 0 + }; + const static WCHAR math_text[] = { + 0xd835, 0xdc00, 0xd835, 0xdc01, 0xd835, 0xdc02, 0xd835, 0xdc03, + 0xd835, 0xdd52, 0xd835, 0xdd53, 0xd835, 0xdd54, 0xd835, 0xdd55, 0 + }; + const static WCHAR math_result[] = L"ABCDabcd"; + const static WCHAR math_arabic_text[] = { + 0xd83b, 0xde00, 0xd83b, 0xde01, 0xd83b, 0xde02, 0xd83b, 0xde03, + 0xd83b, 0xde10, 0xd83b, 0xde11, 0xd83b, 0xde12, 0xd83b, 0xde13, 0 + }; + const static WCHAR math_arabic_result[] = { + 0x0627, 0x0628, 0x062c, 0x062f, 0x0641, 0x0635, 0x0642, 0x0631, 0 + }; + const static WCHAR cjk_compat_text[] = { + 0xd87e, 0xdc20, 0xd87e, 0xdc21, 0xd87e, 0xdc22, 0xd87e, 0xdc23, + 0xd87e, 0xdc24, 0xd87e, 0xdc25, 0xd87e, 0xdc26, 0xd87e, 0xdc27, 0 + }; + const static WCHAR cjk_compat_result[] = { + 0x523b, 0x5246, 0x5272, 0x5277, 0x3515, 0x52c7, 0x52c9, 0x52e4, 0 + }; + const static WCHAR accents_text[] = { + 0x00e0, 0x00e7, ' ', 0x00e9, ',', 0x00ee, 0x00f1, '/', 0x00f6, 0x00fb, 0x00fd, '!', 0 + }; + const static WCHAR accents_result[] = L"ac e,in/ouy!"; + const static WCHAR accents_result2[] = L"aceinouy"; int ret, ret2, i; WCHAR buf[256], buf2[256]; char *p_buf = (char *)buf, *p_buf2 = (char *)buf2; /* LCMAP_LOWERCASE | LCMAP_UPPERCASE makes LCMAP_TITLECASE, so it's valid now. */ - ret = func_ptr(LCMAP_LOWERCASE | LCMAP_UPPERCASE, - lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR)); + ret = func_ptr(LCMAP_LOWERCASE | LCMAP_UPPERCASE, lower_case, -1, buf, ARRAY_SIZE(buf)); todo_wine ok(ret == lstrlenW(title_case) + 1 || broken(!ret), - "%s ret %d, error %d, expected value %d\n", func_name, + "%s ret %d, error %ld, expected value %d\n", func_name, ret, GetLastError(), lstrlenW(title_case) + 1); todo_wine ok(lstrcmpW(buf, title_case) == 0 || broken(!ret), "Expected title case string\n"); /* test invalid flag combinations */ - for (i = 0; i < sizeof(lcmap_invalid_flags)/sizeof(lcmap_invalid_flags[0]); i++) { + for (i = 0; i < ARRAY_SIZE(lcmap_invalid_flags); i++) { lstrcpyW(buf, fooW); SetLastError(0xdeadbeef); ret = func_ptr(lcmap_invalid_flags[i], lower_case, -1, buf, sizeof(buf)); ok(GetLastError() == ERROR_INVALID_FLAGS, - "%s (flag %08x) unexpected error code %d\n", + "%s (flag %08lx) unexpected error code %ld\n", func_name, lcmap_invalid_flags[i], GetLastError()); - ok(!ret, "%s (flag %08x) should return 0, got %d\n", + ok(!ret, "%s (flag %08lx) should return 0, got %d\n", func_name, lcmap_invalid_flags[i], ret); } /* test LCMAP_LOWERCASE */ - ret = func_ptr(LCMAP_LOWERCASE, - upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR)); - ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name, + ret = func_ptr(LCMAP_LOWERCASE, upper_case, -1, buf, ARRAY_SIZE(buf)); + ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %ld, expected value %d\n", func_name, ret, GetLastError(), lstrlenW(upper_case) + 1); ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name); /* test LCMAP_UPPERCASE */ - ret = func_ptr(LCMAP_UPPERCASE, - lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR)); - ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name, + ret = func_ptr(LCMAP_UPPERCASE, lower_case, -1, buf, ARRAY_SIZE(buf)); + ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %ld, expected value %d\n", func_name, ret, GetLastError(), lstrlenW(lower_case) + 1); ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name); /* test LCMAP_HIRAGANA */ - ret = func_ptr(LCMAP_HIRAGANA, - japanese_text, -1, buf, sizeof(buf)/sizeof(WCHAR)); - ok(ret == lstrlenW(hiragana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name, + ret = func_ptr(LCMAP_HIRAGANA, japanese_text, -1, buf, ARRAY_SIZE(buf)); + ok(ret == lstrlenW(hiragana_text) + 1, "%s ret %d, error %ld, expected value %d\n", func_name, ret, GetLastError(), lstrlenW(hiragana_text) + 1); ok(!lstrcmpW(buf, hiragana_text), "%s string compare mismatch\n", func_name); buf[0] = 0x30f5; /* KATAKANA LETTER SMALL KA */ ret = func_ptr(LCMAP_HIRAGANA, buf, 1, buf2, 1); - ok(ret == 1, "%s ret %d, error %d, expected value 1\n", func_name, + ok(ret == 1, "%s ret %d, error %ld, expected value 1\n", func_name, ret, GetLastError()); /* U+3095: HIRAGANA LETTER SMALL KA was added in Unicode 3.2 */ ok(buf2[0] == 0x3095 || broken(buf2[0] == 0x30f5 /* Vista and earlier versions */), "%s expected %04x, got %04x\n", func_name, 0x3095, buf2[0]); /* test LCMAP_KATAKANA | LCMAP_LOWERCASE */ - ret = func_ptr(LCMAP_KATAKANA | LCMAP_LOWERCASE, - japanese_text, -1, buf, sizeof(buf)/sizeof(WCHAR)); - ok(ret == lstrlenW(katakana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name, + ret = func_ptr(LCMAP_KATAKANA | LCMAP_LOWERCASE, japanese_text, -1, buf, ARRAY_SIZE(buf)); + ok(ret == lstrlenW(katakana_text) + 1, "%s ret %d, error %ld, expected value %d\n", func_name, ret, GetLastError(), lstrlenW(katakana_text) + 1); ok(!lstrcmpW(buf, katakana_text), "%s string compare mismatch\n", func_name); /* test LCMAP_FULLWIDTH */ - ret = func_ptr(LCMAP_FULLWIDTH, - halfwidth_text, -1, buf, sizeof(buf)/sizeof(WCHAR)); - ok(ret == lstrlenW(japanese_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name, + ret = func_ptr(LCMAP_FULLWIDTH, halfwidth_text, -1, buf, ARRAY_SIZE(buf)); + ok(ret == lstrlenW(japanese_text) + 1, "%s ret %d, error %ld, expected value %d\n", func_name, ret, GetLastError(), lstrlenW(japanese_text) + 1); ok(!lstrcmpW(buf, japanese_text), "%s string compare mismatch\n", func_name); ret2 = func_ptr(LCMAP_FULLWIDTH, halfwidth_text, -1, NULL, 0); ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret2, ret); + ret = func_ptr(LCMAP_FULLWIDTH, math_text, -1, buf, ARRAY_SIZE(buf)); + ok(ret == lstrlenW(buf) + 1, "%s ret %d, error %ld, expected value %d\n", func_name, + ret, GetLastError(), lstrlenW(buf) + 1); +#ifdef __REACTOS__ + ok(!lstrcmpW(buf, math_result) || broken(!lstrcmpW(buf, math_text)) /* WS03 */, "%s string compare mismatch %s\n", func_name, debugstr_w(buf)); +#else + ok(!lstrcmpW(buf, math_result), "%s string compare mismatch %s\n", func_name, debugstr_w(buf)); +#endif + + ret = func_ptr(LCMAP_FULLWIDTH, math_arabic_text, -1, buf, ARRAY_SIZE(buf)); + ok(ret == lstrlenW(buf) + 1, "%s ret %d, error %ld, expected value %d\n", func_name, + ret, GetLastError(), lstrlenW(buf) + 1); + ok(!lstrcmpW(buf, math_arabic_result) || + broken(!lstrcmpW( buf, math_arabic_text )), /* win7 */ + "%s string compare mismatch %s\n", func_name, debugstr_w(buf)); + + ret = func_ptr(LCMAP_FULLWIDTH, cjk_compat_text, -1, buf, ARRAY_SIZE(buf)); + ok(ret == lstrlenW(buf) + 1, "%s ret %d, error %ld, expected value %d\n", func_name, + ret, GetLastError(), lstrlenW(buf) + 1); +#ifdef __REACTOS__ + ok(!lstrcmpW(buf, cjk_compat_result) || broken(!lstrcmpW(buf, cjk_compat_text)) /* WS03 */, "%s string compare mismatch %s\n", func_name, debugstr_w(buf)); +#else + ok(!lstrcmpW(buf, cjk_compat_result), "%s string compare mismatch %s\n", func_name, debugstr_w(buf)); +#endif + /* test LCMAP_FULLWIDTH | LCMAP_HIRAGANA (half-width katakana is converted into full-width hiragana) */ - ret = func_ptr(LCMAP_FULLWIDTH | LCMAP_HIRAGANA, - halfwidth_text, -1, buf, sizeof(buf)/sizeof(WCHAR)); - ok(ret == lstrlenW(hiragana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name, + ret = func_ptr(LCMAP_FULLWIDTH | LCMAP_HIRAGANA, halfwidth_text, -1, buf, ARRAY_SIZE(buf)); + ok(ret == lstrlenW(hiragana_text) + 1, "%s ret %d, error %ld, expected value %d\n", func_name, ret, GetLastError(), lstrlenW(hiragana_text) + 1); ok(!lstrcmpW(buf, hiragana_text), "%s string compare mismatch\n", func_name); ret2 = func_ptr(LCMAP_FULLWIDTH | LCMAP_HIRAGANA, halfwidth_text, -1, NULL, 0); ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2); + /* LCMAP_FULLWIDTH | LCMAP_KATAKANA maps to full-width first */ + ret = func_ptr(LCMAP_FULLWIDTH | LCMAP_KATAKANA, halfwidth_text, -1, buf, ARRAY_SIZE(buf)); + ok(ret == lstrlenW(katakana_text) + 1, "%s ret %d, error %ld, expected value %d\n", func_name, + ret, GetLastError(), lstrlenW(katakana_text) + 1); + ok(!lstrcmpW(buf, katakana_text), "%s string compare mismatch\n", func_name); + /* test LCMAP_HALFWIDTH */ - ret = func_ptr(LCMAP_HALFWIDTH, - japanese_text, -1, buf, sizeof(buf)/sizeof(WCHAR)); - ok(ret == lstrlenW(halfwidth_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name, + ret = func_ptr(LCMAP_HALFWIDTH, japanese_text, -1, buf, ARRAY_SIZE(buf)); + ok(ret == lstrlenW(halfwidth_text) + 1, "%s ret %d, error %ld, expected value %d\n", func_name, ret, GetLastError(), lstrlenW(halfwidth_text) + 1); ok(!lstrcmpW(buf, halfwidth_text), "%s string compare mismatch\n", func_name); ret2 = func_ptr(LCMAP_HALFWIDTH, japanese_text, -1, NULL, 0); ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2); + /* test LCMAP_HALFWIDTH | LCMAP_KATAKANA + (hiragana character is converted into half-width katakana) */ + ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_KATAKANA, japanese_text, -1, buf, ARRAY_SIZE(buf)); + ok(ret == lstrlenW(halfwidth_text2) + 1, "%s ret %d, error %ld, expected value %d\n", func_name, + ret, GetLastError(), lstrlenW(halfwidth_text2) + 1); + ok(!lstrcmpW(buf, halfwidth_text2), "%s string compare mismatch\n", func_name); + + ret2 = func_ptr(LCMAP_HALFWIDTH | LCMAP_KATAKANA, japanese_text, -1, NULL, 0); + ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2); + + /* LCMAP_HALFWIDTH | LCMAP_HIRAGANA maps to Hiragana first */ + ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_HIRAGANA, japanese_text, -1, buf, ARRAY_SIZE(buf)); + ret2 = func_ptr(LCMAP_HALFWIDTH, hiragana_text, -1, buf2, ARRAY_SIZE(buf2)); + ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2); + ok(!lstrcmpW(buf, buf2), "%s string compare mismatch %s vs %s\n", func_name, debugstr_w(buf), debugstr_w(buf2)); + /* test buffer overflow */ SetLastError(0xdeadbeef); ret = func_ptr(LCMAP_UPPERCASE, @@ -2515,18 +2723,37 @@ static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *f ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret); + buf[0] = 'a'; + buf[1] = 0x30ac; + ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_UPPERCASE, buf, 2, buf2, 0); + ok(ret == 3, "%s ret %d, expected value 3\n", func_name, ret); + + SetLastError(0xdeadbeef); + ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_UPPERCASE, buf, 2, buf2, 1); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret); + + SetLastError(0xdeadbeef); + ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_UPPERCASE, buf, 2, buf2, 2); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret); + + ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_UPPERCASE, buf, 2, buf2, 3); + ok(ret == 3, "%s ret %d, expected value 3\n", func_name, ret); + + ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_UPPERCASE, buf, 2, buf2, 4); + ok(ret == 3, "%s ret %d, expected value 3\n", func_name, ret); + /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */ lstrcpyW(buf, lower_case); - ret = func_ptr(LCMAP_UPPERCASE, - buf, -1, buf, sizeof(buf)/sizeof(WCHAR)); - ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name, + ret = func_ptr(LCMAP_UPPERCASE, buf, -1, buf, ARRAY_SIZE(buf)); + ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %ld, expected value %d\n", func_name, ret, GetLastError(), lstrlenW(lower_case) + 1); ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name); lstrcpyW(buf, upper_case); - ret = func_ptr(LCMAP_LOWERCASE, - buf, -1, buf, sizeof(buf)/sizeof(WCHAR)); - ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name, + ret = func_ptr(LCMAP_LOWERCASE, buf, -1, buf, ARRAY_SIZE(buf)); + ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %ld, expected value %d\n", func_name, ret, GetLastError(), lstrlenW(lower_case) + 1); ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name); @@ -2536,7 +2763,7 @@ static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *f buf, 10, buf, sizeof(buf)); ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ || GetLastError() == ERROR_INVALID_PARAMETER /* Win7+ */, - "%s unexpected error code %d\n", func_name, GetLastError()); + "%s unexpected error code %ld\n", func_name, GetLastError()); ok(!ret, "%s src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n", func_name); /* test whether '\0' is always appended */ @@ -2547,7 +2774,34 @@ static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *f upper_case, lstrlenW(upper_case), buf2, sizeof(buf2)); ok(ret, "%s func_ptr must succeed\n", func_name); ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name); - ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name); + ok(!memcmp(p_buf, p_buf2, ret), "%s sort keys must be equal\n", func_name); + + /* test contents with short buffer */ +#if defined(__REACTOS__) && defined(_WIN64) + if (is_reactos()) { + ok(FALSE, "FIXME: These tests crash on ReactOS x64\n"); + } else { +#endif + memset( buf, 0xcc, sizeof(buf) ); + ret = func_ptr(LCMAP_SORTKEY, upper_case, -1, buf, ret - 1); + ok( !ret, "%s succeeded with %u\n", func_name, ret ); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "%s wrong error %lu\n", func_name, GetLastError() ); + ret = (char *)memchr( p_buf, 0xcc, sizeof(buf) ) - p_buf; + ok( ret, "%s buffer not filled\n", func_name ); + ok( p_buf[ret - 1] == 0x01, "%s buffer filled up to %02x\n", func_name, (BYTE)p_buf[ret - 1] ); + ok( !memcmp( p_buf, p_buf2, ret - 1 ), "%s buffers differ\n", func_name ); + + memset( buf, 0xcc, sizeof(buf) ); + ret = func_ptr(LCMAP_SORTKEY, upper_case, -1, buf, ret2 - 20); + ok( !ret, "%s succeeded with %u\n", func_name, ret ); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "%s wrong error %lu\n", func_name, GetLastError() ); + ret = (char *)memchr( p_buf, 0xcc, sizeof(buf) ) - p_buf; + ok( ret, "%s buffer not filled\n", func_name ); + ok( p_buf[ret - 1] == 0x01, "%s buffer filled up to %02x\n", func_name, (BYTE)p_buf[ret - 1] ); + ok( !memcmp( p_buf, p_buf2, ret - 1 ), "%s buffers differ\n", func_name ); +#if defined(__REACTOS__) && defined(_WIN64) + } +#endif /* test LCMAP_SORTKEY | NORM_IGNORECASE */ ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORECASE, @@ -2557,7 +2811,7 @@ static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *f lower_case, -1, buf2, sizeof(buf2)); ok(ret2, "%s func_ptr must succeed\n", func_name); ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name); - ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name); + ok(!memcmp(p_buf, p_buf2, ret), "%s sort keys must be equal\n", func_name); /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different results from plain LCMAP_SORTKEY on Vista */ @@ -2570,38 +2824,54 @@ static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *f symbols_stripped, -1, buf2, sizeof(buf2)); ok(ret2, "%s func_ptr must succeed\n", func_name); ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name); - ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name); + ok(!memcmp(p_buf, p_buf2, ret), "%s sort keys must be equal\n", func_name); /* test NORM_IGNORENONSPACE */ lstrcpyW(buf, fooW); - ret = func_ptr(NORM_IGNORENONSPACE, - lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR)); + ret = func_ptr(NORM_IGNORENONSPACE, lower_case, -1, buf, ARRAY_SIZE(buf)); ok(ret == lstrlenW(lower_case) + 1, "%s func_ptr should return %d, ret = %d\n", func_name, lstrlenW(lower_case) + 1, ret); ok(!lstrcmpW(buf, lower_case), "%s string comparison mismatch\n", func_name); + lstrcpyW(buf, fooW); + ret = func_ptr(NORM_IGNORENONSPACE, accents_text, -1, buf, ARRAY_SIZE(buf)); + ok(ret == lstrlenW(buf) + 1, "%s func_ptr should return %d, ret = %d\n", func_name, + lstrlenW(buf) + 1, ret); + ok(!lstrcmpW(buf, accents_result), "%s string comparison mismatch %s\n", func_name, debugstr_w(buf)); + /* test NORM_IGNORESYMBOLS */ lstrcpyW(buf, fooW); - ret = func_ptr(NORM_IGNORESYMBOLS, - lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR)); + ret = func_ptr(NORM_IGNORESYMBOLS, lower_case, -1, buf, ARRAY_SIZE(buf)); ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name, lstrlenW(symbols_stripped) + 1, ret); ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name); /* test NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE */ lstrcpyW(buf, fooW); - ret = func_ptr(NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE, - lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR)); + ret = func_ptr(NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE, lower_case, -1, buf, ARRAY_SIZE(buf)); ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name, lstrlenW(symbols_stripped) + 1, ret); ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name); + lstrcpyW(buf, fooW); + ret = func_ptr(NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE, accents_text, -1, buf, ARRAY_SIZE(buf)); + ok(ret == lstrlenW(buf) + 1, "%s func_ptr should return %d, ret = %d\n", func_name, + lstrlenW(buf) + 1, ret); + ok(!lstrcmpW(buf, accents_result2), "%s string comparison mismatch %s\n", func_name, debugstr_w(buf)); + + /* test small buffer */ + lstrcpyW(buf, fooW); + ret = func_ptr(LCMAP_SORTKEY, lower_case, -1, buf, 2); + ok(ret == 0, "Expected a failure\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "%s unexpected error code %ld\n", func_name, GetLastError()); + /* test srclen = 0 */ SetLastError(0xdeadbeef); - ret = func_ptr(0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR)); + ret = func_ptr(0, upper_case, 0, buf, ARRAY_SIZE(buf)); ok(!ret, "%s func_ptr should fail with srclen = 0\n", func_name); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "%s unexpected error code %d\n", func_name, GetLastError()); + "%s unexpected error code %ld\n", func_name, GetLastError()); } static INT LCMapStringW_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen) @@ -2617,11 +2887,14 @@ static void test_LCMapStringW(void) trace("testing LCMapStringW\n"); SetLastError(0xdeadbeef); - ret = LCMapStringW((LCID)-1, LCMAP_LOWERCASE, upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR)); - todo_wine { + ret = LCMapStringW((LCID)-1, LCMAP_LOWERCASE, upper_case, -1, buf, ARRAY_SIZE(buf)); ok(!ret, "LCMapStringW should fail with bad lcid\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError()); - } + ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %ld\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = LCMapStringW((LCID)0xdead, LCMAP_HIRAGANA, upper_case, -1, buf, ARRAY_SIZE(buf)); + ok(!ret, "LCMapStringW should fail with bad lcid\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %ld\n", GetLastError()); test_lcmapstring_unicode(LCMapStringW_wrapper, "LCMapStringW:"); } @@ -2646,29 +2919,36 @@ static void test_LCMapStringEx(void) SetLastError(0xdeadbeef); ret = pLCMapStringEx(invalidW, LCMAP_LOWERCASE, - upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 0); - todo_wine { + upper_case, -1, buf, ARRAY_SIZE(buf), NULL, NULL, 0); ok(!ret, "LCMapStringEx should fail with bad locale name\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError()); - } + ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %ld\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = pLCMapStringEx(invalidW, LCMAP_HIRAGANA, + upper_case, -1, buf, ARRAY_SIZE(buf), NULL, NULL, 0); +#ifdef __REACTOS__ + ok(ret || broken(GetNTVersion() == _WIN32_WINNT_VISTA), "LCMapStringEx should not fail with bad locale name\n"); +#else + ok(ret, "LCMapStringEx should not fail with bad locale name\n"); +#endif /* test reserved parameters */ ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE, - upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 1); - ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n", + upper_case, -1, buf, ARRAY_SIZE(buf), NULL, NULL, 1); + ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %ld, expected value %d\n", ret, GetLastError(), lstrlenW(upper_case) + 1); ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n"); ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE, - upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, (void*)1, 0); - ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n", + upper_case, -1, buf, ARRAY_SIZE(buf), NULL, (void*)1, 0); + ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %ld, expected value %d\n", ret, GetLastError(), lstrlenW(upper_case) + 1); ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n"); /* crashes on native */ if(0) ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE, - upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), (void*)1, NULL, 0); + upper_case, -1, buf, ARRAY_SIZE(buf), (void*)1, NULL, 0); test_lcmapstring_unicode(LCMapStringEx_wrapper, "LCMapStringEx:"); } @@ -2677,7 +2957,6 @@ struct neutralsublang_name_t { WCHAR name[3]; WCHAR sname[16]; LCID lcid; - int todo; }; static const struct neutralsublang_name_t neutralsublang_names[] = { @@ -2691,7 +2970,7 @@ static const struct neutralsublang_name_t neutralsublang_names[] = { { {'m','s',0}, {'m','s','-','M','Y',0}, MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) }, { {'n','l',0}, {'n','l','-','N','L',0}, MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) }, { {'p','t',0}, {'p','t','-','B','R',0}, MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) }, - { {'s','r',0}, {'s','r','-','L','a','t','n','-','R','S',0}, MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN), SORT_DEFAULT), 1 }, + { {'s','r',0}, {'s','r','-','L','a','t','n','-','R','S',0}, MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN), SORT_DEFAULT) }, { {'s','v',0}, {'s','v','-','S','E',0}, MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) }, { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0}, MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) }, { {'z','h',0}, {'z','h','-','C','N',0}, MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT) }, @@ -2700,135 +2979,428 @@ static const struct neutralsublang_name_t neutralsublang_names[] = { static void test_LocaleNameToLCID(void) { - LCID lcid; + LCID lcid, expect; + NTSTATUS status; INT ret; WCHAR buffer[LOCALE_NAME_MAX_LENGTH]; - static const WCHAR enW[] = {'e','n',0}; - static const WCHAR esesW[] = {'e','s','-','e','s',0}; - static const WCHAR zhHansW[] = {'z','h','-','H','a','n','s',0}; - static const WCHAR zhhansW[] = {'z','h','-','h','a','n','s',0}; - static const WCHAR zhHantW[] = {'z','h','-','H','a','n','t',0}; - static const WCHAR zhhantW[] = {'z','h','-','h','a','n','t',0}; - static const WCHAR zhcnW[] = {'z','h','-','C','N',0}; - static const WCHAR zhhkW[] = {'z','h','-','H','K',0}; + WCHAR expbuff[LOCALE_NAME_MAX_LENGTH]; + const struct neutralsublang_name_t *ptr; if (!pLocaleNameToLCID) { win_skip( "LocaleNameToLCID not available\n" ); return; } +#if defined(__REACTOS__) && defined(_WIN64) + if (is_reactos()) { + ok(FALSE, "FIXME: Most of test_LocaleNameToLCID() crashes on ReactOS x64\n"); + return; + } +#endif /* special cases */ buffer[0] = 0; SetLastError(0xdeadbeef); lcid = pLocaleNameToLCID(LOCALE_NAME_USER_DEFAULT, 0); ok(lcid == GetUserDefaultLCID() || broken(GetLastError() == ERROR_INVALID_PARAMETER /* Vista */), - "Expected lcid == %08x, got %08x, error %d\n", GetUserDefaultLCID(), lcid, GetLastError()); + "Expected lcid == %08lx, got %08lx, error %ld\n", GetUserDefaultLCID(), lcid, GetLastError()); ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0); - ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError()); - trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer)); + ok(ret > 0, "Expected ret > 0, got %d, error %ld\n", ret, GetLastError()); + trace("%08lx, %s\n", lcid, wine_dbgstr_w(buffer)); buffer[0] = 0; SetLastError(0xdeadbeef); - lcid = pLocaleNameToLCID(LOCALE_NAME_SYSTEM_DEFAULT, 0); - ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected lcid == 0, got %08x, error %d\n", lcid, GetLastError()); +#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600 + lcid = LocaleNameToLCID(LOCALE_NAME_SYSTEM_DEFAULT, 0); + expect = GetSystemDefaultLCID(); +#if defined(__REACTOS__) && defined(_WIN64) + ok(lcid == expect || broken(lcid == 0) /* x86_64 */, "Expected lcid == %08lx, got %08lx, error %ld\n", expect, lcid, GetLastError()); +#else + ok(lcid == expect, "Expected lcid == %08lx, got %08lx, error %ld\n", expect, lcid, GetLastError()); +#endif +#endif ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0); - ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError()); - trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer)); + ok(ret > 0, "Expected ret > 0, got %d, error %ld\n", ret, GetLastError()); + trace("%08lx, %s\n", lcid, wine_dbgstr_w(buffer)); buffer[0] = 0; SetLastError(0xdeadbeef); lcid = pLocaleNameToLCID(LOCALE_NAME_INVARIANT, 0); - ok(lcid == 0x7F, "Expected lcid = 0x7F, got %08x, error %d\n", lcid, GetLastError()); + ok(lcid == 0x7F, "Expected lcid = 0x7F, got %08lx, error %ld\n", lcid, GetLastError()); ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0); - ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError()); - trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer)); + ok(ret > 0, "Expected ret > 0, got %d, error %ld\n", ret, GetLastError()); + trace("%08lx, %s\n", lcid, wine_dbgstr_w(buffer)); + + pLCIDToLocaleName(GetUserDefaultLCID(), expbuff, LOCALE_NAME_MAX_LENGTH, 0); + ret = pLCIDToLocaleName(LOCALE_NEUTRAL, buffer, LOCALE_NAME_MAX_LENGTH, 0); + ok(ret > 0, "Expected ret > 0, got %d, error %ld\n", ret, GetLastError()); + ok( !wcscmp( buffer, expbuff ), "got %s / %s\n", debugstr_w(buffer), debugstr_w(expbuff)); + + ret = pLCIDToLocaleName(LOCALE_CUSTOM_DEFAULT, buffer, LOCALE_NAME_MAX_LENGTH, 0); + ok(ret > 0, "Expected ret > 0, got %d, error %ld\n", ret, GetLastError()); + ok( !wcscmp( buffer, expbuff ), "got %s / %s\n", debugstr_w(buffer), debugstr_w(expbuff)); + + SetLastError( 0xdeadbeef ); + ret = pLCIDToLocaleName(LOCALE_CUSTOM_UNSPECIFIED, buffer, LOCALE_NAME_MAX_LENGTH, 0); + ok(ret > 0 || broken(!ret), /* <= win8 */ "Expected ret > 0, got %d, error %ld\n", ret, GetLastError()); + if (ret) ok( !wcscmp( buffer, expbuff ), "got %s / %s\n", debugstr_w(buffer), debugstr_w(expbuff)); + + SetLastError( 0xdeadbeef ); + ret = pLCIDToLocaleName(LOCALE_CUSTOM_UI_DEFAULT, buffer, LOCALE_NAME_MAX_LENGTH, 0); + if (ret) trace("%08x, %s\n", GetUserDefaultUILanguage(), wine_dbgstr_w(buffer)); + else ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError()); /* bad name */ SetLastError(0xdeadbeef); lcid = pLocaleNameToLCID(invalidW, 0); ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected lcid == 0, got %08x, error %d\n", lcid, GetLastError()); + "Expected lcid == 0, got %08lx, error %ld\n", lcid, GetLastError()); /* lower-case */ - lcid = pLocaleNameToLCID(esesW, 0); - ok(lcid == MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT), "Got wrong lcid for es-es: 0x%x\n", lcid); + lcid = pLocaleNameToLCID(L"es-es", 0); + ok(lcid == MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT), "Got wrong lcid for es-es: 0x%lx\n", lcid); /* english neutral name */ - lcid = pLocaleNameToLCID(enW, 0); + lcid = pLocaleNameToLCID(L"en", LOCALE_ALLOW_NEUTRAL_NAMES); + ok(lcid == MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), SORT_DEFAULT) || + broken(lcid == 0) /* Vista */, "got 0x%04lx\n", lcid); + lcid = pLocaleNameToLCID(L"en", 0); ok(lcid == MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) || - broken(lcid == 0) /* Vista */, "got 0x%04x\n", lcid); + broken(lcid == 0) /* Vista */, "got 0x%04lx\n", lcid); if (lcid) { - const struct neutralsublang_name_t *ptr = neutralsublang_names; - - while (*ptr->name) + for (ptr = neutralsublang_names; *ptr->name; ptr++) { lcid = pLocaleNameToLCID(ptr->name, 0); - todo_wine_if (ptr->todo) - ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", - wine_dbgstr_w(ptr->name), lcid, ptr->lcid); + ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04lx, expected 0x%04lx\n", + wine_dbgstr_w(ptr->name), lcid, ptr->lcid); *buffer = 0; - ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0); + ret = pLCIDToLocaleName(lcid, buffer, ARRAY_SIZE(buffer), 0); ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(ptr->name), ret); ok(!lstrcmpW(ptr->sname, buffer), "%s: got wrong locale name %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(buffer)); - ptr++; } /* zh-Hant has LCID 0x7c04, but LocaleNameToLCID actually returns 0x0c04, which is the LCID of zh-HK */ - lcid = pLocaleNameToLCID(zhHantW, 0); + lcid = pLocaleNameToLCID(L"zh-Hant", 0); ok(lcid == MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_HONGKONG), SORT_DEFAULT), - "%s: got wrong lcid 0x%04x\n", wine_dbgstr_w(zhHantW), lcid); - ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0); - ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhHantW), ret); - ok(!lstrcmpW(zhhkW, buffer), "%s: got wrong locale name %s\n", - wine_dbgstr_w(zhHantW), wine_dbgstr_w(buffer)); + "%s: got wrong lcid 0x%04lx\n", wine_dbgstr_w(L"zh-Hant"), lcid); + ret = pLCIDToLocaleName(lcid, buffer, ARRAY_SIZE(buffer), 0); + ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(L"zh-Hant"), ret); + ok(!lstrcmpW(L"zh-HK", buffer), "%s: got wrong locale name %s\n", + wine_dbgstr_w(L"zh-Hant"), wine_dbgstr_w(buffer)); /* check that 0x7c04 also works and is mapped to zh-HK */ - ret = pLCIDToLocaleName(MAKELANGID(LANG_CHINESE_TRADITIONAL, SUBLANG_CHINESE_TRADITIONAL), buffer, sizeof(buffer)/sizeof(WCHAR), 0); - todo_wine ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhHantW), ret); - ok(!lstrcmpW(zhhkW, buffer), "%s: got wrong locale name %s\n", - wine_dbgstr_w(zhHantW), wine_dbgstr_w(buffer)); + ret = pLCIDToLocaleName(MAKELANGID(LANG_CHINESE_TRADITIONAL, SUBLANG_CHINESE_TRADITIONAL), + buffer, ARRAY_SIZE(buffer), 0); + ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(L"zh-Hant"), ret); + ok(!lstrcmpW(L"zh-HK", buffer), "%s: got wrong locale name %s\n", + wine_dbgstr_w(L"zh-Hant"), wine_dbgstr_w(buffer)); /* zh-hant */ - lcid = pLocaleNameToLCID(zhhantW, 0); + lcid = pLocaleNameToLCID(L"zh-hant", 0); ok(lcid == MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_HONGKONG), SORT_DEFAULT), - "%s: got wrong lcid 0x%04x\n", wine_dbgstr_w(zhhantW), lcid); - ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0); - ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhhantW), ret); - ok(!lstrcmpW(zhhkW, buffer), "%s: got wrong locale name %s\n", - wine_dbgstr_w(zhhantW), wine_dbgstr_w(buffer)); + "%s: got wrong lcid 0x%04lx\n", wine_dbgstr_w(L"zh-hant"), lcid); + ret = pLCIDToLocaleName(lcid, buffer, ARRAY_SIZE(buffer), 0); + ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(L"zh-hant"), ret); + ok(!lstrcmpW(L"zh-HK", buffer), "%s: got wrong locale name %s\n", + wine_dbgstr_w(L"zh-hant"), wine_dbgstr_w(buffer)); /* zh-Hans has LCID 0x0004, but LocaleNameToLCID actually returns 0x0804, which is the LCID of zh-CN */ - lcid = pLocaleNameToLCID(zhHansW, 0); + lcid = pLocaleNameToLCID(L"zh-Hans", 0); /* check that LocaleNameToLCID actually returns 0x0804 */ ok(lcid == MAKELCID(MAKELANGID(LANG_CHINESE_SIMPLIFIED, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), - "%s: got wrong lcid 0x%04x\n", wine_dbgstr_w(zhHansW), lcid); - ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0); - ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhHansW), ret); - ok(!lstrcmpW(zhcnW, buffer), "%s: got wrong locale name %s\n", - wine_dbgstr_w(zhHansW), wine_dbgstr_w(buffer)); + "%s: got wrong lcid 0x%04lx\n", wine_dbgstr_w(L"zh-Hans"), lcid); + ret = pLCIDToLocaleName(lcid, buffer, ARRAY_SIZE(buffer), 0); + ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(L"zh-Hans"), ret); + ok(!lstrcmpW(L"zh-CN", buffer), "%s: got wrong locale name %s\n", + wine_dbgstr_w(L"zh-Hans"), wine_dbgstr_w(buffer)); /* check that 0x0004 also works and is mapped to zh-CN */ - ret = pLCIDToLocaleName(MAKELANGID(LANG_CHINESE, SUBLANG_NEUTRAL), buffer, sizeof(buffer)/sizeof(WCHAR), 0); - ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhHansW), ret); - ok(!lstrcmpW(zhcnW, buffer), "%s: got wrong locale name %s\n", - wine_dbgstr_w(zhHansW), wine_dbgstr_w(buffer)); + ret = pLCIDToLocaleName(MAKELANGID(LANG_CHINESE, SUBLANG_NEUTRAL), buffer, ARRAY_SIZE(buffer), 0); + ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(L"zh-Hans"), ret); + ok(!lstrcmpW(L"zh-CN", buffer), "%s: got wrong locale name %s\n", + wine_dbgstr_w(L"zh-Hans"), wine_dbgstr_w(buffer)); /* zh-hans */ - lcid = pLocaleNameToLCID(zhhansW, 0); + lcid = pLocaleNameToLCID(L"zh-hans", 0); ok(lcid == MAKELCID(MAKELANGID(LANG_CHINESE_SIMPLIFIED, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), - "%s: got wrong lcid 0x%04x\n", wine_dbgstr_w(zhhansW), lcid); - ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0); - ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhhansW), ret); - ok(!lstrcmpW(zhcnW, buffer), "%s: got wrong locale name %s\n", - wine_dbgstr_w(zhhansW), wine_dbgstr_w(buffer)); + "%s: got wrong lcid 0x%04lx\n", wine_dbgstr_w(L"zh-hans"), lcid); + ret = pLCIDToLocaleName(lcid, buffer, ARRAY_SIZE(buffer), 0); + ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(L"zh-hans"), ret); + ok(!lstrcmpW(L"zh-CN", buffer), "%s: got wrong locale name %s\n", + wine_dbgstr_w(L"zh-hans"), wine_dbgstr_w(buffer)); + + /* de-DE_phoneb */ + lcid = pLocaleNameToLCID(L"de-DE_phoneb", 0); + ok(lcid == MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), SORT_GERMAN_PHONE_BOOK), + "%s: got wrong lcid 0x%04lx\n", wine_dbgstr_w(L"zh-hans"), lcid); + ret = pLCIDToLocaleName(lcid, buffer, ARRAY_SIZE(buffer), 0); + ok(!lstrcmpW(L"de-DE_phoneb", buffer), "got wrong locale name %s\n", + wine_dbgstr_w(buffer)); } + + if (pRtlLocaleNameToLcid) + { + status = pRtlLocaleNameToLcid( LOCALE_NAME_USER_DEFAULT, &lcid, 0 ); + ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %lx\n", status ); + status = pRtlLocaleNameToLcid( LOCALE_NAME_SYSTEM_DEFAULT, &lcid, 0 ); + ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %lx\n", status ); + status = pRtlLocaleNameToLcid( invalidW, &lcid, 0 ); + ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %lx\n", status ); + + lcid = 0; + status = pRtlLocaleNameToLcid( LOCALE_NAME_INVARIANT, &lcid, 0 ); + ok( !status, "failed error %lx\n", status ); + ok( lcid == LANG_INVARIANT, "got %08lx\n", lcid ); + + lcid = 0; + status = pRtlLocaleNameToLcid( localeW, &lcid, 0 ); + ok( !status, "failed error %lx\n", status ); + ok( lcid == MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), "got %08lx\n", lcid ); + + lcid = 0; + status = pRtlLocaleNameToLcid( L"es-es", &lcid, 0 ); + ok( !status, "failed error %lx\n", status ); + ok( lcid == MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), "got %08lx\n", lcid ); + + lcid = 0; + status = pRtlLocaleNameToLcid( L"de-DE_phoneb", &lcid, 0 ); + ok( !status, "failed error %lx\n", status ); + ok( lcid == 0x00010407, "got %08lx\n", lcid ); + + lcid = 0; + status = pRtlLocaleNameToLcid( L"DE_de-PHONEB", &lcid, 0 ); + ok( !status || broken( status == STATUS_INVALID_PARAMETER_1 ), "failed error %lx\n", status ); + if (!status) ok( lcid == 0x00010407, "got %08lx\n", lcid ); + + lcid = 0xdeadbeef; + status = pRtlLocaleNameToLcid( L"de+de+phoneb", &lcid, 0 ); + ok( status == STATUS_INVALID_PARAMETER_1, "failed error %lx\n", status ); + ok( lcid == 0xdeadbeef, "got %08lx\n", lcid ); + + lcid = 0; + status = pRtlLocaleNameToLcid( L"en", &lcid, 0 ); + ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %lx\n", status ); + status = pRtlLocaleNameToLcid( L"en", &lcid, 1 ); + ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %lx\n", status ); + status = pRtlLocaleNameToLcid( L"en", &lcid, 2 ); + ok( !status, "failed error %lx\n", status ); + ok( lcid == MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), "got %08lx\n", lcid ); + status = pRtlLocaleNameToLcid( L"en-RR", &lcid, 2 ); + ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %lx\n", status ); + status = pRtlLocaleNameToLcid( L"en-Latn-RR", &lcid, 2 ); + ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %lx\n", status ); + + for (ptr = neutralsublang_names; *ptr->name; ptr++) + { + switch (LANGIDFROMLCID(ptr->lcid)) + { + case MAKELANGID( LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN): expect = LANG_SERBIAN_NEUTRAL; break; + case MAKELANGID( LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_CYRILLIC): expect = 0x6c1a; break; + case MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED ): expect = 0x7804; break; + case MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_HONGKONG ): expect = LANG_CHINESE_TRADITIONAL; break; + default: expect = MAKELANGID( PRIMARYLANGID(ptr->lcid), SUBLANG_NEUTRAL ); break; + } + + status = pRtlLocaleNameToLcid( ptr->name, &lcid, 2 ); + ok( !status || broken(ptr->lcid == MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)), /* vista */ + "%s failed error %lx\n", wine_dbgstr_w(ptr->name), status ); + if (!status) ok( lcid == expect, "%s: got wrong lcid 0x%04lx, expected 0x%04lx\n", + wine_dbgstr_w(ptr->name), lcid, expect ); + status = pRtlLocaleNameToLcid( ptr->sname, &lcid, 0 ); + ok( !status || broken(ptr->lcid == MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN)), /* vista */ + "%s failed error %lx\n", wine_dbgstr_w(ptr->name), status ); + if (!status) ok( lcid == ptr->lcid, "%s: got wrong lcid 0x%04lx, expected 0x%04lx\n", + wine_dbgstr_w(ptr->name), lcid, ptr->lcid ); + } + } + else win_skip( "RtlLocaleNameToLcid not available\n" ); + + if (pRtlLcidToLocaleName) + { +#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600 + WCHAR buffer[128], expect[128]; +#else + WCHAR buffer[128]; +#endif + UNICODE_STRING str; + + str.Buffer = buffer; + str.MaximumLength = sizeof( buffer ); + memset( buffer, 0xcc, sizeof(buffer) ); + + ok( !IsValidLocale( LOCALE_NEUTRAL, 0 ), "expected invalid\n" ); + status = pRtlLcidToLocaleName( LOCALE_NEUTRAL, &str, 0, 0 ); + ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %lx\n", status ); + status = pRtlLcidToLocaleName( LOCALE_NEUTRAL, &str, 2, 0 ); + ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %lx\n", status ); + status = pRtlLcidToLocaleName( LOCALE_INVARIANT, NULL, 0, 0 ); + ok( status == STATUS_INVALID_PARAMETER_2, "wrong error %lx\n", status ); + + memset( buffer, 0xcc, sizeof(buffer) ); + status = pRtlLcidToLocaleName( MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), &str, 0, 0 ); + ok( status == STATUS_SUCCESS, "wrong error %lx\n", status ); + ok( !wcscmp( buffer, L"en-US" ), "wrong name %s\n", debugstr_w(buffer) ); + ok( str.Length == wcslen(buffer) * sizeof(WCHAR), "wrong len %u\n", str.Length ); + ok( str.MaximumLength == sizeof(buffer), "wrong max len %u\n", str.MaximumLength ); + + status = pRtlLcidToLocaleName( MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), &str, 0, 0 ); + ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %lx\n", status ); + + memset( buffer, 0xcc, sizeof(buffer) ); + status = pRtlLcidToLocaleName( MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), &str, 2, 0 ); + ok( status == STATUS_SUCCESS, "wrong error %lx\n", status ); + ok( str.Length == wcslen(buffer) * sizeof(WCHAR), "wrong len %u\n", str.Length ); + ok( !wcscmp( buffer, L"en" ), "wrong name %s\n", debugstr_w(buffer) ); + + ok( IsValidLocale( 0x00010407, 0 ), "expected valid\n" ); + memset( buffer, 0xcc, sizeof(buffer) ); + status = pRtlLcidToLocaleName( 0x00010407, &str, 0, 0 ); + ok( status == STATUS_SUCCESS, "wrong error %lx\n", status ); + ok( str.Length == wcslen(buffer) * sizeof(WCHAR), "wrong len %u\n", str.Length ); + ok( !wcscmp( buffer, L"de-DE_phoneb" ), "wrong name %s\n", debugstr_w(buffer) ); + + ok( !IsValidLocale( LOCALE_SYSTEM_DEFAULT, 0 ), "expected invalid\n" ); + memset( buffer, 0xcc, sizeof(buffer) ); + status = pRtlLcidToLocaleName( LOCALE_SYSTEM_DEFAULT, &str, 0, 0 ); + ok( status == STATUS_SUCCESS, "wrong error %lx\n", status ); + ok( str.Length == wcslen(buffer) * sizeof(WCHAR), "wrong len %u\n", str.Length ); +#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600 + LCIDToLocaleName( GetSystemDefaultLCID(), expect, ARRAY_SIZE(expect), 0 ); + ok( !wcscmp( buffer, expect ), "wrong name %s / %s\n", debugstr_w(buffer), debugstr_w(expect) ); +#endif + + ok( !IsValidLocale( LOCALE_USER_DEFAULT, 0 ), "expected invalid\n" ); + memset( buffer, 0xcc, sizeof(buffer) ); + status = pRtlLcidToLocaleName( LOCALE_USER_DEFAULT, &str, 0, 0 ); + ok( status == STATUS_SUCCESS, "wrong error %lx\n", status ); + ok( str.Length == wcslen(buffer) * sizeof(WCHAR), "wrong len %u\n", str.Length ); +#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600 + LCIDToLocaleName( GetUserDefaultLCID(), expect, ARRAY_SIZE(expect), 0 ); + ok( !wcscmp( buffer, expect ), "wrong name %s / %s\n", debugstr_w(buffer), debugstr_w(expect) ); +#endif + + ok( IsValidLocale( LOCALE_INVARIANT, 0 ), "expected valid\n" ); + memset( buffer, 0xcc, sizeof(buffer) ); + status = pRtlLcidToLocaleName( LOCALE_INVARIANT, &str, 0, 0 ); + ok( status == STATUS_SUCCESS, "wrong error %lx\n", status ); + ok( str.Length == wcslen(buffer) * sizeof(WCHAR), "wrong len %u\n", str.Length ); + ok( !wcscmp( buffer, L"" ), "wrong name %s\n", debugstr_w(buffer) ); + + memset( buffer, 0xcc, sizeof(buffer) ); + status = pRtlLcidToLocaleName( LOCALE_CUSTOM_DEFAULT, &str, 0, 0 ); + ok( status == STATUS_SUCCESS, "wrong error %lx\n", status ); + ok( str.Length == wcslen(buffer) * sizeof(WCHAR), "wrong len %u\n", str.Length ); +#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600 + LCIDToLocaleName( GetUserDefaultLCID(), expect, ARRAY_SIZE(expect), 0 ); + ok( !wcscmp( buffer, expect ), "wrong name %s / %s\n", debugstr_w(buffer), debugstr_w(expect) ); +#endif + + status = pRtlLcidToLocaleName( LOCALE_CUSTOM_UI_DEFAULT, &str, 0, 0 ); + ok( status == STATUS_SUCCESS || status == STATUS_UNSUCCESSFUL, "wrong error %lx\n", status ); + + status = pRtlLcidToLocaleName( LOCALE_CUSTOM_UNSPECIFIED, &str, 0, 0 ); + ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %lx\n", status ); + + memset( buffer, 0xcc, sizeof(buffer) ); + str.Length = 0xbeef; + str.MaximumLength = 5 * sizeof(WCHAR); + status = pRtlLcidToLocaleName( 0x00010407, &str, 0, 0 ); + ok( status == STATUS_BUFFER_TOO_SMALL, "wrong error %lx\n", status ); + ok( str.Length == 0xbeef, "wrong len %u\n", str.Length ); + ok( str.MaximumLength == 5 * sizeof(WCHAR), "wrong len %u\n", str.MaximumLength ); + ok( buffer[0] == 0xcccc, "wrong name %s\n", debugstr_w(buffer) ); + + memset( &str, 0xcc, sizeof(str) ); + status = pRtlLcidToLocaleName( MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), &str, 0, 1 ); + ok( status == STATUS_SUCCESS, "wrong error %lx\n", status ); + ok( str.Length == wcslen(str.Buffer) * sizeof(WCHAR), "wrong len %u\n", str.Length ); + ok( str.MaximumLength == str.Length + sizeof(WCHAR), "wrong max len %u\n", str.MaximumLength ); + ok( !wcscmp( str.Buffer, L"en-US" ), "wrong name %s\n", debugstr_w(str.Buffer) ); + RtlFreeUnicodeString( &str ); + } + else win_skip( "RtlLcidToLocaleName not available\n" ); + + if (pNlsValidateLocale) + { + void *ret, *ret2; + LCID lcid; + + lcid = LOCALE_NEUTRAL; + ret = pNlsValidateLocale( &lcid, 0 ); + ok( !!ret, "failed for %04lx\n", lcid ); + ok( lcid == GetUserDefaultLCID(), "wrong lcid %04lx\n", lcid ); + + lcid = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); + ret = pNlsValidateLocale( &lcid, 0 ); + ok( !!ret, "failed for %04lx\n", lcid ); + ok( lcid == MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), "wrong lcid %04lx\n", lcid ); + + lcid = MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL); + ret2 = pNlsValidateLocale( &lcid, 0 ); + ok( !!ret2, "failed for %04lx\n", lcid ); + ok( ret == ret2, "got different pointer for neutral\n" ); + ok( lcid == MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), "wrong lcid %04lx\n", lcid ); + + lcid = MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL); + ret2 = pNlsValidateLocale( &lcid, LOCALE_ALLOW_NEUTRAL_NAMES ); + ok( !!ret2, "failed for %04lx\n", lcid ); + ok( ret != ret2, "got same pointer for neutral\n" ); + ok( lcid == MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), "wrong lcid %04lx\n", lcid ); + + lcid = 0x00010407; + ret = pNlsValidateLocale( &lcid, 0 ); + ok( !!ret, "failed for %04lx\n", lcid ); + ok( lcid == 0x00010407, "wrong lcid %04lx\n", lcid ); + + lcid = LOCALE_SYSTEM_DEFAULT; + ret = pNlsValidateLocale( &lcid, 0 ); + ok( !!ret, "failed for %04lx\n", lcid ); + ok( lcid == GetSystemDefaultLCID(), "wrong lcid %04lx\n", lcid ); + ret2 = pNlsValidateLocale( &lcid, 0 ); + ok( ret == ret2, "got different pointer for system\n" ); + + lcid = LOCALE_USER_DEFAULT; + ret = pNlsValidateLocale( &lcid, 0 ); + ok( !!ret, "failed for %04lx\n", lcid ); + ok( lcid == GetUserDefaultLCID(), "wrong lcid %04lx\n", lcid ); + ret2 = pNlsValidateLocale( &lcid, 0 ); + ok( ret == ret2, "got different pointer for user\n" ); + + lcid = LOCALE_INVARIANT; + ret = pNlsValidateLocale( &lcid, 0 ); + ok( !!ret, "failed for %04lx\n", lcid ); + ok( lcid == LOCALE_INVARIANT, "wrong lcid %04lx\n", lcid ); + ret2 = pNlsValidateLocale( &lcid, 0 ); + ok( ret == ret2, "got different pointer for invariant\n" ); + + lcid = LOCALE_CUSTOM_DEFAULT; + ret = pNlsValidateLocale( &lcid, 0 ); + ok( !!ret, "failed for %04lx\n", lcid ); + ok( lcid == GetUserDefaultLCID(), "wrong lcid %04lx\n", lcid ); + ret2 = pNlsValidateLocale( &lcid, 0 ); + ok( ret == ret2, "got different pointer for custom default\n" ); + + lcid = LOCALE_CUSTOM_UNSPECIFIED; + ret = pNlsValidateLocale( &lcid, 0 ); + ok( ret || broken(!ret), /* <= win8 */ "failed for %04lx\n", lcid ); + if (ret) ok( lcid == GetUserDefaultLCID(), "wrong lcid %04lx\n", lcid ); + + SetLastError( 0xdeadbeef ); + lcid = LOCALE_CUSTOM_UI_DEFAULT; + ret = pNlsValidateLocale( &lcid, 0 ); + if (!ret) ok( GetLastError() == 0xdeadbeef, "error %lu\n", GetLastError()); + + lcid = 0xbeef; + ret = pNlsValidateLocale( &lcid, 0 ); + ok( !ret, "succeeded\n" ); + ok( lcid == 0xbeef, "wrong lcid %04lx\n", lcid ); + ok( GetLastError() == 0xdeadbeef, "error %lu\n", GetLastError()); + } + else win_skip( "NlsValidateLocale not available\n" ); } -/* this requires collation table patch to make it MS compatible */ static const char * const strings_sorted[] = { "'", @@ -2915,9 +3487,11 @@ static int compare_string3(const void *e1, const void *e2) const char *s2 = *(const char *const *)e2; char key1[256], key2[256]; - LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1)); - LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2)); - return strcmp(key1, key2); + int len1 = LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1)); + int len2 = LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2)); + int ret = memcmp(key1, key2, min(len1, len2)); + if (!ret) ret = len1 - len2; + return ret; } static void test_sorting(void) @@ -2930,30 +3504,415 @@ static void test_sorting(void) /* 1. sort using lstrcmpA */ memcpy(buf, strings, sizeof(strings)); - qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1); - for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++) + qsort(buf, ARRAY_SIZE(strings), sizeof(strings[0]), compare_string1); + for (i = 0; i < ARRAY_SIZE(strings); i++) { ok(!strcmp(strings_sorted[i], str_buf[i]), "qsort using lstrcmpA failed for element %d\n", i); } /* 2. sort using CompareStringA */ memcpy(buf, strings, sizeof(strings)); - qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2); - for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++) + qsort(buf, ARRAY_SIZE(strings), sizeof(strings[0]), compare_string2); + for (i = 0; i < ARRAY_SIZE(strings); i++) { ok(!strcmp(strings_sorted[i], str_buf[i]), "qsort using CompareStringA failed for element %d\n", i); } /* 3. sort using sort keys */ memcpy(buf, strings, sizeof(strings)); - qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3); - for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++) + qsort(buf, ARRAY_SIZE(strings), sizeof(strings[0]), compare_string3); + for (i = 0; i < ARRAY_SIZE(strings); i++) { ok(!strcmp(strings_sorted[i], str_buf[i]), "qsort using sort keys failed for element %d\n", i); } } +struct sorting_test_entry { + const WCHAR *locale; + int result_sortkey; + int result_compare; + DWORD flags; + const WCHAR *first; + const WCHAR *second; +}; + +static const struct sorting_test_entry unicode_sorting_tests[] = +{ + /* Normal character */ + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x0037", L"\x277c" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x1eca", L"\x1ecb" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x1d05", L"\x1d48" }, + /* Normal character diacritics */ + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x19d7", L"\x096d" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x00f5", L"\x1ecf" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x2793", L"\x0d70" }, + /* Normal character case weights */ + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"A", L"a" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"z", L"Z" }, + /* PUA character */ + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\xe5a6", L"\xe5a5\x0333" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\xe5d7", L"\xe5d6\x0330" }, + /* Symbols add diacritic weight */ + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\u276a", L"\u2768" }, + /* Symbols add case weight */ + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\u204d", L"\uff02" }, + /* Default character, when there is main weight extra there must be no diacritic weight */ + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\ue6e3\u0a02", L"\ue6e3\u20dc" }, + /* Unsortable characters */ + { L"en-US", 0, CSTR_EQUAL, 0, L"a \u2060 b", L"a b" }, + /* Invalid/undefined characters */ + { L"en-US", 0, CSTR_EQUAL, 0, L"a \xfff0 b", L"a b" }, + { L"en-US", 0, CSTR_EQUAL, 0, L"a\x139F a", L"a a" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"a\x139F a", L"a b" }, + /* Default characters */ + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x00fc", L"\x016d" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x3fcb\x7fd5", L"\x0006\x3032" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x00fc\x30fd", L"\x00fa\x1833" }, + /* Diacritic is added */ + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x1B56\x0330", L"\x1096" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x1817\x0333", L"\x19d7" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x04de\x05ac", L"\x0499" }, + /* Diacritic can overflow */ + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x01ba\x0654", L"\x01b8" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x06b7\x06eb", L"\x06b6" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x1420\x0333", L"\x141f" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x1b56\x0654", L"\x1b56\x0655" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x1b56\x0654\x0654", L"\x1b56\x0655" }, + /* Jamo case weight */ + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x11bc", L"\x110b" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x11c1", L"\x1111" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x11af", L"\x1105" }, + /* Jamo main weight */ + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x11c2", L"\x11f5" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x1108", L"\x1121" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x1116", L"\x11c7" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x11b1", L"\x11d1" }, + /* CJK main weight 1 */ + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x4550\x73d2", L"\x3211\x23ad" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x3265", L"\x4079" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x4c19\x68d0\x52d0", L"\x316d" }, + /* CJK main weight 2 */ + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x72dd", L"\x6b8a" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x6785\x3bff\x6f83", L"\x7550\x34c9\x71a7" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x5d61", L"\x3aef" }, + /* Symbols case weights */ + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x207a", L"\xfe62" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\xfe65", L"\xff1e" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x2502", L"\xffe8" }, + /* Symbols diacritic weights */ + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x21da", L"\x21dc" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x29fb", L"\x2295" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x0092", L"\x009c" }, + /* NORM_IGNORESYMBOLS */ + { L"en-US", 0, CSTR_EQUAL, NORM_IGNORESYMBOLS, L"\x21da", L"\x21dc" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNORESYMBOLS, L"\x29fb", L"\x2295" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNORESYMBOLS, L"\x0092", L"\x009c" }, + { L"en-US", 0, CSTR_EQUAL, 0, L"\x3099", L"\x309b" }, /* Small diacritic weights at the end get ignored */ + /* Main weights have priority over diacritic weights */ + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"a b", L"\x0103 a" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"a", L"\x0103" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"e x", L"\x0113 v" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"e", L"\x0113" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"c s", L"\x0109 r" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"c", L"\x0109" }, + /* Diacritic weights have priority over case weights */ + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"a \x0103", L"A a" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"a", L"A" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"e \x0113", L"E e" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"e", L"E" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"c \x0109", L"C c" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"c", L"C" }, + /* Diacritic values for Jamo are not ignored */ + { L"en-US", -1, CSTR_LESS_THAN, NORM_IGNORENONSPACE, L"\x1152", L"\x1153" }, + { L"en-US", -1, CSTR_LESS_THAN, NORM_IGNORENONSPACE, L"\x1143", L"\x1145" }, + { L"en-US", -1, CSTR_LESS_THAN, NORM_IGNORENONSPACE, L"\x1196", L"\x1174" }, + /* Jungseong < PUA */ + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x318e", L"\x382a" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\xffcb", L"\x3d13" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\xffcc", L"\x8632" }, + /* Surrogate > PUA */ + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\xd847", L"\x382a" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\xd879", L"\x3d13" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\xd850", L"\x8632" }, + /* Unsortable combined with diacritics */ + { L"en-US", 0, CSTR_EQUAL, 0, L"A\x0301\x0301", L"A\x0301\x00ad\x0301" }, + { L"en-US", 0, CSTR_EQUAL, 0, L"b\x07f2\x07f2", L"b\x07f2\x2064\x07f2" }, + { L"en-US", 0, CSTR_EQUAL, 0, L"X\x0337\x0337", L"X\x0337\xfffd\x0337" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNORECASE, L"c", L"C" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNORECASE, L"e", L"E" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNORECASE, L"A", L"a" }, + /* Punctuation primary weight */ + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x001b", L"\x001c" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x0005", L"\x0006" }, + /* Punctuation diacritic/case weight */ + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x0027", L"\xff07" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x07f4", L"\x07f5" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x207b", L"\x0008" }, + /* Punctuation primary weight has priority */ + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\xff07", L"\x07f4" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\xfe32", L"\x2014" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x058a", L"\x2027" }, + /* Punctuation */ + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x207b", L"\x0008" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x0004", L"\x0011" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNORESYMBOLS, L"\x207b", L"\x0008" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNORESYMBOLS, L"\x0004", L"\x0011" }, + { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\x207b", L"\x0008" }, + { L"en-US", -1, CSTR_LESS_THAN, SORT_STRINGSORT, L"\x0004", L"\x0011" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNORESYMBOLS | SORT_STRINGSORT, L"\x207b", L"\x0008" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNORESYMBOLS | SORT_STRINGSORT, L"\x0004", L"\x0011" }, + /* Punctuation main weight */ + { L"en-US", -1, CSTR_LESS_THAN, SORT_STRINGSORT, L"\x001a", L"\x001b" }, + { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\x2027", L"\x2011" }, + { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\x3030", L"\x301c" }, + /* Punctuation diacritic weight */ + { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\x058a", L"\x2010" }, + { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\x07F5", L"\x07F4" }, + /* Punctuation case weight */ + { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\xfe32", L"\x2013" }, + { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\xfe31", L"\xfe58" }, + { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\xff07", L"\x0027" }, + /* Punctuation NORM_IGNORESYMBOLS */ + { L"en-US", 0, CSTR_EQUAL, NORM_IGNORESYMBOLS, L"\x207b", L"\x0008" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNORESYMBOLS, L"\x0004", L"\x0011" }, + /* Punctuation NORM_IGNORESYMBOLS SORT_STRINGSORT */ + { L"en-US", 0, CSTR_EQUAL, NORM_IGNORESYMBOLS | SORT_STRINGSORT, L"\x207b", L"\x0008" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNORESYMBOLS | SORT_STRINGSORT, L"\x0004", L"\x0011" }, + /* Punctuation SORT_STRINGSORT main weight */ + { L"en-US", -1, CSTR_LESS_THAN, SORT_STRINGSORT, L"\x001a", L"\x001b" }, + { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\x2027", L"\x2011", }, + { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\x3030", L"\x301c", }, + /* Punctuation SORT_STRINGSORT diacritic weight */ + { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\x058a", L"\x2010" }, + { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\x07F5", L"\x07F4" }, + /* Punctuation SORT_STRINGSORT case weight */ + { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\xfe32", L"\x2013" }, + { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\xfe31", L"\xfe58" }, + { L"en-US", 1, CSTR_GREATER_THAN, SORT_STRINGSORT, L"\xff07", L"\x0027" }, + /* Japanese main weight */ + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x04b0", L"\x32db" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x3093", L"\x1e62\x013f" }, + /* Japanese diacritic weight */ + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30d3", L"\x30d4" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x307b", L"\x307c" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30ea", L"\x32f7" }, + /* Japanese case weight small */ + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x31fb", L"\x30e9" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x30db", L"\x31f9" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\xff6d", L"\xff95" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNORENONSPACE, L"\x31fb", L"\x30e9" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNORENONSPACE, L"\x30db", L"\x31f9" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNORENONSPACE, L"\xff6d", L"\xff95" }, + /* Japanese case weight kana */ + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30d5", L"\x3075" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x306a", L"\x30ca" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x305a", L"\x30ba" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREKANATYPE, L"\x30d5", L"\x3075" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREKANATYPE, L"\x306a", L"\x30ca" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREKANATYPE, L"\x305a", L"\x30ba" }, + /* Japanese case weight width */ + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x30bf", L"\xff80" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x30ab", L"\xff76" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x30a2", L"\xff71" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREWIDTH, L"\x30bf", L"\xff80" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREWIDTH, L"\x30ab", L"\xff76" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREWIDTH, L"\x30a2", L"\xff71" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNORENONSPACE, L"\x31a2", L"\x3110" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNORENONSPACE, L"\x1342", L"\x133a" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNORENONSPACE, L"\x16a4", L"\x16a5" }, + /* Kana small data must have priority over width data */ + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30b1\x30f6", L"\xff79\x30b1" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30a6\x30a5", L"\xff73\x30a6" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30a8\x30a7", L"\xff74\x30a8" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x30b1", L"\xff79" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x30a6", L"\xff73" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x30a8", L"\xff74" }, + /* Kana small data must have priority over kana type data */ + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x3046\x30a9", L"\x30a6\x30aa" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x304a\x3041", L"\x30aa\x3042" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x3059\x30a7", L"\x30b9\x30a8" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x3046", L"\x30a6" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x304a", L"\x30aa" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x3059", L"\x30b9" }, + /* Kana type data must have priority over width data */ + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30a6\x30a8", L"\xff73\x3048" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30ab\x30a3", L"\xff76\x3043" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30b5\x30ac", L"\xff7b\x304c" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x30a6", L"\xff73" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x30ab", L"\xff76" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x30b5", L"\xff7b" }, + /* Case weights have priority over extra weights */ + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x305a a", L"\x30ba A" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30c1 b", L"\xff81 B" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\xff8b x", L"\x31f6 X" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x305a", L"\x30ba" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x30c1", L"\xff81" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\xff8b", L"\x31f6" }, + /* Extra weights have priority over special weights */ + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x0027\x31ff", L"\x007f\xff9b" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x07f5\x30f3", L"\x07f4\x3093" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\xfe63\x30e0", L"\xff0d\x3080" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x0027", L"\x007f" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x07f5", L"\x07f4" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\xfe63", L"\xff0d" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREWIDTH, L"\xff68", L"\x30a3" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREWIDTH, L"\xff75", L"\x30aa" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREWIDTH, L"\x30e2", L"\xff93" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\xff68", L"\x30a3" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\xff75", L"\x30aa" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x30e2", L"\xff93" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREKANATYPE, L"\x30a8", L"\x3048" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREKANATYPE, L"\x30af", L"\x304f" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREKANATYPE, L"\x3067", L"\x30c7" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30a8", L"\x3048" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30af", L"\x304f" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x3067", L"\x30c7" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREWIDTH, L"\xffb7", L"\x3147" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREWIDTH, L"\xffb6", L"\x3146" }, + { L"en-US", 0, CSTR_EQUAL, NORM_IGNOREWIDTH, L"\x3145", L"\xffb5" }, + { L"en-US", -1, CSTR_LESS_THAN, NORM_IGNORECASE, L"\xffb7", L"\x3147" }, + { L"en-US", -1, CSTR_LESS_THAN, NORM_IGNORECASE, L"\xffb6", L"\x3146" }, + { L"en-US", 1, CSTR_GREATER_THAN, NORM_IGNORECASE, L"\x3145", L"\xffb5" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x3075\x30fc", L"\x30d5\x30fc" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x30a1\x30fc", L"\x30a2\x30fc" }, + /* Coptic < Japanese */ + { L"en-US", -1, CSTR_LESS_THAN, NORM_IGNORECASE, L"\x2cff", L"\x30ba" }, + { L"en-US", -1, CSTR_LESS_THAN, NORM_IGNORECASE, L"\x2cdb", L"\x32de" }, + { L"en-US", -1, CSTR_LESS_THAN, NORM_IGNORECASE, L"\x2ce0", L"\x30c6" }, + /* Hebrew > Japanese */ + { L"en-US", 1, CSTR_GREATER_THAN, NORM_IGNORECASE, L"\x05d3", L"\x30ba" }, + { L"en-US", 1, CSTR_GREATER_THAN, NORM_IGNORECASE, L"\x05e3", L"\x32de" }, + { L"en-US", 1, CSTR_GREATER_THAN, NORM_IGNORECASE, L"\x05d7", L"\x30c6" }, + /* Expansion */ + { L"en-US", 0, CSTR_EQUAL, 0, L"\x00c6", L"\x0041\x0045" }, + { L"en-US", 0, CSTR_EQUAL, 0, L"\x0f5c", L"\x0f5b\x0fb7" }, + { L"en-US", 0, CSTR_EQUAL, 0, L"\x05f0", L"\x05d5\x05d5" }, + { L"en-US", -1, CSTR_EQUAL, 0, L"\x0f75", L"\x0f71\x0f74" }, + { L"en-US", -1, CSTR_EQUAL, 0, L"\xfc5e", L"\x064c\x0651" }, + { L"en-US", -1, CSTR_EQUAL, 0, L"\xfb2b", L"\x05e9\x05c2" }, + { L"en-US", -1, CSTR_EQUAL, 0, L"\xfe71", L"\x0640\x064b" }, + /* Japanese locale */ + { L"ja-JP", -1, CSTR_LESS_THAN, 0, L"\x6df8", L"\x654b\x29e9" }, + { L"ja-JP", -1, CSTR_LESS_THAN, 0, L"\x685d\x1239\x1b61", L"\x59b6\x6542\x2a62\x04a7" }, + { L"ja-JP", -1, CSTR_LESS_THAN, 0, L"\x62f3\x43e9", L"\x5760" }, + { L"ja-JP", -1, CSTR_LESS_THAN, 0, L"\x634c", L"\x2f0d\x5f1c\x7124" }, + { L"ja-JP", -1, CSTR_LESS_THAN, 0, L"\x69e7\x0502", L"\x57cc" }, + { L"ja-JP", -1, CSTR_LESS_THAN, 0, L"\x7589", L"\x67c5" }, + { L"ja-JP", 1, CSTR_GREATER_THAN, 0, L"\x5ede\x765c", L"\x7324" }, + { L"ja-JP", 1, CSTR_GREATER_THAN, 0, L"\x5c7f\x5961", L"\x7cbe" }, + { L"ja-JP", 1, CSTR_GREATER_THAN, 0, L"\x3162", L"\x6a84\x1549\x0b60" }, + { L"ja-JP", -1, CSTR_LESS_THAN, 0, L"\x769e\x448e", L"\x4e6e" }, + { L"ja-JP", 1, CSTR_GREATER_THAN, 0, L"\x59a4", L"\x5faa\x607c" }, + { L"ja-JP", 1, CSTR_GREATER_THAN, 0, L"\x529b", L"\x733f" }, + { L"ja-JP", 1, CSTR_GREATER_THAN, 0, L"\x6ff8\x2a0a", L"\x7953\x6712" }, + { L"ja-JP", -1, CSTR_LESS_THAN, 0, L"\x6dfb", L"\x6793" }, + { L"ja-JP", 1, CSTR_GREATER_THAN, 0, L"\x67ed", L"\x6aa2" }, + { L"ja-JP", 1, CSTR_GREATER_THAN, 0, L"\x4e61", L"\x6350\x6b08" }, + { L"ja-JP", 1, CSTR_GREATER_THAN, 0, L"\x5118", L"\x53b3\x75b4" }, + { L"ja-JP", -1, CSTR_LESS_THAN, 0, L"\x6bbf", L"\x65a3" }, + { L"ja-JP", 1, CSTR_GREATER_THAN, 0, L"\x5690", L"\x5fa8" }, + { L"ja-JP", 1, CSTR_GREATER_THAN, 0, L"\x61e2", L"\x76e5" }, + /* Misc locales */ + { L"ko-KR", -1, CSTR_LESS_THAN, 0, L"\x8db6", L"\xd198" }, + { L"ko-KR", -1, CSTR_LESS_THAN, 0, L"\x8f72", L"\xd2b9" }, + { L"ko-KR", -1, CSTR_LESS_THAN, 0, L"\x91d8", L"\xd318" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x8db6", L"\xd198" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x8f72", L"\xd2b9" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x91d8", L"\xd318" }, + { L"cs-CZ", 1, CSTR_GREATER_THAN, 0, L"\x0160", L"\x0219" }, + { L"cs-CZ", 1, CSTR_GREATER_THAN, 0, L"\x059a", L"\x0308" }, + { L"cs-CZ", 1, CSTR_GREATER_THAN, 0, L"\x013a", L"\x013f" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x0160", L"\x0219" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x059a", L"\x0308" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x013a", L"\x013f" }, + { L"vi-VN", -1, CSTR_LESS_THAN, 0, L"\x1d8f", L"\x1ea8" }, + { L"vi-VN", -1, CSTR_LESS_THAN, 0, L"\x0323", L"\xfe26" }, + { L"vi-VN", 1, CSTR_GREATER_THAN, 0, L"R", L"\xff32" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x1d8f", L"\x1ea8" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x0323", L"\xfe26" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"R", L"\xff32" }, + { L"zh-HK", -1, CSTR_LESS_THAN, 0, L"\x83ae", L"\x71b9" }, + { L"zh-HK", -1, CSTR_LESS_THAN, 0, L"\x7e50", L"\xc683" }, + { L"zh-HK", 1, CSTR_GREATER_THAN, 0, L"\x6c69", L"\x7f8a" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x83ae", L"\x71b9" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x7e50", L"\xc683" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x6c69", L"\x7f8a" }, + { L"tr-TR", 1, CSTR_GREATER_THAN, 0, L"\x00dc", L"\x1ee9" }, + { L"tr-TR", 1, CSTR_GREATER_THAN, 0, L"\x00fc", L"\x1ee6" }, + { L"tr-TR", -1, CSTR_LESS_THAN, 0, L"\x0152", L"\x00d6" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x00dc", L"\x1ee9" }, + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x00fc", L"\x1ee6" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\x0152", L"\x00d6" }, + /* Diacritic is added */ + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\xa042\x09bc", L"\xa042" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\xa063\x302b", L"\xa063" }, + { L"en-US", 1, CSTR_GREATER_THAN, 0, L"\xa07e\x0c56", L"\xa07e" }, + /* Reversed diacritics */ + { L"en-US", -1, CSTR_LESS_THAN, 0, L"\x00e9\x00e8", L"\x00e8\x00e9" }, + { L"fr-FR", 1, CSTR_GREATER_THAN, 0, L"\x00e9\x00e8", L"\x00e8\x00e9" }, + /* Digit sort */ + { L"en-US", -1, CSTR_LESS_THAN, 0, L"1230", L"321" }, + { L"en-US", 1, CSTR_GREATER_THAN, SORT_DIGITSASNUMBERS, L"1230", L"321" }, + { L"en-US", 1, CSTR_GREATER_THAN, SORT_DIGITSASNUMBERS, L"\xc6f\xc6c\xc6a", L"\xc6f\xc6e" }, + /* Compressions */ + { L"en-US", -1, CSTR_LESS_THAN, 0, L"E\x0300", L"F" }, + { L"rm-CH", 1, CSTR_GREATER_THAN, 0, L"E\x0300", L"F" }, +}; + +static void test_unicode_sorting(void) +{ + int i; + int ret1; + int ret2; + BYTE buffer[1000]; + if (!pLCMapStringEx) + { + win_skip("LCMapStringEx not available\n"); + return; + } + for (i = 0; i < ARRAY_SIZE(unicode_sorting_tests); i++) + { + BYTE buff1[1000]; + BYTE buff2[1000]; + int len1, len2; + int result; + const struct sorting_test_entry *entry = &unicode_sorting_tests[i]; + + len1 = pLCMapStringEx(entry->locale, LCMAP_SORTKEY | entry->flags, entry->first, -1, (WCHAR*)buff1, ARRAY_SIZE(buff1), NULL, NULL, 0); + len2 = pLCMapStringEx(entry->locale, LCMAP_SORTKEY | entry->flags, entry->second, -1, (WCHAR*)buff2, ARRAY_SIZE(buff2), NULL, NULL, 0); + + result = memcmp(buff1, buff2, min(len1, len2)); + if (result < 0) result = -1; + else if (result > 0) result = 1; + else if (len1 < len2) result = -1; + else if (len1 > len2) result = 1; + +#ifdef __REACTOS__ + ok (result == entry->result_sortkey || broken(GetNTVersion() == _WIN32_WINNT_VISTA), "Test %d (%s, %s) - Expected %d, got %d\n", +#else + ok (result == entry->result_sortkey, "Test %d (%s, %s) - Expected %d, got %d\n", +#endif + i, wine_dbgstr_w(entry->first), wine_dbgstr_w(entry->second), entry->result_sortkey, result); + +#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600 +#if defined(__REACTOS__) && defined(_WIN64) + if ((i == 0 || i == 5 || i == 8 || i == 9 || i == 17 || i == 80 || i == 81 || i == 84 || + i == 199 || i == 200 || i == 202 || i == 235 || i == 236 || i == 250 || i == 251 || + i == 259 || i == 260) && (GetNTVersion() == _WIN32_WINNT_VISTA)) + continue; +#endif + result = CompareStringEx(entry->locale, entry->flags, entry->first, -1, entry->second, -1, NULL, NULL, 0); + ok (result == entry->result_compare, "Test %d (%s, %s) - Expected %d, got %d\n", + i, wine_dbgstr_w(entry->first), wine_dbgstr_w(entry->second), entry->result_compare, result); +#endif + } + /* Test diacritics when buffer is short */ + ret1 = pLCMapStringEx(L"en-US", LCMAP_SORTKEY, L"\x0e49\x0e49\x0e49\x0e49\x0e49", -1, (WCHAR*)buffer, 20, NULL, NULL, 0); + ret2 = pLCMapStringEx(L"en-US", LCMAP_SORTKEY, L"\x0e49\x0e49\x0e49\x0e49\x0e49", -1, (WCHAR*)buffer, 0, NULL, NULL, 0); + ok(ret1 == ret2, "Got ret1=%d, ret2=%d\n", ret1, ret2); +} + static void test_FoldStringA(void) { int ret, i, j; @@ -3042,9 +4001,6 @@ static void test_FoldStringA(void) { 0x00 } }; - if (!pFoldStringA) - return; /* FoldString is present in NT v3.1+, but not 95/98/Me */ - /* these tests are locale specific */ if (GetACP() != 1252) { @@ -3053,14 +4009,9 @@ static void test_FoldStringA(void) } /* MAP_FOLDDIGITS */ - SetLastError(0); - ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256); - if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) - { - win_skip("FoldStringA is not implemented\n"); - return; - } - ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError()); + SetLastError(0xdeadbeef); + ret = FoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256); + ok(ret == 4, "Expected ret == 4, got %d, error %ld\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++) @@ -3069,20 +4020,17 @@ static void test_FoldStringA(void) { src[0] = i; src[1] = '\0'; - SetLastError(0); - ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256); - ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); + ret = FoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256); + ok(ret == 2, "Expected ret == 2, got %d, error %ld\n", ret, GetLastError()); ok(dst[0] == src[0], "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst); } } - /* MAP_EXPAND_LIGATURES */ - SetLastError(0); - 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)) { - ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError()); + /* MAP_EXPAND_LIGATURES */ + SetLastError(0xdeadbeef); + ret = FoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256); + ok(ret == sizeof(ligatures_dst), "Got %d, error %ld\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++) @@ -3091,8 +4039,7 @@ static void test_FoldStringA(void) { src[0] = i; src[1] = '\0'; - SetLastError(0); - ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256); + ret = FoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256); if (ret == 3) { /* Vista */ @@ -3102,18 +4049,19 @@ static void test_FoldStringA(void) } else { - ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); + ok(ret == 2, "Expected ret == 2, got %d, error %ld\n", ret, GetLastError()); ok(dst[0] == src[0], "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst); } } } - } /* MAP_COMPOSITE */ - SetLastError(0); - ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + SetLastError(0xdeadbeef); + ret = FoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256); + ok(ret, "Expected ret != 0, got %d, error %ld\n", ret, GetLastError()); + ok( GetLastError() == 0xdeadbeef || broken(!GetLastError()), /* vista */ + "wrong error %lu\n", GetLastError()); ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret); ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0, "MAP_COMPOSITE: Mismatch, got '%s'\n", dst); @@ -3124,9 +4072,8 @@ static void test_FoldStringA(void) { src[0] = i; src[1] = '\0'; - SetLastError(0); - ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256); - ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); + ret = FoldStringA(MAP_COMPOSITE, src, -1, dst, 256); + ok(ret == 2, "Expected ret == 2, got %d, error %ld\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]); @@ -3138,15 +4085,15 @@ static void test_FoldStringA(void) { src[0] = i; src[1] = '\0'; - SetLastError(0); - ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256); + SetLastError(0xdeadbeef); + ret = FoldStringA(MAP_FOLDCZONE, src, -1, dst, 256); is_special = FALSE; for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++) { if (foldczone_special[j].src == src[0]) { ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1, - "Expected ret == 2 or %d, got %d, error %d\n", + "Expected ret == 2 or %d, got %d, error %ld\n", lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError()); ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0, "MAP_FOLDCZONE: string mismatch for 0x%02x\n", @@ -3156,7 +4103,7 @@ static void test_FoldStringA(void) } if (! is_special) { - ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); + ok(ret == 2, "Expected ret == 2, got %d, error %ld\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]); @@ -3168,9 +4115,8 @@ static void test_FoldStringA(void) { src[0] = i; src[1] = '\0'; - SetLastError(0); - ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256); - ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); + ret = FoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256); + ok(ret == 2, "Expected ret == 2, got %d, error %ld\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]); @@ -3180,8 +4126,10 @@ static void test_FoldStringA(void) static void test_FoldStringW(void) { int ret; - unsigned int i, j; - WCHAR src[256], dst[256], ch, prev_ch = 1; + WORD type; + unsigned int i, j, len; + WCHAR src[256], dst[256]; + UINT ch, prev_ch = 1; static const DWORD badFlags[] = { 0, @@ -3190,114 +4138,189 @@ static void test_FoldStringW(void) MAP_COMPOSITE|MAP_EXPAND_LIGATURES }; /* Ranges of digits 0-9 : Must be sorted! */ - static const WCHAR digitRanges[] = + static const struct { UINT ch, first, last; int broken; } digitRanges[] = { - 0x0030, /* '0'-'9' */ - 0x0660, /* Eastern Arabic */ - 0x06F0, /* Arabic - Hindu */ - 0x07C0, /* Nko */ - 0x0966, /* Devengari */ - 0x09E6, /* Bengalii */ - 0x0A66, /* Gurmukhi */ - 0x0AE6, /* Gujarati */ - 0x0B66, /* Oriya */ - 0x0BE6, /* Tamil - No 0 */ - 0x0C66, /* Telugu */ - 0x0CE6, /* Kannada */ - 0x0D66, /* Maylayalam */ - 0x0DE6, /* Sinhala Lith */ - 0x0E50, /* Thai */ - 0x0ED0, /* Laos */ - 0x0F20, /* Tibet */ - 0x0F29, /* Tibet half - 0 is out of sequence */ - 0x1040, /* Myanmar */ - 0x1090, /* Myanmar Shan */ - 0x1368, /* Ethiopic - no 0 */ - 0x17E0, /* Khmer */ - 0x1810, /* Mongolian */ - 0x1946, /* Limbu */ - 0x19D0, /* New Tai Lue */ - 0x1A80, /* Tai Tham Hora */ - 0x1A90, /* Tai Tham Tham */ - 0x1B50, /* Balinese */ - 0x1BB0, /* Sundanese */ - 0x1C40, /* Lepcha */ - 0x1C50, /* Ol Chiki */ - 0x2070, /* Superscript - 1, 2, 3 are out of sequence */ - 0x2080, /* Subscript */ - 0x245F, /* Circled - 0 is out of sequence */ - 0x2473, /* Bracketed */ - 0x2487, /* Full stop */ - 0x24F4, /* Double Circled */ - 0x2775, /* Inverted circled - No 0 */ - 0x277F, /* Patterned circled - No 0 */ - 0x2789, /* Inverted Patterned circled - No 0 */ - 0x3020, /* Hangzhou */ - 0xA620, /* Vai */ - 0xA8D0, /* Saurashtra */ - 0xA900, /* Kayah Li */ - 0xA9D0, /* Javanese */ - 0xA9F0, /* Myanmar Tai Laing */ - 0xAA50, /* Cham */ - 0xABF0, /* Meetei Mayek */ - 0xff10, /* Pliene chasse (?) */ - 0xffff /* Terminator */ - }; - /* Digits which are represented, but out of sequence */ - static const WCHAR outOfSequenceDigits[] = - { - 0xB9, /* Superscript 1 */ - 0xB2, /* Superscript 2 */ - 0xB3, /* Superscript 3 */ - 0x0C78, /* Telugu Fraction 0 */ - 0x0C79, /* Telugu Fraction 1 */ - 0x0C7A, /* Telugu Fraction 2 */ - 0x0C7B, /* Telugu Fraction 3 */ - 0x0C7C, /* Telugu Fraction 1 */ - 0x0C7D, /* Telugu Fraction 2 */ - 0x0C7E, /* Telugu Fraction 3 */ - 0x0F33, /* Tibetan half zero */ - 0x19DA, /* New Tai Lue Tham 1 */ - 0x24EA, /* Circled 0 */ - 0x24FF, /* Negative Circled 0 */ - 0x3007, /* Ideographic number zero */ - '\0' /* Terminator */ - }; - /* Digits in digitRanges for which no representation is available */ - static const WCHAR noDigitAvailable[] = - { - 0x0BE6, /* No Tamil 0 */ - 0x0F29, /* No Tibetan half zero (out of sequence) */ - 0x1368, /* No Ethiopic 0 */ - 0x2473, /* No Bracketed 0 */ - 0x2487, /* No 0 Full stop */ - 0x24F4, /* No double circled 0 */ - 0x2775, /* No inverted circled 0 */ - 0x277F, /* No patterned circled */ - 0x2789, /* No inverted Patterned circled */ - 0x3020, /* No Hangzhou 0 */ - '\0' /* Terminator */ + { 0x0030, 0, 9 }, /* '0'-'9' */ + { 0x00b2, 2, 3 }, /* Superscript 2, 3 */ + { 0x00b9, 1, 1 }, /* Superscript 1 */ + { 0x0660, 0, 9 }, /* Eastern Arabic */ + { 0x06f0, 0, 9 }, /* Arabic - Hindu */ +#ifdef __REACTOS__ + { 0x07c0, 0, 9, TRUE /* WS03 */ }, /* Nko */ +#else + { 0x07c0, 0, 9 }, /* Nko */ +#endif + { 0x0966, 0, 9 }, /* Devengari */ + { 0x09e6, 0, 9 }, /* Bengalii */ + { 0x0a66, 0, 9 }, /* Gurmukhi */ + { 0x0ae6, 0, 9 }, /* Gujarati */ +#ifdef __REACTOS__ + { 0x0b66, 0, 9, TRUE /* WS03 */ }, /* Oriya */ + { 0x0be6, 0, 9, TRUE /* WS03 */ }, /* Tamil */ +#else + { 0x0b66, 0, 9 }, /* Oriya */ + { 0x0be6, 0, 9 }, /* Tamil */ +#endif + { 0x0c66, 0, 9 }, /* Telugu */ + { 0x0c78, 0, 3, TRUE /*win7*/ }, /* Telugu Fraction */ + { 0x0c7c, 1, 3, TRUE /*win7*/ }, /* Telugu Fraction */ + { 0x0ce6, 0, 9 }, /* Kannada */ + { 0x0d66, 0, 9 }, /* Maylayalam */ + { 0x0de6, 0, 9, TRUE /*win10*/ }, /* Sinhala Lith */ + { 0x0e50, 0, 9 }, /* Thai */ + { 0x0ed0, 0, 9 }, /* Laos */ +#ifdef __REACTOS__ + { 0x0f20, 0, 9, TRUE /* WS03 */ }, /* Tibet */ + { 0x1040, 0, 9, TRUE /* WS03 */ }, /* Myanmar */ + { 0x1090, 0, 9, TRUE /* WS03 */ }, /* Myanmar Shan */ + { 0x1369, 1, 9, TRUE /* WS03 */ }, /* Ethiopic */ + { 0x17e0, 0, 9, TRUE /* WS03 */ }, /* Khmer */ + { 0x1810, 0, 9, TRUE /* WS03 */ }, /* Mongolian */ + { 0x1946, 0, 9, TRUE /* WS03 */ }, /* Limbu */ + { 0x19d0, 0, 9, TRUE /* WS03 */ }, /* New Tai Lue */ +#else + { 0x0f20, 0, 9 }, /* Tibet */ + { 0x1040, 0, 9 }, /* Myanmar */ + { 0x1090, 0, 9 }, /* Myanmar Shan */ + { 0x1369, 1, 9 }, /* Ethiopic */ + { 0x17e0, 0, 9 }, /* Khmer */ + { 0x1810, 0, 9 }, /* Mongolian */ + { 0x1946, 0, 9 }, /* Limbu */ + { 0x19d0, 0, 9 }, /* New Tai Lue */ +#endif + { 0x19da, 1, 1, TRUE /*win7*/ }, /* New Tai Lue Tham 1 */ + { 0x1a80, 0, 9, TRUE /*win7*/ }, /* Tai Tham Hora */ + { 0x1a90, 0, 9, TRUE /*win7*/ }, /* Tai Tham Tham */ +#ifdef __REACTOS__ + { 0x1b50, 0, 9, TRUE /* WS03 */ }, /* Balinese */ + { 0x1bb0, 0, 9, TRUE /* WS03 */ }, /* Sundanese */ + { 0x1c40, 0, 9, TRUE /* WS03 */ }, /* Lepcha */ + { 0x1c50, 0, 9, TRUE /* WS03 */ }, /* Ol Chiki */ +#else + { 0x1b50, 0, 9 }, /* Balinese */ + { 0x1bb0, 0, 9 }, /* Sundanese */ + { 0x1c40, 0, 9 }, /* Lepcha */ + { 0x1c50, 0, 9 }, /* Ol Chiki */ +#endif + { 0x2070, 0, 0 }, /* Superscript 0 */ + { 0x2074, 4, 9 }, /* Superscript 4-9 */ + { 0x2080, 0, 9 }, /* Subscript */ + { 0x2460, 1, 9 }, /* Circled */ + { 0x2474, 1, 9 }, /* Bracketed */ + { 0x2488, 1, 9 }, /* Full stop */ + { 0x24ea, 0, 0 }, /* Circled 0 */ +#ifdef __REACTOS__ + { 0x24f5, 1, 9, TRUE /* WS03 */ }, /* Double Circled */ + { 0x24ff, 0, 0, TRUE /* WS03 */ }, /* Negative Circled 0 */ +#else + { 0x24f5, 1, 9 }, /* Double Circled */ + { 0x24ff, 0, 0 }, /* Negative Circled 0 */ +#endif + { 0x2776, 1, 9 }, /* Inverted Circled */ + { 0x2780, 1, 9 }, /* Patterned Circled */ + { 0x278a, 1, 9 }, /* Inverted Patterned Circled */ +#ifdef __REACTOS__ + { 0x3007, 0, 0, TRUE /* WS03 */ }, /* Ideographic Number 0 */ + { 0x3021, 1, 9, TRUE /* WS03 */ }, /* Hangzhou */ + { 0xa620, 0, 9, TRUE /* WS03 */ }, /* Vai */ + { 0xa8d0, 0, 9, TRUE /* WS03 */ }, /* Saurashtra */ +#else + { 0x3007, 0, 0 }, /* Ideographic Number 0 */ + { 0x3021, 1, 9 }, /* Hangzhou */ + { 0xa620, 0, 9 }, /* Vai */ + { 0xa8d0, 0, 9 }, /* Saurashtra */ +#endif + { 0xa8e0, 0, 9, TRUE /*win7*/ }, /* Combining Devanagari */ +#ifdef __REACTOS__ + { 0xa900, 0, 9, TRUE /* WS03 */ }, /* Kayah Li */ +#else + { 0xa900, 0, 9 }, /* Kayah Li */ +#endif + { 0xa9d0, 0, 9, TRUE /*win7*/ }, /* Javanese */ + { 0xa9f0, 0, 9, TRUE /*win10*/ }, /* Myanmar Tai Laing */ +#ifdef __REACTOS__ + { 0xaa50, 0, 9, TRUE /* WS03 */ }, /* Cham */ +#else + { 0xaa50, 0, 9 }, /* Cham */ +#endif + { 0xabf0, 0, 9, TRUE /*win7*/ }, /* Meetei Mayek */ + { 0xff10, 0, 9 }, /* Full Width */ +#ifdef __REACTOS__ + { 0x10107, 1, 9, TRUE /* WS03 */ }, /* Aegean */ + { 0x10320, 1, 1, TRUE /* WS03 */ }, /* Old Italic Numeral 1 */ + { 0x10321, 5, 5, TRUE /* WS03 */ }, /* Old Italic Numeral 5 */ + { 0x104a0, 0, 9, TRUE /* WS03 */ }, /* Osmanya */ +#else + { 0x10107, 1, 9 }, /* Aegean */ + { 0x10320, 1, 1 }, /* Old Italic Numeral 1 */ + { 0x10321, 5, 5 }, /* Old Italic Numeral 5 */ + { 0x104a0, 0, 9 }, /* Osmanya */ +#endif + { 0x10a40, 1, 4, TRUE /*win10*/ }, /* Kharoshthi */ + { 0x10d30, 0, 9, TRUE /*win10*/ }, /* Hanifi Rohingya */ + { 0x10d40, 0, 9, TRUE /*win10*/ }, /* Garay */ + { 0x10e60, 1, 9, TRUE /*win10*/ }, /* Rumi */ + { 0x11052, 1, 9, TRUE /*win10*/ }, /* Brahmi Number */ + { 0x11066, 0, 9, TRUE /*win10*/ }, /* Brahmi Digit */ + { 0x110f0, 0, 9, TRUE /*win10*/ }, /* Sora Sompeng */ + { 0x11136, 0, 9, TRUE /*win10*/ }, /* Chakma */ + { 0x111d0, 0, 9, TRUE /*win10*/ }, /* Sharada */ + { 0x112f0, 0, 9, TRUE /*win10*/ }, /* Khudawadi */ + { 0x11450, 0, 9, TRUE /*win10*/ }, /* Newa */ + { 0x114d0, 0, 9, TRUE /*win10*/ }, /* Tirhuta */ + { 0x11650, 0, 9, TRUE /*win10*/ }, /* Modi */ + { 0x116c0, 0, 9, TRUE /*win10*/ }, /* Takri */ + { 0x116d0, 0, 9, TRUE /*win10*/ }, /* Myanmar Pa-O */ + { 0x116da, 0, 9, TRUE /*win10*/ }, /* Myanmar Eastern Pwo */ + { 0x11730, 0, 9, TRUE /*win10*/ }, /* Ahom */ + { 0x118e0, 0, 9, TRUE /*win10*/ }, /* Warang */ + { 0x11950, 0, 9, TRUE /*win10*/ }, /* Dives Akuru */ + { 0x11bf0, 0, 9, TRUE /*win10*/ }, /* Sunuwar */ + { 0x11c50, 0, 9, TRUE /*win10*/ }, /* Bhaiksuki */ + { 0x11d50, 0, 9, TRUE /*win10*/ }, /* Masaram Gondi */ + { 0x11da0, 0, 9, TRUE /*win10*/ }, /* Gunjala Gondi */ + { 0x11f50, 0, 9, TRUE /*win10*/ }, /* Kawi */ + { 0x16130, 0, 9, TRUE /*win10*/ }, /* Gurung Khema */ + { 0x16a60, 0, 9, TRUE /*win10*/ }, /* Mro */ + { 0x16ac0, 0, 9, TRUE /*win10*/ }, /* Tangsa */ + { 0x16b50, 0, 9, TRUE /*win10*/ }, /* Pahawh Hmong */ + { 0x16d70, 0, 9, TRUE /*win10*/ }, /* Kirat Rai */ + { 0x1ccf0, 0, 9, TRUE /*win10*/ }, /* Outlined digits */ +#ifdef __REACTOS__ + { 0x1d7ce, 0, 9, TRUE /* WS03 */ }, /* Mathematical Bold */ + { 0x1d7d8, 0, 9, TRUE /* WS03 */ }, /* Mathematical Double Struck */ + { 0x1d7e2, 0, 9, TRUE /* WS03 */ }, /* Mathematical Sans Serif */ + { 0x1d7ec, 0, 9, TRUE /* WS03 */ }, /* Mathematical Sans Serif Bold */ + { 0x1d7f6, 0, 9, TRUE /* WS03 */ }, /* Mathematical Monospace */ +#else + { 0x1d7ce, 0, 9 }, /* Mathematical Bold */ + { 0x1d7d8, 0, 9 }, /* Mathematical Double Struck */ + { 0x1d7e2, 0, 9 }, /* Mathematical Sans Serif */ + { 0x1d7ec, 0, 9 }, /* Mathematical Sans Serif Bold */ + { 0x1d7f6, 0, 9 }, /* Mathematical Monospace */ +#endif + { 0x1e140, 0, 9, TRUE /*win10*/ }, /* Nyiakeng Puachue Hmong */ + { 0x1e2f0, 0, 9, TRUE /*win10*/ }, /* Wancho */ + { 0x1e4f0, 0, 9, TRUE /*win10*/ }, /* Nag Mundari */ + { 0x1e5f1, 0, 9, TRUE /*win10*/ }, /* Ol Onal */ + { 0x1e950, 0, 9, TRUE /*win10*/ }, /* Adlam */ + { 0x1f100, 0, 0, TRUE /*win10*/ }, /* Full Stop */ + { 0x1f101, 0, 9, TRUE /*win10*/ }, /* Comma */ + { 0x1fbf0, 0, 9, TRUE /*win10*/ }, /* Segmented */ + { 0x10ffff } /* Terminator */ }; static const WCHAR foldczone_src[] = { 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d, - 0xff37, 0xff49, 0xff4e, 0xff45, '\0' + 0xff37, 0xff49, 0xff4e, 0xff45, 0x3c5, 0x308, 0x6a, 0x30c, 0xa0, 0xaa, 0 }; static const WCHAR foldczone_dst[] = { - 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0' + 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e',0x3cb,0x1f0,' ','a',0 }; - static const WCHAR foldczone_todo_src[] = + static const WCHAR foldczone_broken_dst[] = { - 0x3c5,0x308,0x6a,0x30c,0xa0,0xaa,0 - }; - static const WCHAR foldczone_todo_dst[] = - { - 0x3cb,0x1f0,' ','a',0 - }; - static const WCHAR foldczone_todo_broken_dst[] = - { - 0x3cb,0x1f0,0xa0,0xaa,0 + 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e',0x03c5,0x0308,'j',0x030c,0x00a0,0x00aa,0 }; static const WCHAR ligatures_src[] = { @@ -3318,149 +4341,126 @@ static void test_FoldStringW(void) 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0' }; - if (!pFoldStringW) - { - win_skip("FoldStringW is not available\n"); - return; /* FoldString is present in NT v3.1+, but not 95/98/Me */ - } - /* Invalid flag combinations */ - for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++) + for (i = 0; i < ARRAY_SIZE(badFlags); i++) { src[0] = dst[0] = '\0'; - SetLastError(0); - ret = pFoldStringW(badFlags[i], src, 256, dst, 256); - if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) - { - win_skip("FoldStringW is not implemented\n"); - return; - } + SetLastError(0xdeadbeef); + ret = FoldStringW(badFlags[i], src, 256, dst, 256); ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, - "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); + "Expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError()); } /* src & dst cannot be the same */ - SetLastError(0); - ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256); + SetLastError(0xdeadbeef); + ret = FoldStringW(MAP_FOLDCZONE, src, -1, src, 256); ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); /* src can't be NULL */ - SetLastError(0); - ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256); + SetLastError(0xdeadbeef); + ret = FoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256); ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); /* srclen can't be 0 */ - SetLastError(0); - ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256); + SetLastError(0xdeadbeef); + ret = FoldStringW(MAP_FOLDCZONE, src, 0, dst, 256); ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); /* dstlen can't be < 0 */ - SetLastError(0); - ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1); + SetLastError(0xdeadbeef); + ret = FoldStringW(MAP_FOLDCZONE, src, -1, dst, -1); ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); /* Ret includes terminating NUL which is appended if srclen = -1 */ - SetLastError(0); + SetLastError(0xdeadbeef); src[0] = 'A'; src[1] = '\0'; dst[0] = '\0'; - ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256); - ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); + ret = FoldStringW(MAP_FOLDCZONE, src, -1, dst, 256); + ok(ret == 2, "Expected ret == 2, got %d, error %ld\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", + "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%ld\n", 'A', '\0', ret, dst[0], dst[1], GetLastError()); /* If size is given, result is not NUL terminated */ - SetLastError(0); + SetLastError(0xdeadbeef); src[0] = 'A'; src[1] = 'A'; dst[0] = 'X'; dst[1] = 'X'; - ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256); - ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError()); + ret = FoldStringW(MAP_FOLDCZONE, src, 1, dst, 256); + ok(ret == 1, "Expected ret == 1, got %d, error %ld\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", + "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%ld\n", 'A','X', ret, dst[0], dst[1], GetLastError()); /* MAP_FOLDDIGITS */ - for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++) + for (j = 0; j < ARRAY_SIZE(digitRanges); j++) { /* Check everything before this range */ - for (ch = prev_ch; ch < digitRanges[j]; ch++) + for (ch = prev_ch; ch < digitRanges[j].ch; ch++) { - SetLastError(0); - src[0] = ch; - src[1] = dst[0] = '\0'; - ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256); - ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); - - ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) || - (ch >= 0xa8e0 && ch <= 0xa8e9), /* combining Devanagari on Win8 */ - "MAP_FOLDDIGITS: ch 0x%04x Expected unchanged got %04x\n", ch, dst[0]); - ok(!isdigitW(ch) || strchrW(outOfSequenceDigits, ch) || - broken( ch >= 0xbf0 && ch <= 0xbf2 ), /* win2k */ - "char %04x should not be a digit\n", ch ); + len = put_utf16( src, ch ); + src[len] = 0; + SetLastError(0xdeadbeef); + ret = FoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256); + if (ret == 3) + { + ok( !wcscmp( src, dst ), "%s changed to %s\n", debugstr_w(src), debugstr_w(dst) ); + continue; + } + ok(ret == 2, "Expected ret == 2, got %d, error %ld\n", ret, GetLastError()); +#ifdef __REACTOS__ + ok(dst[0] == ch || broken(GetNTVersion() == _WIN32_WINNT_VISTA), "MAP_FOLDDIGITS: ch 0x%04x Expected unchanged got %04x\n", ch, dst[0]); +#else + ok(dst[0] == ch, "MAP_FOLDDIGITS: ch 0x%04x Expected unchanged got %04x\n", ch, dst[0]); +#endif + if (ch < 0x10000) + { + WCHAR wch = ch; + GetStringTypeW( CT_CTYPE1, &wch, 1, &type ); + ok(!(type & C1_DIGIT), "char %04x should not be a digit\n", wch ); + } } - - if (digitRanges[j] == 0xffff) + if (digitRanges[j].ch == 0x10ffff) break; /* Finished the whole code point space */ - for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++) + for (ch = digitRanges[j].ch; ch <= digitRanges[j].ch + digitRanges[j].last - digitRanges[j].first; ch++) { - WCHAR c; + UINT exp = '0' + digitRanges[j].first + ch - digitRanges[j].ch; - /* Map out of sequence characters */ - if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */ - else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */ - else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */ - else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */ - else c = ch; - SetLastError(0); - src[0] = c; - src[1] = dst[0] = '\0'; - ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256); - 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 */ - (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */ - (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */ - strchrW(noDigitAvailable, c), - "MAP_FOLDDIGITS: ch %04x Expected %04x got %04x\n", - ch, '0' + digitRanges[j] - ch, dst[0]); + SetLastError(0xdeadbeef); + len = put_utf16( src, ch ); + src[len] = 0; + ret = FoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256); + ok(ret == 2 || broken( digitRanges[j].broken && ch >= 0x10000 ), + "%04x: Expected ret == 2, got %d, error %ld\n", ch, ret, GetLastError()); + ok((dst[0] == exp && dst[1] == '\0') || broken( digitRanges[j].broken ), + "MAP_FOLDDIGITS: ch %04x Expected %04x got %04x\n", ch, exp, dst[0]); } prev_ch = ch; } /* MAP_FOLDCZONE */ - SetLastError(0); - ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256); - ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]), - "Got %d, error %d\n", ret, GetLastError()); - ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)), - "MAP_FOLDCZONE: Expanded incorrectly\n"); + SetLastError(0xdeadbeef); + ret = FoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256); + ok(ret == ARRAY_SIZE(foldczone_dst) + || broken(ret == ARRAY_SIZE(foldczone_broken_dst)), /* winxp, win2003 */ + "Got %d, error %ld.\n", ret, GetLastError()); + ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)) + || broken(!memcmp(dst, foldczone_broken_dst, sizeof(foldczone_broken_dst))), /* winxp, win2003 */ + "Got unexpected string %s.\n", wine_dbgstr_w(dst)); - ret = pFoldStringW(MAP_FOLDCZONE|MAP_PRECOMPOSED, foldczone_todo_src, -1, dst, 256); - todo_wine ok(ret == sizeof(foldczone_todo_dst)/sizeof(foldczone_todo_dst[0]), - "Got %d, error %d\n", ret, GetLastError()); - todo_wine ok(!memcmp(dst, foldczone_todo_dst, sizeof(foldczone_todo_dst)) - || broken(!memcmp(dst, foldczone_todo_broken_dst, sizeof(foldczone_todo_broken_dst))), - "MAP_FOLDCZONE: Expanded incorrectly (%s)\n", wine_dbgstr_w(dst)); - - /* MAP_EXPAND_LIGATURES */ - SetLastError(0); - 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)) { - ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]), - "Got %d, error %d\n", ret, GetLastError()); + /* MAP_EXPAND_LIGATURES */ + SetLastError(0xdeadbeef); + ret = FoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256); + ok(ret == ARRAY_SIZE(ligatures_dst), "Got %d, error %ld\n", ret, GetLastError()); ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)), - "MAP_EXPAND_LIGATURES: Expanded incorrectly\n"); - } + "Got unexpected string %s.\n", wine_dbgstr_w(dst)); /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */ } @@ -3468,27 +4468,78 @@ static void test_FoldStringW(void) #define LCID_OK(l) \ - ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid) + ok(lcid == l, "Expected lcid = %08lx, got %08lx\n", l, lcid) #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z) -#define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res) +#define LCID_RES(src, res) do { lcid = ConvertDefaultLocale(src); LCID_OK(res); } while (0) #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b)) #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c)) static void test_ConvertDefaultLocale(void) { - LCID lcid; + /* some languages use a different default than SUBLANG_DEFAULT */ + static const struct { WORD lang, sublang; } nondefault_langs[] = + { + { LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED }, + { LANG_SPANISH, SUBLANG_SPANISH_MODERN }, + { LANG_IRISH, SUBLANG_IRISH_IRELAND }, + { LANG_BENGALI, SUBLANG_BENGALI_BANGLADESH }, + { LANG_SINDHI, SUBLANG_SINDHI_AFGHANISTAN }, + { LANG_INUKTITUT, SUBLANG_INUKTITUT_CANADA_LATIN }, + { LANG_TAMAZIGHT, SUBLANG_TAMAZIGHT_ALGERIA_LATIN }, + { LANG_FULAH, SUBLANG_FULAH_SENEGAL }, + { LANG_TIGRINYA, SUBLANG_TIGRINYA_ERITREA } + }; + LCID lcid; + unsigned int i; /* Doesn't change lcid, even if non default sublang/sort used */ TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT); TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT); TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT); TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE); + lcid = ConvertDefaultLocale( MKLCID( LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_JAPANESE_UNICODE )); + ok( lcid == MKLCID( LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_JAPANESE_UNICODE ) || + broken( lcid == MKLCID( LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE )), /* <= vista */ + "Expected lcid = %08lx got %08lx\n", + MKLCID( LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_JAPANESE_UNICODE ), lcid ); + lcid = ConvertDefaultLocale( MKLCID( LANG_IRISH, SUBLANG_NEUTRAL, SORT_JAPANESE_UNICODE )); + ok( lcid == MKLCID( LANG_IRISH, SUBLANG_NEUTRAL, SORT_JAPANESE_UNICODE ) || + broken( lcid == MKLCID( LANG_IRISH, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE )), /* <= vista */ + "Expected lcid = %08lx got %08lx\n", + MKLCID( LANG_IRISH, SUBLANG_NEUTRAL, SORT_JAPANESE_UNICODE ), lcid ); /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */ LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT), MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT)); LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT), MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT)); + for (i = 0; i < ARRAY_SIZE(nondefault_langs); i++) + { + lcid = ConvertDefaultLocale( MAKELANGID( nondefault_langs[i].lang, SUBLANG_NEUTRAL )); + ok( lcid == MAKELANGID( nondefault_langs[i].lang, nondefault_langs[i].sublang ) || + broken( lcid == MAKELANGID( nondefault_langs[i].lang, SUBLANG_DEFAULT )) || /* <= vista */ + broken( lcid == MAKELANGID( nondefault_langs[i].lang, SUBLANG_NEUTRAL )), /* w7 */ + "Expected lcid = %08x got %08lx\n", + MAKELANGID( nondefault_langs[i].lang, nondefault_langs[i].sublang ), lcid ); + } + lcid = ConvertDefaultLocale( 0x7804 ); + ok( lcid == MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED ) || + broken( lcid == 0x7804 ), /* <= vista */ + "Expected lcid = %08x got %08lx\n", MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED ), lcid ); + lcid = ConvertDefaultLocale( 0x7c04 ); + ok( lcid == MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_HONGKONG ) || + broken( lcid == 0x7c04 ) || /* winxp */ + broken( lcid == 0x0404 ), /* vista */ + "Expected lcid = %08x got %08lx\n", MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_HONGKONG ), lcid ); + lcid = ConvertDefaultLocale( LANG_SERBIAN_NEUTRAL ); + ok( lcid == MAKELANGID( LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN ) || +#ifdef __REACTOS__ + broken( lcid == MAKELANGID( LANG_SERBIAN, SUBLANG_SERBIAN_LATIN ) ) || /* Vista */ + broken( lcid == LANG_SERBIAN_NEUTRAL ), /* WS03 */ +#else + broken( lcid == MAKELANGID( LANG_SERBIAN, SUBLANG_SERBIAN_LATIN ) ), /* <= vista */ +#endif + "Expected lcid = %08x got %08lx\n", MAKELANGID( LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN ), lcid ); /* Invariant language is not treated specially */ TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT); @@ -3501,24 +4552,37 @@ static void test_ConvertDefaultLocale(void) LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID()); LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID()); LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID()); +#ifdef __REACTOS__ + lcid = ConvertDefaultLocale( LOCALE_CUSTOM_DEFAULT ); + ok(lcid == GetUserDefaultLCID() || + broken(lcid == 0x0c00) /* WS03 */, + "Expected lcid = %08lx, got %08lx\n", GetUserDefaultLCID(), lcid); +#else + LCID_RES(LOCALE_CUSTOM_DEFAULT, GetUserDefaultLCID()); +#endif + lcid = ConvertDefaultLocale( LOCALE_CUSTOM_UNSPECIFIED ); + ok( lcid == GetUserDefaultLCID() || broken(lcid == LOCALE_CUSTOM_UNSPECIFIED), /* <= win8 */ + "wrong lcid %04lx\n", lcid ); + lcid = ConvertDefaultLocale( LOCALE_CUSTOM_UI_DEFAULT ); + ok( lcid == GetUserDefaultUILanguage() || lcid == LOCALE_CUSTOM_UI_DEFAULT, "wrong lcid %04lx\n", lcid ); lcid = ConvertDefaultLocale(LOCALE_INVARIANT); ok(lcid == LOCALE_INVARIANT || broken(lcid == 0x47f) /* win2k[3]/winxp */, - "Expected lcid = %08x, got %08x\n", LOCALE_INVARIANT, lcid); + "Expected lcid = %08lx, got %08lx\n", LOCALE_INVARIANT, lcid); } static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName, DWORD dwFlags, LONG_PTR lParam) { if (winetest_debug > 1) - trace("%08x, %s, %s, %08x, %08lx\n", + trace("%08lx, %s, %s, %08lx, %08Ix\n", lgrpid, lpszNum, lpszName, dwFlags, lParam); ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE, - "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags); + "Enumerated grp %ld not valid (flags %ld)\n", lgrpid, dwFlags); /* If lParam is one, we are calling with flags defaulted from 0 */ ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED), - "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags); + "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %ld\n", dwFlags); return TRUE; } @@ -3542,26 +4606,203 @@ static void test_EnumSystemLanguageGroupsA(void) return; } ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); /* Invalid flags */ SetLastError(0); pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0); - ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError()); /* No flags - defaults to LGRPID_INSTALLED */ SetLastError(0xdeadbeef); pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1); - ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "got error %ld\n", GetLastError()); pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0); pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0); } +static LONG default_seen; +static LONG alternate_seen; + +static BOOL CALLBACK test_EnumSystemLocalesA_callback(LPSTR str) +{ + LCID lcid; + WORD sortid; + + if (sscanf(str, "%lx", &lcid) != 1) + { + ok(FALSE, "EnumSystemLocalesA callback received unparsable LCID string \"%s\"\n", str); + return FALSE; + } + + sortid = SORTIDFROMLCID(lcid); + if (sortid == SORT_DEFAULT) + { + default_seen++; + } + else + { + alternate_seen++; + } + + return TRUE; +} + +static BOOL CALLBACK test_EnumSystemLocalesW_callback(LPWSTR str) +{ + LCID lcid; + WORD sortid; + + if (swscanf(str, L"%lx", &lcid) != 1) + { + ok(FALSE, "unparsable LCID string %s\n", debugstr_w(str)); + return FALSE; + } + + sortid = SORTIDFROMLCID(lcid); + if (sortid == SORT_DEFAULT) + { + default_seen++; + } + else + { + alternate_seen++; + } + + return TRUE; +} + +static void test_EnumSystemLocalesA(void) +{ + if (!pEnumSystemLocalesA) + { + win_skip("EnumSystemLocalesA not available"); + return; + } + + default_seen = 0; + alternate_seen = 0; + + pEnumSystemLocalesA(test_EnumSystemLocalesA_callback, 0); + ok(default_seen, "EnumSystemLocalesA(..., 0) returned 0 locales " + "with default sort order, expected > 0\n"); + ok(!alternate_seen, "EnumSystemLocalesA(..., 0) returned %ld locales " + "with alternate sort order, expected 0\n", alternate_seen); + + default_seen = 0; + alternate_seen = 0; + + pEnumSystemLocalesA(test_EnumSystemLocalesA_callback, LCID_INSTALLED); + ok(default_seen, "EnumSystemLocalesA(..., LCID_INSTALLED) returned 0 locales " + "with default sort order, expected > 0\n"); + ok(!alternate_seen, "EnumSystemLocalesA(..., LCID_INSTALLED) returned %ld locales " + "with alternate sort order, expected 0\n", alternate_seen); + + default_seen = 0; + alternate_seen = 0; + + pEnumSystemLocalesA(test_EnumSystemLocalesA_callback, LCID_SUPPORTED); + ok(default_seen, "EnumSystemLocalesA(..., LCID_SUPPORTED) returned 0 locales " + "with default sort order, expected > 0\n"); + ok(!alternate_seen, "EnumSystemLocalesA(..., LCID_SUPPORTED) returned %ld locales " + "with alternate sort order, expected 0\n", alternate_seen); + + default_seen = 0; + alternate_seen = 0; + + pEnumSystemLocalesA(test_EnumSystemLocalesA_callback, LCID_ALTERNATE_SORTS); + ok(alternate_seen, "EnumSystemLocalesA(..., LCID_ALTERNATE_SORTS) returned 0 locales " + "with alternate sort order, expected > 0\n"); + ok(!default_seen, "EnumSystemLocalesA(..., LCID_ALTERNATE_SORTS) returned %ld locales " + "with default sort order, expected 0\n", alternate_seen); + + default_seen = 0; + alternate_seen = 0; + + pEnumSystemLocalesA(test_EnumSystemLocalesA_callback, LCID_INSTALLED | LCID_ALTERNATE_SORTS); + ok(default_seen, "EnumSystemLocalesA(..., LCID_INSTALLED | LCID_ALTERNATE_SORTS) returned 0 locales " + "with default sort order, expected > 0\n"); + ok(alternate_seen, "EnumSystemLocalesA(..., LCID_INSTALLED | LCID_ALTERNATE_SORTS) returned 0 locales " + "with alternate sort order, expected > 0\n"); + + default_seen = 0; + alternate_seen = 0; + + pEnumSystemLocalesA(test_EnumSystemLocalesA_callback, LCID_SUPPORTED | LCID_ALTERNATE_SORTS); + ok(default_seen, "EnumSystemLocalesA(..., LCID_SUPPORTED | LCID_ALTERNATE_SORTS) returned 0 locales " + "with default sort order, expected > 0\n"); + ok(alternate_seen, "EnumSystemLocalesA(..., LCID_SUPPORTED | LCID_ALTERNATE_SORTS) returned 0 locales " + "with alternate sort order, expected > 0\n"); +} + +static void test_EnumSystemLocalesW(void) +{ + if (!pEnumSystemLocalesW) + { + win_skip("EnumSystemLocalesW not available"); + return; + } + + default_seen = 0; + alternate_seen = 0; + + pEnumSystemLocalesW(test_EnumSystemLocalesW_callback, 0); + ok(default_seen, "EnumSystemLocalesW(..., 0) returned 0 locales " + "with default sort order, expected > 0\n"); + ok(!alternate_seen, "EnumSystemLocalesW(..., 0) returned %ld locales " + "with alternate sort order, expected 0\n", alternate_seen); + + default_seen = 0; + alternate_seen = 0; + + pEnumSystemLocalesW(test_EnumSystemLocalesW_callback, LCID_INSTALLED); + ok(default_seen, "EnumSystemLocalesW(..., LCID_INSTALLED) returned 0 locales " + "with default sort order, expected > 0\n"); + ok(!alternate_seen, "EnumSystemLocalesW(..., LCID_INSTALLED) returned %ld locales " + "with alternate sort order, expected 0\n", alternate_seen); + + default_seen = 0; + alternate_seen = 0; + + pEnumSystemLocalesW(test_EnumSystemLocalesW_callback, LCID_SUPPORTED); + ok(default_seen, "EnumSystemLocalesW(..., LCID_SUPPORTED) returned 0 locales " + "with default sort order, expected > 0\n"); + ok(!alternate_seen, "EnumSystemLocalesW(..., LCID_SUPPORTED) returned %ld locales " + "with alternate sort order, expected 0\n", alternate_seen); + + default_seen = 0; + alternate_seen = 0; + + pEnumSystemLocalesW(test_EnumSystemLocalesW_callback, LCID_ALTERNATE_SORTS); + ok(alternate_seen, "EnumSystemLocalesW(..., LCID_ALTERNATE_SORTS) returned 0 locales " + "with alternate sort order, expected > 0\n"); + ok(!default_seen, "EnumSystemLocalesW(..., LCID_ALTERNATE_SORTS) returned %ld locales " + "with default sort order, expected 0\n", alternate_seen); + + default_seen = 0; + alternate_seen = 0; + + pEnumSystemLocalesW(test_EnumSystemLocalesW_callback, LCID_INSTALLED | LCID_ALTERNATE_SORTS); + ok(default_seen, "EnumSystemLocalesW(..., LCID_INSTALLED | LCID_ALTERNATE_SORTS) returned 0 locales " + "with default sort order, expected > 0\n"); + ok(alternate_seen, "EnumSystemLocalesW(..., LCID_INSTALLED | LCID_ALTERNATE_SORTS) returned 0 locales " + "with alternate sort order, expected > 0\n"); + + default_seen = 0; + alternate_seen = 0; + + pEnumSystemLocalesW(test_EnumSystemLocalesW_callback, LCID_SUPPORTED | LCID_ALTERNATE_SORTS); + ok(default_seen, "EnumSystemLocalesW(..., LCID_SUPPORTED | LCID_ALTERNATE_SORTS) returned 0 locales " + "with default sort order, expected > 0\n"); + ok(alternate_seen, "EnumSystemLocalesW(..., LCID_SUPPORTED | LCID_ALTERNATE_SORTS) returned 0 locales " + "with alternate sort order, expected > 0\n"); +} + static BOOL CALLBACK enum_func( LPWSTR name, DWORD flags, LPARAM lparam ) { if (winetest_debug > 1) - trace( "%s %x\n", wine_dbgstr_w(name), flags ); + trace( "%s %lx\n", wine_dbgstr_w(name), flags ); return TRUE; } @@ -3577,26 +4818,26 @@ static void test_EnumSystemLocalesEx(void) SetLastError( 0xdeadbeef ); ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 ); ok( !ret, "should have failed\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL ); - ok( ret, "failed err %u\n", GetLastError() ); + ok( ret, "failed err %lu\n", GetLastError() ); } static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum, LONG_PTR lParam) { if (winetest_debug > 1) - trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam); + trace("%08lx, %08lx, %s, %08Ix\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); + "Enumerated grp %ld not valid\n", lgrpid); ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE, - "Enumerated grp locale %04x not valid\n", lcid); + "Enumerated grp locale %04lx not valid\n", lcid); return TRUE; } @@ -3619,57 +4860,110 @@ static void test_EnumLanguageGroupLocalesA(void) return; } ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); /* lgrpid too small */ SetLastError(0); ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0); ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); /* lgrpid too big */ SetLastError(0); ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0); ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); /* dwFlags is reserved */ SetLastError(0); ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0); ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0); } -static void test_SetLocaleInfoA(void) +static void test_SetLocaleInfo(void) { - BOOL bRet; - LCID lcid = GetUserDefaultLCID(); + BOOL bRet; + LCID lcid = GetUserDefaultLCID(); + UINT i; - /* Null data */ - SetLastError(0); - bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0); - ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + /* Null data */ + SetLastError(0xdeadbeef); + bRet = SetLocaleInfoA(lcid, LOCALE_SSHORTDATE, NULL); + ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); - /* IDATE */ - SetLastError(0); - bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA"); - ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS, - "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); + SetLastError(0xdeadbeef); + bRet = SetLocaleInfoW(lcid, LOCALE_SSHORTDATE, NULL); + ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); - /* ILDATE */ - SetLastError(0); - bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA"); - ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS, - "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); + SetLastError(0xdeadbeef); + bRet = SetLocaleInfoW(lcid, LOCALE_SDAYNAME1, NULL); + ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); + + for (i = 0; i <= 0x1014; i++) + { + WCHAR buffer[80]; + if (!GetLocaleInfoW( LOCALE_USER_DEFAULT, i, buffer, ARRAY_SIZE(buffer) )) continue; + SetLastError(0xdeadbeef); + bRet = SetLocaleInfoW(lcid, i, buffer); + switch (i) + { + case LOCALE_ICALENDARTYPE: + case LOCALE_ICURRDIGITS: + case LOCALE_ICURRENCY: + case LOCALE_IDIGITS: + case LOCALE_IDIGITSUBSTITUTION: + case LOCALE_IFIRSTDAYOFWEEK: + case LOCALE_IFIRSTWEEKOFYEAR: + case LOCALE_ILZERO: + case LOCALE_IMEASURE: + case LOCALE_INEGCURR: + case LOCALE_INEGNUMBER: + case LOCALE_IPAPERSIZE: + case LOCALE_ITIME: + case LOCALE_S1159: + case LOCALE_S2359: + case LOCALE_SCURRENCY: + case LOCALE_SDATE: + case LOCALE_SDECIMAL: + case LOCALE_SGROUPING: + case LOCALE_SLIST: + case LOCALE_SLONGDATE: + case LOCALE_SMONDECIMALSEP: + case LOCALE_SMONGROUPING: + case LOCALE_SMONTHOUSANDSEP: + case LOCALE_SNATIVEDIGITS: + case LOCALE_SNEGATIVESIGN: + case LOCALE_SPOSITIVESIGN: + case LOCALE_SSHORTDATE: + case LOCALE_SSHORTTIME: + case LOCALE_STHOUSAND: + case LOCALE_STIME: + case LOCALE_STIMEFORMAT: + case LOCALE_SYEARMONTH: + ok( bRet, "%04x: failed err %lu\n", i, GetLastError() ); + break; + case LOCALE_SINTLSYMBOL: + ok( bRet || broken(!bRet), /* win10 <= 1507 */ + "%04x: failed err %lu\n", i, GetLastError() ); + break; + default: + ok( !bRet, "%04x: succeeded\n", i ); + ok( GetLastError() == ERROR_INVALID_FLAGS, "%04x: wrong error %lu\n", i, GetLastError() ); + break; + } + } } static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam) { if (winetest_debug > 1) - trace("%s %08lx\n", value, lParam); + trace("%s %08Ix\n", value, lParam); return(TRUE); } @@ -3701,29 +4995,45 @@ static void test_EnumUILanguageA(void) win_skip("EnumUILanguagesA is not implemented\n"); return; } - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + ok(ret, "Expected ret != 0, got %d, error %ld\n", ret, GetLastError()); + + SetLastError(0xdeadbeef); + ret = pEnumUILanguagesA(luilocale_proc1A, MUI_LANGUAGE_NAME, 0); +#ifdef __REACTOS__ + ok(ret || broken(!ret && GetLastError() == ERROR_INVALID_FLAGS) /* WS03 */, "Expected ret != 0, got %d, error %ld\n", ret, GetLastError()); +#else + ok(ret, "Expected ret != 0, got %d, error %ld\n", ret, GetLastError()); +#endif enumCount = 0; SetLastError(ERROR_SUCCESS); ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0); - ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + ok(ret, "Expected ret != 0, got %d, error %ld\n", ret, GetLastError()); + ok(enumCount == 1, "enumCount = %u\n", enumCount); + + enumCount = 0; + SetLastError(ERROR_SUCCESS); + ret = pEnumUILanguagesA(luilocale_proc2A, MUI_LANGUAGE_ID, 0); + ok(ret || broken(!ret && GetLastError() == ERROR_INVALID_FLAGS), /* winxp */ + "Expected ret != 0, got %d, error %ld\n", ret, GetLastError()); + if (ret) ok(enumCount == 1, "enumCount = %u\n", enumCount); SetLastError(ERROR_SUCCESS); ret = pEnumUILanguagesA(NULL, 0, 0); ok(!ret, "Expected return value FALSE, got %u\n", ret); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); SetLastError(ERROR_SUCCESS); ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0); ok(!ret, "Expected return value FALSE, got %u\n", ret); - ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError()); SetLastError(ERROR_SUCCESS); ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0); ok(!ret, "Expected return value FALSE, got %u\n", ret); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); } static char date_fmt_buf[1024]; @@ -3757,12 +5067,12 @@ static void test_EnumDateFormatsA(void) } else { - ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError()); + ok(ret, "EnumDateFormatsA(0) error %ld\n", GetLastError()); trace("EnumDateFormatsA(0): %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(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %ld\n", GetLastError()); ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf); } @@ -3775,33 +5085,33 @@ static void test_EnumDateFormatsA(void) } else { - ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError()); + ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %ld\n", GetLastError()); trace("EnumDateFormatsA(LOCALE_USE_CP_ACP): %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(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %ld\n", GetLastError()); ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf); } date_fmt_buf[0] = 0; ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE); - ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError()); + ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %ld\n", GetLastError()); trace("EnumDateFormatsA(DATE_SHORTDATE): %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(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %ld\n", GetLastError()); ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf); date_fmt_buf[0] = 0; ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE); - ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError()); + ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %ld\n", GetLastError()); trace("EnumDateFormatsA(DATE_LONGDATE): %s\n", date_fmt_buf); /* test the 1st enumerated format */ if ((p = strchr(date_fmt_buf, '\n'))) *p = 0; ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf)); - ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError()); + ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %ld\n", GetLastError()); ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf); date_fmt_buf[0] = 0; @@ -3812,12 +5122,12 @@ static void test_EnumDateFormatsA(void) win_skip("DATE_YEARMONTH is only present on W2K and later\n"); return; } - ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError()); + ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %ld\n", GetLastError()); trace("EnumDateFormatsA(DATE_YEARMONTH): %s\n", date_fmt_buf); /* test the 1st enumerated format */ 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(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %ld\n", GetLastError()); ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */, "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf); } @@ -3830,22 +5140,22 @@ static void test_EnumTimeFormatsA(void) date_fmt_buf[0] = 0; ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0); - ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError()); + ok(ret, "EnumTimeFormatsA(0) error %ld\n", GetLastError()); trace("EnumTimeFormatsA(0): %s\n", date_fmt_buf); /* test the 1st enumerated format */ if ((p = strchr(date_fmt_buf, '\n'))) *p = 0; ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf)); - ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError()); + ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %ld\n", GetLastError()); ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf); date_fmt_buf[0] = 0; ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP); - ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError()); + ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %ld\n", GetLastError()); trace("EnumTimeFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf); /* test the 1st enumerated format */ if ((p = strchr(date_fmt_buf, '\n'))) *p = 0; ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf)); - ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError()); + ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %ld\n", GetLastError()); ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf); } @@ -3857,17 +5167,17 @@ static void test_EnumTimeFormatsW(void) date_fmt_bufW[0] = 0; ret = EnumTimeFormatsW(enum_datetime_procW, lcid, 0); - ok(ret, "EnumTimeFormatsW(0) error %d\n", GetLastError()); - ret = GetLocaleInfoW(lcid, LOCALE_STIMEFORMAT, bufW, sizeof(bufW)/sizeof(bufW[0])); - ok(ret, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %d\n", GetLastError()); + ok(ret, "EnumTimeFormatsW(0) error %ld\n", GetLastError()); + ret = GetLocaleInfoW(lcid, LOCALE_STIMEFORMAT, bufW, ARRAY_SIZE(bufW)); + ok(ret, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %ld\n", GetLastError()); ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW), wine_dbgstr_w(bufW)); date_fmt_bufW[0] = 0; ret = EnumTimeFormatsW(enum_datetime_procW, lcid, LOCALE_USE_CP_ACP); - ok(ret, "EnumTimeFormatsW(LOCALE_USE_CP_ACP) error %d\n", GetLastError()); - ret = GetLocaleInfoW(lcid, LOCALE_STIMEFORMAT, bufW, sizeof(bufW)/sizeof(bufW[0])); - ok(ret, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %d\n", GetLastError()); + ok(ret, "EnumTimeFormatsW(LOCALE_USE_CP_ACP) error %ld\n", GetLastError()); + ret = GetLocaleInfoW(lcid, LOCALE_STIMEFORMAT, bufW, ARRAY_SIZE(bufW)); + ok(ret, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %ld\n", GetLastError()); ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW), wine_dbgstr_w(bufW)); @@ -3879,38 +5189,41 @@ static void test_EnumTimeFormatsW(void) else { char buf[256]; - ok(ret, "EnumTimeFormatsW(TIME_NOSECONDS) error %d\n", GetLastError()); - ret = GetLocaleInfoW(lcid, LOCALE_SSHORTTIME, bufW, sizeof(bufW)/sizeof(bufW[0])); - ok(ret, "GetLocaleInfoW(LOCALE_SSHORTTIME) error %d\n", GetLastError()); + ok(ret, "EnumTimeFormatsW(TIME_NOSECONDS) error %ld\n", GetLastError()); + ret = GetLocaleInfoW(lcid, LOCALE_SSHORTTIME, bufW, ARRAY_SIZE(bufW)); + ok(ret, "GetLocaleInfoW(LOCALE_SSHORTTIME) error %ld\n", GetLastError()); ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW), wine_dbgstr_w(bufW)); /* EnumTimeFormatsA doesn't support this flag */ ret = EnumTimeFormatsA(enum_datetime_procA, lcid, TIME_NOSECONDS); - ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %d\n", ret, + ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %ld\n", ret, GetLastError()); ret = EnumTimeFormatsA(NULL, lcid, TIME_NOSECONDS); - ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %d\n", ret, + ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %ld\n", ret, GetLastError()); /* And it's not supported by GetLocaleInfoA either */ - ret = GetLocaleInfoA(lcid, LOCALE_SSHORTTIME, buf, sizeof(buf)/sizeof(buf[0])); - ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "GetLocaleInfoA(LOCALE_SSHORTTIME) ret %d, error %d\n", ret, + ret = GetLocaleInfoA(lcid, LOCALE_SSHORTTIME, buf, ARRAY_SIZE(buf)); + ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "GetLocaleInfoA(LOCALE_SSHORTTIME) ret %d, error %ld\n", ret, GetLastError()); } } + static void test_GetCPInfo(void) { BOOL ret; CPINFO cpinfo; + CPINFOEXW cpiw; SetLastError(0xdeadbeef); ret = GetCPInfo(CP_SYMBOL, &cpinfo); ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); + memset(cpinfo.LeadByte, '-', ARRAY_SIZE(cpinfo.LeadByte)); SetLastError(0xdeadbeef); ret = GetCPInfo(CP_UTF7, &cpinfo); if (!ret && GetLastError() == ERROR_INVALID_PARAMETER) @@ -3919,14 +5232,34 @@ static void test_GetCPInfo(void) } else { - ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError()); + unsigned int i; + + ok(ret, "GetCPInfo(CP_UTF7) error %lu\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]); + for (i = 0; i < sizeof(cpinfo.LeadByte); i++) + ok(!cpinfo.LeadByte[i], "expected NUL byte in index %u\n", i); ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize); + + memset( &cpiw, 0xcc, sizeof(cpiw) ); + ret = GetCPInfoExW( CP_UTF7, 0, &cpiw ); + ok( ret, "GetCPInfoExW failed err %lu\n", GetLastError() ); + ok( cpiw.DefaultChar[0] == 0x3f, "wrong DefaultChar[0] %02x\n", cpiw.DefaultChar[0] ); + ok( cpiw.DefaultChar[1] == 0, "wrong DefaultChar[1] %02x\n", cpiw.DefaultChar[1] ); + for (i = 0; i < 12; i++) ok( cpiw.LeadByte[i] == 0, "wrong LeadByte[%u] %02x\n", i, cpiw.LeadByte[i] ); + ok( cpiw.MaxCharSize == 5, "wrong MaxCharSize %02x\n", cpiw.MaxCharSize ); + ok( cpiw.CodePage == CP_UTF7, "wrong CodePage %02x\n", cpiw.CodePage ); +#ifdef __REACTOS__ + ok( cpiw.UnicodeDefaultChar == 0xfffd || + broken(cpiw.UnicodeDefaultChar == 0x3f) /* WS03 */, "wrong UnicodeDefaultChar %02x\n", cpiw.UnicodeDefaultChar ); +#else + ok( cpiw.UnicodeDefaultChar == 0xfffd, "wrong UnicodeDefaultChar %02x\n", cpiw.UnicodeDefaultChar ); +#endif + ok( !wcscmp( cpiw.CodePageName, L"65000 (UTF-7)" ), + "wrong CodePageName %s\n", debugstr_w(cpiw.CodePageName) ); } + memset(cpinfo.LeadByte, '-', ARRAY_SIZE(cpinfo.LeadByte)); SetLastError(0xdeadbeef); ret = GetCPInfo(CP_UTF8, &cpinfo); if (!ret && GetLastError() == ERROR_INVALID_PARAMETER) @@ -3935,14 +5268,208 @@ static void test_GetCPInfo(void) } else { - ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError()); + unsigned int i; + + ok(ret, "GetCPInfo(CP_UTF8) error %lu\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); + for (i = 0; i < sizeof(cpinfo.LeadByte); i++) + ok(!cpinfo.LeadByte[i], "expected NUL byte in index %u\n", i); + ok(cpinfo.MaxCharSize == 4, "expected 4, got %u\n", cpinfo.MaxCharSize); + + memset( &cpiw, 0xcc, sizeof(cpiw) ); + ret = GetCPInfoExW( CP_UTF8, 0, &cpiw ); + ok( ret, "GetCPInfoExW failed err %lu\n", GetLastError() ); + ok( cpiw.DefaultChar[0] == 0x3f, "wrong DefaultChar[0] %02x\n", cpiw.DefaultChar[0] ); + ok( cpiw.DefaultChar[1] == 0, "wrong DefaultChar[1] %02x\n", cpiw.DefaultChar[1] ); + for (i = 0; i < 12; i++) ok( cpiw.LeadByte[i] == 0, "wrong LeadByte[%u] %02x\n", i, cpiw.LeadByte[i] ); + ok( cpiw.MaxCharSize == 4, "wrong MaxCharSize %02x\n", cpiw.MaxCharSize ); + ok( cpiw.CodePage == CP_UTF8, "wrong CodePage %02x\n", cpiw.CodePage ); +#ifdef __REACTOS__ + ok( cpiw.UnicodeDefaultChar == 0xfffd || + broken(cpiw.UnicodeDefaultChar == 0x3f) /* WS03 */, "wrong UnicodeDefaultChar %02x\n", cpiw.UnicodeDefaultChar ); +#else + ok( cpiw.UnicodeDefaultChar == 0xfffd, "wrong UnicodeDefaultChar %02x\n", cpiw.UnicodeDefaultChar ); +#endif + ok( !wcscmp( cpiw.CodePageName, L"65001 (UTF-8)" ), + "wrong CodePageName %s\n", debugstr_w(cpiw.CodePageName) ); } + + + SetLastError( 0xdeadbeef ); + ret = GetCPInfoExW( 0xbeef, 0, &cpiw ); + ok( !ret, "GetCPInfoExW succeeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); + +#if defined(__REACTOS__) && DLL_EXPORT_VERSION >= 0x600 + /* FIXME: NtGetNlsSectionPtr is a STUB on ReactOS! */ + if (!is_reactos() && pNtGetNlsSectionPtr) +#else + if (pNtGetNlsSectionPtr) +#endif + { + CPTABLEINFO table; + NTSTATUS status; + void *ptr, *ptr2; + SIZE_T size; + int i; + + for (i = 0; i < 100; i++) + { + ptr = NULL; + size = 0; + status = pNtGetNlsSectionPtr( i, 9999, NULL, &ptr, &size ); + switch (i) + { + case 9: /* sortkeys */ + case 13: /* unknown */ + ok( status == STATUS_INVALID_PARAMETER_1 || status == STATUS_INVALID_PARAMETER_3, /* vista */ + "%u: failed %lx\n", i, status ); + break; + case 10: /* casemap */ + ok( status == STATUS_INVALID_PARAMETER_1 || status == STATUS_UNSUCCESSFUL, + "%u: failed %lx\n", i, status ); + break; + case 11: /* codepage */ + case 12: /* normalization */ + ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "%u: failed %lx\n", i, status ); + break; + case 14: /* unknown */ + ok( status == STATUS_INVALID_PARAMETER_1 || + status == STATUS_SUCCESS, /* win11 */ + "%u: failed %lx\n", i, status ); + break; + default: + ok( status == STATUS_INVALID_PARAMETER_1, "%u: failed %lx\n", i, status ); + break; + } + } + + /* casemap table */ + + status = pNtGetNlsSectionPtr( 10, 0, NULL, &ptr, &size ); + if (status != STATUS_INVALID_PARAMETER_1) + { + ok( !status, "failed %lx\n", status ); + ok( size > 0x1000 && size <= 0x8000 , "wrong size %Ix\n", size ); + status = pNtGetNlsSectionPtr( 10, 0, NULL, &ptr2, &size ); + ok( !status, "failed %lx\n", status ); + ok( ptr != ptr2, "got same pointer\n" ); + ret = UnmapViewOfFile( ptr ); + ok( ret, "UnmapViewOfFile failed err %lu\n", GetLastError() ); + ret = UnmapViewOfFile( ptr2 ); + ok( ret, "UnmapViewOfFile failed err %lu\n", GetLastError() ); + } + + /* codepage tables */ + + ptr = (void *)0xdeadbeef; + size = 0xdeadbeef; + status = pNtGetNlsSectionPtr( 11, 437, NULL, &ptr, &size ); + ok( !status, "failed %lx\n", status ); + ok( size > 0x10000 && size <= 0x20000, "wrong size %Ix\n", size ); + memset( &table, 0xcc, sizeof(table) ); + if (pRtlInitCodePageTable) + { + pRtlInitCodePageTable( ptr, &table ); + ok( table.CodePage == 437, "wrong codepage %u\n", table.CodePage ); + ok( table.MaximumCharacterSize == 1, "wrong char size %u\n", table.MaximumCharacterSize ); + ok( table.DefaultChar == '?', "wrong default char %x\n", table.DefaultChar ); + ok( !table.DBCSCodePage, "wrong dbcs %u\n", table.DBCSCodePage ); + } + ret = UnmapViewOfFile( ptr ); + ok( ret, "UnmapViewOfFile failed err %lu\n", GetLastError() ); + + status = pNtGetNlsSectionPtr( 11, 936, NULL, &ptr, &size ); + ok( !status, "failed %lx\n", status ); + ok( size > 0x30000 && size <= 0x40000, "wrong size %Ix\n", size ); + memset( &table, 0xcc, sizeof(table) ); + if (pRtlInitCodePageTable) + { + pRtlInitCodePageTable( ptr, &table ); + ok( table.CodePage == 936, "wrong codepage %u\n", table.CodePage ); + ok( table.MaximumCharacterSize == 2, "wrong char size %u\n", table.MaximumCharacterSize ); + ok( table.DefaultChar == '?', "wrong default char %x\n", table.DefaultChar ); + ok( table.DBCSCodePage == TRUE, "wrong dbcs %u\n", table.DBCSCodePage ); + + if (pRtlCustomCPToUnicodeN) + { + static const unsigned char buf[] = { 0xbf, 0xb4, 0xc7, 0, 0x78 }; + static const WCHAR expect[][4] = { { 0xcccc, 0xcccc, 0xcccc, 0xcccc }, + { 0x0000, 0xcccc, 0xcccc, 0xcccc }, + { 0x770b, 0xcccc, 0xcccc, 0xcccc }, + { 0x770b, 0x0000, 0xcccc, 0xcccc }, + { 0x770b, 0x003f, 0xcccc, 0xcccc }, + { 0x770b, 0x003f, 0x0078, 0xcccc } }; + WCHAR wbuf[5]; + DWORD i, j, reslen; + + for (i = 0; i <= sizeof(buf); i++) + { + memset( wbuf, 0xcc, sizeof(wbuf) ); + pRtlCustomCPToUnicodeN( &table, wbuf, sizeof(wbuf), &reslen, (char *)buf, i ); + for (j = 0; j < 4; j++) if (expect[i][j] == 0xcccc) break; + ok( reslen == j * sizeof(WCHAR), "%lu: wrong len %lu\n", i, reslen ); + for (j = 0; j < 4; j++) + ok( wbuf[j] == expect[i][j], "%lu: char %lu got %04x\n", i, j, wbuf[j] ); + } + } + } + ret = UnmapViewOfFile( ptr ); + ok( ret, "UnmapViewOfFile failed err %lu\n", GetLastError() ); + + status = pNtGetNlsSectionPtr( 11, 65001, NULL, &ptr, &size ); + ok( status == STATUS_OBJECT_NAME_NOT_FOUND || broken(!status), /* win10 1709 */ + "failed %lx\n", status ); + if (!status) UnmapViewOfFile( ptr ); + if (pRtlInitCodePageTable) + { + static USHORT utf8[20] = { 0, CP_UTF8 }; + + memset( &table, 0xcc, sizeof(table) ); + pRtlInitCodePageTable( utf8, &table ); + ok( table.CodePage == CP_UTF8, "wrong codepage %u\n", table.CodePage ); + if (table.MaximumCharacterSize) + { + ok( table.MaximumCharacterSize == 4, "wrong char size %u\n", table.MaximumCharacterSize ); + ok( table.DefaultChar == '?', "wrong default char %x\n", table.DefaultChar ); + ok( table.UniDefaultChar == 0xfffd, "wrong default char %x\n", table.UniDefaultChar ); + ok( table.TransDefaultChar == '?', "wrong default char %x\n", table.TransDefaultChar ); + ok( table.TransUniDefaultChar == '?', "wrong default char %x\n", table.TransUniDefaultChar ); + ok( !table.DBCSCodePage, "wrong dbcs %u\n", table.DBCSCodePage ); + ok( !table.MultiByteTable, "wrong mbtable %p\n", table.MultiByteTable ); + ok( !table.WideCharTable, "wrong wctable %p\n", table.WideCharTable ); + ok( !table.DBCSRanges, "wrong ranges %p\n", table.DBCSRanges ); + ok( !table.DBCSOffsets, "wrong offsets %p\n", table.DBCSOffsets ); + } + else win_skip( "utf-8 codepage not supported\n" ); + } + + /* normalization tables */ + + for (i = 0; i < 100; i++) + { + status = pNtGetNlsSectionPtr( 12, i, NULL, &ptr, &size ); + switch (i) + { + case NormalizationC: + case NormalizationD: + case NormalizationKC: + case NormalizationKD: + case 13: /* IDN */ + ok( !status, "%u: failed %lx\n", i, status ); + if (status) break; + ok( size > 0x8000 && size <= 0x30000 , "wrong size %Ix\n", size ); + ret = UnmapViewOfFile( ptr ); + ok( ret, "UnmapViewOfFile failed err %lu\n", GetLastError() ); + break; + default: + ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "%u: failed %lx\n", i, status ); + break; + } + } + } + else win_skip( "NtGetNlsSectionPtr not supported\n" ); } /* @@ -4010,6 +5537,9 @@ static void test_GetStringTypeW(void) 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff, 0xfff9, 0xfffa, 0xfffb}; static const WCHAR space_special[] = {0x09, 0x0d, 0x85}; + static const WCHAR alpha_thai[] = {0xe31, 0xe34, 0xe35, 0xe36, 0xe37, 0xe38, 0xe39, 0xe3a, + 0xe47, 0xe48, 0xe49, 0xe4a, 0xe4b, 0xe4c, 0xe4d, 0xe4e, + 0x1885, 0x1886}; WORD types[20]; WCHAR ch[2]; @@ -4020,17 +5550,17 @@ static void test_GetStringTypeW(void) SetLastError(0xdeadbeef); ret = GetStringTypeW(CT_CTYPE1, NULL, 0, NULL); ok(!ret, "got %d\n", ret); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = GetStringTypeW(CT_CTYPE1, NULL, 0, types); ok(!ret, "got %d\n", ret); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = GetStringTypeW(CT_CTYPE1, NULL, 5, types); ok(!ret, "got %d\n", ret); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %ld\n", GetLastError()); memset(types,0,sizeof(types)); GetStringTypeW(CT_CTYPE1, blanks, 5, types); @@ -4087,6 +5617,12 @@ static void test_GetStringTypeW(void) for (i = 0; i < 3; i++) ok(types[i] & C1_SPACE || broken(types[i] == C1_CNTRL) || broken(types[i] == 0), "incorrect types returned for %x -> (%x does not have %x)\n",space_special[i], types[i], C1_SPACE ); + /* alpha is set for certain Thai and Mongolian */ + memset(types, 0, sizeof(types)); + GetStringTypeW(CT_CTYPE1, alpha_thai, 18, types); + for (i = 0; i < 18; i++) + ok(types[i] == (C1_ALPHA|C1_DEFINED), "incorrect types returned for %x -> (%x does not have %x)\n",alpha_thai[i], types[i], (C1_ALPHA|C1_DEFINED)); + /* surrogate pairs */ ch[0] = 0xd800; memset(types, 0, sizeof(types)); @@ -4126,316 +5662,325 @@ static void test_GetStringTypeW(void) static void test_IdnToNameprepUnicode(void) { struct { - DWORD in_len; - const WCHAR in[64]; + int in_len; + const WCHAR in[80]; + DWORD flags; DWORD ret; DWORD broken_ret; - const WCHAR out[64]; - DWORD flags; - DWORD err; - DWORD todo; + const WCHAR out[80]; + NTSTATUS status; + NTSTATUS broken_status; } test_data[] = { - { - 5, {'t','e','s','t',0}, - 5, 5, {'t','e','s','t',0}, - 0, 0xdeadbeef - }, - { - 3, {'a',0xe111,'b'}, - 0, 0, {0}, - 0, ERROR_INVALID_NAME - }, - { - 4, {'t',0,'e',0}, - 0, 0, {0}, - 0, ERROR_INVALID_NAME - }, - { - 1, {'T',0}, - 1, 1, {'T',0}, - 0, 0xdeadbeef - }, - { - 1, {0}, - 0, 0, {0}, - 0, ERROR_INVALID_NAME - }, - { - 6, {' ','-','/','[',']',0}, - 6, 6, {' ','-','/','[',']',0}, - 0, 0xdeadbeef - }, - { - 3, {'a','-','a'}, - 3, 3, {'a','-','a'}, - IDN_USE_STD3_ASCII_RULES, 0xdeadbeef - }, - { - 3, {'a','a','-'}, - 0, 0, {0}, - IDN_USE_STD3_ASCII_RULES, ERROR_INVALID_NAME - }, - { /* FoldString is not working as expected when MAP_FOLDCZONE is specified (composition+compatibility) */ - 10, {'T',0xdf,0x130,0x143,0x37a,0x6a,0x30c,' ',0xaa,0}, - 12, 12, {'t','s','s','i',0x307,0x144,' ',0x3b9,0x1f0,' ','a',0}, - 0, 0xdeadbeef, TRUE - }, - { - 11, {'t',0xad,0x34f,0x1806,0x180b,0x180c,0x180d,0x200b,0x200c,0x200d,0}, - 2, 0, {'t',0}, - 0, 0xdeadbeef - }, - { /* Another example of incorrectly working FoldString (composition) */ - 2, {0x3b0, 0}, - 2, 2, {0x3b0, 0}, - 0, 0xdeadbeef, TRUE - }, - { - 2, {0x221, 0}, - 0, 2, {0}, - 0, ERROR_NO_UNICODE_TRANSLATION - }, - { - 2, {0x221, 0}, - 2, 2, {0x221, 0}, - IDN_ALLOW_UNASSIGNED, 0xdeadbeef - }, - { - 5, {'a','.','.','a',0}, - 0, 0, {0}, - 0, ERROR_INVALID_NAME - }, - { - 3, {'a','.',0}, - 3, 3, {'a','.',0}, - 0, 0xdeadbeef - }, + /* 0 */ + { 5, L"test", 0, 5, 5, L"test" }, + { 3, L"a\xe111z", 0, 0, 0, L"a\xe111z", 0, STATUS_NO_UNICODE_TRANSLATION }, + { 4, L"t\0e", 0, 0, 0, {0}, STATUS_NO_UNICODE_TRANSLATION, STATUS_NO_UNICODE_TRANSLATION }, + { 1, L"T", 0, 1, 1, L"T" }, + { 1, {0}, 0, 0 }, + /* 5 */ + { 6, L" -/[]", 0, 6, 6, L" -/[]" }, + { 3, L"a-a", IDN_USE_STD3_ASCII_RULES, 3, 3, L"a-a" }, + { 3, L"aa-", IDN_USE_STD3_ASCII_RULES, 0, 0, L"aa-" }, + { -1, L"T\xdf\x130\x143\x37a\x6a\x30c \xaa", 0, 12, 12, L"tssi\x307\x144 \x3b9\x1f0 a" }, +#ifndef __REACTOS__ // This test only passes on Win8 and WS03. + { 11, L"t\xad\x34f\x2066\x180b\x180c\x180d\x200b\x200c\x200d", 0, 0, 2, L"t", + STATUS_NO_UNICODE_TRANSLATION }, +#endif + /* 10 */ + { 2, {0x3b0}, 0, 2, 2, {0x3b0} }, + { 2, {0x380}, 0, 0, 2, {0x380} }, + { 2, {0x380}, IDN_ALLOW_UNASSIGNED, 2, 2, {0x380} }, + { 5, L"a..a", 0, 0, 0, L"a..a" }, + { 3, L"a.", 0, 3, 3, L"a." }, + /* 15 */ + { 5, L"T.\x105.A", 0, 5, 5, L"t.\x105.a" }, + { 5, L"T.*.A", 0, 5, 5, L"T.*.A" }, + { 5, L"X\xff0e.Z", 0, 0, 0, L"x..z" }, + { 63, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0, + 63, 63, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" }, + { 64, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0, + 0, 0, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" }, }; WCHAR buf[1024]; DWORD i, ret, err; - if (!pIdnToNameprepUnicode) - { - win_skip("IdnToNameprepUnicode is not available\n"); - return; - } - ret = pIdnToNameprepUnicode(0, test_data[0].in, test_data[0].in_len, NULL, 0); - ok(ret == test_data[0].ret, "ret = %d\n", ret); + ok(ret == test_data[0].ret, "ret = %ld\n", ret); SetLastError(0xdeadbeef); ret = pIdnToNameprepUnicode(0, test_data[1].in, test_data[1].in_len, NULL, 0); err = GetLastError(); - ok(ret == test_data[1].ret, "ret = %d\n", ret); - ok(err == test_data[1].err, "err = %d\n", err); + ok(ret == test_data[1].ret, "ret = %ld\n", ret); + ok(err == ret ? 0xdeadbeef : ERROR_INVALID_NAME, "err = %ld\n", err); SetLastError(0xdeadbeef); - ret = pIdnToNameprepUnicode(0, test_data[0].in, -1, - buf, sizeof(buf)/sizeof(WCHAR)); + ret = pIdnToNameprepUnicode(0, test_data[0].in, -1, buf, ARRAY_SIZE(buf)); err = GetLastError(); - ok(ret == test_data[0].ret, "ret = %d\n", ret); - ok(err == 0xdeadbeef, "err = %d\n", err); + ok(ret == test_data[0].ret, "ret = %ld\n", ret); + ok(err == 0xdeadbeef, "err = %ld\n", err); SetLastError(0xdeadbeef); - ret = pIdnToNameprepUnicode(0, test_data[0].in, -2, - buf, sizeof(buf)/sizeof(WCHAR)); + ret = pIdnToNameprepUnicode(0, test_data[0].in, -2, buf, ARRAY_SIZE(buf)); err = GetLastError(); - ok(ret == 0, "ret = %d\n", ret); - ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err); + ok(ret == 0, "ret = %ld\n", ret); + ok(err == ERROR_INVALID_PARAMETER, "err = %ld\n", err); SetLastError(0xdeadbeef); - ret = pIdnToNameprepUnicode(0, test_data[0].in, 0, - buf, sizeof(buf)/sizeof(WCHAR)); + ret = pIdnToNameprepUnicode(0, test_data[0].in, 0, buf, ARRAY_SIZE(buf)); err = GetLastError(); - ok(ret == 0, "ret = %d\n", ret); - ok(err == ERROR_INVALID_NAME, "err = %d\n", err); + ok(ret == 0, "ret = %ld\n", ret); + ok(err == ERROR_INVALID_NAME, "err = %ld\n", err); ret = pIdnToNameprepUnicode(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES, - test_data[0].in, -1, buf, sizeof(buf)/sizeof(WCHAR)); - ok(ret == test_data[0].ret, "ret = %d\n", ret); + test_data[0].in, -1, buf, ARRAY_SIZE(buf)); + ok(ret == test_data[0].ret, "ret = %ld\n", ret); SetLastError(0xdeadbeef); ret = pIdnToNameprepUnicode(0, NULL, 0, NULL, 0); err = GetLastError(); - ok(ret == 0, "ret = %d\n", ret); - ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err); + ok(ret == 0, "ret = %ld\n", ret); + ok(err == ERROR_INVALID_PARAMETER, "err = %ld\n", err); SetLastError(0xdeadbeef); ret = pIdnToNameprepUnicode(4, NULL, 0, NULL, 0); err = GetLastError(); - ok(ret == 0, "ret = %d\n", ret); + ok(ret == 0, "ret = %ld\n", ret); ok(err == ERROR_INVALID_FLAGS || err == ERROR_INVALID_PARAMETER /* Win8 */, - "err = %d\n", err); + "err = %ld\n", err); - for (i=0; i= 0x600 + /* FIXME: Idn functions are STUBS on ReactOS */ + if (is_reactos() || !pIdnToAscii || !pIdnToUnicode || !pIdnToNameprepUnicode) +#else + if (!pIdnToAscii || !pIdnToUnicode || !pIdnToNameprepUnicode) +#endif + { + win_skip("Idn support is not available\n"); return; } - for (i=0; i p; end--) if (end[-1] != ' ') break; + *end = 0; + MultiByteToWideChar( CP_UTF8, 0, p, -1, columns[i], 256 ); + p = strtok( NULL, ";" ); + } + if (i < 7) continue; + + expect = columns[5]; + if (!*expect) expect = columns[3]; + if (!*expect) expect = columns[1]; + if (!*expect) expect = columns[0]; + error = columns[6]; + if (!*error) error = columns[4]; + if (!*error) error = columns[2]; + SetLastError( 0xdeadbeef ); + memset( dst, 0xcc, sizeof(dst) ); + ret = pIdnToAscii( 0, columns[0], -1, dst, ARRAY_SIZE(dst) ); + if (!is_idn_error( error )) + { + ok( ret, "line %u: toAscii failed for %s expected %s\n", line, + debugstr_w(columns[0]), debugstr_w(expect) ); + if (ret) ok( !wcscmp( dst, expect ), "line %u: got %s expected %s\n", + line, debugstr_w(dst), debugstr_w(expect) ); + } + else + { + ok( !ret, "line %u: toAscii didn't fail for %s got %s expected error %s\n", + line, debugstr_w(columns[0]), debugstr_w(dst), debugstr_w(error) ); + } + + expect = columns[1]; + if (!*expect) expect = columns[0]; + error = columns[2]; + SetLastError( 0xdeadbeef ); + memset( dst, 0xcc, sizeof(dst) ); + ret = pIdnToUnicode( IDN_USE_STD3_ASCII_RULES, columns[0], -1, dst, ARRAY_SIZE(dst) ); + for (i = 0; columns[0][i]; i++) if (columns[0][i] > 0x7f) break; + if (columns[0][i]) + { + ok( !ret, "line %u: didn't fail for unicode chars in %s\n", line, debugstr_w(columns[0]) ); + } + else if (!is_idn_error( error )) + { + ok( ret, "line %u: toUnicode failed for %s expected %s\n", line, + debugstr_w(columns[0]), debugstr_w(expect) ); + if (ret) ok( !wcscmp( dst, expect ), "line %u: got %s expected %s\n", + line, debugstr_w(dst), debugstr_w(expect) ); + } + else + { + ok( !ret, "line %u: toUnicode didn't fail for %s got %s expected error %s\n", + line, debugstr_w(columns[0]), debugstr_w(dst), debugstr_w(error) ); + } + } + fclose( f ); } } + static void test_GetLocaleInfoEx(void) { static const WCHAR enW[] = {'e','n',0}; @@ -4448,7 +5993,7 @@ static void test_GetLocaleInfoEx(void) return; } - ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR)); + ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, ARRAY_SIZE(bufferW)); ok(ret || broken(ret == 0) /* Vista */, "got %d\n", ret); if (ret) { @@ -4465,33 +6010,37 @@ static void test_GetLocaleInfoEx(void) SetLastError(0xdeadbeef); ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, 2); - ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, %d\n", ret, GetLastError()); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, %ld\n", ret, GetLastError()); SetLastError(0xdeadbeef); ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, NULL, 0); - ok(ret == 3 && GetLastError() == 0xdeadbeef, "got %d, %d\n", ret, GetLastError()); + ok(ret == 3 && GetLastError() == 0xdeadbeef, "got %d, %ld\n", ret, GetLastError()); - ret = pGetLocaleInfoEx(enusW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR)); + ret = pGetLocaleInfoEx(enusW, LOCALE_SNAME, bufferW, ARRAY_SIZE(bufferW)); ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret); ok(!lstrcmpW(bufferW, enusW), "got %s\n", wine_dbgstr_w(bufferW)); - ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVCTRYNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR)); + ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVCTRYNAME, bufferW, ARRAY_SIZE(bufferW)); ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret); ok(!lstrcmpW(bufferW, usaW), "got %s\n", wine_dbgstr_w(bufferW)); - ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVLANGNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR)); + ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVLANGNAME, bufferW, ARRAY_SIZE(bufferW)); ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret); ok(!lstrcmpW(bufferW, enuW), "got %s\n", wine_dbgstr_w(bufferW)); - ret = pGetLocaleInfoEx(enusW, LOCALE_SPARENT, bufferW, sizeof(bufferW)/sizeof(WCHAR)); + ret = pGetLocaleInfoEx(enusW, LOCALE_SPARENT, bufferW, ARRAY_SIZE(bufferW)); ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret); ok(!lstrcmpW(bufferW, enW), "got %s\n", wine_dbgstr_w(bufferW)); - ret = pGetLocaleInfoEx(enW, LOCALE_SPARENT, bufferW, sizeof(bufferW)/sizeof(WCHAR)); + ret = pGetLocaleInfoEx(enW, LOCALE_SPARENT, bufferW, ARRAY_SIZE(bufferW)); ok(ret == 1, "got %d\n", ret); ok(!bufferW[0], "got %s\n", wine_dbgstr_w(bufferW)); - ret = pGetLocaleInfoEx(enW, LOCALE_SCOUNTRY, bufferW, sizeof(bufferW)/sizeof(WCHAR)); + ret = pGetLocaleInfoEx(enW, LOCALE_SPARENT | LOCALE_NOUSEROVERRIDE, bufferW, ARRAY_SIZE(bufferW)); + ok(ret == 1, "got %d\n", ret); + ok(!bufferW[0], "got %s\n", wine_dbgstr_w(bufferW)); + + ret = pGetLocaleInfoEx(enW, LOCALE_SCOUNTRY, bufferW, ARRAY_SIZE(bufferW)); ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret); if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) || (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH)) @@ -4503,36 +6052,39 @@ static void test_GetLocaleInfoEx(void) bufferW[0] = 0; SetLastError(0xdeadbeef); - ret = pGetLocaleInfoEx(dummyW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR)); - ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError()); + ret = pGetLocaleInfoEx(dummyW, LOCALE_SNAME, bufferW, ARRAY_SIZE(bufferW)); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %ld\n", ret, GetLastError()); +#if defined(__REACTOS__) && defined(_WIN64) + if (is_reactos()) { + ok(FALSE, "FIXME: These tests crash on ReactOS x64\n"); + } else { +#endif while (*ptr->name) { val = 0; pGetLocaleInfoEx(ptr->name, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR)); - todo_wine_if (ptr->todo) - ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid); + ok(val == ptr->lcid, "%s: got wrong lcid 0x%04lx, expected 0x%04lx\n", wine_dbgstr_w(ptr->name), val, ptr->lcid); bufferW[0] = 0; - ret = pGetLocaleInfoEx(ptr->name, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR)); + ret = pGetLocaleInfoEx(ptr->name, LOCALE_SNAME, bufferW, ARRAY_SIZE(bufferW)); ok(ret == lstrlenW(bufferW)+1, "%s: got ret value %d\n", wine_dbgstr_w(ptr->name), ret); ok(!lstrcmpW(bufferW, ptr->name), "%s: got wrong LOCALE_SNAME %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW)); ptr++; } - ret = pGetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR)); + ret = pGetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, bufferW, ARRAY_SIZE(bufferW)); ok(ret && ret == lstrlenW(bufferW)+1, "got ret value %d\n", ret); - ret = GetLocaleInfoW(GetUserDefaultLCID(), LOCALE_SNAME, buffer2, sizeof(buffer2)/sizeof(WCHAR)); + ret = GetLocaleInfoW(GetUserDefaultLCID(), LOCALE_SNAME, buffer2, ARRAY_SIZE(buffer2)); ok(ret && ret == lstrlenW(buffer2)+1, "got ret value %d\n", ret); ok(!lstrcmpW(bufferW, buffer2), "LOCALE_SNAMEs don't match %s %s\n", wine_dbgstr_w(bufferW), wine_dbgstr_w(buffer2)); +#if defined(__REACTOS__) && defined(_WIN64) + } +#endif } } static void test_IsValidLocaleName(void) { - static const WCHAR enusW[] = {'e','n','-','U','S',0}; - static const WCHAR zzW[] = {'z','z',0}; - static const WCHAR zz_zzW[] = {'z','z','-','Z','Z',0}; - static const WCHAR zzzzW[] = {'z','z','z','z',0}; BOOL ret; if (!pIsValidLocaleName) @@ -4541,18 +6093,173 @@ static void test_IsValidLocaleName(void) return; } - ret = pIsValidLocaleName(enusW); + ret = pIsValidLocaleName(L"en-US"); ok(ret, "IsValidLocaleName failed\n"); - ret = pIsValidLocaleName(zzW); + ret = pIsValidLocaleName(L"en"); +#ifdef __REACTOS__ + ok(ret || broken(GetNTVersion() == _WIN32_WINNT_VISTA), "IsValidLocaleName failed\n"); +#else + ok(ret, "IsValidLocaleName failed\n"); +#endif + ret = pIsValidLocaleName(L"es-es"); + ok(ret, "IsValidLocaleName failed\n"); + ret = pIsValidLocaleName(L"de-DE_phoneb"); + ok(ret, "IsValidLocaleName failed\n"); + ret = pIsValidLocaleName(L"DE_de-phoneb"); + ok(ret || broken(!ret), "IsValidLocaleName failed\n"); + ret = pIsValidLocaleName(L"DE_de_PHONEB"); + ok(ret || broken(!ret), "IsValidLocaleName failed\n"); + ret = pIsValidLocaleName(L"DE_de+phoneb"); + ok(!ret, "IsValidLocaleName should have failed\n"); + ret = pIsValidLocaleName(L"zz"); ok(!ret || broken(ret), "IsValidLocaleName should have failed\n"); - ret = pIsValidLocaleName(zz_zzW); + ret = pIsValidLocaleName(L"zz-ZZ"); ok(!ret || broken(ret), "IsValidLocaleName should have failed\n"); - ret = pIsValidLocaleName(zzzzW); + ret = pIsValidLocaleName(L"zzz"); + ok(!ret || broken(ret), "IsValidLocaleName should have failed\n"); + ret = pIsValidLocaleName(L"zzz-ZZZ"); + ok(!ret, "IsValidLocaleName should have failed\n"); + ret = pIsValidLocaleName(L"zzzz"); ok(!ret, "IsValidLocaleName should have failed\n"); ret = pIsValidLocaleName(LOCALE_NAME_INVARIANT); ok(ret, "IsValidLocaleName failed\n"); - ret = pIsValidLocaleName(NULL); + ret = pIsValidLocaleName(LOCALE_NAME_USER_DEFAULT); ok(!ret, "IsValidLocaleName should have failed\n"); + ret = pIsValidLocaleName(LOCALE_NAME_SYSTEM_DEFAULT); + ok(!ret, "IsValidLocaleName should have failed\n"); + + if (!pRtlIsValidLocaleName) + { + win_skip( "RtlIsValidLocaleName not available\n" ); + return; + } + + ret = pRtlIsValidLocaleName( L"en-US", 0 ); + ok(ret, "RtlIsValidLocaleName failed\n"); + ret = pRtlIsValidLocaleName( L"en", 0 ); + ok(!ret, "RtlIsValidLocaleName should have failed\n"); + ret = pRtlIsValidLocaleName( L"en", 1 ); + ok(!ret, "RtlIsValidLocaleName should have failed\n"); + ret = pRtlIsValidLocaleName( L"en", 2 ); + ok(ret, "RtlIsValidLocaleName failed\n"); + ret = pRtlIsValidLocaleName( L"en-RR", 2 ); + ok(!ret, "RtlIsValidLocaleName should have failed\n"); + ret = pRtlIsValidLocaleName( L"es-es", 0 ); + ok(ret, "RtlIsValidLocaleName failed\n"); + ret = pRtlIsValidLocaleName( L"de-DE_phoneb", 0 ); + ok(ret, "RtlIsValidLocaleName failed\n"); + ret = pRtlIsValidLocaleName( L"DE_de_PHONEB", 0 ); + ok(ret || broken(!ret), "RtlIsValidLocaleName failed\n"); + ret = pRtlIsValidLocaleName( L"DE_de+phoneb", 0 ); + ok(!ret, "RtlIsValidLocaleName should have failed\n"); + ret = pRtlIsValidLocaleName( L"zz", 0 ); + ok(!ret, "RtlIsValidLocaleName should have failed\n"); + ret = pRtlIsValidLocaleName( L"zz", 2 ); + ok(!ret, "RtlIsValidLocaleName should have failed\n"); + ret = pRtlIsValidLocaleName( L"zz-ZZ", 0 ); + ok(!ret, "RtlIsValidLocaleName should have failed\n"); + ret = pRtlIsValidLocaleName( L"zzz", 0 ); + ok(!ret, "RtlIsValidLocaleName should have failed\n"); + ret = pRtlIsValidLocaleName( L"zzz-ZZZ", 0 ); + ok(!ret, "RtlIsValidLocaleName should have failed\n"); + ret = pRtlIsValidLocaleName( L"zzzz", 0 ); + ok(!ret, "RtlIsValidLocaleName should have failed\n"); + ret = pRtlIsValidLocaleName( LOCALE_NAME_INVARIANT, 0 ); + ok(ret, "RtlIsValidLocaleName failed\n"); + ret = pRtlIsValidLocaleName( LOCALE_NAME_USER_DEFAULT, 0 ); + ok(!ret, "RtlIsValidLocaleName should have failed\n"); + ret = pRtlIsValidLocaleName( LOCALE_NAME_SYSTEM_DEFAULT, 0 ); + ok(!ret, "RtlIsValidLocaleName should have failed\n"); +} + +static void test_ResolveLocaleName(void) +{ + static const struct { const WCHAR *name, *exp; BOOL broken; } tests[] = + { + { L"en-US", L"en-US" }, + { L"en", L"en-US" }, + { L"en-RR", L"en-US" }, + { L"en-na", L"en-NA", TRUE /* <= win8 */ }, + { L"EN-zz", L"en-US" }, + { L"en-US", L"en-US" }, + { L"de-DE_phoneb", L"de-DE" }, + { L"DE-de-phoneb", L"de-DE" }, + { L"fr-029", L"fr-029", TRUE /* <= win8 */ }, + { L"fr-CH_XX", L"fr-CH", TRUE /* <= win10 1809 */ }, + { L"fr-CHXX", L"fr-FR" }, + { L"zh", L"zh-CN" }, + { L"zh-Hant", L"zh-HK" }, + { L"zh-hans", L"zh-CN" }, + { L"ja-jp_radstr", L"ja-JP" }, + { L"az", L"az-Latn-AZ" }, + { L"uz", L"uz-Latn-UZ" }, + { L"uz-cyrl", L"uz-Cyrl-UZ" }, + { L"ia", L"ia-001", TRUE /* <= win10 1809 */ }, + { L"zz", L"" }, + { L"zzz-ZZZ", L"" }, + { L"zzzz", L"" }, + { L"zz+XX", NULL }, + { L"zz.XX", NULL }, + { LOCALE_NAME_INVARIANT, L"" }, + }; + INT i, ret; +#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600 + WCHAR buffer[LOCALE_NAME_MAX_LENGTH], system[LOCALE_NAME_MAX_LENGTH]; +#else + WCHAR buffer[LOCALE_NAME_MAX_LENGTH]; +#endif + + if (!pResolveLocaleName) + { + win_skip( "ResolveLocaleName not available\n" ); + return; + } + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + SetLastError( 0xdeadbeef ); + memset( buffer, 0xcc, sizeof(buffer) ); + ret = pResolveLocaleName( tests[i].name, buffer, ARRAY_SIZE(buffer) ); + if (tests[i].exp) + { + ok( !wcscmp( buffer, tests[i].exp ) || broken( tests[i].broken ), + "%s: got %s\n", debugstr_w(tests[i].name), debugstr_w(buffer) ); + ok( ret == wcslen(buffer) + 1, "%s: got %u\n", debugstr_w(tests[i].name), ret ); + } + else + { + ok( !ret || broken( ret == 1 ) /* win7 */, + "%s: got %s\n", debugstr_w(tests[i].name), debugstr_w(buffer) ); + if (!ret) + ok( GetLastError() == ERROR_INVALID_PARAMETER, + "%s: wrong error %lu\n", debugstr_w(tests[i].name), GetLastError() ); + } + } + SetLastError( 0xdeadbeef ); + memset( buffer, 0xcc, sizeof(buffer) ); + ret = pResolveLocaleName( LOCALE_NAME_SYSTEM_DEFAULT, buffer, ARRAY_SIZE(buffer) ); +#ifdef __REACTOS__ + ok( ret || broken(GetLastError() == ERROR_INVALID_PARAMETER) /* Win8 */, "failed err %lu\n", GetLastError() ); +#else + ok( ret, "failed err %lu\n", GetLastError() ); +#endif +#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600 + GetSystemDefaultLocaleName( system, ARRAY_SIZE(system) ); +#if !(defined(__REACTOS__) && defined(_WIN64)) + ok( !wcscmp( buffer, system ), "got wrong syslocale %s / %s\n", debugstr_w(buffer), debugstr_w(system)); + ok( ret == wcslen(system) + 1, "wrong len %u / %Iu\n", ret, wcslen(system) + 1 ); +#endif +#endif + + SetLastError( 0xdeadbeef ); + ret = pResolveLocaleName( L"en-US", buffer, 4 ); + ok( !ret, "got %u\n", ret ); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "wrong error %lu\n", GetLastError() ); + ok( !wcscmp( buffer, L"en-" ), "got %s\n", debugstr_w(buffer) ); + + SetLastError( 0xdeadbeef ); + ret = pResolveLocaleName( L"en-US", NULL, 0 ); + ok( ret == 6, "got %u\n", ret ); + ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() ); } static void test_CompareStringOrdinal(void) @@ -4581,15 +6288,15 @@ static void test_CompareStringOrdinal(void) SetLastError(0xdeadbeef); ret = pCompareStringOrdinal(NULL, 0, NULL, 0, FALSE); ok(!ret, "Got %u, expected 0\n", ret); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %lx, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER); SetLastError(0xdeadbeef); ret = pCompareStringOrdinal(test1, -1, NULL, 0, FALSE); ok(!ret, "Got %u, expected 0\n", ret); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %lx, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER); SetLastError(0xdeadbeef); ret = pCompareStringOrdinal(NULL, 0, test1, -1, FALSE); ok(!ret, "Got %u, expected 0\n", ret); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %lx, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER); /* Check case */ ret = pCompareStringOrdinal(test1, -1, test1, -1, FALSE); @@ -4646,6 +6353,7 @@ static void test_CompareStringOrdinal(void) static void test_GetGeoInfo(void) { char buffA[20]; + WCHAR buffW[20]; INT ret; if (!pGetGeoInfoA) @@ -4658,7 +6366,8 @@ static void test_GetGeoInfo(void) SetLastError(0xdeadbeef); ret = pGetGeoInfoA(344, GEO_ISO2, NULL, 0, 0); ok(ret == 0, "got %d\n", ret); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER || + broken(GetLastError() == 0xdeadbeef /* Win10 */), "got %ld\n", GetLastError()); ret = pGetGeoInfoA(203, GEO_ISO2, NULL, 0, 0); ok(ret == 3, "got %d\n", ret); @@ -4687,13 +6396,45 @@ static void test_GetGeoInfo(void) ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 2, 0); ok(ret == 0, "got %d\n", ret); ok(!strcmp(buffA, "RU"), "got %s\n", buffA); - ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d\n", GetLastError()); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %ld\n", GetLastError()); + + /* GEO_NATION returns GEOID in a string form, but only for GEOCLASS_NATION-type IDs */ + ret = pGetGeoInfoA(203, GEO_NATION, buffA, 20, 0); /* GEOCLASS_NATION */ + ok(ret == 4, "GEO_NATION of nation: expected 4, got %d\n", ret); + ok(!strcmp(buffA, "203"), "GEO_NATION of nation: expected 203, got %s\n", buffA); - /* GEO_NATION returns GEOID in a string form */ buffA[0] = 0; - ret = pGetGeoInfoA(203, GEO_NATION, buffA, 20, 0); - ok(ret == 4, "got %d\n", ret); - ok(!strcmp(buffA, "203"), "got %s\n", buffA); + ret = pGetGeoInfoA(39070, GEO_NATION, buffA, 20, 0); /* GEOCLASS_REGION */ + ok(ret == 0, "GEO_NATION of region: expected 0, got %d\n", ret); + ok(*buffA == 0, "GEO_NATION of region: expected empty string, got %s\n", buffA); + + buffA[0] = 0; + ret = pGetGeoInfoA(333, GEO_NATION, buffA, 20, 0); /* LOCATION_BOTH internal Wine type */ + ok(ret == 0 || + broken(ret == 4) /* Win7 and older */, + "GEO_NATION of LOCATION_BOTH: expected 0, got %d\n", ret); + ok(*buffA == 0 || + broken(!strcmp(buffA, "333")) /* Win7 and older */, + "GEO_NATION of LOCATION_BOTH: expected empty string, got %s\n", buffA); + + /* GEO_ID is like GEO_NATION but works for any ID */ + buffA[0] = 0; + ret = pGetGeoInfoA(203, GEO_ID, buffA, 20, 0); /* GEOCLASS_NATION */ + if (ret == 0) + win_skip("GEO_ID not supported.\n"); + else + { + ok(ret == 4, "GEO_ID: expected 4, got %d\n", ret); + ok(!strcmp(buffA, "203"), "GEO_ID: expected 203, got %s\n", buffA); + + ret = pGetGeoInfoA(47610, GEO_ID, buffA, 20, 0); /* GEOCLASS_REGION */ + ok(ret == 6, "got %d\n", ret); + ok(!strcmp(buffA, "47610"), "got %s\n", buffA); + + ret = pGetGeoInfoA(333, GEO_ID, buffA, 20, 0); /* LOCATION_BOTH internal Wine type */ + ok(ret == 4, "got %d\n", ret); + ok(!strcmp(buffA, "333"), "got %s\n", buffA); + } /* GEO_PARENT */ buffA[0] = 0; @@ -4718,18 +6459,49 @@ static void test_GetGeoInfo(void) /* try invalid type value */ SetLastError(0xdeadbeef); - ret = pGetGeoInfoA(203, GEO_CURRENCYSYMBOL + 1, NULL, 0, 0); + ret = pGetGeoInfoA(203, GEO_ID + 1, NULL, 0, 0); ok(ret == 0, "got %d\n", ret); - ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_FLAGS, "got %ld\n", GetLastError()); + + /* Test for GetGeoInfoEx */ + if (!pGetGeoInfoEx) + { + win_skip("GetGeoInfoEx is not available\n"); + return; + } + + /* Test with ISO 3166-1 */ + ret = pGetGeoInfoEx(L"AR", GEO_ISO3, buffW, ARRAYSIZE(buffW)); + ok(ret != 0, "GetGeoInfoEx failed %ld.\n", GetLastError()); + ok(!wcscmp(buffW, L"ARG"), "expected string to be ARG, got %ls\n", buffW); + + /* Test with UN M.49 */ + SetLastError(0xdeadbeef); + ret = pGetGeoInfoEx(L"032", GEO_ISO3, buffW, ARRAYSIZE(buffW)); + ok(ret == 0, "expected GetGeoInfoEx to fail.\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "expected ERROR_INVALID_PARAMETER got %ld.\n", GetLastError()); + + /* Test GEO_ID */ + ret = pGetGeoInfoEx(L"AR", GEO_ID, buffW, ARRAYSIZE(buffW)); + ok(ret != 0, "GetGeoInfoEx failed %ld.\n", GetLastError()); + ok(!wcscmp(buffW, L"11"), "expected string to be 11, got %ls\n", buffW); + + /* Test with invalid geo type */ + SetLastError(0xdeadbeef); + ret = pGetGeoInfoEx(L"AR", GEO_LCID, buffW, ARRAYSIZE(buffW)); + ok(ret == 0, "expected GetGeoInfoEx to fail.\n"); + ok(GetLastError() == ERROR_INVALID_FLAGS, + "expected ERROR_INVALID_PARAMETER got %ld.\n", GetLastError()); } static int geoidenum_count; static BOOL CALLBACK test_geoid_enumproc(GEOID geoid) { INT ret = pGetGeoInfoA(geoid, GEO_ISO2, NULL, 0, 0); - ok(ret == 3, "got %d for %d\n", ret, geoid); + ok(ret == 3, "got %d for %ld\n", ret, geoid); /* valid geoid starts at 2 */ - ok(geoid >= 2, "got geoid %d\n", geoid); + ok(geoid >= 2, "got geoid %ld\n", geoid); return geoidenum_count++ < 5; } @@ -4753,17 +6525,17 @@ static void test_EnumSystemGeoID(void) SetLastError(0xdeadbeef); ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, NULL); ok(!ret, "got %d\n", ret); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, test_geoid_enumproc); ok(!ret, "got %d\n", ret); - ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_FLAGS, "got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, NULL); ok(!ret, "got %d\n", ret); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %ld\n", GetLastError()); ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, test_geoid_enumproc); ok(ret, "got %d\n", ret); @@ -4788,6 +6560,19 @@ static void test_EnumSystemGeoID(void) ret = pEnumSystemGeoID(GEOCLASS_REGION, 0, test_geoid_enumproc2); ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count); } + + geoidenum_count = 0; + ret = pEnumSystemGeoID(GEOCLASS_ALL, 39070, test_geoid_enumproc2); + if (ret == 0) + win_skip("GEOCLASS_ALL is not supported in EnumSystemGeoID.\n"); + else + { + ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count); + + geoidenum_count = 0; + ret = pEnumSystemGeoID(GEOCLASS_ALL, 0, test_geoid_enumproc2); + ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count); + } } struct invariant_entry { @@ -4932,7 +6717,7 @@ static void test_invariant(void) { len = strlen(ptr->expect)+1; /* include \0 */ ok(ret == len || (ptr->expect2 && ret == strlen(ptr->expect2)+1), - "For id %d, expected ret == %d, got %d, error %d\n", + "For id %d, expected ret == %d, got %d, error %ld\n", ptr->id, len, ret, GetLastError()); ok(!strcmp(buffer, ptr->expect) || (ptr->expect2 && !strcmp(buffer, ptr->expect2)), "For id %d, Expected %s, got '%s'\n", @@ -4953,36 +6738,32 @@ static void test_invariant(void) static const char lang[] = "Invariant Language (Invariant Country)"; static const char cntry[] = "Invariant Country"; static const char sortm[] = "Math Alphanumerics"; + static const char sortms[] = "Maths Alphanumerics"; static const char sortd[] = "Default"; /* win2k3 */ ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SLANGUAGE, buffer, sizeof(buffer)); len = lstrlenA(lang) + 1; - ok(ret == len, "Expected ret == %d, got %d, error %d\n", len, ret, GetLastError()); + ok(ret == len, "Expected ret == %d, got %d, error %ld\n", len, ret, GetLastError()); ok(!strcmp(buffer, lang), "Expected %s, got '%s'\n", lang, buffer); ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SCOUNTRY, buffer, sizeof(buffer)); len = lstrlenA(cntry) + 1; - ok(ret == len, "Expected ret == %d, got %d, error %d\n", len, ret, GetLastError()); + ok(ret == len, "Expected ret == %d, got %d, error %ld\n", len, ret, GetLastError()); ok(!strcmp(buffer, cntry), "Expected %s, got '%s'\n", cntry, buffer); ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SSORTNAME, buffer, sizeof(buffer)); - if (ret == lstrlenA(sortm)+1) - ok(!strcmp(buffer, sortm), "Expected %s, got '%s'\n", sortm, buffer); - else if (ret == lstrlenA(sortd)+1) /* win2k3 */ - ok(!strcmp(buffer, sortd), "Expected %s, got '%s'\n", sortd, buffer); - else - ok(0, "Expected ret == %d or %d, got %d, error %d\n", - lstrlenA(sortm)+1, lstrlenA(sortd)+1, ret, GetLastError()); + ok(ret, "Failed err %ld\n", GetLastError()); + ok(!strcmp(buffer, sortm) || !strcmp(buffer, sortd) || !strcmp(buffer, sortms), "Got '%s'\n", buffer); } } static void test_GetSystemPreferredUILanguages(void) { BOOL ret; - ULONG count, size, size_id, size_name, size_buffer; + NTSTATUS status; + ULONG i, count, size, size_id, size_name, size_buffer; WCHAR *buffer; - if (!pGetSystemPreferredUILanguages) { win_skip("GetSystemPreferredUILanguages is not available.\n"); @@ -4990,53 +6771,50 @@ static void test_GetSystemPreferredUILanguages(void) } /* (in)valid first parameter */ - count = 0xdeadbeef; + count = 0; size = 0; SetLastError(0xdeadbeef); ret = pGetSystemPreferredUILanguages(0, &count, NULL, &size); ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n"); ok(count, "Expected count > 0\n"); - ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size); + ok(size % 6 == 1, "Expected size (%ld) %% 6 == 1\n", size); - count = 0xdeadbeef; size = 0; SetLastError(0xdeadbeef); ret = pGetSystemPreferredUILanguages(MUI_FULL_LANGUAGE, &count, NULL, &size); ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n"); ok(ERROR_INVALID_PARAMETER == GetLastError(), - "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "Expected error ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); - count = 0xdeadbeef; size = 0; SetLastError(0xdeadbeef); ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_FULL_LANGUAGE, &count, NULL, &size); ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n"); ok(ERROR_INVALID_PARAMETER == GetLastError(), - "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "Expected error ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); - count = 0xdeadbeef; size = 0; SetLastError(0xdeadbeef); ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_LANGUAGE_NAME, &count, NULL, &size); ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n"); ok(ERROR_INVALID_PARAMETER == GetLastError(), - "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "Expected error ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); - count = 0xdeadbeef; + count = 0; size = 0; SetLastError(0xdeadbeef); ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size); ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n"); ok(count, "Expected count > 0\n"); - ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size); + ok(size % 5 == 1, "Expected size (%ld) %% 5 == 1\n", size); - count = 0xdeadbeef; + count = 0; size = 0; SetLastError(0xdeadbeef); ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size); ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n"); ok(count, "Expected count > 0\n"); - ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size); + ok(size % 6 == 1, "Expected size (%ld) %% 6 == 1\n", size); /* second parameter * ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, NULL, NULL, &size); @@ -5044,34 +6822,33 @@ static void test_GetSystemPreferredUILanguages(void) */ /* invalid third parameter */ - count = 0xdeadbeef; size = 1; SetLastError(0xdeadbeef); ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size); ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n"); ok(ERROR_INVALID_PARAMETER == GetLastError(), - "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "Expected error ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); /* fourth parameter * ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, NULL); * -> unhandled exception c0000005 */ - count = 0xdeadbeef; + count = 0; size_id = 0; SetLastError(0xdeadbeef); ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size_id); ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n"); ok(count, "Expected count > 0\n"); - ok(size_id % 5 == 1, "Expected size (%d) %% 5 == 1\n", size_id); + ok(size_id % 5 == 1, "Expected size (%ld) %% 5 == 1\n", size_id); - count = 0xdeadbeef; + count = 0; size_name = 0; SetLastError(0xdeadbeef); ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME, &count, NULL, &size_name); ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n"); ok(count, "Expected count > 0\n"); - ok(size_name % 6 == 1, "Expected size (%d) %% 6 == 1\n", size_name); + ok(size_name % 6 == 1, "Expected size (%ld) %% 6 == 1\n", size_name); size_buffer = max(size_id, size_name); if(!size_buffer) @@ -5083,85 +6860,132 @@ static void test_GetSystemPreferredUILanguages(void) buffer = HeapAlloc(GetProcessHeap(), 0, size_buffer * sizeof(WCHAR)); if (!buffer) { - skip("Failed to allocate memory for %d chars\n", size_buffer); + skip("Failed to allocate memory for %ld chars\n", size_buffer); return; } - count = 0xdeadbeef; + count = 0; size = size_buffer; memset(buffer, 0x5a, size_buffer * sizeof(WCHAR)); SetLastError(0xdeadbeef); ret = pGetSystemPreferredUILanguages(0, &count, buffer, &size); ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n"); ok(count, "Expected count > 0\n"); - ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size); + ok(size % 6 == 1, "Expected size (%ld) %% 6 == 1\n", size); if (ret && size % 6 == 1) ok(!buffer[size -2] && !buffer[size -1], "Expected last two WCHARs being empty, got 0x%x 0x%x\n", buffer[size -2], buffer[size -1]); - count = 0xdeadbeef; + count = 0; size = size_buffer; memset(buffer, 0x5a, size_buffer * sizeof(WCHAR)); SetLastError(0xdeadbeef); ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size); ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n"); ok(count, "Expected count > 0\n"); - ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size); + ok(size % 5 == 1, "Expected size (%ld) %% 5 == 1\n", size); if (ret && size % 5 == 1) ok(!buffer[size -2] && !buffer[size -1], "Expected last two WCHARs being empty, got 0x%x 0x%x\n", buffer[size -2], buffer[size -1]); + for (i = 0; buffer[i]; i++) + ok(('0' <= buffer[i] && buffer[i] <= '9') || + ('A' <= buffer[i] && buffer[i] <= 'F'), + "MUI_LANGUAGE_ID [%ld] is bad in %s\n", i, wine_dbgstr_w(buffer)); - count = 0xdeadbeef; + count = 0; size = size_buffer; SetLastError(0xdeadbeef); ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME, &count, buffer, &size); ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n"); ok(count, "Expected count > 0\n"); - ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size); + ok(size % 6 == 1, "Expected size (%ld) %% 6 == 1\n", size); if (ret && size % 5 == 1) ok(!buffer[size -2] && !buffer[size -1], "Expected last two WCHARs being empty, got 0x%x 0x%x\n", buffer[size -2], buffer[size -1]); - count = 0xdeadbeef; + count = 0; size = 0; SetLastError(0xdeadbeef); ret = pGetSystemPreferredUILanguages(MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size); ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n"); ok(count, "Expected count > 0\n"); - ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size); + ok(size % 6 == 1, "Expected size (%ld) %% 6 == 1\n", size); if (ret && size % 6 == 1) ok(!buffer[size -2] && !buffer[size -1], "Expected last two WCHARs being empty, got 0x%x 0x%x\n", buffer[size -2], buffer[size -1]); - count = 0xdeadbeef; + /* ntdll version is the same, but apparently takes an extra second parameter */ + count = 0; + size = size_buffer; + memset(buffer, 0x5a, size_buffer * sizeof(WCHAR)); + status = pRtlGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, 0, &count, buffer, &size); + ok(!status, "got %lx\n", status); + ok(count, "Expected count > 0\n"); + ok(size % 5 == 1, "Expected size (%ld) %% 5 == 1\n", size); + if (ret && size % 5 == 1) + ok(!buffer[size -2] && !buffer[size -1], + "Expected last two WCHARs being empty, got 0x%x 0x%x\n", + buffer[size -2], buffer[size -1]); + + count = 0; + size = size_buffer; + status = pRtlGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME, 0, &count, buffer, &size); + ok(!status, "got %lx\n", status); + ok(count, "Expected count > 0\n"); + ok(size % 6 == 1, "Expected size (%ld) %% 6 == 1\n", size); + if (ret && size % 5 == 1) + ok(!buffer[size -2] && !buffer[size -1], + "Expected last two WCHARs being empty, got 0x%x 0x%x\n", + buffer[size -2], buffer[size -1]); + + count = 0; + size = 0; + status = pRtlGetSystemPreferredUILanguages(MUI_MACHINE_LANGUAGE_SETTINGS, 0, &count, NULL, &size); + ok(!status, "got %lx\n", status); + ok(count, "Expected count > 0\n"); + ok(size % 6 == 1, "Expected size (%ld) %% 6 == 1\n", size); + if (ret && size % 6 == 1) + ok(!buffer[size -2] && !buffer[size -1], + "Expected last two WCHARs being empty, got 0x%x 0x%x\n", + buffer[size -2], buffer[size -1]); + + size = 0; + SetLastError(0xdeadbeef); + ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size); + ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n"); + ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(), + "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError()); + ok(size == size_id, "expected %lu, got %lu\n", size_id, size); + size = 1; SetLastError(0xdeadbeef); ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size); ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n"); ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(), - "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); + "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError()); + ok(size == size_id, "expected %lu, got %lu\n", size_id, size); - count = 0xdeadbeef; size = size_id -1; memset(buffer, 0x5a, size_buffer * sizeof(WCHAR)); SetLastError(0xdeadbeef); ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size); ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n"); ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(), - "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); + "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError()); + ok(size == size_id, "expected %lu, got %lu\n", size_id, size); - count = 0xdeadbeef; size = size_id -2; memset(buffer, 0x5a, size_buffer * sizeof(WCHAR)); SetLastError(0xdeadbeef); ret = pGetSystemPreferredUILanguages(0, &count, buffer, &size); ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n"); ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(), - "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); + "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError()); + ok(size == size_id + 2 || size == size_id + 1 /* before win10 1809 */, "expected %lu, got %lu\n", size_id + 2, size); HeapFree(GetProcessHeap(), 0, buffer); } @@ -5169,7 +6993,8 @@ static void test_GetSystemPreferredUILanguages(void) static void test_GetThreadPreferredUILanguages(void) { BOOL ret; - ULONG count, size; + NTSTATUS status; + ULONG count, size, size_id; WCHAR *buf; if (!pGetThreadPreferredUILanguages) @@ -5180,78 +7005,123 @@ static void test_GetThreadPreferredUILanguages(void) size = count = 0; ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID|MUI_UI_FALLBACK, &count, NULL, &size); - ok(ret, "got %u\n", GetLastError()); + ok(ret, "got %lu\n", GetLastError()); ok(count, "expected count > 0\n"); ok(size, "expected size > 0\n"); count = 0; buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size * sizeof(WCHAR)); ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID|MUI_UI_FALLBACK, &count, buf, &size); - ok(ret, "got %u\n", GetLastError()); + ok(ret, "got %lu\n", GetLastError()); ok(count, "expected count > 0\n"); + + size_id = count = 0; + ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size_id); + ok(ret, "got %lu\n", GetLastError()); + ok(count, "expected count > 0\n"); + ok(size_id, "expected size > 0\n"); + ok(size_id <= size, "expected size > 0\n"); + + /* ntdll function is the same */ + size_id = count = 0; + status = pRtlGetThreadPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size_id); + ok(!status, "got %lx\n", status); + ok(count, "expected count > 0\n"); + ok(size_id, "expected size > 0\n"); + ok(size_id <= size, "expected size > 0\n"); + + size = 0; + SetLastError(0xdeadbeef); + ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID, &count, buf, &size); + ok(!ret, "Expected GetThreadPreferredUILanguages to fail\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError()); + ok(size == size_id, "expected %lu, got %lu\n", size_id, size); + + size = 1; + SetLastError(0xdeadbeef); + ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID, &count, buf, &size); + ok(!ret, "Expected GetThreadPreferredUILanguages to fail\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError()); + ok(size == size_id, "expected %lu, got %lu\n", size_id, size); + + size = size_id - 1; + SetLastError(0xdeadbeef); + ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID, &count, buf, &size); + ok(!ret, "Expected GetThreadPreferredUILanguages to fail\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError()); + ok(size == size_id, "expected %lu, got %lu\n", size_id, size); + + size = size_id - 2; + SetLastError(0xdeadbeef); + ret = pGetThreadPreferredUILanguages(0, &count, buf, &size); + ok(!ret, "Expected GetThreadPreferredUILanguages to fail\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError()); + todo_wine + ok(size == size_id || size == size_id - 1 /* before win10 1809 */, "expected %lu, got %lu\n", size_id, size); + HeapFree(GetProcessHeap(), 0, buf); } static void test_GetUserPreferredUILanguages(void) { BOOL ret; + NTSTATUS status; ULONG count, size, size_id, size_name, size_buffer; WCHAR *buffer; - if (!pGetUserPreferredUILanguages) { win_skip("GetUserPreferredUILanguages is not available.\n"); return; } - count = 0xdeadbeef; size = 0; SetLastError(0xdeadbeef); ret = pGetUserPreferredUILanguages(MUI_FULL_LANGUAGE, &count, NULL, &size); ok(!ret, "Expected GetUserPreferredUILanguages to fail\n"); ok(ERROR_INVALID_PARAMETER == GetLastError(), - "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "Expected error ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); - count = 0xdeadbeef; size = 0; SetLastError(0xdeadbeef); ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID | MUI_FULL_LANGUAGE, &count, NULL, &size); ok(!ret, "Expected GetUserPreferredUILanguages to fail\n"); ok(ERROR_INVALID_PARAMETER == GetLastError(), - "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "Expected error ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); - count = 0xdeadbeef; size = 0; SetLastError(0xdeadbeef); ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size); ok(!ret, "Expected GetUserPreferredUILanguages to fail\n"); ok(ERROR_INVALID_PARAMETER == GetLastError(), - "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "Expected error ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); - count = 0xdeadbeef; size = 1; SetLastError(0xdeadbeef); ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size); ok(!ret, "Expected GetUserPreferredUILanguages to fail\n"); ok(ERROR_INVALID_PARAMETER == GetLastError(), - "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "Expected error ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); - count = 0xdeadbeef; + count = 0; size_id = 0; SetLastError(0xdeadbeef); ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size_id); ok(ret, "Expected GetUserPreferredUILanguages to succeed\n"); ok(count, "Expected count > 0\n"); - ok(size_id % 5 == 1, "Expected size (%d) %% 5 == 1\n", size_id); + ok(size_id % 5 == 1, "Expected size (%ld) %% 5 == 1\n", size_id); - count = 0xdeadbeef; + count = 0; size_name = 0; SetLastError(0xdeadbeef); ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &count, NULL, &size_name); ok(ret, "Expected GetUserPreferredUILanguages to succeed\n"); ok(count, "Expected count > 0\n"); - ok(size_name % 6 == 1, "Expected size (%d) %% 6 == 1\n", size_name); + ok(size_name % 6 == 1, "Expected size (%ld) %% 6 == 1\n", size_name); size_buffer = max(size_id, size_name); if(!size_buffer) @@ -5260,79 +7130,1788 @@ static void test_GetUserPreferredUILanguages(void) return; } + /* ntdll version is the same, but apparently takes an extra second parameter */ + count = 0; + size_id = 0; + SetLastError(0xdeadbeef); + status = pRtlGetUserPreferredUILanguages(MUI_LANGUAGE_ID, 0, &count, NULL, &size_id); + ok(!status, "got %lx\n", status); + ok(count, "Expected count > 0\n"); + ok(size_id % 5 == 1, "Expected size (%ld) %% 5 == 1\n", size_id); + buffer = HeapAlloc(GetProcessHeap(), 0, size_buffer * sizeof(WCHAR)); - count = 0xdeadbeef; + count = 0; size = size_buffer; memset(buffer, 0x5a, size_buffer * sizeof(WCHAR)); SetLastError(0xdeadbeef); ret = pGetUserPreferredUILanguages(0, &count, buffer, &size); ok(ret, "Expected GetUserPreferredUILanguages to succeed\n"); ok(count, "Expected count > 0\n"); - ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size); + ok(size % 6 == 1, "Expected size (%ld) %% 6 == 1\n", size); if (ret && size % 6 == 1) ok(!buffer[size -2] && !buffer[size -1], "Expected last two WCHARs being empty, got 0x%x 0x%x\n", buffer[size -2], buffer[size -1]); - count = 0xdeadbeef; + count = 0; size = size_buffer; memset(buffer, 0x5a, size_buffer * sizeof(WCHAR)); SetLastError(0xdeadbeef); ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size); ok(ret, "Expected GetUserPreferredUILanguages to succeed\n"); ok(count, "Expected count > 0\n"); - ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size); + ok(size % 5 == 1, "Expected size (%ld) %% 5 == 1\n", size); if (ret && size % 5 == 1) ok(!buffer[size -2] && !buffer[size -1], "Expected last two WCHARs being empty, got 0x%x 0x%x\n", buffer[size -2], buffer[size -1]); - count = 0xdeadbeef; + count = 0; size = size_buffer; SetLastError(0xdeadbeef); ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &count, buffer, &size); ok(ret, "Expected GetUserPreferredUILanguages to succeed\n"); ok(count, "Expected count > 0\n"); - ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size); + ok(size % 6 == 1, "Expected size (%ld) %% 6 == 1\n", size); if (ret && size % 5 == 1) ok(!buffer[size -2] && !buffer[size -1], "Expected last two WCHARs being empty, got 0x%x 0x%x\n", buffer[size -2], buffer[size -1]); - count = 0xdeadbeef; size = 1; SetLastError(0xdeadbeef); ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size); ok(!ret, "Expected GetUserPreferredUILanguages to fail\n"); ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(), - "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); + "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError()); - count = 0xdeadbeef; size = size_id -1; memset(buffer, 0x5a, size_buffer * sizeof(WCHAR)); SetLastError(0xdeadbeef); ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size); ok(!ret, "Expected GetUserPreferredUILanguages to fail\n"); ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(), - "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); + "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError()); - count = 0xdeadbeef; + count = 0; size = size_id -2; memset(buffer, 0x5a, size_buffer * sizeof(WCHAR)); SetLastError(0xdeadbeef); ret = pGetUserPreferredUILanguages(0, &count, buffer, &size); ok(!ret, "Expected GetUserPreferredUILanguages to fail\n"); ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(), - "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); + "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError()); HeapFree(GetProcessHeap(), 0, buffer); } +static void test_FindNLSStringEx(void) +{ + INT res; + static const WCHAR comb_s_accent1W[] = {0x1e69, 'o','u','r','c','e',0}; + static const WCHAR comb_s_accent2W[] = {0x0073,0x323,0x307,'o','u','r','c','e',0}; + static const WCHAR comb_q_accent1W[] = {'a','b',0x0071,0x0307,0x323,'u','o','t','e','\n',0}; + static const WCHAR comb_q_accent2W[] = {0x0071,0x0323,0x307,'u','o','t','e',0}; + struct test_data { + const WCHAR *locale; + DWORD flags; + const WCHAR *src; + const WCHAR *value; + INT expected_ret; + INT expected_found; + }; + + static struct test_data tests[] = + { + { localeW, FIND_FROMSTART, L"SimpleSimple", L"Simple", 0, 6}, + { localeW, FIND_FROMEND, L"SimpleSimple", L"Simp", 6, 4}, + { localeW, FIND_STARTSWITH, L"SimpleSimple", L"Simp", 0, 4}, + { localeW, FIND_ENDSWITH, L"SimpleSimple", L"Simple", 6, 6}, + { localeW, FIND_ENDSWITH, L"SimpleSimple", L"Simp", -1, 0xdeadbeef}, + { localeW, FIND_FROMSTART, comb_s_accent1W, comb_s_accent2W, 0, 6 }, + { localeW, FIND_FROMSTART, comb_q_accent1W, comb_q_accent2W, 2, 7 }, + { localeW, FIND_STARTSWITH, L"--Option", L"--", 0, 2}, + { localeW, FIND_ENDSWITH, L"Option--", L"--", 6, 2}, + { localeW, FIND_FROMSTART, L"----", L"--", 0, 2}, + { localeW, FIND_FROMEND, L"----", L"--", 2, 2}, + { localeW, FIND_FROMSTART, L"opt1--opt2--opt3", L"--", 4, 2}, + { localeW, FIND_FROMEND, L"opt1--opt2--opt3", L"--", 10, 2}, + { localeW, FIND_FROMSTART, L"x-oss-security", L"x-oss-", 0, 6}, + { localeW, FIND_FROMSTART, L"x-oss-security", L"-oss", 1, 4}, + { localeW, FIND_FROMSTART, L"x-oss-security", L"-oss--", -1, 0xdeadbeef}, + { localeW, FIND_FROMEND, L"x-oss-oss2", L"-oss", 5, 4}, + }; + unsigned int i; + +#if defined(__REACTOS__) && DLL_EXPORT_VERSION >= 0x600 + /* FIXME: FindNLSStringEx is a STUB on ReactOS! */ + if (is_reactos() || !pFindNLSStringEx) +#else + if (!pFindNLSStringEx) +#endif + { + win_skip("FindNLSStringEx is not available.\n"); + return; + } + + SetLastError( 0xdeadbeef ); + res = pFindNLSStringEx(invalidW, FIND_FROMSTART, fooW, 3, fooW, + 3, NULL, NULL, NULL, 0); + ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res); + ok(ERROR_INVALID_PARAMETER == GetLastError(), + "Expected ERROR_INVALID_PARAMETER as last error; got %ld\n", GetLastError()); + + SetLastError( 0xdeadbeef ); + res = pFindNLSStringEx(localeW, FIND_FROMSTART, NULL, 3, fooW, 3, + NULL, NULL, NULL, 0); + ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res); + ok(ERROR_INVALID_PARAMETER == GetLastError(), + "Expected ERROR_INVALID_PARAMETER as last error; got %ld\n", GetLastError()); + + SetLastError( 0xdeadbeef ); + res = pFindNLSStringEx(localeW, FIND_FROMSTART, fooW, -5, fooW, 3, + NULL, NULL, NULL, 0); + ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res); + ok(ERROR_INVALID_PARAMETER == GetLastError(), + "Expected ERROR_INVALID_PARAMETER as last error; got %ld\n", GetLastError()); + + SetLastError( 0xdeadbeef ); + res = pFindNLSStringEx(localeW, FIND_FROMSTART, fooW, 3, NULL, 3, + NULL, NULL, NULL, 0); + ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res); + ok(ERROR_INVALID_PARAMETER == GetLastError(), + "Expected ERROR_INVALID_PARAMETER as last error; got %ld\n", GetLastError()); + + SetLastError( 0xdeadbeef ); + res = pFindNLSStringEx(localeW, FIND_FROMSTART, fooW, 3, fooW, -5, + NULL, NULL, NULL, 0); + ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res); + ok(ERROR_INVALID_PARAMETER == GetLastError(), + "Expected ERROR_INVALID_PARAMETER as last error; got %ld\n", GetLastError()); + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { +#ifdef __REACTOS__ + if (GetNTVersion() == _WIN32_WINNT_VISTA && i == 5) // Skip tests[5] on Vista + continue; +#endif + int found = 0xdeadbeef; + res = pFindNLSStringEx(tests[i].locale, tests[i].flags, tests[i].src, -1, + tests[i].value, -1, &found, NULL, NULL, 0); + ok(res == tests[i].expected_ret, + "%u: Expected FindNLSStringEx to return %d. Returned value was %d\n", i, + tests[i].expected_ret, res); + ok(found == tests[i].expected_found, + "%u: Expected FindNLSStringEx to output %d. Value was %d\n", i, + tests[i].expected_found, found); + } +} + +static void test_FindStringOrdinal(void) +{ + static const WCHAR abc123aBcW[] = {'a', 'b', 'c', '1', '2', '3', 'a', 'B', 'c', 0}; + static const WCHAR abcW[] = {'a', 'b', 'c', 0}; + static const WCHAR aBcW[] = {'a', 'B', 'c', 0}; + static const WCHAR aaaW[] = {'a', 'a', 'a', 0}; + static const struct + { + DWORD flag; + const WCHAR *src; + INT src_size; + const WCHAR *val; + INT val_size; + BOOL ignore_case; + INT ret; + DWORD err; + } + tests[] = + { + /* Invalid */ + {1, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, abcW, ARRAY_SIZE(abcW) - 1, FALSE, -1, ERROR_INVALID_FLAGS}, + {FIND_FROMSTART, NULL, ARRAY_SIZE(abc123aBcW) - 1, abcW, ARRAY_SIZE(abcW) - 1, FALSE, -1, + ERROR_INVALID_PARAMETER}, + {FIND_FROMSTART, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, NULL, ARRAY_SIZE(abcW) - 1, FALSE, -1, + ERROR_INVALID_PARAMETER}, + {FIND_FROMSTART, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, NULL, 0, FALSE, -1, ERROR_INVALID_PARAMETER}, + {FIND_FROMSTART, NULL, 0, abcW, ARRAY_SIZE(abcW) - 1, FALSE, -1, ERROR_INVALID_PARAMETER}, + {FIND_FROMSTART, NULL, 0, NULL, 0, FALSE, -1, ERROR_INVALID_PARAMETER}, + /* Case-insensitive */ + {FIND_FROMSTART, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, abcW, ARRAY_SIZE(abcW) - 1, FALSE, 0, NO_ERROR}, + {FIND_FROMEND, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, abcW, ARRAY_SIZE(abcW) - 1, FALSE, 0, NO_ERROR}, + {FIND_STARTSWITH, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, abcW, ARRAY_SIZE(abcW) - 1, FALSE, 0, NO_ERROR}, + {FIND_ENDSWITH, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, abcW, ARRAY_SIZE(abcW) - 1, FALSE, -1, NO_ERROR}, + /* Case-sensitive */ + {FIND_FROMSTART, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, aBcW, ARRAY_SIZE(aBcW) - 1, TRUE, 0, NO_ERROR}, + {FIND_FROMEND, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, aBcW, ARRAY_SIZE(aBcW) - 1, TRUE, 6, NO_ERROR}, + {FIND_STARTSWITH, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, aBcW, ARRAY_SIZE(aBcW) - 1, TRUE, 0, NO_ERROR}, + {FIND_ENDSWITH, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, aBcW, ARRAY_SIZE(aBcW) - 1, TRUE, 6, NO_ERROR}, + /* Other */ + {FIND_FROMSTART, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, aaaW, ARRAY_SIZE(aaaW) - 1, FALSE, -1, NO_ERROR}, + {FIND_FROMSTART, abc123aBcW, -1, abcW, ARRAY_SIZE(abcW) - 1, FALSE, 0, NO_ERROR}, + {FIND_FROMSTART, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, abcW, -1, FALSE, 0, NO_ERROR}, + {FIND_FROMSTART, abc123aBcW, 0, abcW, ARRAY_SIZE(abcW) - 1, FALSE, -1, NO_ERROR}, + {FIND_FROMSTART, abc123aBcW, ARRAY_SIZE(abc123aBcW) - 1, abcW, 0, FALSE, 0, NO_ERROR}, + {FIND_FROMSTART, abc123aBcW, 0, abcW, 0, FALSE, 0, NO_ERROR}, + }; + INT ret; + DWORD err; + INT i; + + if (!pFindStringOrdinal) + { + win_skip("FindStringOrdinal is not available.\n"); + return; + } + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + SetLastError(0xdeadbeef); + ret = pFindStringOrdinal(tests[i].flag, tests[i].src, tests[i].src_size, tests[i].val, tests[i].val_size, + tests[i].ignore_case); + err = GetLastError(); + ok(ret == tests[i].ret, "Item %d expected %d, got %d\n", i, tests[i].ret, ret); + ok(err == tests[i].err, "Item %d expected %#lx, got %#lx\n", i, tests[i].err, err); + } +} + +static void test_SetThreadUILanguage(void) +{ + LANGID res; + + if (!pGetThreadUILanguage) + { + win_skip("GetThreadUILanguage isn't implemented, skipping SetThreadUILanguage tests for version < Vista\n"); + return; /* BTW SetThreadUILanguage is present on winxp/2003 but doesn`t set the LANGID anyway when tested */ + } + + res = pSetThreadUILanguage(0); + ok(res == pGetThreadUILanguage(), "expected %d got %d\n", pGetThreadUILanguage(), res); + + res = pSetThreadUILanguage(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH_BELGIAN)); + ok(res == MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH_BELGIAN), + "expected %d got %d\n", MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH_BELGIAN), res); + + res = pSetThreadUILanguage(0); + todo_wine ok(res == MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH_BELGIAN), + "expected %d got %d\n", MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH_BELGIAN), res); +} + +/* read a Unicode string from NormalizationTest.txt format; helper for test_NormalizeString */ +static int read_str( char *str, WCHAR res[32] ) +{ + int pos = 0; + char *end; + + while (*str && pos < 31) + { + unsigned int c = strtoul( str, &end, 16 ); + pos += put_utf16( res + pos, c ); + while (*end == ' ') end++; + str = end; + } + res[pos] = 0; + return pos; +} + +static void test_NormalizeString(void) +{ + /* part 0: specific cases */ + /* LATIN CAPITAL LETTER D WITH DOT ABOVE */ + static const WCHAR part0_str1[] = {0x1e0a,0}; + static const WCHAR part0_nfd1[] = {0x0044,0x0307,0}; + + /* LATIN CAPITAL LETTER D, COMBINING DOT BELOW, COMBINING DOT ABOVE */ + static const WCHAR part0_str2[] = {0x0044,0x0323,0x0307,0}; + static const WCHAR part0_nfc2[] = {0x1e0c,0x0307,0}; + + /* LATIN CAPITAL LETTER D, COMBINING HORN, COMBINING DOT BELOW, COMBINING DOT ABOVE */ + static const WCHAR part0_str3[] = {0x0044,0x031b,0x0323,0x0307,0}; + static const WCHAR part0_nfc3[] = {0x1e0c,0x031b,0x0307,0}; + + /* LATIN CAPITAL LETTER D, COMBINING HORN, COMBINING DOT BELOW, COMBINING DOT ABOVE */ + static const WCHAR part0_str4[] = {0x0044,0x031b,0x0323,0x0307,0}; + static const WCHAR part0_nfc4[] = {0x1e0c,0x031b,0x0307,0}; + + /* + * HEBREW ACCENT SEGOL, HEBREW POINT PATAH, HEBREW POINT DAGESH OR MAPIQ, + * HEBREW ACCENT MERKHA, HEBREW POINT SHEVA, HEBREW PUNCTUATION PASEQ, + * HEBREW MARK UPPER DOT, HEBREW ACCENT DEHI + */ + static const WCHAR part0_str5[] = {0x0592,0x05B7,0x05BC,0x05A5,0x05B0,0x05C0,0x05C4,0x05AD,0}; + static const WCHAR part0_nfc5[] = {0x05B0,0x05B7,0x05BC,0x05A5,0x0592,0x05C0,0x05AD,0x05C4,0}; + + /* + * HEBREW POINT QAMATS, HEBREW POINT HOLAM, HEBREW POINT HATAF SEGOL, + * HEBREW ACCENT ETNAHTA, HEBREW PUNCTUATION SOF PASUQ, HEBREW POINT SHEVA, + * HEBREW ACCENT ILUY, HEBREW ACCENT QARNEY PARA + */ + static const WCHAR part0_str6[] = {0x05B8,0x05B9,0x05B1,0x0591,0x05C3,0x05B0,0x05AC,0x059F,0}; + static const WCHAR part0_nfc6[] = {0x05B1,0x05B8,0x05B9,0x0591,0x05C3,0x05B0,0x05AC,0x059F,0}; + + /* LATIN CAPITAL LETTER D WITH DOT BELOW */ + static const WCHAR part0_str8[] = {0x1E0C,0}; + static const WCHAR part0_nfd8[] = {0x0044,0x0323,0}; + + /* LATIN CAPITAL LETTER D WITH DOT ABOVE, COMBINING DOT BELOW */ + static const WCHAR part0_str9[] = {0x1E0A,0x0323,0}; + static const WCHAR part0_nfc9[] = {0x1E0C,0x0307,0}; + static const WCHAR part0_nfd9[] = {0x0044,0x0323,0x0307,0}; + + /* LATIN CAPITAL LETTER D WITH DOT BELOW, COMBINING DOT ABOVE */ + static const WCHAR part0_str10[] = {0x1E0C,0x0307,0}; + static const WCHAR part0_nfd10[] = {0x0044,0x0323,0x0307,0}; + + /* LATIN CAPITAL LETTER E WITH MACRON AND GRAVE, COMBINING MACRON */ + static const WCHAR part0_str11[] = {0x1E14,0x0304,0}; + static const WCHAR part0_nfd11[] = {0x0045,0x0304,0x0300,0x0304,0}; + + /* LATIN CAPITAL LETTER E WITH MACRON, COMBINING GRAVE ACCENT */ + static const WCHAR part0_str12[] = {0x0112,0x0300,0}; + static const WCHAR part0_nfc12[] = {0x1E14,0}; + static const WCHAR part0_nfd12[] = {0x0045,0x0304,0x0300,0}; + + /* part 1: character by character */ + /* DIAERESIS */ + static const WCHAR part1_str1[] = {0x00a8,0}; + static const WCHAR part1_nfkc1[] = {0x0020,0x0308,0}; + + /* VULGAR FRACTION ONE QUARTER */ + static const WCHAR part1_str2[] = {0x00bc,0}; + static const WCHAR part1_nfkc2[] = {0x0031,0x2044,0x0034,0}; + + /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */ + static const WCHAR part1_str3[] = {0x00ca,0}; + static const WCHAR part1_nfd3[] = {0x0045,0x0302,0}; + + /* MODIFIER LETTER SMALL GAMMA */ + static const WCHAR part1_str4[] = {0x02e0,0}; + static const WCHAR part1_nfkc4[] = {0x0263,0}; + + /* CYRILLIC CAPITAL LETTER IE WITH GRAVE */ + static const WCHAR part1_str5[] = {0x0400,0}; + static const WCHAR part1_nfd5[] = {0x0415,0x0300,0}; + + /* CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT */ + static const WCHAR part1_str6[] = {0x0476,0}; + static const WCHAR part1_nfd6[] = {0x0474,0x030F,0}; + + /* ARABIC LIGATURE HAH WITH JEEM INITIAL FORM */ + static const WCHAR part1_str7[] = {0xFCA9,0}; + static const WCHAR part1_nfkc7[] = {0x062D,0x062C,0}; + + /* GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA */ + static const WCHAR part1_str8[] = {0x1F42,0}; + static const WCHAR part1_nfd8[] = {0x03BF,0x0313,0x0300,0}; + + /* QUADRUPLE PRIME */ + static const WCHAR part1_str9[] = {0x2057,0}; + static const WCHAR part1_nfkc9[] = {0x2032,0x2032,0x2032,0x2032,0}; + + /* KATAKANA-HIRAGANA VOICED SOUND MARK */ + static const WCHAR part1_str10[] = {0x309B,0}; + static const WCHAR part1_nfkc10[] = {0x20,0x3099,0}; + + /* ANGSTROM SIGN */ + static const WCHAR part1_str11[] = {0x212B,0}; + static const WCHAR part1_nfc11[] = {0xC5,0}; + static const WCHAR part1_nfd11[] = {'A',0x030A,0}; + + static const WCHAR composite_src[] = + { + 0x008a, 0x008e, 0x009a, 0x009e, 0x009f, 0x00c0, 0x00c1, 0x00c2, + 0x00c3, 0x00c4, 0x00c5, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, + 0x00cc, 0x00cd, 0x00ce, 0x00cf, 0x00d1, 0x00d2, 0x00d3, 0x00d4, + 0x00d5, 0x00d6, 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, + 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e7, 0x00e8, + 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f1, + 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f8, 0x00f9, 0x00fa, + 0x00fb, 0x00fc, 0x00fd, 0x00ff, 0x212b + }; + + struct test_data_normal { + const WCHAR *str; + const WCHAR *expected[4]; + }; + static const struct test_data_normal test_arr[] = + { + { part0_str1, { part0_str1, part0_nfd1, part0_str1, part0_nfd1 } }, + { part0_str2, { part0_nfc2, part0_str2, part0_nfc2, part0_str2 } }, + { part0_str3, { part0_nfc3, part0_str3, part0_nfc3, part0_str3 } }, + { part0_str4, { part0_nfc4, part0_str4, part0_nfc4, part0_str4 } }, + { part0_str5, { part0_nfc5, part0_nfc5, part0_nfc5, part0_nfc5 } }, + { part0_str6, { part0_nfc6, part0_nfc6, part0_nfc6, part0_nfc6 } }, + { part0_str8, { part0_str8, part0_nfd8, part0_str8, part0_nfd8 } }, + { part0_str9, { part0_nfc9, part0_nfd9, part0_nfc9, part0_nfd9 } }, + { part0_str10, { part0_str10, part0_nfd10, part0_str10, part0_nfd10 } }, + { part0_str11, { part0_str11, part0_nfd11, part0_str11, part0_nfd11 } }, + { part0_str12, { part0_nfc12, part0_nfd12, part0_nfc12, part0_nfd12 } }, + { part1_str1, { part1_str1, part1_str1, part1_nfkc1, part1_nfkc1 } }, + { part1_str2, { part1_str2, part1_str2, part1_nfkc2, part1_nfkc2 } }, + { part1_str3, { part1_str3, part1_nfd3, part1_str3, part1_nfd3 } }, + { part1_str4, { part1_str4, part1_str4, part1_nfkc4, part1_nfkc4 } }, + { part1_str5, { part1_str5, part1_nfd5, part1_str5, part1_nfd5 } }, + { part1_str6, { part1_str6, part1_nfd6, part1_str6, part1_nfd6 } }, + { part1_str7, { part1_str7, part1_str7, part1_nfkc7, part1_nfkc7 } }, + { part1_str8, { part1_str8, part1_nfd8, part1_str8, part1_nfd8 } }, + { part1_str9, { part1_str9, part1_str9, part1_nfkc9, part1_nfkc9 } }, + { part1_str10, { part1_str10, part1_str10, part1_nfkc10, part1_nfkc10 } }, + { part1_str11, { part1_nfc11, part1_nfd11, part1_nfc11, part1_nfd11 } }, + { 0 } + }; + const struct test_data_normal *ptest = test_arr; + const int norm_forms[] = { NormalizationC, NormalizationD, NormalizationKC, NormalizationKD }; + WCHAR dst[256]; + BOOLEAN ret; + NTSTATUS status; + int dstlen, str_cmp, i, j; + FILE *f; + + if (!pNormalizeString) + { + win_skip("NormalizeString is not available.\n"); + return; + } + if (!pRtlNormalizeString) win_skip("RtlNormalizeString is not available.\n"); + + /* + * For each string, first test passing -1 as srclen to NormalizeString, + * thereby assuming a null-terminating string in src, and then test passing + * explicitly the string length. + * Do that for all 4 normalization forms. + */ + while (ptest->str) + { + for (i = 0; i < 4; i++) + { + SetLastError(0xdeadbeef); + dstlen = pNormalizeString( norm_forms[i], ptest->str, -1, NULL, 0 ); + ok( dstlen > lstrlenW(ptest->str), "%s:%d: wrong len %d / %d\n", + wine_dbgstr_w(ptest->str), i, dstlen, lstrlenW(ptest->str) ); + ok(GetLastError() == ERROR_SUCCESS, "%s:%d: got error %lu\n", + wine_dbgstr_w(ptest->str), i, GetLastError()); + SetLastError(0xdeadbeef); + dstlen = pNormalizeString( norm_forms[i], ptest->str, -1, dst, dstlen ); + ok(GetLastError() == ERROR_SUCCESS, "%s:%d: got error %lu\n", + wine_dbgstr_w(ptest->str), i, GetLastError()); + ok(dstlen == lstrlenW( dst )+1, "%s:%d: Copied length differed: was %d, should be %d\n", + wine_dbgstr_w(ptest->str), i, dstlen, lstrlenW( dst )+1); + str_cmp = wcsncmp( ptest->expected[i], dst, dstlen+1 ); + ok( str_cmp == 0, "%s:%d: string incorrect got %s expect %s\n", wine_dbgstr_w(ptest->str), i, + wine_dbgstr_w(dst), wine_dbgstr_w(ptest->expected[i]) ); + + dstlen = pNormalizeString( norm_forms[i], ptest->str, lstrlenW(ptest->str), NULL, 0 ); + memset(dst, 0xcc, sizeof(dst)); + dstlen = pNormalizeString( norm_forms[i], ptest->str, lstrlenW(ptest->str), dst, dstlen ); + ok(dstlen == lstrlenW( ptest->expected[i] ), "%s:%d: Copied length differed: was %d, should be %d\n", + wine_dbgstr_w(ptest->str), i, dstlen, lstrlenW( dst )); + str_cmp = wcsncmp( ptest->expected[i], dst, dstlen ); + ok( str_cmp == 0, "%s:%d: string incorrect got %s expect %s\n", wine_dbgstr_w(ptest->str), i, + wine_dbgstr_w(dst), wine_dbgstr_w(ptest->expected[i]) ); + + if (pRtlNormalizeString) + { + dstlen = 0; + status = pRtlNormalizeString( norm_forms[i], ptest->str, lstrlenW(ptest->str), NULL, &dstlen ); + ok( !status, "%s:%d: failed %lx\n", wine_dbgstr_w(ptest->str), i, status ); + ok( dstlen > lstrlenW(ptest->str), "%s:%d: wrong len %d / %d\n", + wine_dbgstr_w(ptest->str), i, dstlen, lstrlenW(ptest->str) ); + memset(dst, 0, sizeof(dst)); + status = pRtlNormalizeString( norm_forms[i], ptest->str, lstrlenW(ptest->str), dst, &dstlen ); + ok( !status, "%s:%d: failed %lx\n", wine_dbgstr_w(ptest->str), i, status ); + ok(dstlen == lstrlenW( dst ), "%s:%d: Copied length differed: was %d, should be %d\n", + wine_dbgstr_w(ptest->str), i, dstlen, lstrlenW( dst )); + str_cmp = wcsncmp( ptest->expected[i], dst, dstlen ); + ok( str_cmp == 0, "%s:%d: string incorrect got %s expect %s\n", wine_dbgstr_w(ptest->str), i, + wine_dbgstr_w(dst), wine_dbgstr_w(ptest->expected[i]) ); + ret = FALSE; + status = pRtlIsNormalizedString( norm_forms[i], ptest->str, -1, &ret ); + ok( !status, "%s:%d: failed %lx\n", wine_dbgstr_w(ptest->str), i, status ); + if (!wcscmp( ptest->str, dst )) + ok( ret, "%s:%d: not normalized\n", wine_dbgstr_w(ptest->str), i ); + else + ok( !ret, "%s:%d: normalized (dst %s)\n", wine_dbgstr_w(ptest->str), i, wine_dbgstr_w(dst) ); + ret = FALSE; + status = pRtlIsNormalizedString( norm_forms[i], dst, dstlen, &ret ); + ok( !status, "%s:%d: failed %lx\n", wine_dbgstr_w(ptest->str), i, status ); + ok( ret, "%s:%d: not normalized\n", wine_dbgstr_w(ptest->str), i ); + } + } + ptest++; + } + + /* buffer overflows */ + + SetLastError(0xdeadbeef); + dstlen = pNormalizeString( NormalizationD, part0_str1, -1, dst, 1 ); + ok( dstlen <= 0, "wrong len %d\n", dstlen ); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + dstlen = pNormalizeString( NormalizationC, part0_str2, -1, dst, 1 ); + ok( dstlen <= 0, "wrong len %d\n", dstlen ); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + dstlen = pNormalizeString( NormalizationC, part0_str2, -1, NULL, 0 ); + ok( dstlen == 12, "wrong len %d\n", dstlen ); + ok(GetLastError() == ERROR_SUCCESS, "got error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + dstlen = pNormalizeString( NormalizationC, part0_str2, -1, dst, 3 ); + ok( dstlen == 3, "wrong len %d\n", dstlen ); + ok(GetLastError() == ERROR_SUCCESS, "got error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + dstlen = pNormalizeString( NormalizationC, part0_str2, 0, NULL, 0 ); + ok( dstlen == 0, "wrong len %d\n", dstlen ); + ok(GetLastError() == ERROR_SUCCESS, "got error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + dstlen = pNormalizeString( NormalizationC, part0_str2, 0, dst, 3 ); + ok( dstlen == 0, "wrong len %d\n", dstlen ); + ok(GetLastError() == ERROR_SUCCESS, "got error %lu\n", GetLastError()); + + /* size estimations */ + + memset( dst, 'A', sizeof(dst) ); + for (j = 1; j < ARRAY_SIZE(dst); j++) + { + for (i = 0; i < 4; i++) + { + int expect = (i < 2) ? j * 3 : j * 18; + if (expect > 64) expect = max( 64, j + j / 8 ); + dstlen = pNormalizeString( norm_forms[i], dst, j, NULL, 0 ); + ok( dstlen == expect, "%d: %d -> wrong len %d\n", i, j, dstlen ); + if (pRtlNormalizeString) + { + dstlen = 0; + status = pRtlNormalizeString( norm_forms[i], dst, j, NULL, &dstlen ); + ok( !status, "%d: failed %lx\n", i, status ); + ok( dstlen == expect, "%d: %d -> wrong len %d\n", i, j, dstlen ); + } + } + } + for (i = 0; i < 4; i++) + { + int srclen = ARRAY_SIZE( composite_src ); + int expect = max( 64, srclen + srclen / 8 ); + dstlen = pNormalizeString( norm_forms[i], composite_src, srclen, NULL, 0 ); + ok( dstlen == expect, "%d: wrong len %d\n", i, dstlen ); + dstlen = pNormalizeString( norm_forms[i], composite_src, srclen, dst, dstlen ); + if (i == 0 || i == 2) + { + ok( dstlen == srclen, "%d: wrong len %d\n", i, dstlen ); + ok(GetLastError() == ERROR_SUCCESS, "got error %lu\n", GetLastError()); + } + else + { + ok( dstlen < -expect, "%d: wrong len %d\n", i, dstlen ); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got error %lu\n", GetLastError()); + } + if (pRtlNormalizeString) + { + dstlen = 0; + status = pRtlNormalizeString( norm_forms[i], composite_src, srclen, NULL, &dstlen ); + ok( !status, "%d: failed %lx\n", i, status ); + ok( dstlen == expect, "%d: wrong len %d\n", i, dstlen ); + status = pRtlNormalizeString( norm_forms[i], composite_src, srclen, dst, &dstlen ); + if (i == 0 || i == 2) + { + ok( !status, "%d: failed %lx\n", i, status ); + ok( dstlen == srclen, "%d: wrong len %d\n", i, dstlen ); + } + else + { + ok( status == STATUS_BUFFER_TOO_SMALL, "%d: failed %lx\n", i, status ); + ok( dstlen > expect, "%d: wrong len %d\n", i, dstlen ); + } + } + } + + /* invalid parameters */ + + for (i = 0; i < 32; i++) + { + SetLastError(0xdeadbeef); + dstlen = pNormalizeString( i, L"ABC", -1, NULL, 0 ); + switch (i) + { + case NormalizationC: + case NormalizationD: + case NormalizationKC: + case NormalizationKD: + case 13: /* Idn */ + ok( dstlen > 0, "%d: wrong len %d\n", i, dstlen ); + ok( GetLastError() == ERROR_SUCCESS, "%d: got error %lu\n", i, GetLastError()); + break; + default: + ok( dstlen <= 0, "%d: wrong len %d\n", i, dstlen ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "%d: got error %lu\n", i, GetLastError()); + break; + } + if (pRtlNormalizeString) + { + dstlen = 0; + status = pRtlNormalizeString( i, L"ABC", -1, NULL, &dstlen ); + switch (i) + { + case 0: + ok( status == STATUS_INVALID_PARAMETER, "%d: failed %lx\n", i, status ); + break; + case NormalizationC: + case NormalizationD: + case NormalizationKC: + case NormalizationKD: + case 13: /* Idn */ + ok( status == STATUS_SUCCESS, "%d: failed %lx\n", i, status ); + break; + default: + ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "%d: failed %lx\n", i, status ); + break; + } + } + } + + /* invalid sequences */ + + for (i = 0; i < 4; i++) + { + dstlen = pNormalizeString( norm_forms[i], L"AB\xd800Z", -1, NULL, 0 ); + ok( dstlen == (i < 2 ? 15 : 64), "%d: wrong len %d\n", i, dstlen ); + SetLastError( 0xdeadbeef ); + dstlen = pNormalizeString( norm_forms[i], L"AB\xd800Z", -1, dst, ARRAY_SIZE(dst) ); + ok( dstlen == -3, "%d: wrong len %d\n", i, dstlen ); + ok( GetLastError() == ERROR_NO_UNICODE_TRANSLATION, "%d: wrong error %ld\n", i, GetLastError() ); + dstlen = pNormalizeString( norm_forms[i], L"ABCD\xdc12Z", -1, NULL, 0 ); + ok( dstlen == (i < 2 ? 21 : 64), "%d: wrong len %d\n", i, dstlen ); + SetLastError( 0xdeadbeef ); + dstlen = pNormalizeString( norm_forms[i], L"ABCD\xdc12Z", -1, dst, ARRAY_SIZE(dst) ); + ok( dstlen == -4, "%d: wrong len %d\n", i, dstlen ); + ok( GetLastError() == ERROR_NO_UNICODE_TRANSLATION, "%d: wrong error %ld\n", i, GetLastError() ); + SetLastError( 0xdeadbeef ); + dstlen = pNormalizeString( norm_forms[i], L"ABCD\xdc12Z", -1, dst, 2 ); + todo_wine + ok( dstlen == (i < 2 ? -18 : -74), "%d: wrong len %d\n", i, dstlen ); + todo_wine_if (i == 0 || i == 2) + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "%d: wrong error %ld\n", i, GetLastError() ); + if (pRtlNormalizeString) + { + dstlen = 0; + status = pRtlNormalizeString( norm_forms[i], L"AB\xd800Z", -1, NULL, &dstlen ); + ok( !status, "%d: failed %lx\n", i, status ); + ok( dstlen == (i < 2 ? 15 : 64), "%d: wrong len %d\n", i, dstlen ); + dstlen = ARRAY_SIZE(dst); + status = pRtlNormalizeString( norm_forms[i], L"AB\xd800Z", -1, dst, &dstlen ); + ok( status == STATUS_NO_UNICODE_TRANSLATION, "%d: failed %lx\n", i, status ); + ok( dstlen == 3, "%d: wrong len %d\n", i, dstlen ); + dstlen = 1; + status = pRtlNormalizeString( norm_forms[i], L"AB\xd800Z", -1, dst, &dstlen ); + todo_wine_if( i == 0 || i == 2) + ok( status == STATUS_BUFFER_TOO_SMALL, "%d: failed %lx\n", i, status ); + todo_wine_if( i != 3) + ok( dstlen == (i < 2 ? 14 : 73), "%d: wrong len %d\n", i, dstlen ); + dstlen = 2; + status = pRtlNormalizeString( norm_forms[i], L"AB\xd800Z", -1, dst, &dstlen ); + ok( status == STATUS_NO_UNICODE_TRANSLATION, "%d: failed %lx\n", i, status ); + ok( dstlen == 3, "%d: wrong len %d\n", i, dstlen ); + } + } + + /* optionally run the full test file from Unicode.org + * available at http://www.unicode.org/Public/UCD/latest/ucd/NormalizationTest.txt + */ + if ((f = fopen( "NormalizationTest.txt", "r" ))) + { + char *p, buffer[1024]; + WCHAR str[3], srcW[32], dstW[32], resW[4][32]; + int line = 0, part = 0, ch; + char tested[0x110000 / 8]; + + while (fgets( buffer, sizeof(buffer), f )) + { + line++; + if ((p = strchr( buffer, '#' ))) *p = 0; + if (!strncmp( buffer, "@Part", 5 )) + { + part = atoi( buffer + 5 ); + continue; + } + if (!(p = strtok( buffer, ";" ))) continue; + read_str( p, srcW ); + for (i = 0; i < 4; i++) + { + p = strtok( NULL, ";" ); + read_str( p, &resW[i][0] ); + } + if (part == 1) + { + ch = srcW[0]; + if (ch >= 0xd800 && ch <= 0xdbff) + ch = 0x10000 + ((srcW[0] & 0x3ff) << 10) + (srcW[1] & 0x3ff); + tested[ch / 8] |= 1 << (ch % 8); + } + for (i = 0; i < 4; i++) + { + memset( dstW, 0xcc, sizeof(dstW) ); + dstlen = pNormalizeString( norm_forms[i], srcW, -1, dstW, ARRAY_SIZE(dstW) ); + ok( !wcscmp( dstW, resW[i] ), + "line %u form %u: wrong result %s for %s expected %s\n", line, i, + wine_dbgstr_w( dstW ), wine_dbgstr_w( srcW ), wine_dbgstr_w( resW[i] )); + + ret = FALSE; + status = pRtlIsNormalizedString( norm_forms[i], srcW, -1, &ret ); + ok( !status, "line %u form %u: RtlIsNormalizedString failed %lx\n", line, i, status ); + if (!wcscmp( srcW, dstW )) + ok( ret, "line %u form %u: source not normalized %s\n", line, i, wine_dbgstr_w(srcW) ); + else + ok( !ret, "line %u form %u: source normalized %s\n", line, i, wine_dbgstr_w(srcW) ); + ret = FALSE; + status = pRtlIsNormalizedString( norm_forms[i], dstW, -1, &ret ); + ok( !status, "line %u form %u: RtlIsNormalizedString failed %lx\n", line, i, status ); + ok( ret, "line %u form %u: dest not normalized %s\n", line, i, wine_dbgstr_w(dstW) ); + + for (j = 0; j < 4; j++) + { + int expect = i | (j & 2); + memset( dstW, 0xcc, sizeof(dstW) ); + dstlen = pNormalizeString( norm_forms[i], resW[j], -1, dstW, ARRAY_SIZE(dstW) ); + ok( !wcscmp( dstW, resW[expect] ), + "line %u form %u res %u: wrong result %s for %s expected %s\n", line, i, j, + wine_dbgstr_w( dstW ), wine_dbgstr_w( resW[j] ), wine_dbgstr_w( resW[expect] )); + } + } + } + fclose( f ); + + /* test chars that are not in the @Part1 list */ + for (ch = 0; ch < 0x110000; ch++) + { + if (tested[ch / 8] & (1 << (ch % 8))) continue; + str[put_utf16( str, ch )] = 0; + for (i = 0; i < 4; i++) + { + memset( dstW, 0xcc, sizeof(dstW) ); + SetLastError( 0xdeadbeef ); + dstlen = pNormalizeString( norm_forms[i], str, -1, dstW, ARRAY_SIZE(dstW) ); + if ((ch >= 0xd800 && ch <= 0xdfff) || + (ch >= 0xfdd0 && ch <= 0xfdef) || + ((ch & 0xffff) >= 0xfffe)) + { + ok( dstlen <= 0, "char %04x form %u: wrong result %d %s expected error\n", + ch, i, dstlen, wine_dbgstr_w( dstW )); + ok( GetLastError() == ERROR_NO_UNICODE_TRANSLATION, + "char %04x form %u: error %lu\n", str[0], i, GetLastError() ); + status = pRtlIsNormalizedString( norm_forms[i], str, -1, &ret ); + ok( status == STATUS_NO_UNICODE_TRANSLATION, + "char %04x form %u: failed %lx\n", ch, i, status ); + } + else + { + ok( !wcscmp( dstW, str ), + "char %04x form %u: wrong result %s expected unchanged\n", + ch, i, wine_dbgstr_w( dstW )); + ret = FALSE; + status = pRtlIsNormalizedString( norm_forms[i], str, -1, &ret ); + ok( !status, "char %04x form %u: failed %lx\n", ch, i, status ); + ok( ret, "char %04x form %u: not normalized\n", ch, i ); + } + } + } + } +} + +static void test_SpecialCasing(void) +{ + int ret, i, len; + UINT val = 0, exp; + WCHAR src[8], buffer[8]; + static const struct test { + const WCHAR *lang; + DWORD flags; + UINT ch; + UINT exp; /* 0 if self */ + UINT exp_ling; /* 0 if exp */ + BOOL broken; + } tests[] = { + {L"de-DE", LCMAP_UPPERCASE, 0x00DF}, /* LATIN SMALL LETTER SHARP S */ + + {L"en-US", LCMAP_UPPERCASE, 0xFB00}, /* LATIN SMALL LIGATURE FF */ + {L"en-US", LCMAP_UPPERCASE, 0xFB01}, /* LATIN SMALL LIGATURE FI */ + {L"en-US", LCMAP_UPPERCASE, 0xFB02}, /* LATIN SMALL LIGATURE FL */ + {L"en-US", LCMAP_UPPERCASE, 0xFB03}, /* LATIN SMALL LIGATURE FFI */ + {L"en-US", LCMAP_UPPERCASE, 0xFB04}, /* LATIN SMALL LIGATURE FFL */ + {L"en-US", LCMAP_UPPERCASE, 0xFB05}, /* LATIN SMALL LIGATURE LONG S T */ + {L"en-US", LCMAP_UPPERCASE, 0xFB06}, /* LATIN SMALL LIGATURE ST */ + + {L"hy-AM", LCMAP_UPPERCASE, 0x0587}, /* ARMENIAN SMALL LIGATURE ECH YIWN */ + {L"hy-AM", LCMAP_UPPERCASE, 0xFB13}, /* ARMENIAN SMALL LIGATURE MEN NOW */ + {L"hy-AM", LCMAP_UPPERCASE, 0xFB14}, /* ARMENIAN SMALL LIGATURE MEN ECH */ + {L"hy-AM", LCMAP_UPPERCASE, 0xFB15}, /* ARMENIAN SMALL LIGATURE MEN INI */ + {L"hy-AM", LCMAP_UPPERCASE, 0xFB16}, /* ARMENIAN SMALL LIGATURE VEW NOW */ + {L"hy-AM", LCMAP_UPPERCASE, 0xFB17}, /* ARMENIAN SMALL LIGATURE MEN XEH */ + + {L"en-US", LCMAP_UPPERCASE, 0x0149}, /* LATIN SMALL LETTER N PRECEDED BY APOSTROPHE */ + {L"el-GR", LCMAP_UPPERCASE, 0x0390,0,0,TRUE /*win7*/ }, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */ + {L"el-GR", LCMAP_UPPERCASE, 0x03B0,0,0,TRUE /*win7*/ }, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */ + {L"en-US", LCMAP_UPPERCASE, 0x01F0}, /* LATIN SMALL LETTER J WITH CARON */ + {L"en-US", LCMAP_UPPERCASE, 0x1E96}, /* LATIN SMALL LETTER H WITH LINE BELOW */ + {L"en-US", LCMAP_UPPERCASE, 0x1E97}, /* LATIN SMALL LETTER T WITH DIAERESIS */ + {L"en-US", LCMAP_UPPERCASE, 0x1E98}, /* LATIN SMALL LETTER W WITH RING ABOVE */ + {L"en-US", LCMAP_UPPERCASE, 0x1E99}, /* LATIN SMALL LETTER Y WITH RING ABOVE */ + {L"en-US", LCMAP_UPPERCASE, 0x1E9A}, /* LATIN SMALL LETTER A WITH RIGHT HALF RING */ + {L"el-GR", LCMAP_UPPERCASE, 0x1F50}, /* GREEK SMALL LETTER UPSILON WITH PSILI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1F52}, /* GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA */ + {L"el-GR", LCMAP_UPPERCASE, 0x1F54}, /* GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA */ + {L"el-GR", LCMAP_UPPERCASE, 0x1F56}, /* GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1FB6}, /* GREEK SMALL LETTER ALPHA WITH PERISPOMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1FC6}, /* GREEK SMALL LETTER ETA WITH PERISPOMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1FD2}, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA */ + {L"el-GR", LCMAP_UPPERCASE, 0x1FD3}, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA */ + {L"el-GR", LCMAP_UPPERCASE, 0x1FD6}, /* GREEK SMALL LETTER IOTA WITH PERISPOMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1FD7}, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1FE2}, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA */ + {L"el-GR", LCMAP_UPPERCASE, 0x1FE3}, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA */ + {L"el-GR", LCMAP_UPPERCASE, 0x1FE4}, /* GREEK SMALL LETTER RHO WITH PSILI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1FE6}, /* GREEK SMALL LETTER UPSILON WITH PERISPOMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1FE7}, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1FF6}, /* GREEK SMALL LETTER OMEGA WITH PERISPOMENI */ + + {L"el-GR", LCMAP_UPPERCASE, 0x1F80,0x1F88}, /* GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1F81,0x1F89}, /* GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1F82,0x1F8A}, /* GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1F83,0x1F8B}, /* GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1F84,0x1F8C}, /* GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1F85,0x1F8D}, /* GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1F86,0x1F8E}, /* GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1F87,0x1F8F}, /* GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI */ + + {L"el-GR", LCMAP_LOWERCASE, 0x1F88,0x1F80}, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI */ + {L"el-GR", LCMAP_LOWERCASE, 0x1F89,0x1F81}, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI */ + {L"el-GR", LCMAP_LOWERCASE, 0x1F8A,0x1F82}, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI */ + {L"el-GR", LCMAP_LOWERCASE, 0x1F8B,0x1F83}, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI */ + {L"el-GR", LCMAP_LOWERCASE, 0x1F8C,0x1F84}, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI */ + {L"el-GR", LCMAP_LOWERCASE, 0x1F8D,0x1F85}, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI */ + {L"el-GR", LCMAP_LOWERCASE, 0x1F8E,0x1F86}, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI */ + {L"el-GR", LCMAP_LOWERCASE, 0x1F8F,0x1F87}, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI */ + + {L"el-GR", LCMAP_UPPERCASE, 0x1F90,0x1F98}, /* GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1F91,0x1F99}, /* GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1F92,0x1F9A}, /* GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1F93,0x1F9B}, /* GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1F94,0x1F9C}, /* GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1F95,0x1F9D}, /* GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1F96,0x1F9E}, /* GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1F97,0x1F9F}, /* GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI */ + + {L"el-GR", LCMAP_LOWERCASE, 0x1FA8,0x1FA0}, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI */ + {L"el-GR", LCMAP_LOWERCASE, 0x1FA9,0x1FA1}, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI */ + {L"el-GR", LCMAP_LOWERCASE, 0x1FAA,0x1FA2}, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI */ + {L"el-GR", LCMAP_LOWERCASE, 0x1FAB,0x1FA3}, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI */ + {L"el-GR", LCMAP_LOWERCASE, 0x1FAC,0x1FA4}, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI */ + {L"el-GR", LCMAP_LOWERCASE, 0x1FAD,0x1FA5}, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI */ + {L"el-GR", LCMAP_LOWERCASE, 0x1FAE,0x1FA6}, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI */ + {L"el-GR", LCMAP_LOWERCASE, 0x1FAF,0x1FA7}, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI */ + + {L"el-GR", LCMAP_UPPERCASE, 0x1FB3,0x1FBC}, /* GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI */ + {L"el-GR", LCMAP_LOWERCASE, 0x1FBC,0x1FB3}, /* GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI */ +#ifdef __REACTOS__ + {L"el-GR", LCMAP_UPPERCASE, 0x1FC3,0x1FCC,0, TRUE /* Vista */}, /* GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI */ + {L"el-GR", LCMAP_LOWERCASE, 0x1FCC,0x1FC3,0, TRUE /* Vista */}, /* GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1FF3,0x1FFC,0, TRUE /* Vista */}, /* GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI */ + {L"el-GR", LCMAP_LOWERCASE, 0x1FFC,0x1FF3,0, TRUE /* Vista */}, /* GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI */ +#else + {L"el-GR", LCMAP_UPPERCASE, 0x1FC3,0x1FCC}, /* GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI */ + {L"el-GR", LCMAP_LOWERCASE, 0x1FCC,0x1FC3}, /* GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1FF3,0x1FFC}, /* GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI */ + {L"el-GR", LCMAP_LOWERCASE, 0x1FFC,0x1FF3}, /* GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI */ +#endif + + {L"el-GR", LCMAP_UPPERCASE, 0x1FB2}, /* GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1FB4}, /* GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1FC2}, /* GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1FC4}, /* GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1FF2}, /* GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1FF4}, /* GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI */ + + {L"el-GR", LCMAP_UPPERCASE, 0x1FB7}, /* GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1FC7}, /* GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI */ + {L"el-GR", LCMAP_UPPERCASE, 0x1FF7}, /* GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI */ + + {L"el-GR", LCMAP_LOWERCASE, 0x03A3,0x03C3}, /* GREEK CAPITAL LETTER SIGMA */ + + {L"lt-LT", LCMAP_LOWERCASE, 'J','j'}, /* LATIN CAPITAL LETTER J */ + {L"lt-LT", LCMAP_LOWERCASE, 0x012E,0x012F}, /* LATIN CAPITAL LETTER I WITH OGONEK */ + {L"lt-LT", LCMAP_LOWERCASE, 0x00CC,0x00EC}, /* LATIN CAPITAL LETTER I WITH GRAVE */ + {L"lt-LT", LCMAP_LOWERCASE, 0x00CD,0x00ED}, /* LATIN CAPITAL LETTER I WITH ACUTE */ + {L"lt-LT", LCMAP_LOWERCASE, 0x0128,0x0129}, /* LATIN CAPITAL LETTER I WITH TILDE */ + + {L"en-US", LCMAP_UPPERCASE, 'i', 'I'}, /* LATIN SMALL LETTER I */ + {L"lt-LT", LCMAP_UPPERCASE, 'i', 'I'}, /* LATIN SMALL LETTER I */ + {L"tr-TR", LCMAP_UPPERCASE, 'i', 'I', 0x0130}, /* LATIN SMALL LETTER I */ + {L"TR-TR", LCMAP_UPPERCASE, 'i', 'I', 0x0130}, /* LATIN SMALL LETTER I */ + {L"az-Cyrl-az", LCMAP_UPPERCASE, 'i', 'I', 0x0130, TRUE /*win7*/}, /* LATIN SMALL LETTER I */ + {L"az-Latn-az", LCMAP_UPPERCASE, 'i', 'I', 0x0130}, /* LATIN SMALL LETTER I */ + + {L"en-US", LCMAP_LOWERCASE, 'I', 'i'}, /* LATIN CAPITAL LETTER I */ + {L"lt-LT", LCMAP_LOWERCASE, 'I', 'i'}, /* LATIN CAPITAL LETTER I */ + {L"tr-TR", LCMAP_LOWERCASE, 'I', 'i', 0x0131}, /* LATIN CAPITAL LETTER I */ + {L"TR-TR", LCMAP_LOWERCASE, 'I', 'i', 0x0131}, /* LATIN CAPITAL LETTER I */ + {L"az-Cyrl-az", LCMAP_LOWERCASE, 'I', 'i', 0x0131, TRUE /*win7*/}, /* LATIN CAPITAL LETTER I */ + {L"az-Latn-az", LCMAP_LOWERCASE, 'I', 'i', 0x0131}, /* LATIN CAPITAL LETTER I */ + + {L"en-US", LCMAP_LOWERCASE, 0x0130,0,'i'}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */ + {L"tr-TR", LCMAP_LOWERCASE, 0x0130,0,'i'}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */ + {L"TR-TR", LCMAP_LOWERCASE, 0x0130,0,'i'}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */ + {L"az-Cyrl-az", LCMAP_LOWERCASE, 0x0130,0,'i'}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */ + {L"az-Latn-az", LCMAP_LOWERCASE, 0x0130,0,'i'}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */ + + {L"en-US", LCMAP_UPPERCASE, 0x0131,0,'I'}, /* LATIN SMALL LETTER DOTLESS I */ + {L"tr-TR", LCMAP_UPPERCASE, 0x0131,0,'I'}, /* LATIN SMALL LETTER DOTLESS I */ + {L"TR-TR", LCMAP_UPPERCASE, 0x0131,0,'I'}, /* LATIN SMALL LETTER DOTLESS I */ + {L"az-Cyrl-az", LCMAP_UPPERCASE, 0x0131,0,'I'}, /* LATIN SMALL LETTER DOTLESS I */ + {L"az-Latn-az", LCMAP_UPPERCASE, 0x0131,0,'I'}, /* LATIN SMALL LETTER DOTLESS I */ + + {L"en-US", LCMAP_LOWERCASE, 0x10418,0x10440,0,TRUE /*win7*/}, /* DESERET CAPITAL LETTER GAY */ + {L"en-US", LCMAP_UPPERCASE, 0x10431,0x10409,0,TRUE /*win7*/}, /* DESERET SMALL LETTER SHORT AH */ + }; + + if (!pLCMapStringEx) + { + win_skip("LCMapStringEx not available\n"); + return; + } + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + memset(buffer, 0, sizeof(buffer)); + len = put_utf16( src, tests[i].ch ); + ret = pLCMapStringEx(tests[i].lang, tests[i].flags, + src, len, buffer, ARRAY_SIZE(buffer), NULL, NULL, 0); + len = get_utf16( buffer, ret, &val ); + ok(ret == len, "got %d for %04x for %s\n", ret, tests[i].ch, wine_dbgstr_w(tests[i].lang)); + exp = tests[i].exp ? tests[i].exp : tests[i].ch; + ok(val == exp || broken(tests[i].broken), + "expected %04x, got %04x for %04x for %s\n", + exp, val, tests[i].ch, wine_dbgstr_w(tests[i].lang)); + + memset(buffer, 0, sizeof(buffer)); + len = put_utf16( src, tests[i].ch ); + ret = pLCMapStringEx(tests[i].lang, tests[i].flags|LCMAP_LINGUISTIC_CASING, + src, len, buffer, ARRAY_SIZE(buffer), NULL, NULL, 0); + len = get_utf16( buffer, ret, &val ); + ok(ret == len, "got %d for %04x for %s\n", ret, tests[i].ch, wine_dbgstr_w(tests[i].lang)); + exp = tests[i].exp_ling ? tests[i].exp_ling : exp; + ok(val == exp || broken(tests[i].broken), + "expected %04x, got %04x for %04x for %s\n", + exp, val, tests[i].ch, wine_dbgstr_w(tests[i].lang)); + } +} + +static void test_NLSVersion(void) +{ + static const GUID guid_null = { 0 }; + static const GUID guid_def = { 0x000000001, 0x57ee, 0x1e5c, {0x00,0xb4,0xd0,0x00,0x0b,0xb1,0xe1,0x1e}}; + static const GUID guid_fr = { 0x000000003, 0x57ee, 0x1e5c, {0x00,0xb4,0xd0,0x00,0x0b,0xb1,0xe1,0x1e}}; + static const GUID guid_ja = { 0x000000046, 0x57ee, 0x1e5c, {0x00,0xb4,0xd0,0x00,0x0b,0xb1,0xe1,0x1e}}; + BOOL ret; + NLSVERSIONINFOEX info; + + if (!pGetNLSVersion) + { + win_skip( "GetNLSVersion not available\n" ); + return; + } + + SetLastError( 0xdeadbeef ); + memset( &info, 0xcc, sizeof(info) ); + info.dwNLSVersionInfoSize = offsetof( NLSVERSIONINFO, dwEffectiveId ); + ret = pGetNLSVersion( COMPARE_STRING, MAKELANGID( LANG_FRENCH, SUBLANG_FRENCH_CANADIAN ), + (NLSVERSIONINFO *)&info ); + ok( ret, "GetNLSVersion failed err %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + memset( &info, 0xcc, sizeof(info) ); + info.dwNLSVersionInfoSize = sizeof(info); + ret = pGetNLSVersion( COMPARE_STRING, MAKELANGID( LANG_FRENCH, SUBLANG_FRENCH_CANADIAN ), + (NLSVERSIONINFO *)&info ); + ok( ret || GetLastError() == ERROR_INSUFFICIENT_BUFFER /* < Vista */, + "GetNLSVersion failed err %lu\n", GetLastError() ); + if (ret) + { + ok( info.dwEffectiveId == MAKELANGID( LANG_FRENCH, SUBLANG_FRENCH_CANADIAN ), + "wrong id %lx\n", info.dwEffectiveId ); + ok( IsEqualIID( &info.guidCustomVersion, &guid_fr ) || + broken( IsEqualIID( &info.guidCustomVersion, &guid_null )), /* <= win7 */ + "wrong guid %s\n", debugstr_guid(&info.guidCustomVersion) ); + } + + SetLastError( 0xdeadbeef ); + info.dwNLSVersionInfoSize = 8; + ret = pGetNLSVersion( COMPARE_STRING, LOCALE_USER_DEFAULT, (NLSVERSIONINFO *)&info ); + ok( !ret, "GetNLSVersion succeeded\n" ); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "wrong error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + info.dwNLSVersionInfoSize = sizeof(info); + ret = pGetNLSVersion( 2, LOCALE_USER_DEFAULT, (NLSVERSIONINFO *)&info ); + ok( !ret, "GetNLSVersion succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_FLAGS || + broken( GetLastError() == ERROR_INSUFFICIENT_BUFFER ), /* win2003 */ + "wrong error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + info.dwNLSVersionInfoSize = sizeof(info); + ret = pGetNLSVersion( COMPARE_STRING, 0xdeadbeef, (NLSVERSIONINFO *)&info ); + ok( !ret, "GetNLSVersion succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); + +#ifdef __REACTOS__ + /* HACK: ReactOS's implementation for GetNLSVersionEx is a STUB! */ + if (pGetNLSVersionEx && !is_reactos()) +#else + if (pGetNLSVersionEx) +#endif + { + SetLastError( 0xdeadbeef ); + memset( &info, 0xcc, sizeof(info) ); + info.dwNLSVersionInfoSize = sizeof(info); + ret = pGetNLSVersionEx( COMPARE_STRING, L"ja-JP", &info ); + ok( ret, "GetNLSVersionEx failed err %lu\n", GetLastError() ); + ok( info.dwEffectiveId == MAKELANGID( LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN ), + "wrong id %lx\n", info.dwEffectiveId ); + ok( IsEqualIID( &info.guidCustomVersion, &guid_ja ) || + broken( IsEqualIID( &info.guidCustomVersion, &guid_null )), /* <= win7 */ + "wrong guid %s\n", debugstr_guid(&info.guidCustomVersion) ); + trace( "version %08lx %08lx %08lx %s\n", info.dwNLSVersion, info.dwDefinedVersion, info.dwEffectiveId, + debugstr_guid(&info.guidCustomVersion) ); + + SetLastError( 0xdeadbeef ); + memset( &info, 0xcc, sizeof(info) ); + info.dwNLSVersionInfoSize = sizeof(info); + ret = pGetNLSVersionEx( COMPARE_STRING, L"fr", &info ); + ok( !ret == !pIsValidLocaleName(L"fr"), "GetNLSVersionEx doesn't match IsValidLocaleName\n" ); + if (ret) + { + ok( info.dwEffectiveId == MAKELANGID( LANG_FRENCH, SUBLANG_DEFAULT ), + "wrong id %lx\n", info.dwEffectiveId ); + ok( IsEqualIID( &info.guidCustomVersion, &guid_fr ) || + broken( IsEqualIID( &info.guidCustomVersion, &guid_null )), /* <= win7 */ + "wrong guid %s\n", debugstr_guid(&info.guidCustomVersion) ); + } + + SetLastError( 0xdeadbeef ); + info.dwNLSVersionInfoSize = sizeof(info) - 1; + ret = pGetNLSVersionEx( COMPARE_STRING, L"en-US", &info ); + ok( !ret, "GetNLSVersionEx succeeded\n" ); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "wrong error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + memset( &info, 0xcc, sizeof(info) ); + info.dwNLSVersionInfoSize = offsetof( NLSVERSIONINFO, dwEffectiveId ); + ret = pGetNLSVersionEx( COMPARE_STRING, L"en-US", &info ); + ok( ret, "GetNLSVersionEx failed err %lu\n", GetLastError() ); + ok( info.dwEffectiveId == 0xcccccccc, "wrong id %lx\n", info.dwEffectiveId ); + + SetLastError( 0xdeadbeef ); + info.dwNLSVersionInfoSize = sizeof(info); + ret = pGetNLSVersionEx( 2, L"en-US", &info ); + ok( !ret, "GetNLSVersionEx succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_FLAGS, "wrong error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + info.dwNLSVersionInfoSize = sizeof(info); + ret = pGetNLSVersionEx( COMPARE_STRING, L"foobar", &info ); + ok( !ret, "GetNLSVersionEx succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + memset( &info, 0xcc, sizeof(info) ); + info.dwNLSVersionInfoSize = sizeof(info); + ret = pGetNLSVersionEx( COMPARE_STRING, L"zz-XX", &info ); + if (!ret) ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); + ok( !ret == !pIsValidLocaleName(L"zz-XX"), "GetNLSVersionEx doesn't match IsValidLocaleName\n" ); + if (ret) + { + ok( info.dwEffectiveId == LOCALE_CUSTOM_UNSPECIFIED, "wrong id %lx\n", info.dwEffectiveId ); + ok( IsEqualIID( &info.guidCustomVersion, &guid_def ), + "wrong guid %s\n", debugstr_guid(&info.guidCustomVersion) ); + } + + SetLastError( 0xdeadbeef ); + memset( &info, 0xcc, sizeof(info) ); + info.dwNLSVersionInfoSize = sizeof(info); + ret = pGetNLSVersionEx( COMPARE_STRING, LOCALE_NAME_INVARIANT, &info ); + ok( ret, "GetNLSVersionEx failed err %lu\n", GetLastError() ); + if (ret) + { + ok( info.dwEffectiveId == LOCALE_INVARIANT, "wrong id %lx\n", info.dwEffectiveId ); + ok( IsEqualIID( &info.guidCustomVersion, &guid_def ) || + broken( IsEqualIID( &info.guidCustomVersion, &guid_null )), /* <= win7 */ + "wrong guid %s\n", debugstr_guid(&info.guidCustomVersion) ); + } + else ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); + } + else win_skip( "GetNLSVersionEx not available\n" ); + + if (pIsValidNLSVersion) + { + info.dwNLSVersionInfoSize = sizeof(info); + pGetNLSVersion( COMPARE_STRING, LOCALE_USER_DEFAULT, (NLSVERSIONINFO *)&info ); + + SetLastError( 0xdeadbeef ); + info.dwNLSVersionInfoSize = sizeof(info); + ret = pIsValidNLSVersion( COMPARE_STRING, L"ja-JP", &info ); + ok( ret, "IsValidNLSVersion failed err %lu\n", GetLastError() ); + ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + info.dwNLSVersionInfoSize = offsetof( NLSVERSIONINFO, dwEffectiveId ); + ret = pIsValidNLSVersion( COMPARE_STRING, L"en-US", &info ); + ok( ret, "IsValidNLSVersion failed err %lu\n", GetLastError() ); + ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + info.dwNLSVersionInfoSize = sizeof(info); + ret = pIsValidNLSVersion( 2, L"en-US", &info ); + ok( !ret, "IsValidNLSVersion succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + info.dwNLSVersionInfoSize = sizeof(info); + ret = pIsValidNLSVersion( COMPARE_STRING, L"foobar", &info ); + ok( !ret, "IsValidNLSVersion succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + memset( &info, 0xcc, sizeof(info) ); + info.dwNLSVersionInfoSize = sizeof(info); + ret = pIsValidNLSVersion( COMPARE_STRING, L"en-US", &info ); + ok( !ret, "IsValidNLSVersion succeeded\n" ); + ok( GetLastError() == ERROR_SUCCESS, "wrong error %lu\n", GetLastError() ); + + info.dwNLSVersionInfoSize = sizeof(info); + pGetNLSVersion( COMPARE_STRING, LOCALE_USER_DEFAULT, (NLSVERSIONINFO *)&info ); + info.dwNLSVersion++; + SetLastError( 0xdeadbeef ); + ret = pIsValidNLSVersion( COMPARE_STRING, L"en-US", &info ); + ok( ret, "IsValidNLSVersion failed err %lu\n", GetLastError() ); + ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() ); + + info.dwNLSVersion += 0x700; /* much higher ver -> surely invalid */ + SetLastError( 0xdeadbeef ); + ret = pIsValidNLSVersion( COMPARE_STRING, L"en-US", &info ); + ok( !ret, "IsValidNLSVersion succeeded\n" ); + ok( GetLastError() == 0, "wrong error %lu\n", GetLastError() ); + + info.dwNLSVersion -= 2 * 0x700; /* much lower ver -> surely invalid */ + SetLastError( 0xdeadbeef ); + ret = pIsValidNLSVersion( COMPARE_STRING, L"en-US", &info ); + ok( !ret, "IsValidNLSVersion succeeded\n" ); + ok( GetLastError() == 0, "wrong error %lu\n", GetLastError() ); + + info.dwNLSVersion += 0x700; + info.dwDefinedVersion += 0x100; + SetLastError( 0xdeadbeef ); + ret = pIsValidNLSVersion( COMPARE_STRING, L"en-US", &info ); + ok( ret, "IsValidNLSVersion failed err %lu\n", GetLastError() ); + ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() ); + + info.dwDefinedVersion -= 0x100; + info.guidCustomVersion.Data1 = 0x123; + SetLastError( 0xdeadbeef ); + ret = pIsValidNLSVersion( COMPARE_STRING, L"en-US", &info ); + ok( !ret, "IsValidNLSVersion succeeded\n" ); + ok( GetLastError() == 0, "wrong error %lu\n", GetLastError() ); + + info.guidCustomVersion = guid_null; + SetLastError( 0xdeadbeef ); + ret = pIsValidNLSVersion( COMPARE_STRING, L"en-US", &info ); + ok( ret, "IsValidNLSVersion failed err %lu\n", GetLastError() ); + ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() ); + } + else win_skip( "IsValidNLSVersion not available\n" ); + + if (pIsNLSDefinedString) + { + SetLastError( 0xdeadbeef ); + info.dwNLSVersionInfoSize = sizeof(info); + ret = pIsNLSDefinedString( COMPARE_STRING, 0, (NLSVERSIONINFO *)&info, L"A", 1 ); + if (ret) + ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() ); + else + ok( broken( GetLastError() == ERROR_INSUFFICIENT_BUFFER ), /* win7 */ + "wrong error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + info.dwNLSVersionInfoSize = sizeof(info) + 1; + ret = pIsNLSDefinedString( COMPARE_STRING, 0, (NLSVERSIONINFO *)&info, L"A", 1 ); + ok( !ret, "IsNLSDefinedString succeeded\n" ); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "wrong error %lu\n", GetLastError() ); + +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) { +#endif + SetLastError( 0xdeadbeef ); + info.dwNLSVersionInfoSize = offsetof( NLSVERSIONINFO, dwEffectiveId ); + ret = pIsNLSDefinedString( COMPARE_STRING, 0, (NLSVERSIONINFO *)&info, L"A", 1 ); + ok( ret, "IsNLSDefinedString failed err %lu\n", GetLastError() ); + ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() ); +#ifdef __REACTOS__ + } +#endif + + SetLastError( 0xdeadbeef ); + ret = pIsNLSDefinedString( 2, 0, (NLSVERSIONINFO *)&info, L"A", 1 ); + ok( !ret, "IsNLSDefinedString succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_FLAGS, "wrong error %lu\n", GetLastError() ); + +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) { +#endif + SetLastError( 0xdeadbeef ); + ret = pIsNLSDefinedString( COMPARE_STRING, 0, (NLSVERSIONINFO *)&info, L"ABC", -10 ); + ok( ret, "IsNLSDefinedString failed err %lu\n", GetLastError() ); + ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + ret = pIsNLSDefinedString( COMPARE_STRING, 0, (NLSVERSIONINFO *)&info, L"ABC", -1 ); + ok( ret, "IsNLSDefinedString failed err %lu\n", GetLastError() ); + ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + ret = pIsNLSDefinedString( COMPARE_STRING, 0, (NLSVERSIONINFO *)&info, L"\xd800", 1 ); + ok( !ret, "IsNLSDefinedString failed err %lu\n", GetLastError() ); + ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + ret = pIsNLSDefinedString( COMPARE_STRING, 0, (NLSVERSIONINFO *)&info, L"\xd800", -20 ); + ok( !ret, "IsNLSDefinedString failed err %lu\n", GetLastError() ); + ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() ); +#ifdef __REACTOS__ + } +#endif + } + else win_skip( "IsNLSDefinedString not available\n" ); +} + +static void test_locale_nls(void) +{ + NTSTATUS status; + void *addr, *addr2; + UINT *ptr; + LCID lcid; + LARGE_INTEGER size; + + if (!pNtInitializeNlsFiles || !pRtlGetLocaleFileMappingAddress) + { + win_skip( "locale.nls functions not supported\n" ); + return; + } + size.QuadPart = 0xdeadbeef; + status = pNtInitializeNlsFiles( &addr, &lcid, &size ); + ok( !status, "NtInitializeNlsFiles failed %lx\n", status ); + trace( "locale %04lx size %I64x\n", lcid, size.QuadPart ); + ptr = addr; + ok( size.QuadPart == 0xdeadbeef || size.QuadPart == ptr[4] || size.QuadPart == ptr[4] + 8, + "wrong offset %x / %I64x\n", ptr[4], size.QuadPart ); + ptr = (UINT *)((char *)addr + ptr[4]); + ok( ptr[0] == 8, "wrong offset %u\n", ptr[0] ); + ok( ptr[3] == 0x5344534e, "wrong magic %x\n", ptr[3] ); + + status = pNtInitializeNlsFiles( &addr2, &lcid, &size ); + ok( !status, "NtInitializeNlsFiles failed %lx\n", status ); + ok( addr != addr2, "got same address %p\n", addr ); + ok( !memcmp( addr, addr2, ptr[4] ), "contents differ\n" ); + status = NtUnmapViewOfSection( GetCurrentProcess(), addr ); + ok( !status, "NtUnmapViewOfSection failed %lx\n", status ); + status = NtUnmapViewOfSection( GetCurrentProcess(), addr2 ); + ok( !status, "NtUnmapViewOfSection failed %lx\n", status ); + + size.QuadPart = 0xdeadbeef; + status = pRtlGetLocaleFileMappingAddress( &addr, &lcid, &size ); + ok( !status, "NtInitializeNlsFiles failed %lx\n", status ); + ptr = addr; + ok( size.QuadPart == 0xdeadbeef || size.QuadPart == ptr[4] || size.QuadPart == ptr[4] + 8, + "wrong offset %x / %I64x\n", ptr[4], size.QuadPart ); + ptr = (UINT *)((char *)addr + ptr[4]); + ok( ptr[0] == 8, "wrong offset %u\n", ptr[0] ); + ok( ptr[3] == 0x5344534e, "wrong magic %x\n", ptr[3] ); + + /* RtlGetLocaleFileMappingAddress caches the pointer */ + status = pRtlGetLocaleFileMappingAddress( &addr2, &lcid, &size ); + ok( !status, "NtInitializeNlsFiles failed %lx\n", status ); + ok( addr == addr2, "got different address %p / %p\n", addr, addr2 ); +} + +static void test_geo_name(void) +{ + WCHAR reg_name[32], buf[32], set_name[32], nation[32], region[32]; + BOOL have_name = FALSE, have_region = FALSE, have_nation = FALSE; + DWORD size, type, name_size; + LSTATUS status; + GEOID geoid; + BOOL bret; + HKEY key; + int ret; + + if (!pSetUserGeoName || !pGetUserDefaultGeoName) + { + win_skip("GetUserDefaultGeoName / SetUserGeoName is not available, skipping test.\n"); + return; + } + + status = RegOpenKeyExA(HKEY_CURRENT_USER, "Control Panel\\International\\Geo", 0, KEY_READ | KEY_WRITE, &key); + ok(status == ERROR_SUCCESS, "Got unexpected status %#lx.\n", status); + + size = sizeof(reg_name); + if (!RegQueryValueExW(key, L"Name", NULL, &type, (BYTE *)reg_name, &size)) + have_name = TRUE; + + lstrcpyW(buf, L"QQ"); + RegSetValueExW(key, L"Name", 0, REG_SZ, (BYTE *)buf, (lstrlenW(buf) + 1) * sizeof(WCHAR)); + + size = sizeof(reg_name); + if ((ret = pGetUserDefaultGeoName(NULL, 0)) == 1) + { + if (have_name) + { + status = RegSetValueExW(key, L"Name", 0, REG_SZ, (BYTE *)reg_name, (lstrlenW(reg_name) + 1) * sizeof(*reg_name)); + ok(status == ERROR_SUCCESS, "Got unexpected status %#lx.\n", status); + } + else + { + RegDeleteValueW(key, L"Name"); + } + win_skip("Geo names are not available, skipping test.\n"); + return; + } + + size = sizeof(nation); + if (!RegQueryValueExW(key, L"Nation", NULL, &type, (BYTE *)nation, &size)) + have_nation = TRUE; + size = sizeof(region); + if (!RegQueryValueExW(key, L"Region", NULL, &type, (BYTE *)region, &size)) + have_region = TRUE; + + SetLastError(0xdeadbeef); + ret = pGetUserDefaultGeoName(NULL, 0); + ok((ret == 3 || ret == 4) && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError()); + name_size = ret; + + SetLastError(0xdeadbeef); + ret = pGetUserDefaultGeoName(buf, 0); + ok(ret >= 3 && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError()); + + SetLastError(0xdeadbeef); + ret = pGetUserDefaultGeoName(buf, 2); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError()); + + SetLastError(0xdeadbeef); + ret = pGetUserDefaultGeoName(NULL, 1); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError()); + + SetLastError(0xdeadbeef); + ret = pGetUserDefaultGeoName(NULL, name_size); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError()); + + SetLastError(0xdeadbeef); + ret = pGetUserDefaultGeoName(buf, name_size); + ok(ret == name_size && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError()); + ok(!lstrcmpW(buf, L"QQ"), "Got unexpected name %s.\n", wine_dbgstr_w(buf)); + + SetLastError(0xdeadbeef); + bret = pSetUserGeoName(NULL); + ok(!bret && GetLastError() == ERROR_INVALID_PARAMETER, "Got unexpected bret %#x, GetLastError() %lu.\n", bret, GetLastError()); + + lstrcpyW(set_name, L"QQ"); + SetLastError(0xdeadbeef); + bret = pSetUserGeoName(set_name); + ok(!bret && GetLastError() == ERROR_INVALID_PARAMETER, "Got unexpected bret %#x, GetLastError() %lu.\n", bret, GetLastError()); + + lstrcpyW(set_name, L"Xx"); + SetLastError(0xdeadbeef); + bret = pSetUserGeoName(set_name); + ok((bret && GetLastError() == 0xdeadbeef) || broken(bret && GetLastError() == 0), + "Got unexpected bret %#x, GetLastError() %lu.\n", bret, GetLastError()); + + SetLastError(0xdeadbeef); + ret = pGetUserDefaultGeoName(buf, ARRAY_SIZE(buf)); + ok(ret == 4 && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError()); + ok(!lstrcmpW(buf, L"001"), "Got unexpected name %s.\n", wine_dbgstr_w(buf)); + geoid = GetUserGeoID(GEOCLASS_REGION); + ok(geoid == 39070, "Got unexpected geoid %lu.\n", geoid); + size = sizeof(buf); + status = RegQueryValueExW(key, L"Name", NULL, &type, (BYTE *)buf, &size); + ok(status == ERROR_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(type == REG_SZ, "Got unexpected type %#lx.\n", type); + ok(!lstrcmpW(buf, L"001"), "Got unexpected name %s.\n", wine_dbgstr_w(buf)); + + lstrcpyW(set_name, L"ar"); + SetLastError(0xdeadbeef); + bret = pSetUserGeoName(set_name); + ok((bret && GetLastError() == 0xdeadbeef) || broken(bret && GetLastError() == 0), + "Got unexpected bret %#x, GetLastError() %lu.\n", bret, GetLastError()); + ret = pGetUserDefaultGeoName(buf, ARRAY_SIZE(buf)); + ok((ret == 3 && GetLastError() == 0xdeadbeef) || broken(ret == 3 && GetLastError() == 0), + "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError()); + ok(!lstrcmpW(buf, L"AR"), "Got unexpected name %s.\n", wine_dbgstr_w(buf)); + geoid = GetUserGeoID(GEOCLASS_NATION); + ok(geoid == 11, "Got unexpected geoid %lu.\n", geoid); + + lstrcpyW(set_name, L"150"); + SetLastError(0xdeadbeef); + bret = pSetUserGeoName(set_name); + ok((bret && GetLastError() == 0xdeadbeef) || broken(bret && GetLastError() == 0), + "Got unexpected bret %#x, GetLastError() %lu.\n", bret, GetLastError()); + ret = pGetUserDefaultGeoName(buf, ARRAY_SIZE(buf)); + ok((ret == 4 && GetLastError() == 0xdeadbeef) || broken(ret == 4 && GetLastError() == 0), + "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError()); + ok(!lstrcmpW(buf, L"150"), "Got unexpected name %s.\n", wine_dbgstr_w(buf)); + geoid = GetUserGeoID(GEOCLASS_NATION); + ok(geoid == 11, "Got unexpected geoid %lu.\n", geoid); + + lstrcpyW(set_name, L"150a"); + SetLastError(0xdeadbeef); + bret = pSetUserGeoName(set_name); + ok(!bret && GetLastError() == ERROR_INVALID_PARAMETER, "Got unexpected bret %#x, GetLastError() %lu.\n", bret, GetLastError()); + + bret = SetUserGeoID(21242); + ok(bret, "Got unexpected bret %#x, GetLastError() %lu.\n", bret, GetLastError()); + SetLastError(0xdeadbeef); + ret = pGetUserDefaultGeoName(buf, ARRAY_SIZE(buf)); + ok(ret == 3 && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError()); + ok(!lstrcmpW(buf, L"XX"), "Got unexpected name %s.\n", wine_dbgstr_w(buf)); + + bret = SetUserGeoID(42483); + ok(bret, "Got unexpected bret %#x, GetLastError() %lu.\n", bret, GetLastError()); + SetLastError(0xdeadbeef); + ret = pGetUserDefaultGeoName(buf, ARRAY_SIZE(buf)); + ok(ret == 4 && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError()); + ok(!lstrcmpW(buf, L"011"), "Got unexpected name %s.\n", wine_dbgstr_w(buf)); + + bret = SetUserGeoID(333); + ok(bret, "Got unexpected bret %#x, GetLastError() %lu.\n", bret, GetLastError()); + SetLastError(0xdeadbeef); + ret = pGetUserDefaultGeoName(buf, ARRAY_SIZE(buf)); + ok(ret == 3 && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError()); + ok(!lstrcmpW(buf, L"AN"), "Got unexpected name %s.\n", wine_dbgstr_w(buf)); + + RegDeleteValueW(key, L"Name"); + RegDeleteValueW(key, L"Region"); + lstrcpyW(buf, L"124"); + status = RegSetValueExW(key, L"Nation", 0, REG_SZ, (BYTE *)buf, (lstrlenW(buf) + 1) * sizeof(*buf)); + ok(status == ERROR_SUCCESS, "Got unexpected status %#lx.\n", status); + SetLastError(0xdeadbeef); + ret = pGetUserDefaultGeoName(buf, ARRAY_SIZE(buf)); + ok(ret == 3 && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError()); + ok(!lstrcmpW(buf, L"JM"), "Got unexpected name %s.\n", wine_dbgstr_w(buf)); + + lstrcpyW(buf, L"333"); + status = RegSetValueExW(key, L"Region", 0, REG_SZ, (BYTE *)buf, (lstrlenW(buf) + 1) * sizeof(*buf)); + ok(status == ERROR_SUCCESS, "Got unexpected status %#lx.\n", status); + SetLastError(0xdeadbeef); + ret = pGetUserDefaultGeoName(buf, ARRAY_SIZE(buf)); + ok(ret == 3 && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError()); + ok(!lstrcmpW(buf, L"JM"), "Got unexpected name %s.\n", wine_dbgstr_w(buf)); + + RegDeleteValueW(key, L"Nation"); + SetLastError(0xdeadbeef); + ret = pGetUserDefaultGeoName(buf, ARRAY_SIZE(buf)); + ok(ret == 4 && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret, GetLastError()); + ok(!lstrcmpW(buf, L"001"), "Got unexpected name %s.\n", wine_dbgstr_w(buf)); + + /* Restore user geo data. */ + if (have_name) + { + status = RegSetValueExW(key, L"Name", 0, REG_SZ, (BYTE *)reg_name, (lstrlenW(reg_name) + 1) * sizeof(*reg_name)); + ok(status == ERROR_SUCCESS, "Got unexpected status %#lx.\n", status); + } + else + { + RegDeleteValueW(key, L"Name"); + } + if (have_nation) + { + status = RegSetValueExW(key, L"Nation", 0, REG_SZ, (BYTE *)nation, (lstrlenW(nation) + 1) * sizeof(*nation)); + ok(status == ERROR_SUCCESS, "Got unexpected status %#lx.\n", status); + } + else + { + RegDeleteValueW(key, L"Nation"); + } + if (have_region) + { + status = RegSetValueExW(key, L"Region", 0, REG_SZ, (BYTE *)region, (lstrlenW(region) + 1) * sizeof(*region)); + ok(status == ERROR_SUCCESS, "Got unexpected status %#lx.\n", status); + } + else + { + RegDeleteValueW(key, L"Region"); + } + + RegCloseKey(key); +} + +static const LCID locales_with_optional_calendars[] = { + MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT), + MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_LEBANON), SORT_DEFAULT), + MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_EGYPT), SORT_DEFAULT), + MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_ALGERIA), SORT_DEFAULT), + MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_BAHRAIN), SORT_DEFAULT), + MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_IRAQ), SORT_DEFAULT), + MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_JORDAN), SORT_DEFAULT), + MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_KUWAIT), SORT_DEFAULT), + MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_LIBYA), SORT_DEFAULT), + MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_MOROCCO), SORT_DEFAULT), + MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_OMAN), SORT_DEFAULT), + MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_QATAR), SORT_DEFAULT), + MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SYRIA), SORT_DEFAULT), + MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_TUNISIA), SORT_DEFAULT), + MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_UAE), SORT_DEFAULT), + MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_YEMEN), SORT_DEFAULT), + MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL), SORT_DEFAULT), + MAKELCID(MAKELANGID(LANG_DIVEHI, SUBLANG_DEFAULT), SORT_DEFAULT), + MAKELCID(MAKELANGID(LANG_PERSIAN, SUBLANG_DEFAULT), SORT_DEFAULT), + MAKELCID(MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT), SORT_DEFAULT), + MAKELCID(MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT), SORT_DEFAULT), + MAKELCID(MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN), SORT_DEFAULT), + MAKELCID(MAKELANGID(LANG_THAI, SUBLANG_DEFAULT), SORT_DEFAULT), + MAKELCID(MAKELANGID(LANG_URDU, SUBLANG_URDU_PAKISTAN), SORT_DEFAULT) +}; + +static BOOL CALLBACK calinfo_procA(LPSTR calinfo) +{ + char *end; + int val = strtoul( calinfo, &end, 10 ); + ok( !*end, "wrong value %s\n", debugstr_a(calinfo) ); + ok(val >= CAL_GREGORIAN && val <= CAL_UMALQURA, "got %d\n", val); + return TRUE; +} + +static void test_EnumCalendarInfoA(void) +{ + BOOL ret; + INT i; + + ret = EnumCalendarInfoA( calinfo_procA, LOCALE_USER_DEFAULT, ENUM_ALL_CALENDARS, CAL_ICALINTVALUE ); + ok( ret, "EnumCalendarInfoA for user default locale failed: %lu\n", GetLastError() ); + + ret = EnumCalendarInfoA( calinfo_procA, LOCALE_USER_DEFAULT, ENUM_ALL_CALENDARS, + CAL_RETURN_NUMBER | CAL_ICALINTVALUE ); + ok( ret, "EnumCalendarInfoA for user default locale failed: %lu\n", GetLastError() ); + + for (i = 0; i < ARRAY_SIZE( locales_with_optional_calendars ); i++) + { + LCID lcid = locales_with_optional_calendars[i]; + ret = EnumCalendarInfoA( calinfo_procA, lcid, ENUM_ALL_CALENDARS, + CAL_RETURN_NUMBER | CAL_ICALINTVALUE ); + ok( ret || broken( GetLastError() == ERROR_INVALID_FLAGS ) /* no locale */, + "EnumCalendarInfoA for LCID %#06lx failed: %lu\n", lcid, GetLastError() ); + } +} + +static BOOL CALLBACK calinfo_procW(LPWSTR calinfo) +{ + WCHAR *end; + int val = wcstoul( calinfo, &end, 10 ); + ok( !*end, "wrong value %s\n", debugstr_w(calinfo) ); + ok(val >= CAL_GREGORIAN && val <= CAL_UMALQURA, "got %d\n", val); + return TRUE; +} + +static void test_EnumCalendarInfoW(void) +{ + BOOL ret; + INT i; + + ret = EnumCalendarInfoW( calinfo_procW, LOCALE_USER_DEFAULT, ENUM_ALL_CALENDARS, CAL_ICALINTVALUE ); + ok( ret, "EnumCalendarInfoW for user default locale failed: %lu\n", GetLastError() ); + + ret = EnumCalendarInfoW( calinfo_procW, LOCALE_USER_DEFAULT, ENUM_ALL_CALENDARS, + CAL_RETURN_NUMBER | CAL_ICALINTVALUE ); + ok( ret, "EnumCalendarInfoW for user default locale failed: %lu\n", GetLastError() ); + + for (i = 0; i < ARRAY_SIZE( locales_with_optional_calendars ); i++) + { + LCID lcid = locales_with_optional_calendars[i]; + ret = EnumCalendarInfoW( calinfo_procW, lcid, ENUM_ALL_CALENDARS, + CAL_RETURN_NUMBER | CAL_ICALINTVALUE ); + ok( ret || broken( GetLastError() == ERROR_INVALID_FLAGS ) /* no locale */, + "EnumCalendarInfoW for LCID %#06lx failed: %lu\n", lcid, GetLastError() ); + } +} + +static BOOL CALLBACK calinfoex_procA(LPSTR calinfo, LCID calid) +{ + char *end; + int val = strtoul( calinfo, &end, 10 ); + ok( !*end, "wrong value %s\n", debugstr_a(calinfo) ); + ok(val >= CAL_GREGORIAN && val <= CAL_UMALQURA, "got %d\n", val); + return TRUE; +} + +static void test_EnumCalendarInfoExA(void) +{ + BOOL ret; + INT i; + + ret = EnumCalendarInfoExA( calinfoex_procA, LOCALE_USER_DEFAULT, ENUM_ALL_CALENDARS, CAL_ICALINTVALUE ); + ok( ret, "EnumCalendarInfoExA for user default locale failed: %lu\n", GetLastError() ); + + ret = EnumCalendarInfoExA( calinfoex_procA, LOCALE_USER_DEFAULT, ENUM_ALL_CALENDARS, + CAL_RETURN_NUMBER | CAL_ICALINTVALUE ); + ok( ret, "EnumCalendarInfoExA for user default locale failed: %lu\n", GetLastError() ); + + for (i = 0; i < ARRAY_SIZE( locales_with_optional_calendars ); i++) + { + LCID lcid = locales_with_optional_calendars[i]; + ret = EnumCalendarInfoExA( calinfoex_procA, lcid, ENUM_ALL_CALENDARS, + CAL_RETURN_NUMBER | CAL_ICALINTVALUE ); + ok( ret || broken( GetLastError() == ERROR_INVALID_FLAGS ) /* no locale */, + "EnumCalendarInfoExA for LCID %#06lx failed: %lu\n", lcid, GetLastError() ); + } +} + +static BOOL CALLBACK calinfoex_procW(LPWSTR calinfo, LCID calid) +{ + WCHAR *end; + int val = wcstoul( calinfo, &end, 10 ); + ok( !*end, "wrong value %s\n", debugstr_w(calinfo) ); + ok(val >= CAL_GREGORIAN && val <= CAL_UMALQURA, "got %d\n", val); + return TRUE; +} + +static void test_EnumCalendarInfoExW(void) +{ + BOOL ret; + INT i; + + ret = EnumCalendarInfoExW( calinfoex_procW, LOCALE_USER_DEFAULT, ENUM_ALL_CALENDARS, CAL_ICALINTVALUE ); + ok( ret, "EnumCalendarInfoExW for user default locale failed: %lu\n", GetLastError() ); + + ret = EnumCalendarInfoExW( calinfoex_procW, LOCALE_USER_DEFAULT, ENUM_ALL_CALENDARS, + CAL_RETURN_NUMBER | CAL_ICALINTVALUE ); + ok( ret, "EnumCalendarInfoExW for user default locale failed: %lu\n", GetLastError() ); + + for (i = 0; i < ARRAY_SIZE( locales_with_optional_calendars ); i++) + { + LCID lcid = locales_with_optional_calendars[i]; + ret = EnumCalendarInfoExW( calinfoex_procW, lcid, ENUM_ALL_CALENDARS, + CAL_RETURN_NUMBER | CAL_ICALINTVALUE ); + ok( ret || broken( GetLastError() == ERROR_INVALID_FLAGS ) /* no locale */, + "EnumCalendarInfoExW for LCID %#06lx failed: %lu\n", lcid, GetLastError() ); + } +} + +/* Generate sort keys for a list of Unicode code points. + * Possible source files: + * The Unicode collation test suite: https://www.unicode.org/Public/UCA/latest/CollationTest.zip + * The list of supported char compressions: winedump nls/sortdefault.nls | grep \\-\> + */ +static void dump_sortkeys( char *argv[] ) +{ + WCHAR data[128]; + WCHAR locale[LOCALE_NAME_MAX_LENGTH]; + BYTE key[256]; + unsigned int i, val, pos, res, flags = 0; + char *p, *end, buffer[1024]; + FILE *f = fopen( argv[1], "r" ); + + locale[0] = 0; + if (argv[2]) + { + MultiByteToWideChar( CP_ACP, 0, argv[2], -1, locale, LOCALE_NAME_MAX_LENGTH ); + if (argv[3]) flags = strtoul( argv[3], NULL, 0 ); + } + + if (!f) + { + fprintf( stderr, "cannot open %s\n", argv[1] ); + return; + } + while (fgets( buffer, sizeof(buffer), f )) + { + if (buffer[0] && buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = 0; + p = buffer; + while (*p == ' ' || *p == '\t') p++; + if (*p == '#') continue; + pos = 0; + while (*p && *p != ';' && *p != '-') + { + val = strtoul( p, &end, 16 ); + if (end == p) break; + if (val >= 0x10000) + { + data[pos++] = 0xd800 | (val >> 10); + data[pos++] = 0xdc00 | (val & 0x3ff); + } + else data[pos++] = val; + p = end; + while (*p == ' ' || *p == '\t') p++; + } + *p = 0; +#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600 + res = LCMapStringEx( locale, flags | LCMAP_SORTKEY, data, pos, + (WCHAR *)key, sizeof(key), NULL, NULL, 0 ); + printf( "%s:", buffer ); + for (i = 0; i < res; i++) printf( " %02x", key[i] ); + printf( "\n" ); +#endif + } + fclose( f ); +} + +static BOOL CALLBACK EnumDateFormatsExEx_proc(LPWSTR date_format_string, CALID calendar_id, LPARAM lp) +{ + return TRUE; +} + +static void test_EnumDateFormatsExEx(void) +{ +#if defined(__REACTOS__) && DLL_EXPORT_VERSION < 0x600 + skip("Cannot build test_EnumDateFormatsExEx() unless DLL_EXPORT_VERSION >= 0x600.\n"); +#else + DWORD error; + BOOL ret; + + /* Invalid locale name */ + ret = EnumDateFormatsExEx(EnumDateFormatsExEx_proc, L"deadbeef", DATE_SHORTDATE, 0); + error = GetLastError(); + ok(!ret, "EnumDateFormatsExEx succeeded.\n"); + ok(error == ERROR_INVALID_PARAMETER, "Got unexpected error %#lx.\n", error); + + /* yi-Hebr is missing on versions < Win10 */ + /* Running the following tests will cause other tests that use LOCALE_CUSTOM_UNSPECIFIED to + * report yi-Hebr instead the default locale on Windows 10. So run them at the end */ + ret = EnumDateFormatsExEx(EnumDateFormatsExEx_proc, L"yi-Hebr", DATE_SHORTDATE, 0); + error = GetLastError(); + ok(ret || (!ret && error == ERROR_INVALID_PARAMETER), /* < Win10 */ + "EnumDateFormatsExEx failed, error %#lx.\n", error); + + ret = EnumDateFormatsExEx(EnumDateFormatsExEx_proc, L"yi-Hebr", DATE_LONGDATE, 0); + error = GetLastError(); + ok(ret || (!ret && error == ERROR_INVALID_PARAMETER), /* < Win10 */ + "EnumDateFormatsExEx failed, error %#lx.\n", error); +#endif +} + START_TEST(locale) { + char **argv; + int argc = winetest_get_mainargs( &argv ); + InitFunctionPointers(); + if (argc >= 4) + { + if (!strcmp( argv[2], "sortkeys" )) + { + dump_sortkeys( argv + 2 ); + return; + } + } + test_EnumTimeFormatsA(); test_EnumTimeFormatsW(); test_EnumDateFormatsA(); @@ -5358,16 +8937,17 @@ START_TEST(locale) test_FoldStringW(); test_ConvertDefaultLocale(); test_EnumSystemLanguageGroupsA(); + test_EnumSystemLocalesA(); + test_EnumSystemLocalesW(); test_EnumSystemLocalesEx(); test_EnumLanguageGroupLocalesA(); - test_SetLocaleInfoA(); + test_SetLocaleInfo(); test_EnumUILanguageA(); test_GetCPInfo(); test_GetStringTypeW(); - test_IdnToNameprepUnicode(); - test_IdnToAscii(); - test_IdnToUnicode(); + test_Idn(); test_IsValidLocaleName(); + test_ResolveLocaleName(); test_CompareStringOrdinal(); test_GetGeoInfo(); test_EnumSystemGeoID(); @@ -5375,5 +8955,21 @@ START_TEST(locale) test_GetSystemPreferredUILanguages(); test_GetThreadPreferredUILanguages(); test_GetUserPreferredUILanguages(); + test_FindNLSStringEx(); + test_FindStringOrdinal(); + test_SetThreadUILanguage(); + test_NormalizeString(); + test_SpecialCasing(); + test_NLSVersion(); + test_locale_nls(); + test_geo_name(); test_sorting(); + test_unicode_sorting(); + test_EnumCalendarInfoA(); + test_EnumCalendarInfoW(); + test_EnumCalendarInfoExA(); + test_EnumCalendarInfoExW(); + + /* Run this test at the end */ + test_EnumDateFormatsExEx(); } diff --git a/modules/rostests/winetests/kernel32/mailslot.c b/modules/rostests/winetests/kernel32/mailslot.c index 27258247287..28a1f1ea546 100644 --- a/modules/rostests/winetests/kernel32/mailslot.c +++ b/modules/rostests/winetests/kernel32/mailslot.c @@ -22,18 +22,27 @@ #include #include +#include +#define WIN32_NO_STATUS #include #include - +#include #include "wine/test.h" +#ifdef __REACTOS__ +#include "winehacks.h" +#endif static const char szmspath[] = "\\\\.\\mailslot\\wine_mailslot_test"; static int mailslot_test(void) { + UNICODE_STRING nt_path = RTL_CONSTANT_STRING( L"\\??\\MAILSLOT\\wine_mailslot_test" ); HANDLE hSlot, hSlot2, hWriter, hWriter2; unsigned char buffer[16]; DWORD count, dwMax, dwNext, dwMsgCount, dwTimeout; + FILE_MAILSLOT_QUERY_INFORMATION info; + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK io; BOOL ret; /* sanity check on GetMailslotInfo */ @@ -81,38 +90,51 @@ static int mailslot_test(void) SetLastError(0xdeadbeef); ret = ReadFile(INVALID_HANDLE_VALUE, buffer, 0, &count, NULL); ok(!ret, "ReadFile should fail\n"); - ok(GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError()); - ok(count == 0, "expected 0, got %u\n", count); + ok(GetLastError() == ERROR_INVALID_HANDLE, "wrong error %lu\n", GetLastError()); + ok(count == 0, "expected 0, got %lu\n", count); count = 0xdeadbeef; SetLastError(0xdeadbeef); ret = ReadFile(hSlot, buffer, 0, &count, NULL); ok(!ret, "ReadFile should fail\n"); -todo_wine - ok(GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError()); - ok(count == 0, "expected 0, got %u\n", count); + ok(GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %lu\n", GetLastError()); + ok(count == 0, "expected 0, got %lu\n", count); count = 0; memset(buffer, 0, sizeof buffer); ret = ReadFile( hSlot, buffer, sizeof buffer, &count, NULL); ok( !ret, "slot read\n"); - if (!ret) ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); - else ok( count == 0, "wrong count %u\n", count ); + if (!ret) ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %lu\n", GetLastError() ); + else ok( count == 0, "wrong count %lu\n", count ); ok( !WriteFile( hSlot, buffer, sizeof buffer, &count, NULL), "slot write\n"); - ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %lu\n", GetLastError() ); + + io.Status = 0xdeadbeef; + io.Information = 0xdeadbeef; + ret = NtReadFile( hSlot, NULL, NULL, NULL, &io, buffer, sizeof(buffer), NULL, NULL ); + ok( ret == STATUS_IO_TIMEOUT, "got %#x\n", ret ); + ok( io.Status == 0xdeadbeef, "got status %#lx\n", io.Status ); + ok( io.Information == 0xdeadbeef, "got size %Iu\n", io.Information ); + + io.Status = 0xdeadbeef; + io.Information = 0xdeadbeef; + ret = NtWriteFile( hSlot, NULL, NULL, NULL, &io, buffer, sizeof(buffer), NULL, NULL ); + ok( ret == STATUS_ACCESS_DENIED, "got %#x\n", ret ); + ok( io.Status == 0xdeadbeef, "got status %#lx\n", io.Status ); + ok( io.Information == 0xdeadbeef, "got size %Iu\n", io.Information ); /* now try and open the client, but with the wrong sharing mode */ hWriter = CreateFileA(szmspath, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); ok( hWriter != INVALID_HANDLE_VALUE /* vista */ || GetLastError() == ERROR_SHARING_VIOLATION, - "error should be ERROR_SHARING_VIOLATION got %p / %u\n", hWriter, GetLastError()); + "error should be ERROR_SHARING_VIOLATION got %p / %lu\n", hWriter, GetLastError()); if (hWriter != INVALID_HANDLE_VALUE) CloseHandle( hWriter ); /* now open the client with the correct sharing mode */ hWriter = CreateFileA(szmspath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - ok( hWriter != INVALID_HANDLE_VALUE, "existing mailslot err %u\n", GetLastError()); + ok( hWriter != INVALID_HANDLE_VALUE, "existing mailslot err %lu\n", GetLastError()); /* * opening a client should make no difference to @@ -120,11 +142,11 @@ todo_wine */ ret = ReadFile( hSlot, buffer, sizeof buffer/2, &count, NULL); ok( !ret, "slot read\n"); - if (!ret) ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); - else ok( count == 0, "wrong count %u\n", count ); + if (!ret) ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %lu\n", GetLastError() ); + else ok( count == 0, "wrong count %lu\n", count ); ok( !WriteFile( hSlot, buffer, sizeof buffer/2, &count, NULL), "slot write\n"); - ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %lu\n", GetLastError() ); /* * we can't read from this client, @@ -133,13 +155,20 @@ todo_wine ok( !ReadFile( hWriter, buffer, sizeof buffer/2, &count, NULL), "can read client\n"); ok( GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_ACCESS_DENIED, - "wrong error %u\n", GetLastError() ); + "wrong error %lu\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"); ok( GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_ACCESS_DENIED, - "wrong error %u\n", GetLastError() ); + "wrong error %lu\n", GetLastError() ); + + io.Status = 0xdeadbeef; + io.Information = 0xdeadbeef; + ret = NtReadFile( hWriter, NULL, NULL, NULL, &io, buffer, sizeof(buffer), NULL, NULL ); + todo_wine ok( ret == STATUS_INVALID_PARAMETER, "got %#x\n", ret ); + ok( io.Status == 0xdeadbeef, "got status %#lx\n", io.Status ); + ok( io.Information == 0xdeadbeef, "got size %Iu\n", io.Information ); /* * seeing as there's something in the slot, @@ -152,8 +181,8 @@ todo_wine /* but not again */ ret = ReadFile( hSlot, buffer, sizeof buffer, &count, NULL); ok( !ret, "slot read\n"); - if (!ret) ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); - else ok( count == 0, "wrong count %u\n", count ); + if (!ret) ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %lu\n", GetLastError() ); + else ok( count == 0, "wrong count %lu\n", count ); /* now try open another writer... should fail */ hWriter2 = CreateFileA(szmspath, GENERIC_READ|GENERIC_WRITE, @@ -214,8 +243,8 @@ todo_wine /* check there's still no data */ ret = ReadFile( hSlot, buffer, sizeof buffer, &count, NULL); ok( !ret, "slot read\n"); - if (!ret) ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); - else ok( count == 0, "wrong count %u\n", count ); + if (!ret) ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %lu\n", GetLastError() ); + else ok( count == 0, "wrong count %lu\n", count ); /* write two messages */ buffer[0] = 'a'; @@ -237,9 +266,7 @@ todo_wine ok( GetMailslotInfo( hSlot, NULL, &dwNext, &dwMsgCount, NULL ), "getmailslotinfo failed\n"); ok( dwNext == 1, "dwNext incorrect\n"); - todo_wine { ok( dwMsgCount == 2, "dwMsgCount incorrect\n"); - } /* write a 3rd message with zero size */ ok( WriteFile( hWriter2, buffer, 0, &count, NULL), "3rd write failed\n"); @@ -249,8 +276,7 @@ todo_wine ok( GetMailslotInfo( hSlot, NULL, &dwNext, &dwMsgCount, NULL ), "getmailslotinfo failed\n"); ok( dwNext == 1, "dwNext incorrect\n"); - todo_wine - ok( dwMsgCount == 3, "dwMsgCount incorrect %u\n", dwMsgCount); + ok( dwMsgCount == 3, "dwMsgCount incorrect %lu\n", dwMsgCount); buffer[0]=buffer[1]=0; @@ -268,9 +294,7 @@ todo_wine ok( GetMailslotInfo( hSlot, NULL, &dwNext, &dwMsgCount, NULL ), "getmailslotinfo failed\n"); ok( dwNext == 2, "dwNext incorrect\n"); - todo_wine { - ok( dwMsgCount == 2, "dwMsgCount incorrect %u\n", dwMsgCount); - } + ok( dwMsgCount == 2, "dwMsgCount incorrect %lu\n", dwMsgCount); /* read the second message */ ok( ReadFile( hSlot, buffer, sizeof buffer, &count, NULL), @@ -282,16 +306,12 @@ todo_wine dwNext = dwMsgCount = 0; ok( GetMailslotInfo( hSlot, NULL, &dwNext, &dwMsgCount, NULL ), "getmailslotinfo failed\n"); - ok( dwNext == 0, "dwNext incorrect %u\n", dwNext); - todo_wine { - ok( dwMsgCount == 1, "dwMsgCount incorrect %u\n", dwMsgCount); - } + ok( dwNext == 0, "dwNext incorrect %lu\n", dwNext); + ok( dwMsgCount == 1, "dwMsgCount incorrect %lu\n", dwMsgCount); /* read the 3rd (zero length) message */ - todo_wine { ok( ReadFile( hSlot, buffer, sizeof buffer, &count, NULL), "3rd slot read failed\n"); - } ok( count == 0, "failed to get 3rd message\n"); /* @@ -307,8 +327,50 @@ todo_wine /* check that reads fail */ ret = ReadFile( hSlot, buffer, sizeof buffer, &count, NULL); ok( !ret, "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 ); + if (!ret) ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %lu\n", GetLastError() ); + else ok( count == 0, "wrong count %lu\n", count ); + + /* Try to perform a partial read. */ + count = 0; + ret = WriteFile( hWriter, buffer, 2, &count, NULL ); + ok( ret, "got %d\n", ret ); + ok( count == 2, "got count %lu\n", count ); + + io.Status = 0xdeadbeef; + io.Information = 0xdeadbeef; + ret = NtReadFile( hSlot, NULL, NULL, NULL, &io, buffer, 1, NULL, NULL ); + ok( ret == STATUS_BUFFER_TOO_SMALL, "got %#x\n", ret ); + ok( io.Status == 0xdeadbeef, "got status %#lx\n", io.Status ); + ok( io.Information == 0xdeadbeef, "got size %Iu\n", io.Information ); + + io.Status = 0xdeadbeef; + io.Information = 0xdeadbeef; + memset( &info, 0xcc, sizeof(info) ); + ret = NtQueryInformationFile( hSlot, &io, &info, sizeof(info), FileMailslotQueryInformation ); + ok( ret == STATUS_SUCCESS, "got %#x\n", ret ); + ok( io.Status == STATUS_SUCCESS, "got status %#lx\n", io.Status ); + ok( io.Information == sizeof(info), "got size %Iu\n", io.Information ); + ok( !info.MaximumMessageSize, "got maximum size %lu\n", info.MaximumMessageSize ); + ok( !info.MailslotQuota, "got quota %lu\n", info.MailslotQuota ); + ok( info.NextMessageSize == 2, "got next size %lu\n", info.NextMessageSize ); + ok( info.MessagesAvailable == 1, "got message count %lu\n", info.MessagesAvailable ); + ok( !info.ReadTimeout.QuadPart, "got timeout %I64u\n", info.ReadTimeout.QuadPart ); + + io.Status = 0xdeadbeef; + io.Information = 0xdeadbeef; + memset( &info, 0xcc, sizeof(info) ); + ret = NtQueryInformationFile( hWriter, &io, &info, sizeof(info), FileMailslotQueryInformation ); + todo_wine ok( ret == STATUS_SUCCESS || ret == STATUS_INVALID_PARAMETER /* Win < 8 */, "got %#x\n", ret ); + if (ret == STATUS_SUCCESS) + { + ok( io.Status == STATUS_SUCCESS, "got status %#lx\n", io.Status ); + ok( io.Information == sizeof(info), "got size %Iu\n", io.Information ); + ok( !info.MaximumMessageSize, "got maximum size %lu\n", info.MaximumMessageSize ); + ok( !info.MailslotQuota, "got quota %lu\n", info.MailslotQuota ); + ok( info.NextMessageSize == 2, "got next size %lu\n", info.NextMessageSize ); + ok( info.MessagesAvailable == 1, "got message count %lu\n", info.MessagesAvailable ); + ok( !info.ReadTimeout.QuadPart, "got timeout %I64u\n", info.ReadTimeout.QuadPart ); + } /* finally close the mailslot and its client */ ok( CloseHandle( hWriter2 ), "closing 2nd client\n"); @@ -322,12 +384,68 @@ todo_wine 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, "wrong error %lu\n", GetLastError() ); dwTimeout = GetTickCount() - dwTimeout; - ros_skip_flaky - ok( dwTimeout >= 990, "timeout too short %u\n", dwTimeout ); + ok( dwTimeout >= 900, "timeout too short %lu\n", dwTimeout ); ok( CloseHandle( hSlot ), "closing the mailslot\n"); + InitializeObjectAttributes( &attr, &nt_path, 0, NULL, NULL ); + ret = NtCreateMailslotFile( &hSlot, GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, &attr, &io, 0, 0, 0, NULL ); + ok( !ret, "got %#x\n", ret ); + + io.Status = 0xdeadbeef; + io.Information = 0xdeadbeef; + ret = NtWriteFile( hSlot, NULL, NULL, NULL, &io, buffer, sizeof(buffer), NULL, NULL ); + todo_wine ok( ret == STATUS_INVALID_PARAMETER, "got %#x\n", ret ); + ok( io.Status == 0xdeadbeef, "got status %#lx\n", io.Status ); + ok( io.Information == 0xdeadbeef, "got size %Iu\n", io.Information ); + +#ifdef __REACTOS__ + if (is_reactos()) { + ok(FALSE, "FIXME: This often bugchecks on ReactOS. This does not bugcheck on checked Windows builds.\n"); + } else { +#endif + io.Status = 0xdeadbeef; + io.Information = 0xdeadbeef; + ret = NtReadFile( hSlot, NULL, NULL, NULL, &io, buffer, sizeof(buffer), NULL, NULL ); + ok( ret == STATUS_PENDING, "got %#x\n", ret ); + ok( io.Status == 0xdeadbeef, "got status %#lx\n", io.Status ); + ok( io.Information == 0xdeadbeef, "got size %Iu\n", io.Information ); +#ifdef __REACTOS__ + } +#endif + + ret = WaitForSingleObject( hSlot, 0 ); + ok( ret == WAIT_TIMEOUT, "got %d\n", ret ); + + hWriter = CreateFileA( szmspath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ); +#ifdef __REACTOS__ + ok( hWriter != INVALID_HANDLE_VALUE || broken(GetLastError() == ERROR_SHARING_VIOLATION) /* WS03 */, "got err %lu\n", GetLastError() ); +#else + ok( hWriter != INVALID_HANDLE_VALUE, "got err %lu\n", GetLastError() ); +#endif + + ret = WriteFile( hWriter, "data", 4, &count, NULL ); +#ifdef __REACTOS__ + ok( ret == TRUE || broken(GetLastError() == ERROR_INVALID_HANDLE) /* WS03 */, "got error %lu\n", GetLastError() ); +#else + ok( ret == TRUE, "got error %lu\n", GetLastError() ); +#endif + + ret = WaitForSingleObject( hSlot, 1000 ); +#ifdef __REACTOS__ + ok( !ret || broken(ret == WAIT_TIMEOUT) /* WS03 */, "got %d\n", ret ); + ok( !io.Status || broken(io.Status == 0xdeadbeef) /* WS03 */, "got status %#lx\n", io.Status ); + if (GetNTVersion() >= _WIN32_WINNT_VISTA) +#else + ok( !ret, "got %d\n", ret ); + ok( !io.Status, "got status %#lx\n", io.Status ); +#endif + ok( io.Information == 4, "got size %Iu\n", io.Information ); + + CloseHandle( hWriter ); + CloseHandle( hSlot ); + return 0; } diff --git a/modules/rostests/winetests/kernel32/module.c b/modules/rostests/winetests/kernel32/module.c index 0b4ce14c46c..84111b87a44 100644 --- a/modules/rostests/winetests/kernel32/module.c +++ b/modules/rostests/winetests/kernel32/module.c @@ -18,10 +18,15 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "wine/test.h" -#include #include +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "winternl.h" #include +#include "wine/test.h" static DWORD (WINAPI *pGetDllDirectoryA)(DWORD,LPSTR); static DWORD (WINAPI *pGetDllDirectoryW)(DWORD,LPWSTR); @@ -32,6 +37,19 @@ static BOOL (WINAPI *pSetDefaultDllDirectories)(DWORD); static BOOL (WINAPI *pK32GetModuleInformation)(HANDLE process, HMODULE module, MODULEINFO *modinfo, DWORD cb); +static NTSTATUS (WINAPI *pApiSetQueryApiSetPresence)(const UNICODE_STRING*,BOOLEAN*); +static NTSTATUS (WINAPI *pApiSetQueryApiSetPresenceEx)(const UNICODE_STRING*,BOOLEAN*,BOOLEAN*); +static NTSTATUS (WINAPI *pLdrGetDllDirectory)(UNICODE_STRING*); +static NTSTATUS (WINAPI *pLdrSetDllDirectory)(UNICODE_STRING*); +static NTSTATUS (WINAPI *pLdrGetDllHandle)( LPCWSTR load_path, ULONG flags, const UNICODE_STRING *name, HMODULE *base ); +static NTSTATUS (WINAPI *pLdrGetDllHandleEx)( ULONG flags, LPCWSTR load_path, ULONG *dll_characteristics, + const UNICODE_STRING *name, HMODULE *base ); +static NTSTATUS (WINAPI *pLdrGetDllFullName)( HMODULE module, UNICODE_STRING *name ); + +static BOOL (WINAPI *pIsApiSetImplemented)(LPCSTR); + +static NTSTATUS (WINAPI *pRtlHashUnicodeString)( const UNICODE_STRING *, BOOLEAN, ULONG, ULONG * ); + static BOOL is_unicode_enabled = TRUE; static BOOL cmpStrAW(const char* a, const WCHAR* b, DWORD lenA, DWORD lenB) @@ -39,7 +57,7 @@ static BOOL cmpStrAW(const char* a, const WCHAR* b, DWORD lenA, DWORD lenB) WCHAR aw[1024]; DWORD len = MultiByteToWideChar( AreFileApisANSI() ? CP_ACP : CP_OEMCP, 0, - a, lenA, aw, sizeof(aw) / sizeof(aw[0]) ); + a, lenA, aw, ARRAY_SIZE(aw)); if (len != lenB) return FALSE; return memcmp(aw, b, len * sizeof(WCHAR)) == 0; } @@ -60,8 +78,6 @@ static const struct IMAGE_FILE_MACHINE_I386, /* Machine */ #elif defined __x86_64__ IMAGE_FILE_MACHINE_AMD64, /* Machine */ -#elif defined __powerpc__ - IMAGE_FILE_MACHINE_POWERPC, /* Machine */ #elif defined __arm__ IMAGE_FILE_MACHINE_ARMNT, /* Machine */ #elif defined __aarch64__ @@ -101,7 +117,7 @@ static const struct sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS), /* SizeOfHeaders */ 0, /* CheckSum */ IMAGE_SUBSYSTEM_WINDOWS_CUI, /* Subsystem */ - 0, /* DllCharacteristics */ + IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLLCHARACTERISTICS_NX_COMPAT, /* DllCharacteristics */ 0, /* SizeOfStackReserve */ 0, /* SizeOfStackCommit */ 0, /* SizeOfHeapReserve */ @@ -120,13 +136,45 @@ static void create_test_dll( const char *name ) DWORD dummy; HANDLE handle = CreateFileA( name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0 ); - ok( handle != INVALID_HANDLE_VALUE, "failed to create file err %u\n", GetLastError() ); + ok( handle != INVALID_HANDLE_VALUE, "failed to create file err %lu\n", GetLastError() ); WriteFile( handle, &dll_image, sizeof(dll_image), &dummy, NULL ); SetFilePointer( handle, dll_image.nt.OptionalHeader.SizeOfImage, NULL, FILE_BEGIN ); SetEndOfFile( handle ); CloseHandle( handle ); } +static BOOL is_old_loader_struct(void) +{ + LDR_DATA_TABLE_ENTRY *mod, *mod2; + LDR_DDAG_NODE *ddag_node; + NTSTATUS status; + HMODULE hexe; + + /* Check for old LDR data strcuture. */ +#ifdef __REACTOS__ + if (GetNTVersion() < _WIN32_WINNT_VISTA) + return TRUE; +#endif + hexe = GetModuleHandleW( NULL ); + ok( !!hexe, "Got NULL exe handle.\n" ); + status = LdrFindEntryForAddress( hexe, &mod ); + ok( !status, "got %#lx.\n", status ); + if (!(ddag_node = mod->DdagNode)) + { + win_skip( "DdagNode is NULL, skipping tests.\n" ); + return TRUE; + } + ok( !!ddag_node->Modules.Flink, "Got NULL module link.\n" ); + mod2 = CONTAINING_RECORD(ddag_node->Modules.Flink, LDR_DATA_TABLE_ENTRY, NodeModuleLink); + ok( mod2 == mod || broken( (void **)mod2 == (void **)mod - 1 ), "got %p, expected %p.\n", mod2, mod ); + if (mod2 != mod) + { + win_skip( "Old LDR_DATA_TABLE_ENTRY structure, skipping tests.\n" ); + return TRUE; + } + return FALSE; +} + static void testGetModuleFileName(const char* name) { HMODULE hMod; @@ -142,25 +190,25 @@ static void testGetModuleFileName(const char* name) len1A = GetModuleFileNameA(hMod, bufA, sizeof(bufA)); ok(GetLastError() == ERROR_SUCCESS || broken(GetLastError() == 0xdeadbeef), /* <= XP SP3 */ - "LastError was not reset: %u\n", GetLastError()); + "LastError was not reset: %lu\n", GetLastError()); ok(len1A > 0, "Getting module filename for handle %p\n", hMod); if (is_unicode_enabled) { memset(bufW, '-', sizeof(bufW)); SetLastError(0xdeadbeef); - len1W = GetModuleFileNameW(hMod, bufW, sizeof(bufW) / sizeof(WCHAR)); + len1W = GetModuleFileNameW(hMod, bufW, ARRAY_SIZE(bufW)); ok(GetLastError() == ERROR_SUCCESS || broken(GetLastError() == 0xdeadbeef), /* <= XP SP3 */ - "LastError was not reset: %u\n", GetLastError()); + "LastError was not reset: %lu\n", GetLastError()); ok(len1W > 0, "Getting module filename for handle %p\n", hMod); } - ok(len1A == strlen(bufA), "Unexpected length of GetModuleFilenameA (%d/%d)\n", len1A, lstrlenA(bufA)); + ok(len1A == strlen(bufA), "Unexpected length of GetModuleFilenameA (%ld/%d)\n", len1A, lstrlenA(bufA)); if (is_unicode_enabled) { - ok(len1W == lstrlenW(bufW), "Unexpected length of GetModuleFilenameW (%d/%d)\n", len1W, lstrlenW(bufW)); + ok(len1W == lstrlenW(bufW), "Unexpected length of GetModuleFilenameW (%ld/%d)\n", len1W, lstrlenW(bufW)); ok(cmpStrAW(bufA, bufW, len1A, len1W), "Comparing GetModuleFilenameAW results\n"); } @@ -175,11 +223,16 @@ static void testGetModuleFileName(const char* name) len2W = GetModuleFileNameW(hMod, bufW, len1W / 2); ok(len2W > 0, "Getting module filename for handle %p\n", hMod); ok(cmpStrAW(bufA, bufW, len2A, len2W), "Comparing GetModuleFilenameAW results with buffer too small\n" ); - ok(len1W / 2 == len2W, "Correct length in GetModuleFilenameW with buffer too small (%d/%d)\n", len1W / 2, len2W); + ok(len1W / 2 == len2W, "Correct length in GetModuleFilenameW with buffer too small (%ld/%ld)\n", len1W / 2, len2W); } ok(len1A / 2 == len2A, - "Correct length in GetModuleFilenameA with buffer too small (%d/%d)\n", len1A / 2, len2A); + "Correct length in GetModuleFilenameA with buffer too small (%ld/%ld)\n", len1A / 2, len2A); + + len1A = GetModuleFileNameA(hMod, bufA, 0x10000); + ok(len1A > 0, "Getting module filename for handle %p\n", hMod); + len1W = GetModuleFileNameW(hMod, bufW, 0x10000); + ok(len1W > 0, "Getting module filename for handle %p\n", hMod); } static void testGetModuleFileName_Wrong(void) @@ -191,7 +244,8 @@ static void testGetModuleFileName_Wrong(void) if (is_unicode_enabled) { bufW[0] = '*'; - ok(GetModuleFileNameW((void*)0xffffffff, bufW, sizeof(bufW) / sizeof(WCHAR)) == 0, "Unexpected success in module handle\n"); + ok(GetModuleFileNameW((void*)0xffffffff, bufW, ARRAY_SIZE(bufW)) == 0, + "Unexpected success in module handle\n"); ok(bufW[0] == '*', "When failing, buffer shouldn't be written to\n"); } @@ -208,16 +262,16 @@ static void testLoadLibraryA(void) SetLastError(0xdeadbeef); hModule = LoadLibraryA("kernel32.dll"); ok( hModule != NULL, "kernel32.dll should be loadable\n"); - ok( GetLastError() == 0xdeadbeef, "GetLastError should be 0xdeadbeef but is %d\n", GetLastError()); + ok( GetLastError() == 0xdeadbeef, "GetLastError should be 0xdeadbeef but is %ld\n", GetLastError()); fp = GetProcAddress(hModule, "CreateFileA"); ok( fp != NULL, "CreateFileA should be there\n"); - ok( GetLastError() == 0xdeadbeef, "GetLastError should be 0xdeadbeef but is %d\n", GetLastError()); + ok( GetLastError() == 0xdeadbeef, "GetLastError should be 0xdeadbeef but is %ld\n", GetLastError()); SetLastError(0xdeadbeef); hModule1 = LoadLibraryA("kernel32 "); ok( hModule1 != NULL, "\"kernel32 \" should be loadable\n" ); - ok( GetLastError() == 0xdeadbeef, "GetLastError should be 0xdeadbeef but is %d\n", GetLastError() ); + ok( GetLastError() == 0xdeadbeef, "GetLastError should be 0xdeadbeef but is %ld\n", GetLastError() ); ok( hModule == hModule1, "Loaded wrong module\n" ); FreeLibrary(hModule1); FreeLibrary(hModule); @@ -282,7 +336,7 @@ static void testLoadLibraryA_Wrong(void) SetLastError(0xdeadbeef); hModule = LoadLibraryA("non_ex_pv.dll"); ok( !hModule, "non_ex_pv.dll should be not loadable\n"); - ok( GetLastError() == ERROR_MOD_NOT_FOUND, "Expected ERROR_MOD_NOT_FOUND, got %d\n", GetLastError() ); + ok( GetLastError() == ERROR_MOD_NOT_FOUND, "Expected ERROR_MOD_NOT_FOUND, got %ld\n", GetLastError() ); /* Just in case */ FreeLibrary(hModule); @@ -295,12 +349,12 @@ static void testGetProcAddress_Wrong(void) SetLastError(0xdeadbeef); fp = GetProcAddress(NULL, "non_ex_call"); ok( !fp, "non_ex_call should not be found\n"); - ok( GetLastError() == ERROR_PROC_NOT_FOUND, "Expected ERROR_PROC_NOT_FOUND, got %d\n", GetLastError() ); + ok( GetLastError() == ERROR_PROC_NOT_FOUND, "Expected ERROR_PROC_NOT_FOUND, got %ld\n", GetLastError() ); SetLastError(0xdeadbeef); fp = GetProcAddress((HMODULE)0xdeadbeef, "non_ex_call"); ok( !fp, "non_ex_call should not be found\n"); - ok( GetLastError() == ERROR_MOD_NOT_FOUND, "Expected ERROR_MOD_NOT_FOUND, got %d\n", GetLastError() ); + ok( GetLastError() == ERROR_MOD_NOT_FOUND, "Expected ERROR_MOD_NOT_FOUND, got %ld\n", GetLastError() ); } static void testLoadLibraryEx(void) @@ -321,7 +375,7 @@ static void testLoadLibraryEx(void) ok(hmodule == 0, "Expected 0, got %p\n", hmodule); ok(GetLastError() == ERROR_MOD_NOT_FOUND || GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_MOD_NOT_FOUND or ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "Expected ERROR_MOD_NOT_FOUND or ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); /* empty lpFileName */ SetLastError(0xdeadbeef); @@ -329,38 +383,29 @@ static void testLoadLibraryEx(void) ok(hmodule == 0, "Expected 0, got %p\n", hmodule); ok(GetLastError() == ERROR_MOD_NOT_FOUND || GetLastError() == ERROR_INVALID_PARAMETER /* win8 */, - "Expected ERROR_MOD_NOT_FOUND or ERROR_DLL_NOT_FOUND, got %d\n", GetLastError()); + "Expected ERROR_MOD_NOT_FOUND or ERROR_DLL_NOT_FOUND, got %ld\n", GetLastError()); /* hFile is non-NULL */ SetLastError(0xdeadbeef); hmodule = LoadLibraryExA("testfile.dll", hfile, 0); ok(hmodule == 0, "Expected 0, got %p\n", hmodule); - todo_wine - { - ok(GetLastError() == ERROR_SHARING_VIOLATION || - GetLastError() == ERROR_INVALID_PARAMETER, /* win2k3 */ - "Unexpected last error, got %d\n", GetLastError()); - } + ok(GetLastError() == ERROR_SHARING_VIOLATION || + GetLastError() == ERROR_INVALID_PARAMETER, /* win2k3 */ + "Unexpected last error, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); hmodule = LoadLibraryExA("testfile.dll", (HANDLE)0xdeadbeef, 0); ok(hmodule == 0, "Expected 0, got %p\n", hmodule); - todo_wine - { - ok(GetLastError() == ERROR_SHARING_VIOLATION || - GetLastError() == ERROR_INVALID_PARAMETER, /* win2k3 */ - "Unexpected last error, got %d\n", GetLastError()); - } + ok(GetLastError() == ERROR_SHARING_VIOLATION || + GetLastError() == ERROR_INVALID_PARAMETER, /* win2k3 */ + "Unexpected last error, got %ld\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, - "Expected ERROR_SHARING_VIOLATION, got %d\n", GetLastError()); - } + ok(GetLastError() == ERROR_SHARING_VIOLATION, + "Expected ERROR_SHARING_VIOLATION, got %ld\n", GetLastError()); /* lpFileName does not matter */ if (is_unicode_enabled) @@ -370,7 +415,7 @@ static void testLoadLibraryEx(void) 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()); + "Expected ERROR_MOD_NOT_FOUND or ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); } CloseHandle(hfile); @@ -379,11 +424,7 @@ static void testLoadLibraryEx(void) 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, - "Expected ERROR_FILE_INVALID, got %d\n", GetLastError()); - } + ok(GetLastError() == ERROR_FILE_INVALID, "Expected ERROR_FILE_INVALID, got %ld\n", GetLastError()); DeleteFileA("testfile.dll"); @@ -398,13 +439,13 @@ static void testLoadLibraryEx(void) ok(hmodule != 0, "Expected valid module handle\n"); ok(GetLastError() == 0xdeadbeef || GetLastError() == ERROR_SUCCESS, - "Expected 0xdeadbeef or ERROR_SUCCESS, got %d\n", GetLastError()); + "Expected 0xdeadbeef or ERROR_SUCCESS, got %ld\n", GetLastError()); /* try invalid file handle */ SetLastError(0xdeadbeef); hmodule = LoadLibraryExA(path, (HANDLE)0xdeadbeef, 0); if (!hmodule) /* succeeds on xp and older */ - ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError()); FreeLibrary(hmodule); @@ -412,7 +453,7 @@ static void testLoadLibraryEx(void) SetLastError(0xdeadbeef); hmodule = LoadLibraryExA("kernel32.dll", NULL, LOAD_LIBRARY_AS_DATAFILE); ok(hmodule != 0, "Expected valid module handle\n"); - ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError()); FreeLibrary(hmodule); @@ -424,12 +465,9 @@ static void testLoadLibraryEx(void) /* 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(hmodule == 0, "Expected 0, got %p\n", hmodule); ok(GetLastError() == ERROR_FILE_NOT_FOUND, - "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError()); /* Free the loaded dll when it's the first time this dll is loaded in process - First time should pass, second fail */ @@ -438,11 +476,16 @@ static void testLoadLibraryEx(void) ok(hmodule != 0, "Expected valid module handle\n"); SetLastError(0xdeadbeef); - ret = FreeLibrary(hmodule); - ok(ret, "Expected to be able to free the module, failed with %d\n", GetLastError()); + ret = FreeLibrary( (HMODULE)((ULONG_PTR)hmodule + 0x1230)); + ok(!ret, "Free succeeded on wrong handle\n"); + ok(GetLastError() == ERROR_BAD_EXE_FORMAT, "wrong error %lu\n", GetLastError()); + SetLastError(0xdeadbeef); ret = FreeLibrary(hmodule); - ok(!ret, "Unexpected ability to free the module, failed with %d\n", GetLastError()); + ok(ret, "Expected to be able to free the module, failed with %ld\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = FreeLibrary(hmodule); + ok(!ret, "Unexpected ability to free the module, failed with %ld\n", GetLastError()); /* load with full path, name without extension */ GetSystemDirectoryA(path, MAX_PATH); @@ -461,6 +504,7 @@ static void testLoadLibraryEx(void) static void test_LoadLibraryEx_search_flags(void) { + static const char apiset_dll[] = "api-ms-win-shcore-obsolete-l1-1-0.dll"; static const struct { int add_dirs[4]; @@ -478,67 +522,172 @@ static void test_LoadLibraryEx_search_flags(void) { { 6, 5 }, 5, 0 }, { { 1, 1, 2 }, 0, 2 }, }; - char *p, path[MAX_PATH], buf[MAX_PATH]; + char *p, path[MAX_PATH], buf[MAX_PATH], curdir[MAX_PATH]; WCHAR bufW[MAX_PATH]; DLL_DIRECTORY_COOKIE cookies[4]; unsigned int i, j, k; BOOL ret; HMODULE mod; - if (!pAddDllDirectory || !pSetDllDirectoryA) return; - GetTempPathA( sizeof(path), path ); GetTempFileNameA( path, "tmp", 0, buf ); DeleteFileA( buf ); ret = CreateDirectoryA( buf, NULL ); - ok( ret, "CreateDirectory failed err %u\n", GetLastError() ); + ok( ret, "CreateDirectory failed err %lu\n", GetLastError() ); p = buf + strlen( buf ); for (i = 1; i <= 6; i++) { sprintf( p, "\\%u", i ); ret = CreateDirectoryA( buf, NULL ); - ok( ret, "CreateDirectory failed err %u\n", GetLastError() ); + ok( ret, "CreateDirectory failed err %lu\n", GetLastError() ); if (i >= 5) continue; /* dirs 5 and 6 are left empty */ sprintf( p, "\\%u\\winetestdll.dll", i ); create_test_dll( buf ); } + + GetCurrentDirectoryA( MAX_PATH, curdir ); + *p = 0; + SetCurrentDirectoryA( buf ); + + SetLastError( 0xdeadbeef ); + mod = LoadLibraryA( "1\\winetestdll.dll" ); + ok( mod != NULL, "LoadLibrary failed err %lu\n", GetLastError() ); + FreeLibrary( mod ); + + SetLastError( 0xdeadbeef ); + sprintf( path, "%c:1\\winetestdll.dll", buf[0] ); + mod = LoadLibraryA( path ); + ok( mod != NULL, "LoadLibrary failed err %lu\n", GetLastError() ); + FreeLibrary( mod ); + + if (pAddDllDirectory) + { + SetLastError( 0xdeadbeef ); + mod = LoadLibraryExA( "1\\winetestdll.dll", 0, LOAD_LIBRARY_SEARCH_SYSTEM32 ); + ok( !mod, "LoadLibrary succeeded\n" ); + ok( GetLastError() == ERROR_MOD_NOT_FOUND, "wrong error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + mod = LoadLibraryExA( path, 0, LOAD_LIBRARY_SEARCH_SYSTEM32 ); + ok( mod != NULL, "LoadLibrary failed err %lu\n", GetLastError() ); + FreeLibrary( mod ); + } + + strcpy( p, "\\1" ); + SetCurrentDirectoryA( buf ); + + SetLastError( 0xdeadbeef ); + mod = LoadLibraryA( "winetestdll.dll" ); + ok( mod != NULL, "LoadLibrary failed err %lu\n", GetLastError() ); + FreeLibrary( mod ); + + SetLastError( 0xdeadbeef ); + sprintf( path, "%c:winetestdll.dll", buf[0] ); + mod = LoadLibraryA( path ); + ok( mod != NULL || broken(!mod), /* win10 disallows this but allows c:1\\winetestdll.dll */ + "LoadLibrary failed err %lu\n", GetLastError() ); + if (!mod) ok( GetLastError() == ERROR_MOD_NOT_FOUND, "wrong error %lu\n", GetLastError() ); + else FreeLibrary( mod ); + + SetLastError( 0xdeadbeef ); + sprintf( path, "%s\\winetestdll.dll", buf + 2 ); + mod = LoadLibraryA( path ); + ok( mod != NULL, "LoadLibrary failed err %lu\n", GetLastError() ); + FreeLibrary( mod ); + + if (pAddDllDirectory) + { + SetLastError( 0xdeadbeef ); + mod = LoadLibraryExA( "winetestdll.dll", 0, LOAD_LIBRARY_SEARCH_SYSTEM32 ); + ok( !mod, "LoadLibrary succeeded\n" ); + ok( GetLastError() == ERROR_MOD_NOT_FOUND, "wrong error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + mod = LoadLibraryExA( path, 0, LOAD_LIBRARY_SEARCH_SYSTEM32 ); + ok( mod != NULL, "LoadLibrary failed err %lu\n", GetLastError() ); + FreeLibrary( mod ); + + SetLastError( 0xdeadbeef ); + sprintf( path, "%s\\winetestdll.dll", buf + 2 ); + mod = LoadLibraryExA( path, 0, LOAD_LIBRARY_SEARCH_SYSTEM32 ); + ok( mod != NULL, "LoadLibrary failed err %lu\n", GetLastError() ); + FreeLibrary( mod ); + + SetLastError( 0xdeadbeef ); + mod = LoadLibraryExA( "winetestdll.dll", 0, LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_WITH_ALTERED_SEARCH_PATH ); + ok( !mod, "LoadLibrary succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + mod = LoadLibraryExA( "winetestdll.dll", 0, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_WITH_ALTERED_SEARCH_PATH ); + ok( !mod, "LoadLibrary succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + mod = LoadLibraryExA( "winetestdll.dll", 0, LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_WITH_ALTERED_SEARCH_PATH ); + ok( !mod, "LoadLibrary succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + mod = LoadLibraryExA( "winetestdll.dll", 0, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_WITH_ALTERED_SEARCH_PATH ); + ok( !mod, "LoadLibrary succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + mod = LoadLibraryExA( "winetestdll.dll", 0, LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_WITH_ALTERED_SEARCH_PATH ); + ok( !mod, "LoadLibrary succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); + } + + SetCurrentDirectoryA( curdir ); + + if (!pAddDllDirectory || !pSetDllDirectoryA) goto done; + SetLastError( 0xdeadbeef ); mod = LoadLibraryExA( "winetestdll.dll", 0, LOAD_LIBRARY_SEARCH_APPLICATION_DIR ); ok( !mod, "LoadLibrary succeeded\n" ); - ok( GetLastError() == ERROR_MOD_NOT_FOUND, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_MOD_NOT_FOUND, "wrong error %lu\n", GetLastError() ); + if (0) /* crashes on win10 */ + { SetLastError( 0xdeadbeef ); mod = LoadLibraryExA( "winetestdll.dll", 0, LOAD_LIBRARY_SEARCH_USER_DIRS ); ok( !mod, "LoadLibrary succeeded\n" ); ok( GetLastError() == ERROR_MOD_NOT_FOUND || broken(GetLastError() == ERROR_NOT_ENOUGH_MEMORY), - "wrong error %u\n", GetLastError() ); + "wrong error %lu\n", GetLastError() ); + } SetLastError( 0xdeadbeef ); mod = LoadLibraryExA( "winetestdll.dll", 0, LOAD_LIBRARY_SEARCH_SYSTEM32 ); ok( !mod, "LoadLibrary succeeded\n" ); - ok( GetLastError() == ERROR_MOD_NOT_FOUND, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_MOD_NOT_FOUND, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); mod = LoadLibraryExA( "winetestdll.dll", 0, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR ); ok( !mod, "LoadLibrary succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); mod = LoadLibraryExA( "winetestdll.dll", 0, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32 ); ok( !mod, "LoadLibrary succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); mod = LoadLibraryExA( "foo\\winetestdll.dll", 0, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR ); ok( !mod, "LoadLibrary succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); mod = LoadLibraryExA( "\\windows\\winetestdll.dll", 0, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR ); ok( !mod, "LoadLibrary succeeded\n" ); - ok( GetLastError() == ERROR_MOD_NOT_FOUND, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_MOD_NOT_FOUND, "wrong error %lu\n", GetLastError() ); - for (j = 0; j < sizeof(tests) / sizeof(tests[0]); j++) + SetLastError( 0xdeadbeef ); + mod = LoadLibraryA( "1\\winetestdll.dll" ); + ok( !mod, "LoadLibrary succeeded\n" ); + ok( GetLastError() == ERROR_MOD_NOT_FOUND, "wrong error %lu\n", GetLastError() ); + + for (j = 0; j < ARRAY_SIZE(tests); j++) { for (k = 0; tests[j].add_dirs[k]; k++) { @@ -558,7 +707,7 @@ static void test_LoadLibraryEx_search_flags(void) mod = LoadLibraryExA( "winetestdll.dll", 0, LOAD_LIBRARY_SEARCH_USER_DIRS ); if (tests[j].expect) { - ok( mod != NULL, "%u: LoadLibrary failed err %u\n", j, GetLastError() ); + ok( mod != NULL, "%u: LoadLibrary failed err %lu\n", j, GetLastError() ); GetModuleFileNameA( mod, path, MAX_PATH ); sprintf( p, "\\%u\\winetestdll.dll", tests[j].expect ); ok( !lstrcmpiA( path, buf ), "%u: wrong module %s expected %s\n", j, path, buf ); @@ -567,13 +716,108 @@ static void test_LoadLibraryEx_search_flags(void) { ok( !mod, "%u: LoadLibrary succeeded\n", j ); ok( GetLastError() == ERROR_MOD_NOT_FOUND || broken(GetLastError() == ERROR_NOT_ENOUGH_MEMORY), - "%u: wrong error %u\n", j, GetLastError() ); + "%u: wrong error %lu\n", j, GetLastError() ); } FreeLibrary( mod ); for (k = 0; tests[j].add_dirs[k]; k++) pRemoveDllDirectory( cookies[k] ); } + mod = GetModuleHandleA( apiset_dll ); + if (mod) + { + win_skip( "%s already referenced, skipping test.\n", apiset_dll ); + } + else + { + LoadLibraryA( "ole32.dll" ); /* FIXME: make sure the dependencies are loaded */ + mod = LoadLibraryA( apiset_dll ); + if (mod) + { + HMODULE shcore; + char buffer[MAX_PATH]; + + FreeLibrary(mod); + mod = LoadLibraryExA( apiset_dll, NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR ); + ok( !!mod, "Got NULL module, error %lu.\n", GetLastError() ); + ok( !!GetModuleHandleA( apiset_dll ), "Got NULL handle.\n" ); + shcore = GetModuleHandleA( "shcore.dll" ); + ok( mod == shcore, "wrong module %p/%p\n", mod, shcore ); + ret = FreeLibrary( mod ); + ok( ret, "FreeLibrary failed, error %lu.\n", GetLastError() ); + shcore = GetModuleHandleA( "shcore.dll" ); + ok( !shcore, "shcore not unloaded\n" ); + + /* api set without .dll */ + strcpy( buffer, apiset_dll ); + buffer[strlen(buffer) - 4] = 0; + mod = LoadLibraryExA( buffer, NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR ); + ok( !!mod, "Got NULL module, error %lu.\n", GetLastError() ); + ok( !!GetModuleHandleA( apiset_dll ), "Got NULL handle.\n" ); + shcore = GetModuleHandleA( "shcore.dll" ); + ok( mod == shcore, "wrong module %p/%p\n", mod, shcore ); + ret = FreeLibrary( mod ); + ok( ret, "FreeLibrary failed, error %lu.\n", GetLastError() ); + shcore = GetModuleHandleA( "shcore.dll" ); + ok( !shcore, "shcore not unloaded\n" ); + + /* api set with different version */ + strcpy( buffer, apiset_dll ); + buffer[strlen(buffer) - 5] = '9'; + mod = LoadLibraryExA( buffer, NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR ); + ok( !!mod || broken(!mod) /* win8 */, "Got NULL module, error %lu.\n", GetLastError() ); + if (mod) + { + ok( !!GetModuleHandleA( apiset_dll ), "Got NULL handle.\n" ); + shcore = GetModuleHandleA( "shcore.dll" ); + ok( mod == shcore, "wrong module %p/%p\n", mod, shcore ); + ret = FreeLibrary( mod ); + ok( ret, "FreeLibrary failed, error %lu.\n", GetLastError() ); + } + shcore = GetModuleHandleA( "shcore.dll" ); + ok( !shcore, "shcore not unloaded\n" ); + + /* api set with full path */ + GetWindowsDirectoryA( buffer, MAX_PATH ); + strcat( buffer, "\\" ); + strcat( buffer, apiset_dll ); + SetLastError( 0xdeadbeef ); + mod = LoadLibraryExA( buffer, NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR ); + ok( !mod, "Loaded %s\n", debugstr_a(buffer) ); + ok( GetLastError() == ERROR_MOD_NOT_FOUND, "wrong error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + mod = LoadLibraryA( buffer ); + ok( !mod, "Loaded %s\n", debugstr_a(buffer) ); + ok( GetLastError() == ERROR_MOD_NOT_FOUND, "wrong error %lu\n", GetLastError() ); + } + else + { + win_skip( "%s not found, skipping test.\n", apiset_dll ); + } + + /* try a library with dependencies */ + mod = GetModuleHandleA( "rasapi32.dll" ); + ok( !mod, "rasapi32 already loaded\n" ); + mod = LoadLibraryA( "rasapi32.dll" ); + ok( !!mod, "rasapi32 not found %lu\n", GetLastError() ); + FreeLibrary( mod ); + SetLastError( 0xdeadbeef ); + mod = LoadLibraryExA( "rasapi32.dll", NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR ); + ok( !mod, "rasapi32 loaded\n" ); + ok( GetLastError() == ERROR_MOD_NOT_FOUND, "wrong error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + mod = LoadLibraryExA( "ext-ms-win-ras-rasapi32-l1-1-0.dll", NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR ); + todo_wine /* rasapi32 doesn't have interesting dependencies on wine */ + ok( !mod, "rasapi32 loaded\n" ); + if (mod) FreeLibrary( mod ); + else ok( GetLastError() == ERROR_MOD_NOT_FOUND, "wrong error %lu\n", GetLastError() ); + mod = LoadLibraryA( "ext-ms-win-ras-rasapi32-l1-1-0.dll" ); + ok( !!mod || broken(!mod) /* win7 */, "rasapi32 not found %lu\n", GetLastError() ); + if (mod) FreeLibrary( mod ); + mod = GetModuleHandleA( "rasapi32.dll" ); + ok( !mod, "rasapi32 still loaded\n" ); + } +done: for (i = 1; i <= 6; i++) { sprintf( p, "\\%u\\winetestdll.dll", i ); @@ -598,7 +842,7 @@ static void testGetDllDirectory(void) "C:\\Some\\Path\\", "Q:\\A\\Long\\Path with spaces that\\probably\\doesn't exist!", }; - const int test_count = sizeof(dll_directories) / sizeof(dll_directories[0]); + const int test_count = ARRAY_SIZE(dll_directories); if (!pGetDllDirectoryA || !pGetDllDirectoryW) { @@ -622,24 +866,24 @@ static void testGetDllDirectory(void) /* no buffer, determine length */ ret = pGetDllDirectoryA(0, NULL); - ok(ret == length + 1, "Expected %u, got %u\n", length + 1, ret); + ok(ret == length + 1, "Expected %lu, got %lu\n", length + 1, ret); ret = pGetDllDirectoryW(0, NULL); - ok(ret == length + 1, "Expected %u, got %u\n", length + 1, ret); + ok(ret == length + 1, "Expected %lu, got %lu\n", length + 1, ret); /* buffer of exactly the right size */ bufferA[length] = 'A'; bufferA[length + 1] = 'A'; ret = pGetDllDirectoryA(length + 1, bufferA); ok(ret == length || broken(ret + 1 == length) /* win8 */, - "i=%d, Expected %u(+1), got %u\n", i, length, ret); + "i=%d, Expected %lu(+1), got %lu\n", i, length, ret); ok(bufferA[length + 1] == 'A', "i=%d, Buffer overflow\n", i); ok(strcmp(bufferA, dll_directories[i]) == 0, "i=%d, Wrong path returned: '%s'\n", i, bufferA); bufferW[length] = 'A'; bufferW[length + 1] = 'A'; ret = pGetDllDirectoryW(length + 1, bufferW); - ok(ret == length, "i=%d, Expected %u, got %u\n", i, length, ret); + ok(ret == length, "i=%d, Expected %lu, got %lu\n", i, length, ret); ok(bufferW[length + 1] == 'A', "i=%d, Buffer overflow\n", i); ok(cmpStrAW(dll_directories[i], bufferW, length, length), "i=%d, Wrong path returned: %s\n", i, wine_dbgstr_w(bufferW)); @@ -648,36 +892,60 @@ static void testGetDllDirectory(void) * on the Windows version and whether the A or W API is called. */ bufferA[0] = 'A'; ret = pGetDllDirectoryA(0, bufferA); - ok(ret == length + 1, "i=%d, Expected %u, got %u\n", i, length + 1, ret); + ok(ret == length + 1, "i=%d, Expected %lu, got %lu\n", i, length + 1, ret); bufferW[0] = 'A'; ret = pGetDllDirectoryW(0, bufferW); - ok(ret == length + 1, "i=%d, Expected %u, got %u\n", i, length + 1, ret); - ok(bufferW[0] == 0 || /* XP, 2003 */ - broken(bufferW[0] == 'A'), "i=%d, Buffer overflow\n", i); + ok(ret == length + 1, "i=%d, Expected %lu, got %lu\n", i, length + 1, ret); + ok(bufferW[0] == 'A' || broken(bufferW[0] == 0), /* XP, 2003 */ + "i=%d, Buffer overflow\n", i); /* buffer just one too short */ bufferA[0] = 'A'; ret = pGetDllDirectoryA(length, bufferA); - ok(ret == length + 1, "i=%d, Expected %u, got %u\n", i, length + 1, ret); + ok(ret == length + 1, "i=%d, Expected %lu, got %lu\n", i, length + 1, ret); if (length != 0) ok(bufferA[0] == 0, "i=%d, Buffer not null terminated\n", i); bufferW[0] = 'A'; ret = pGetDllDirectoryW(length, bufferW); - ok(ret == length + 1, "i=%d, Expected %u, got %u\n", i, length + 1, ret); - ok(bufferW[0] == 0 || /* XP, 2003 */ - broken(bufferW[0] == 'A'), "i=%d, Buffer overflow\n", i); + ok(ret == length + 1, "i=%d, Expected %lu, got %lu\n", i, length + 1, ret); + if (length != 0) + ok(bufferW[0] == 0, "i=%d, Buffer overflow\n", i); if (0) { /* crashes on win8 */ /* no buffer, but too short length */ ret = pGetDllDirectoryA(length, NULL); - ok(ret == length + 1, "i=%d, Expected %u, got %u\n", i, length + 1, ret); + ok(ret == length + 1, "i=%d, Expected %lu, got %lu\n", i, length + 1, ret); ret = pGetDllDirectoryW(length, NULL); - ok(ret == length + 1, "i=%d, Expected %u, got %u\n", i, length + 1, ret); + ok(ret == length + 1, "i=%d, Expected %lu, got %lu\n", i, length + 1, ret); + } + + if (pLdrGetDllDirectory) + { + UNICODE_STRING str; + NTSTATUS status; + str.Buffer = bufferW; + str.MaximumLength = sizeof(bufferW); + status = pLdrGetDllDirectory( &str ); + ok( !status, "LdrGetDllDirectory failed %lx\n", status ); + ok( cmpStrAW( dll_directories[i], bufferW, strlen(dll_directories[i]), + str.Length / sizeof(WCHAR) ), "%u: got %s instead of %s\n", + i, wine_dbgstr_w(bufferW), dll_directories[i] ); + if (dll_directories[i][0]) + { + memset( bufferW, 0xcc, sizeof(bufferW) ); + str.MaximumLength = (strlen( dll_directories[i] ) - 1) * sizeof(WCHAR); + status = pLdrGetDllDirectory( &str ); + ok( status == STATUS_BUFFER_TOO_SMALL, "%u: LdrGetDllDirectory failed %lx\n", i, status ); + ok( bufferW[0] == 0 && bufferW[1] == 0xcccc, + "%u: buffer %x %x\n", i, bufferW[0], bufferW[1] ); + length = (strlen( dll_directories[i] ) + 1) * sizeof(WCHAR); + ok( str.Length == length, "%u: wrong len %u / %lu\n", i, str.Length, length ); + } } } @@ -687,9 +955,9 @@ static void testGetDllDirectory(void) static void init_pointers(void) { - HMODULE hKernel32 = GetModuleHandleA("kernel32.dll"); + HMODULE mod = GetModuleHandleA("kernel32.dll"); -#define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hKernel32, #f)) +#define MAKEFUNC(f) (p##f = (void*)GetProcAddress(mod, #f)) MAKEFUNC(GetDllDirectoryA); MAKEFUNC(GetDllDirectoryW); MAKEFUNC(SetDllDirectoryA); @@ -697,6 +965,17 @@ static void init_pointers(void) MAKEFUNC(RemoveDllDirectory); MAKEFUNC(SetDefaultDllDirectories); MAKEFUNC(K32GetModuleInformation); + mod = GetModuleHandleA( "ntdll.dll" ); + MAKEFUNC(ApiSetQueryApiSetPresence); + MAKEFUNC(ApiSetQueryApiSetPresenceEx); + MAKEFUNC(LdrGetDllDirectory); + MAKEFUNC(LdrSetDllDirectory); + MAKEFUNC(LdrGetDllHandle); + MAKEFUNC(LdrGetDllHandleEx); + MAKEFUNC(LdrGetDllFullName); + MAKEFUNC(RtlHashUnicodeString); + mod = GetModuleHandleA( "kernelbase.dll" ); + MAKEFUNC(IsApiSetImplemented); #undef MAKEFUNC /* before Windows 7 this was not exported in kernel32 */ @@ -709,6 +988,10 @@ static void init_pointers(void) static void testGetModuleHandleEx(void) { + static const char longname[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; static const WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2',0}; static const WCHAR nosuchmodW[] = {'n','o','s','u','c','h','m','o','d',0}; BOOL ret; @@ -719,18 +1002,18 @@ static void testGetModuleHandleEx(void) ret = GetModuleHandleExA( 0, NULL, NULL ); error = GetLastError(); ok( !ret, "unexpected success\n" ); - ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); SetLastError( 0xdeadbeef ); ret = GetModuleHandleExA( 0, "kernel32", NULL ); error = GetLastError(); ok( !ret, "unexpected success\n" ); - ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); SetLastError( 0xdeadbeef ); mod = (HMODULE)0xdeadbeef; ret = GetModuleHandleExA( 0, "kernel32", &mod ); - ok( ret, "unexpected failure %u\n", GetLastError() ); + ok( ret, "unexpected failure %lu\n", GetLastError() ); ok( mod != (HMODULE)0xdeadbeef, "got %p\n", mod ); FreeLibrary( mod ); @@ -739,25 +1022,43 @@ static void testGetModuleHandleEx(void) ret = GetModuleHandleExA( 0, "nosuchmod", &mod ); error = GetLastError(); ok( !ret, "unexpected success\n" ); - ok( error == ERROR_MOD_NOT_FOUND, "got %u\n", error ); + ok( error == ERROR_MOD_NOT_FOUND, "got %lu\n", error ); + ok( mod == NULL, "got %p\n", mod ); + + SetLastError( 0xdeadbeef ); + ret = GetModuleHandleExA( 0, longname, NULL ); + error = GetLastError(); + ok( !ret, "unexpected success\n" ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); + + SetLastError( 0xdeadbeef ); + mod = (HMODULE)0xdeadbeef; + ret = GetModuleHandleExA( 0, longname, &mod ); + error = GetLastError(); + ok( !ret, "unexpected success\n" ); +#ifdef __REACTOS__ + ok( error == ERROR_MOD_NOT_FOUND || broken(error == ERROR_FILENAME_EXCED_RANGE) /* WS03 */, "got %lu\n", error ); +#else + ok( error == ERROR_MOD_NOT_FOUND, "got %lu\n", error ); +#endif ok( mod == NULL, "got %p\n", mod ); SetLastError( 0xdeadbeef ); ret = GetModuleHandleExW( 0, NULL, NULL ); error = GetLastError(); ok( !ret, "unexpected success\n" ); - ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); SetLastError( 0xdeadbeef ); ret = GetModuleHandleExW( 0, kernel32W, NULL ); error = GetLastError(); ok( !ret, "unexpected success\n" ); - ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); SetLastError( 0xdeadbeef ); mod = (HMODULE)0xdeadbeef; ret = GetModuleHandleExW( 0, kernel32W, &mod ); - ok( ret, "unexpected failure %u\n", GetLastError() ); + ok( ret, "unexpected failure %lu\n", GetLastError() ); ok( mod != (HMODULE)0xdeadbeef, "got %p\n", mod ); FreeLibrary( mod ); @@ -766,25 +1067,25 @@ static void testGetModuleHandleEx(void) ret = GetModuleHandleExW( 0, nosuchmodW, &mod ); error = GetLastError(); ok( !ret, "unexpected success\n" ); - ok( error == ERROR_MOD_NOT_FOUND, "got %u\n", error ); + ok( error == ERROR_MOD_NOT_FOUND, "got %lu\n", error ); ok( mod == NULL, "got %p\n", mod ); SetLastError( 0xdeadbeef ); ret = GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, NULL, NULL ); error = GetLastError(); ok( !ret, "unexpected success\n" ); - ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); SetLastError( 0xdeadbeef ); ret = GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, "kernel32", NULL ); error = GetLastError(); ok( !ret, "unexpected success\n" ); - ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); SetLastError( 0xdeadbeef ); mod = (HMODULE)0xdeadbeef; ret = GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, "kernel32", &mod ); - ok( ret, "unexpected failure %u\n", GetLastError() ); + ok( ret, "unexpected failure %lu\n", GetLastError() ); ok( mod != (HMODULE)0xdeadbeef, "got %p\n", mod ); SetLastError( 0xdeadbeef ); @@ -792,25 +1093,25 @@ static void testGetModuleHandleEx(void) ret = GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, "nosuchmod", &mod ); error = GetLastError(); ok( !ret, "unexpected success\n" ); - ok( error == ERROR_MOD_NOT_FOUND, "got %u\n", error ); + ok( error == ERROR_MOD_NOT_FOUND, "got %lu\n", error ); ok( mod == NULL, "got %p\n", mod ); SetLastError( 0xdeadbeef ); ret = GetModuleHandleExW( GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, NULL, NULL ); error = GetLastError(); ok( !ret, "unexpected success\n" ); - ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); SetLastError( 0xdeadbeef ); ret = GetModuleHandleExW( GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, kernel32W, NULL ); error = GetLastError(); ok( !ret, "unexpected success\n" ); - ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); SetLastError( 0xdeadbeef ); mod = (HMODULE)0xdeadbeef; ret = GetModuleHandleExW( GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, kernel32W, &mod ); - ok( ret, "unexpected failure %u\n", GetLastError() ); + ok( ret, "unexpected failure %lu\n", GetLastError() ); ok( mod != (HMODULE)0xdeadbeef, "got %p\n", mod ); SetLastError( 0xdeadbeef ); @@ -818,7 +1119,7 @@ static void testGetModuleHandleEx(void) ret = GetModuleHandleExW( GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, nosuchmodW, &mod ); error = GetLastError(); ok( !ret, "unexpected success\n" ); - ok( error == ERROR_MOD_NOT_FOUND, "got %u\n", error ); + ok( error == ERROR_MOD_NOT_FOUND, "got %lu\n", error ); ok( mod == NULL, "got %p\n", mod ); mod_kernel32 = LoadLibraryA( "kernel32" ); @@ -827,18 +1128,18 @@ static void testGetModuleHandleEx(void) ret = GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, NULL, NULL ); error = GetLastError(); ok( !ret, "unexpected success\n" ); - ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); SetLastError( 0xdeadbeef ); ret = GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCSTR)mod_kernel32, NULL ); error = GetLastError(); ok( !ret, "unexpected success\n" ); - ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); SetLastError( 0xdeadbeef ); mod = (HMODULE)0xdeadbeef; ret = GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCSTR)mod_kernel32, &mod ); - ok( ret, "unexpected failure %u\n", GetLastError() ); + ok( ret, "unexpected failure %lu\n", GetLastError() ); ok( mod == mod_kernel32, "got %p\n", mod ); FreeLibrary( mod ); @@ -847,25 +1148,25 @@ static void testGetModuleHandleEx(void) ret = GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCSTR)0xbeefdead, &mod ); error = GetLastError(); ok( !ret, "unexpected success\n" ); - ok( error == ERROR_MOD_NOT_FOUND, "got %u\n", error ); + ok( error == ERROR_MOD_NOT_FOUND, "got %lu\n", error ); ok( mod == NULL, "got %p\n", mod ); SetLastError( 0xdeadbeef ); ret = GetModuleHandleExW( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, NULL, NULL ); error = GetLastError(); ok( !ret, "unexpected success\n" ); - ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); SetLastError( 0xdeadbeef ); ret = GetModuleHandleExW( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)mod_kernel32, NULL ); error = GetLastError(); ok( !ret, "unexpected success\n" ); - ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); SetLastError( 0xdeadbeef ); mod = (HMODULE)0xdeadbeef; ret = GetModuleHandleExW( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)mod_kernel32, &mod ); - ok( ret, "unexpected failure %u\n", GetLastError() ); + ok( ret, "unexpected failure %lu\n", GetLastError() ); ok( mod == mod_kernel32, "got %p\n", mod ); FreeLibrary( mod ); @@ -874,7 +1175,24 @@ static void testGetModuleHandleEx(void) ret = GetModuleHandleExW( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)0xbeefdead, &mod ); error = GetLastError(); ok( !ret, "unexpected success\n" ); - ok( error == ERROR_MOD_NOT_FOUND, "got %u\n", error ); + ok( error == ERROR_MOD_NOT_FOUND, "got %lu\n", error ); + ok( mod == NULL, "got %p\n", mod ); + + SetLastError( 0xdeadbeef ); + mod = (HMODULE)0xdeadbeef; + ret = GetModuleHandleExW( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT + | GET_MODULE_HANDLE_EX_FLAG_PIN, (LPCWSTR)mod_kernel32, &mod ); + error = GetLastError(); + ok( !ret, "unexpected success\n" ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); + ok( mod == NULL, "got %p\n", mod ); + + SetLastError( 0xdeadbeef ); + mod = (HMODULE)0xdeadbeef; + ret = GetModuleHandleExW( 8, kernel32W, &mod ); + error = GetLastError(); + ok( !ret, "unexpected success\n" ); + ok( error == ERROR_INVALID_PARAMETER, "got %lu\n", error ); ok( mod == NULL, "got %p\n", mod ); FreeLibrary( mod_kernel32 ); @@ -917,34 +1235,34 @@ static void test_AddDllDirectory(void) } buf[0] = '\0'; - GetTempPathW( sizeof(path)/sizeof(path[0]), path ); + GetTempPathW(ARRAY_SIZE(path), path ); ret = GetTempFileNameW( path, tmpW, 0, buf ); - ok( ret, "GetTempFileName failed err %u\n", GetLastError() ); + ok( ret, "GetTempFileName failed err %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); cookie = pAddDllDirectory( buf ); - ok( cookie != NULL, "AddDllDirectory failed err %u\n", GetLastError() ); + ok( cookie != NULL, "AddDllDirectory failed err %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); ret = pRemoveDllDirectory( cookie ); - ok( ret, "RemoveDllDirectory failed err %u\n", GetLastError() ); + ok( ret, "RemoveDllDirectory failed err %lu\n", GetLastError() ); DeleteFileW( buf ); SetLastError( 0xdeadbeef ); cookie = pAddDllDirectory( buf ); ok( !cookie, "AddDllDirectory succeeded\n" ); - ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError() ); cookie = pAddDllDirectory( dotW ); ok( !cookie, "AddDllDirectory succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); cookie = pAddDllDirectory( rootW ); - ok( cookie != NULL, "AddDllDirectory failed err %u\n", GetLastError() ); + ok( cookie != NULL, "AddDllDirectory failed err %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); ret = pRemoveDllDirectory( cookie ); - ok( ret, "RemoveDllDirectory failed err %u\n", GetLastError() ); + ok( ret, "RemoveDllDirectory failed err %lu\n", GetLastError() ); GetWindowsDirectoryW( buf, MAX_PATH ); lstrcpyW( buf + 2, tmpW ); cookie = pAddDllDirectory( buf ); ok( !cookie, "AddDllDirectory succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); } static void test_SetDefaultDllDirectories(void) @@ -962,25 +1280,25 @@ static void test_SetDefaultDllDirectories(void) ok( mod != NULL, "loading authz failed\n" ); FreeLibrary( mod ); ret = pSetDefaultDllDirectories( LOAD_LIBRARY_SEARCH_USER_DIRS ); - ok( ret, "SetDefaultDllDirectories failed err %u\n", GetLastError() ); + ok( ret, "SetDefaultDllDirectories failed err %lu\n", GetLastError() ); mod = LoadLibraryA( "authz.dll" ); - todo_wine ok( !mod, "loading authz succeeded\n" ); + ok( !mod, "loading authz succeeded\n" ); FreeLibrary( mod ); ret = pSetDefaultDllDirectories( LOAD_LIBRARY_SEARCH_SYSTEM32 ); - ok( ret, "SetDefaultDllDirectories failed err %u\n", GetLastError() ); + ok( ret, "SetDefaultDllDirectories failed err %lu\n", GetLastError() ); mod = LoadLibraryA( "authz.dll" ); ok( mod != NULL, "loading authz failed\n" ); FreeLibrary( mod ); mod = LoadLibraryExA( "authz.dll", 0, LOAD_LIBRARY_SEARCH_APPLICATION_DIR ); - todo_wine ok( !mod, "loading authz succeeded\n" ); + ok( !mod, "loading authz succeeded\n" ); FreeLibrary( mod ); ret = pSetDefaultDllDirectories( LOAD_LIBRARY_SEARCH_APPLICATION_DIR ); - ok( ret, "SetDefaultDllDirectories failed err %u\n", GetLastError() ); + ok( ret, "SetDefaultDllDirectories failed err %lu\n", GetLastError() ); mod = LoadLibraryA( "authz.dll" ); - todo_wine ok( !mod, "loading authz succeeded\n" ); + ok( !mod, "loading authz succeeded\n" ); FreeLibrary( mod ); ret = pSetDefaultDllDirectories( LOAD_LIBRARY_SEARCH_DEFAULT_DIRS ); - ok( ret, "SetDefaultDllDirectories failed err %u\n", GetLastError() ); + ok( ret, "SetDefaultDllDirectories failed err %lu\n", GetLastError() ); mod = LoadLibraryA( "authz.dll" ); ok( mod != NULL, "loading authz failed\n" ); FreeLibrary( mod ); @@ -988,32 +1306,608 @@ static void test_SetDefaultDllDirectories(void) SetLastError( 0xdeadbeef ); ret = pSetDefaultDllDirectories( 0 ); ok( !ret, "SetDefaultDllDirectories succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); ret = pSetDefaultDllDirectories( 3 ); ok( !ret, "SetDefaultDllDirectories succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); ret = pSetDefaultDllDirectories( LOAD_LIBRARY_SEARCH_APPLICATION_DIR | 0x8000 ); ok( !ret, "SetDefaultDllDirectories succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); ret = pSetDefaultDllDirectories( LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR ); ok( !ret || broken(ret) /* win7 */, "SetDefaultDllDirectories succeeded\n" ); - if (!ret) ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + if (!ret) ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); ret = pSetDefaultDllDirectories( LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_USER_DIRS ); ok( !ret || broken(ret) /* win7 */, "SetDefaultDllDirectories succeeded\n" ); - if (!ret) ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + if (!ret) ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); /* restore some sane defaults */ pSetDefaultDllDirectories( LOAD_LIBRARY_SEARCH_DEFAULT_DIRS ); } +static void check_refcount( HMODULE mod, unsigned int refcount ) +{ + unsigned int i; + BOOL ret; + + for (i = 0; i < min( refcount, 10 ); ++i) + { + ret = FreeLibrary( mod ); +#ifdef __REACTOS__ + ok( ret || broken( refcount == ~0u && GetLastError() == ERROR_MOD_NOT_FOUND && (i == 2) ) /* Win8 */ || broken( refcount == 2 && GetLastError() == ERROR_MOD_NOT_FOUND && i == 1 ) /* WS03 */, +#else + ok( ret || broken( refcount == ~0u && GetLastError() == ERROR_MOD_NOT_FOUND && i == 2 ) /* Win8 */, +#endif + "Refcount test failed, i %u, error %lu.\n", i, GetLastError(), refcount ); + if (!ret) return; + } + if (refcount != ~0u) + { + ret = FreeLibrary( mod ); + ok( !ret && GetLastError() == ERROR_MOD_NOT_FOUND, "Refcount test failed, ret %d, error %lu.\n", + ret, GetLastError() ); + } +} + +static void test_LdrGetDllHandleEx(void) +{ + HMODULE mod, loaded_mod; + UNICODE_STRING name; + WCHAR path[MAX_PATH]; + NTSTATUS status; + unsigned int i; + BOOL bret; + + if (!pLdrGetDllHandleEx) + { + win_skip( "LdrGetDllHandleEx is not available.\n" ); + return; + } + + RtlInitUnicodeString( &name, L"unknown.dll" ); + status = pLdrGetDllHandleEx( 0, NULL, NULL, &name, &mod ); + ok( status == STATUS_DLL_NOT_FOUND, "Got unexpected status %#lx.\n", status ); + + RtlInitUnicodeString( &name, L"authz.dll" ); + loaded_mod = LoadLibraryW( name.Buffer ); + ok( !!loaded_mod, "Failed to load module.\n" ); + status = pLdrGetDllHandleEx( 0, NULL, NULL, &name, &mod ); + ok( !status, "Got unexpected status %#lx.\n", status ); + ok( mod == loaded_mod, "got %p\n", mod ); + winetest_push_context( "Flags 0" ); + check_refcount( loaded_mod, 2 ); + winetest_pop_context(); + + loaded_mod = LoadLibraryW( name.Buffer ); + ok( !!loaded_mod, "Failed to load module.\n" ); + status = pLdrGetDllHandleEx( LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, NULL, + NULL, &name, &mod ); + ok( !status, "Got unexpected status %#lx.\n", status ); + ok( mod == loaded_mod, "got %p\n", mod ); + winetest_push_context( "LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT" ); + check_refcount( loaded_mod, 1 ); + winetest_pop_context(); + + loaded_mod = LoadLibraryW( name.Buffer ); + ok( !!loaded_mod, "Failed to load module.\n" ); + status = pLdrGetDllHandle( NULL, ~0u, &name, &mod ); + ok( !status, "Got unexpected status %#lx.\n", status ); + ok( mod == loaded_mod, "got %p\n", mod ); + winetest_push_context( "LdrGetDllHandle" ); + check_refcount( loaded_mod, 1 ); + winetest_pop_context(); + + loaded_mod = LoadLibraryW( name.Buffer ); + ok( !!loaded_mod, "Failed to load module.\n" ); + status = pLdrGetDllHandleEx( 4, NULL, NULL, (void *)&name, &mod ); +#ifdef __REACTOS__ + ok( !status || broken(status == STATUS_INVALID_PARAMETER) /* WS03 */, "Got unexpected status %#lx.\n", status ); + ok( mod == loaded_mod || broken(mod == NULL) /* WS03 */, "got %p\n", mod ); +#else + ok( !status, "Got unexpected status %#lx.\n", status ); + ok( mod == loaded_mod, "got %p\n", mod ); +#endif + winetest_push_context( "Flag 4" ); + check_refcount( loaded_mod, 2 ); + winetest_pop_context(); + + for (i = 3; i < 32; ++i) + { + loaded_mod = LoadLibraryW( name.Buffer ); + ok( !!loaded_mod, "Failed to load module.\n" ); + status = pLdrGetDllHandleEx( 1 << i, NULL, NULL, &name, &mod ); + ok( status == STATUS_INVALID_PARAMETER, "Got unexpected status %#lx.\n", status ); + winetest_push_context( "Invalid flags, i %u", i ); + check_refcount( loaded_mod, 1 ); + winetest_pop_context(); + } + + status = pLdrGetDllHandleEx( LDR_GET_DLL_HANDLE_EX_FLAG_PIN | LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + NULL, NULL, &name, &mod ); + ok( status == STATUS_INVALID_PARAMETER, "Got unexpected status %#lx.\n", status ); + + loaded_mod = LoadLibraryW( name.Buffer ); + ok( !!loaded_mod, "Failed to load module.\n" ); + status = pLdrGetDllHandleEx( LDR_GET_DLL_HANDLE_EX_FLAG_PIN, NULL, + NULL, &name, &mod ); + ok( !status, "Got unexpected status %#lx.\n", status ); + ok( mod == loaded_mod, "got %p\n", mod ); + winetest_push_context( "LDR_GET_DLL_HANDLE_EX_FLAG_PIN" ); + check_refcount( loaded_mod, ~0u ); + winetest_pop_context(); + + GetCurrentDirectoryW( ARRAY_SIZE(path), path ); + if (pAddDllDirectory) pAddDllDirectory( path ); + create_test_dll( "d01.dll" ); + mod = LoadLibraryA( "d01.dll" ); + ok( !!mod, "got error %lu.\n", GetLastError() ); + RtlInitUnicodeString( &name, L"d01.dll" ); + status = pLdrGetDllHandleEx( LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, NULL, NULL, &name, &loaded_mod ); + ok( !status, "got %#lx.\n", status ); + + RtlInitUnicodeString( &name, L"d02.dll" ); + status = pLdrGetDllHandleEx( LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, NULL, NULL, &name, &loaded_mod ); + ok( status == STATUS_DLL_NOT_FOUND, "got %#lx.\n", status ); + + /* Same (moved) file, different name: not found in loaded modules with short name but found with path. */ + DeleteFileA( "d02.dll" ); + bret = MoveFileA( "d01.dll", "d02.dll" ); + ok( bret, "got error %lu.\n", GetLastError() ); + status = pLdrGetDllHandleEx( LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, NULL, NULL, &name, &loaded_mod ); + ok( status == STATUS_DLL_NOT_FOUND, "got %#lx.\n", status ); + CreateDirectoryA( "testdir", NULL ); + DeleteFileA( "testdir\\d02.dll" ); + bret = MoveFileA( "d02.dll", "testdir\\d02.dll" ); + ok( bret, "got error %lu.\n", GetLastError() ); + RtlInitUnicodeString( &name, L"testdir\\d02.dll" ); + status = pLdrGetDllHandleEx( LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, NULL, NULL, &name, &loaded_mod ); + ok( !status, "got %#lx.\n", status ); + ok( loaded_mod == mod, "got %p, %p.\n", loaded_mod, mod ); + FreeLibrary( mod ); + status = pLdrGetDllHandleEx( LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, NULL, NULL, &name, &loaded_mod ); + ok( status == STATUS_DLL_NOT_FOUND, "got %#lx.\n", status ); + + DeleteFileA( "testdir\\d02.dll" ); + RemoveDirectoryA( "testdir" ); +} + +static void test_LdrGetDllFullName(void) +{ + WCHAR expected_path[MAX_PATH], path_buffer[MAX_PATH]; + UNICODE_STRING path = {0, 0, path_buffer}; + WCHAR expected_terminator; + NTSTATUS status; + HMODULE ntdll; + + if (!pLdrGetDllFullName) + { + win_skip( "LdrGetDllFullName not available.\n" ); + return; + } + + if (0) /* crashes on Windows */ + pLdrGetDllFullName( ntdll, NULL ); + + ntdll = GetModuleHandleW( L"ntdll.dll" ); + + memset( path_buffer, 0x23, sizeof(path_buffer) ); + + status = pLdrGetDllFullName( ntdll, &path ); + ok( status == STATUS_BUFFER_TOO_SMALL, "Got unexpected status %#lx.\n", status ); + ok( path.Length == 0, "Expected length 0, got %d.\n", path.Length ); + ok( path_buffer[0] == 0x2323, "Expected 0x2323, got 0x%x.\n", path_buffer[0] ); + + GetSystemDirectoryW( expected_path, ARRAY_SIZE(expected_path) ); + path.MaximumLength = 5; /* odd numbers produce partially copied characters */ + + status = pLdrGetDllFullName( ntdll, &path ); + ok( status == STATUS_BUFFER_TOO_SMALL, "Got unexpected status %#lx.\n", status ); + ok( path.Length == path.MaximumLength, "Expected length %u, got %u.\n", path.MaximumLength, path.Length ); + expected_terminator = 0x2300 | (expected_path[path.MaximumLength / sizeof(WCHAR)] & 0xFF); + ok( path_buffer[path.MaximumLength / sizeof(WCHAR)] == expected_terminator, + "Expected 0x%x, got 0x%x.\n", expected_terminator, path_buffer[path.MaximumLength / 2] ); + path_buffer[path.MaximumLength / sizeof(WCHAR)] = 0; + expected_path[path.MaximumLength / sizeof(WCHAR)] = 0; + ok( lstrcmpW(path_buffer, expected_path) == 0, "Expected %s, got %s.\n", + wine_dbgstr_w(expected_path), wine_dbgstr_w(path_buffer) ); + + GetSystemDirectoryW( expected_path, ARRAY_SIZE(expected_path) ); + lstrcatW( expected_path, L"\\ntdll.dll" ); + path.MaximumLength = sizeof(path_buffer); + + status = pLdrGetDllFullName( ntdll, &path ); + ok( status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status ); + ok( !lstrcmpiW(path_buffer, expected_path), "Expected %s, got %s\n", + wine_dbgstr_w(expected_path), wine_dbgstr_w(path_buffer) ); + + status = pLdrGetDllFullName( NULL, &path ); + ok( status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status ); + GetModuleFileNameW( NULL, expected_path, ARRAY_SIZE(expected_path) ); + ok( !lstrcmpiW(path_buffer, expected_path), "Expected %s, got %s.\n", + wine_dbgstr_w(expected_path), wine_dbgstr_w(path_buffer) ); +} + +static void test_apisets(void) +{ + static const struct + { + const char *name; + BOOLEAN present; + NTSTATUS status; + BOOLEAN present_ex, in_schema, broken; + } + tests[] = + { + { "api-ms-win-core-console-l1-1-0", TRUE, STATUS_SUCCESS, TRUE, TRUE }, + { "api-ms-win-core-console-l1-1-0.dll", TRUE, STATUS_INVALID_PARAMETER }, + { "api-ms-win-core-console-l1-1-9", TRUE, STATUS_SUCCESS, FALSE, FALSE, TRUE }, + { "api-ms-win-core-console-l1-1-9.dll", TRUE, STATUS_INVALID_PARAMETER, FALSE, FALSE, TRUE }, + { "api-ms-win-core-console-l1-1", FALSE, STATUS_SUCCESS }, + { "api-ms-win-core-console-l1-1-0.fake", TRUE, STATUS_INVALID_PARAMETER, FALSE, FALSE, TRUE }, + { "api-ms-win-foo-bar-l1-1-0", FALSE, STATUS_SUCCESS }, + { "api-ms-win-foo-bar-l1-1-0.dll", FALSE, STATUS_INVALID_PARAMETER }, + { "ext-ms-win-gdi-draw-l1-1-1", TRUE, STATUS_SUCCESS, TRUE, TRUE }, + { "ext-ms-win-gdi-draw-l1-1-1.dll", TRUE, STATUS_INVALID_PARAMETER }, + { "api-ms-win-deprecated-apis-advapi-l1-1-0", FALSE, STATUS_SUCCESS, FALSE, TRUE }, + { "foo", FALSE, STATUS_INVALID_PARAMETER }, + { "foo.dll", FALSE, STATUS_INVALID_PARAMETER }, + { "", FALSE, STATUS_INVALID_PARAMETER }, + }; + unsigned int i; + NTSTATUS status; + BOOLEAN present, in_schema; + UNICODE_STRING name; + + if (!pApiSetQueryApiSetPresence) + { + win_skip( "ApiSetQueryApiSetPresence not implemented\n" ); + return; + } + if (!pApiSetQueryApiSetPresenceEx) win_skip( "ApiSetQueryApiSetPresenceEx not implemented\n" ); + if (!pIsApiSetImplemented) win_skip( "IsApiSetImplemented not implemented\n" ); + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + RtlCreateUnicodeStringFromAsciiz( &name, tests[i].name ); + name.Buffer[name.Length / sizeof(WCHAR)] = 0xcccc; /* test without null termination */ + winetest_push_context( "%u:%s", i, tests[i].name ); + present = 0xff; + status = pApiSetQueryApiSetPresence( &name, &present ); + ok( status == STATUS_SUCCESS, "wrong ret %lx\n", status ); + ok( present == tests[i].present || broken(!present && tests[i].broken) /* win8 */, + "wrong present %u\n", present ); + if (pApiSetQueryApiSetPresenceEx) + { + present = in_schema = 0xff; + status = pApiSetQueryApiSetPresenceEx( &name, &in_schema, &present ); + ok( status == tests[i].status, "wrong ret %lx\n", status ); + if (!status) + { + ok( in_schema == tests[i].in_schema, "wrong in_schema %u\n", in_schema ); + ok( present == tests[i].present_ex, "wrong present %u\n", present ); + } + else + { + ok( in_schema == 0xff, "wrong in_schema %u\n", in_schema ); + ok( present == 0xff, "wrong present %u\n", present ); + } + } + if (pIsApiSetImplemented) + { + BOOL ret = pIsApiSetImplemented( tests[i].name ); + ok( ret == (!tests[i].status && tests[i].present_ex), "wrong result %u\n", ret ); + } + winetest_pop_context(); + RtlFreeUnicodeString( &name ); + } +} + +static void test_ddag_node(void) +{ +#if defined(__REACTOS__) && defined(_MSC_VER) + struct dll_dependency { + const WCHAR *dllname; + BOOL optional; + }; + + static struct dll_dependency expected_exe_dependencies_Old[] = { + { L"advapi32.dll" }, + { L"msvcrt.dll", TRUE }, + { L"user32.dll", TRUE }, + }; + + static struct dll_dependency expected_exe_dependencies_Win8[] = { + { L"user32.dll" }, + { L"advapi32.dll", TRUE }, + { L"msvcrt.dll", TRUE }, + }; + + static struct dll_dependency* expected_exe_dependencies; + static int expected_exe_dependencies_size; +#else + static const struct + { + const WCHAR *dllname; + BOOL optional; + } + expected_exe_dependencies[] = + { + { L"advapi32.dll" }, + { L"msvcrt.dll", TRUE }, + { L"user32.dll", TRUE }, + }; +#endif + LDR_DDAG_NODE *node, *dep_node, *prev_node; + LDR_DATA_TABLE_ENTRY *mod, *mod2; + SINGLE_LIST_ENTRY *se, *se2; + LDR_DEPENDENCY *dep, *dep2; + NTSTATUS status; + unsigned int i; + HMODULE hexe; + +#ifdef __REACTOS__ + if (GetNTVersion() < _WIN32_WINNT_VISTA) { + skip("test_ddag_node() crashes on WS03.\n"); + return; + } +#endif + hexe = GetModuleHandleW( NULL ); + ok( !!hexe, "Got NULL exe handle.\n" ); + + status = LdrFindEntryForAddress( hexe, &mod ); + ok( !status, "Got unexpected status %#lx.\n", status ); + + if (!(node = mod->DdagNode)) + { + win_skip( "DdagNode is NULL, skipping tests.\n" ); + return; + } + + ok( !!node->Modules.Flink, "Got NULL module link.\n" ); + mod2 = CONTAINING_RECORD(node->Modules.Flink, LDR_DATA_TABLE_ENTRY, NodeModuleLink); + ok( mod2 == mod || broken( (void **)mod2 == (void **)mod - 1 ), "Got unexpected mod2 %p, expected %p.\n", + mod2, mod ); + if (mod2 != mod) + { + win_skip( "Old LDR_DATA_TABLE_ENTRY structure, skipping tests.\n" ); + return; + } + ok( node->Modules.Flink->Flink == &node->Modules, "Expected one element in list.\n" ); + + ok( !node->IncomingDependencies.Tail, "Expected empty incoming dependencies list.\n" ); + + /* node->Dependencies.Tail is NULL on Windows 10 1507-1607 32 bit test, maybe due to broken structure layout. */ + ok( !!node->Dependencies.Tail || broken( sizeof(void *) == 4 && !node->Dependencies.Tail ), + "Expected nonempty dependencies list.\n" ); + if (!node->Dependencies.Tail) + { + win_skip( "Empty dependencies list.\n" ); + return; + } + todo_wine ok( node->LoadCount == -1, "Got unexpected LoadCount %ld.\n", node->LoadCount ); + + prev_node = NULL; + se = node->Dependencies.Tail; +#if defined(__REACTOS__) && defined(_MSC_VER) + if (GetNTVersion() >= _WIN32_WINNT_WIN8) { + expected_exe_dependencies = expected_exe_dependencies_Win8; + expected_exe_dependencies_size = ARRAY_SIZE(expected_exe_dependencies_Win8); + } else { + expected_exe_dependencies = expected_exe_dependencies_Old; + expected_exe_dependencies_size = ARRAY_SIZE(expected_exe_dependencies_Old); + } + for (i = 0; i < expected_exe_dependencies_size; ++i) +#else + for (i = 0; i < ARRAY_SIZE(expected_exe_dependencies); ++i) +#endif + { + winetest_push_context( "Dep %u (%s)", i, debugstr_w(expected_exe_dependencies[i].dllname) ); + + se = se->Next; + + ok( !!se, "Got NULL list element.\n" ); + dep = CONTAINING_RECORD(se, LDR_DEPENDENCY, dependency_to_entry); + ok( dep->dependency_from == node, "Got unexpected dependency_from %p.\n", dep->dependency_from ); + ok( !!dep->dependency_to, "Got null dependency_to.\n" ); + dep_node = dep->dependency_to; + ok( !!dep_node, "Got NULL dep_node.\n" ); + + if (dep_node == prev_node && expected_exe_dependencies[i].optional) + { + win_skip( "Module is not directly referenced.\n" ); + winetest_pop_context(); + prev_node = dep_node; + continue; + } + + mod2 = CONTAINING_RECORD(dep_node->Modules.Flink, LDR_DATA_TABLE_ENTRY, NodeModuleLink); + ok( !lstrcmpW( mod2->BaseDllName.Buffer, expected_exe_dependencies[i].dllname ), + "Got unexpected module %s.\n", debugstr_w(mod2->BaseDllName.Buffer)); + + se2 = dep_node->IncomingDependencies.Tail; + ok( !!se2, "Got empty incoming dependencies list.\n" ); + do + { + se2 = se2->Next; + dep2 = CONTAINING_RECORD(se2, LDR_DEPENDENCY, dependency_from_entry); + } + while (dep2 != dep && se2 != dep_node->IncomingDependencies.Tail); + ok( dep2 == dep, "Dependency not found in incoming deps list.\n" ); + + todo_wine ok( dep_node->LoadCount > 0 || broken(!dep_node->LoadCount) /* Win8 */, + "Got unexpected LoadCount %ld.\n", dep_node->LoadCount ); + + winetest_pop_context(); + prev_node = dep_node; + } + ok( se == node->Dependencies.Tail, "Expected end of the list.\n" ); +} + +static HANDLE test_tls_links_started, test_tls_links_done; + +static DWORD WINAPI test_tls_links_thread(void* tlsidx_v) +{ + SetEvent(test_tls_links_started); + WaitForSingleObject(test_tls_links_done, INFINITE); + return 0; +} + +static void test_tls_links(void) +{ + TEB *teb = NtCurrentTeb(), *thread_teb; + THREAD_BASIC_INFORMATION tbi; + NTSTATUS status; + HANDLE thread; + + ok(!!teb->ThreadLocalStoragePointer, "got NULL.\n"); + + test_tls_links_started = CreateEventW(NULL, FALSE, FALSE, NULL); + test_tls_links_done = CreateEventW(NULL, FALSE, FALSE, NULL); + + thread = CreateThread(NULL, 0, test_tls_links_thread, NULL, CREATE_SUSPENDED, NULL); + do + { + /* workaround currently present Wine bug when thread teb may be not available immediately + * after creating a thread before it is initialized on the Unix side. */ + Sleep(1); + status = NtQueryInformationThread(thread, ThreadBasicInformation, &tbi, sizeof(tbi), NULL); + ok(!status, "got %#lx.\n", status ); + } while (!(thread_teb = tbi.TebBaseAddress)); + ok(!thread_teb->ThreadLocalStoragePointer, "got %p.\n", thread_teb->ThreadLocalStoragePointer); + ResumeThread(thread); + WaitForSingleObject(test_tls_links_started, INFINITE); + + ok(!!thread_teb->ThreadLocalStoragePointer, "got NULL.\n"); + ok(!teb->TlsLinks.Flink, "got %p.\n", teb->TlsLinks.Flink); + ok(!teb->TlsLinks.Blink, "got %p.\n", teb->TlsLinks.Blink); + ok(!thread_teb->TlsLinks.Flink, "got %p.\n", thread_teb->TlsLinks.Flink); + ok(!thread_teb->TlsLinks.Blink, "got %p.\n", thread_teb->TlsLinks.Blink); + SetEvent(test_tls_links_done); + WaitForSingleObject(thread, INFINITE); + + CloseHandle(thread); + CloseHandle(test_tls_links_started); + CloseHandle(test_tls_links_done); +} + + +static RTL_BALANCED_NODE *rtl_node_parent( RTL_BALANCED_NODE *node ) +{ + return (RTL_BALANCED_NODE *)(node->ParentValue & ~(ULONG_PTR)RTL_BALANCED_NODE_RESERVED_PARENT_MASK); +} + +static unsigned int check_address_index_tree( RTL_BALANCED_NODE *node ) +{ + LDR_DATA_TABLE_ENTRY *mod; + unsigned int count; + char *base; + + if (!node) return 0; + ok( (node->ParentValue & RTL_BALANCED_NODE_RESERVED_PARENT_MASK) <= 1, "got ParentValue %#Ix.\n", + node->ParentValue ); + + mod = CONTAINING_RECORD(node, LDR_DATA_TABLE_ENTRY, BaseAddressIndexNode); + base = mod->DllBase; + if (node->Left) + { + mod = CONTAINING_RECORD(node->Left, LDR_DATA_TABLE_ENTRY, BaseAddressIndexNode); + ok( (char *)mod->DllBase < base, "wrong ordering.\n" ); + } + if (node->Right) + { + mod = CONTAINING_RECORD(node->Right, LDR_DATA_TABLE_ENTRY, BaseAddressIndexNode); + ok( (char *)mod->DllBase > base, "wrong ordering.\n" ); + } + + count = check_address_index_tree( node->Left ); + count += check_address_index_tree( node->Right ); + return count + 1; +} + +static void test_base_address_index_tree(void) +{ + LIST_ENTRY *first = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList; + unsigned int tree_count, list_count = 0; + LDR_DATA_TABLE_ENTRY *mod, *mod2; + RTL_BALANCED_NODE *root, *node; + char *base; + + if (is_old_loader_struct()) return; + + mod = CONTAINING_RECORD(first->Flink, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); + ok( mod->BaseAddressIndexNode.ParentValue || mod->BaseAddressIndexNode.Left || mod->BaseAddressIndexNode.Right, + "got zero BaseAddressIndexNode.\n" ); + root = &mod->BaseAddressIndexNode; + while (rtl_node_parent( root )) + root = rtl_node_parent( root ); + tree_count = check_address_index_tree( root ); + for (LIST_ENTRY *entry = first->Flink; entry != first; entry = entry->Flink) + { + ++list_count; + mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); + base = mod->DllBase; + node = root; + mod2 = NULL; + while (1) + { + ok( !!node, "got NULL.\n" ); + if (!node) break; + mod2 = CONTAINING_RECORD(node, LDR_DATA_TABLE_ENTRY, BaseAddressIndexNode); + if (base == (char *)mod2->DllBase) break; + if (base < (char *)mod2->DllBase) node = node->Left; + else node = node->Right; + } + ok( base == (char *)mod2->DllBase, "module %s not found.\n", debugstr_w(mod->BaseDllName.Buffer) ); + } + ok( tree_count == list_count, "count mismatch %u, %u.\n", tree_count, list_count ); +} + +static ULONG hash_basename( const UNICODE_STRING *basename ) +{ + NTSTATUS status; + ULONG hash; + + status = pRtlHashUnicodeString( basename, TRUE, HASH_STRING_ALGORITHM_DEFAULT, &hash ); + ok( !status, "got %#lx.\n", status ); + return hash & 31; +} + +static void test_hash_links(void) +{ + LIST_ENTRY *hash_map, *entry, *entry2, *mark, *root; + LDR_DATA_TABLE_ENTRY *module; + const WCHAR *modname; + BOOL found; + + /* Hash links structure is the same on older Windows loader but hashing algorithm is different. */ + if (is_old_loader_struct()) return; + + root = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList; + module = CONTAINING_RECORD(root->Flink, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); + hash_map = module->HashLinks.Blink - hash_basename( &module->BaseDllName ); + + for (entry = root->Flink; entry != root; entry = entry->Flink) + { + module = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); + modname = module->BaseDllName.Buffer; + mark = &hash_map[hash_basename( &module->BaseDllName )]; + found = FALSE; + for (entry2 = mark->Flink; entry2 != mark; entry2 = entry2->Flink) + { + module = CONTAINING_RECORD(entry2, LDR_DATA_TABLE_ENTRY, HashLinks); + if ((found = !lstrcmpiW( module->BaseDllName.Buffer, modname ))) break; + } + ok( found, "Could not find %s.\n", debugstr_w(modname) ); + } +} + START_TEST(module) { WCHAR filenameW[MAX_PATH]; @@ -1046,4 +1940,11 @@ START_TEST(module) testK32GetModuleInformation(); test_AddDllDirectory(); test_SetDefaultDllDirectories(); + test_LdrGetDllHandleEx(); + test_LdrGetDllFullName(); + test_apisets(); + test_ddag_node(); + test_tls_links(); + test_base_address_index_tree(); + test_hash_links(); } diff --git a/modules/rostests/winetests/kernel32/path.c b/modules/rostests/winetests/kernel32/path.c index c9afb1bee5c..46eef74bce3 100644 --- a/modules/rostests/winetests/kernel32/path.c +++ b/modules/rostests/winetests/kernel32/path.c @@ -22,12 +22,15 @@ #include #include #include -#include "wine/test.h" +#include "ntstatus.h" +#define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" +#include "winternl.h" #include "winuser.h" #include "winerror.h" #include "winnls.h" +#include "wine/test.h" #define HAS_TRAIL_SLASH_A(string) (string[lstrlenA(string)-1]=='\\') @@ -44,12 +47,12 @@ #ifdef __i386__ #define ARCH "x86" +#elif defined __aarch64__ || defined__arm64ec__ +#define ARCH "arm64" #elif defined __x86_64__ #define ARCH "amd64" #elif defined __arm__ #define ARCH "arm" -#elif defined __aarch64__ -#define ARCH "arm64" #else #define ARCH "none" #endif @@ -63,22 +66,19 @@ static const CHAR funny_chars[]="!@#$%^&*()=+{}[],?'`"; static const CHAR is_char_ok[] ="11111110111111111011"; -static DWORD (WINAPI *pGetLongPathNameA)(LPCSTR,LPSTR,DWORD); -static DWORD (WINAPI *pGetLongPathNameW)(LPWSTR,LPWSTR,DWORD); - /* Present in Win2003+ */ static BOOL (WINAPI *pNeedCurrentDirectoryForExePathA)(LPCSTR); static BOOL (WINAPI *pNeedCurrentDirectoryForExePathW)(LPCWSTR); -static DWORD (WINAPI *pSearchPathA)(LPCSTR,LPCSTR,LPCSTR,DWORD,LPSTR,LPSTR*); -static DWORD (WINAPI *pSearchPathW)(LPCWSTR,LPCWSTR,LPCWSTR,DWORD,LPWSTR,LPWSTR*); -static BOOL (WINAPI *pSetSearchPathMode)(DWORD); - -static BOOL (WINAPI *pActivateActCtx)(HANDLE,ULONG_PTR*); -static HANDLE (WINAPI *pCreateActCtxW)(PCACTCTXW); -static BOOL (WINAPI *pDeactivateActCtx)(DWORD,ULONG_PTR); -static BOOL (WINAPI *pGetCurrentActCtx)(HANDLE *); -static void (WINAPI *pReleaseActCtx)(HANDLE); +static DLL_DIRECTORY_COOKIE (WINAPI *pAddDllDirectory)(const WCHAR*); +static BOOL (WINAPI *pRemoveDllDirectory)(DLL_DIRECTORY_COOKIE); +static BOOL (WINAPI *pSetSearchPathMode)(DWORD); +static BOOL (WINAPI *pSetDllDirectoryW)(LPCWSTR); +static BOOL (WINAPI *pSetDefaultDllDirectories)(DWORD); +static NTSTATUS (WINAPI *pRtlGetExePath)(LPCWSTR,LPWSTR*); +static NTSTATUS (WINAPI *pRtlGetSearchPath)(LPWSTR*); +static void (WINAPI *pRtlReleasePath)(LPWSTR); +static NTSTATUS (WINAPI *pLdrGetDllPath)(LPCWSTR,ULONG,LPWSTR*,LPWSTR*); static BOOL (WINAPI *pCheckNameLegalDOS8Dot3W)(const WCHAR *, char *, DWORD, BOOL *, BOOL *); static BOOL (WINAPI *pCheckNameLegalDOS8Dot3A)(const char *, char *, DWORD, BOOL *, BOOL *); @@ -102,10 +102,10 @@ static void test_ValidPathA(const CHAR *curdir, const CHAR *subdir, const CHAR * CHAR *shortstr, SLpassfail *passfail, const CHAR *errstr) { CHAR tmpstr[MAX_PATH], - fullpath[MAX_PATH], /*full path to the file (not short/long) */ + fullpath[MAX_PATH + 1], /*full path to the file (not short/long) */ subpath[MAX_PATH], /*relative path to the file */ - fullpathshort[MAX_PATH], /*absolute path to the file (short format) */ - fullpathlong[MAX_PATH], /*absolute path to the file (long format) */ + fullpathshort[2 * MAX_PATH], /*absolute path to the file (short format) */ + fullpathlong[2 * MAX_PATH], /*absolute path to the file (long format) */ curdirshort[MAX_PATH], /*absolute path to the current dir (short) */ curdirlong[MAX_PATH]; /*absolute path to the current dir (long) */ LPSTR strptr; /*ptr to the filename portion of the path */ @@ -118,21 +118,18 @@ static void test_ValidPathA(const CHAR *curdir, const CHAR *subdir, const CHAR * passfail->shortlen=-1;passfail->s2llen=-1;passfail->longlen=-1; passfail->shorterror=0;passfail->s2lerror=0;passfail->longerror=0; } -/* GetLongPathNameA is only supported on Win2k+ and Win98+ */ - if(pGetLongPathNameA) { - ok((len=pGetLongPathNameA(curdir,curdirlong,MAX_PATH)), - "%s: GetLongPathNameA failed\n",errstr); + + ok((len = GetLongPathNameA(curdir,curdirlong,MAX_PATH)), "%s: GetLongPathNameA failed\n", errstr); /*GetLongPathNameA can return a trailing '\\' but shouldn't do so here */ - ok(! HAS_TRAIL_SLASH_A(curdirlong), - "%s: GetLongPathNameA should not have a trailing \\\n",errstr); - } + ok(!HAS_TRAIL_SLASH_A(curdirlong), "%s: GetLongPathNameA should not have a trailing \\\n", errstr); + ok((len=GetShortPathNameA(curdir,curdirshort,MAX_PATH)), "%s: GetShortPathNameA failed\n",errstr); /*GetShortPathNameA can return a trailing '\\' but shouldn't do so here */ ok(! HAS_TRAIL_SLASH_A(curdirshort), "%s: GetShortPathNameA should not have a trailing \\\n",errstr); /* build relative and absolute paths from inputs */ - if(lstrlenA(subdir)) { + if(*subdir) { sprintf(subpath,"%s\\%s",subdir,filename); } else { lstrcpyA(subpath,filename); @@ -166,35 +163,38 @@ static void test_ValidPathA(const CHAR *curdir, const CHAR *subdir, const CHAR * passfail->shortlen=len; passfail->shorterror=GetLastError(); } -/* Test GetLongPathNameA functionality - We test both conversion from GetFullPathNameA and from GetShortPathNameA -*/ - if(pGetLongPathNameA) { - if(len!=0) { - SetLastError(0); - len=pGetLongPathNameA(shortstr,tmpstr,MAX_PATH); - if(passfail==NULL) { - ok(len, - "%s: GetLongPathNameA failed during Short->Long conversion\n", errstr); - ok(lstrcmpiA(fullpathlong,tmpstr)==0, - "%s: GetLongPathNameA returned '%s' instead of '%s'\n", - errstr,tmpstr,fullpathlong); - } else { - passfail->s2llen=len; - passfail->s2lerror=GetLastError(); - } + + /* Test GetLongPathNameA functionality, both conversion from GetFullPathNameA and from GetShortPathNameA */ + if (len) + { + SetLastError(0); + len = GetLongPathNameA(shortstr, tmpstr, MAX_PATH); + if (!passfail) + { + ok(len, "%s: GetLongPathNameA failed during Short->Long conversion\n", errstr); + ok(!lstrcmpiA(fullpathlong, tmpstr), "%s: GetLongPathNameA returned '%s' instead of '%s'\n", errstr, + tmpstr, fullpathlong); + } + else + { + passfail->s2llen = len; + passfail->s2lerror = GetLastError(); + } } + SetLastError(0); - len=pGetLongPathNameA(fullpath,tmpstr,MAX_PATH); - if(passfail==NULL) { - ok(len, "%s: GetLongPathNameA failed\n",errstr); - ok(!lstrcmpiA(fullpathlong, tmpstr), "%s: GetLongPathNameA returned '%s' instead of '%s'\n", - errstr, tmpstr, fullpathlong); - } else { - passfail->longlen=len; - passfail->longerror=GetLastError(); + len = GetLongPathNameA(fullpath, tmpstr, MAX_PATH); + if (!passfail) + { + ok(len, "%s: GetLongPathNameA failed\n",errstr); + ok(!lstrcmpiA(fullpathlong, tmpstr), "%s: GetLongPathNameA returned '%s' instead of '%s'\n", + errstr, tmpstr, fullpathlong); + } + else + { + passfail->longlen = len; + passfail->longerror = GetLastError(); } - } } /* split path into leading directory, and 8.3 filename */ @@ -265,27 +265,26 @@ static void test_FunnyChars(CHAR *curdir,CHAR *curdir_short,CHAR *filename, INT ok((passfail.shortlen==0 && (passfail.shorterror==ERROR_FILE_NOT_FOUND || passfail.shorterror==ERROR_PATH_NOT_FOUND || !passfail.shorterror)) || (passfail.shortlen==strlen(tmpstr1) && lstrcmpiA(tmpstr,tmpstr1)==0), - "%s: GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n", + "%s: GetShortPathNameA error: len=%ld error=%ld tmpstr=[%s]\n", errstr,passfail.shortlen,passfail.shorterror,tmpstr); } else { ok(passfail.shortlen==0 && (passfail.shorterror==ERROR_INVALID_NAME || passfail.shorterror==ERROR_FILE_NOT_FOUND || !passfail.shorterror), - "%s: GetShortPathA should have failed len=%d, error=%d\n", + "%s: GetShortPathA should have failed len=%ld, error=%ld\n", errstr,passfail.shortlen,passfail.shorterror); } - if(pGetLongPathNameA) { - ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n"); - if(valid) { - ok(passfail.longerror==ERROR_FILE_NOT_FOUND, - "%s: GetLongPathA returned %d and not %d\n", - errstr,passfail.longerror,ERROR_FILE_NOT_FOUND); - } else { - ok(passfail.longerror==ERROR_INVALID_NAME || - passfail.longerror==ERROR_FILE_NOT_FOUND, - "%s: GetLongPathA returned %d and not %d or %d'\n", - errstr, passfail.longerror,ERROR_INVALID_NAME,ERROR_FILE_NOT_FOUND); + + ok(!passfail.longlen, "GetLongPathNameA passed when it shouldn't have\n"); + if (valid) + { + ok(passfail.longerror == ERROR_FILE_NOT_FOUND, "%s: GetLongPathA unexpected error %ld.\n", errstr, + passfail.longerror); + } + else + { + ok(passfail.longerror == ERROR_INVALID_NAME || passfail.longerror == ERROR_FILE_NOT_FOUND, + "%s: GetLongPathA unexpected error %ld.\n", errstr, passfail.longerror); } - } } /* Routine to test that SetCurrentDirectory behaves as expected. */ @@ -311,7 +310,7 @@ static void test_setdir(CHAR *olddir,CHAR *newdir, ok(SetCurrentDirectoryA(olddir), "%s: Couldn't set directory to its original value\n",errstr); } else { -/* else thest that it fails correctly */ +/* else test that it fails correctly */ chklen=lstrlenA(olddir); ok(val==0, "%s: SetCurrentDirectoryA passed when it should have failed\n",errstr); @@ -328,7 +327,7 @@ static void test_InitPathA(CHAR *newdir, CHAR *curDrive, CHAR *otherDrive) CHAR tmppath[MAX_PATH], /*path to TEMP */ tmpstr[MAX_PATH], tmpstr1[MAX_PATH], - invalid_dir[MAX_PATH]; + invalid_dir[MAX_PATH + 29]; DWORD len,len1,drives; INT id; @@ -351,8 +350,7 @@ static void test_InitPathA(CHAR *newdir, CHAR *curDrive, CHAR *otherDrive) "GetTempPathA returned a path that did not end in '\\'\n"); lstrcpyA(tmpstr,"aaaaaaaa"); len1=GetTempPathA(len,tmpstr); - ok(len1==len+1 || broken(len1 == len), /* WinME */ - "GetTempPathA should return string length %d instead of %d\n",len+1,len1); + ok(len1==len+1,"GetTempPathA should return string length %ld instead of %ld\n",len+1,len1); /* Test GetTmpFileNameA */ ok((id=GetTempFileNameA(tmppath,"path",0,newdir)),"GetTempFileNameA failed\n"); @@ -365,25 +363,20 @@ static void test_InitPathA(CHAR *newdir, CHAR *curDrive, CHAR *otherDrive) ok(DeleteFileA(newdir),"Couldn't delete the temporary file we just created\n"); id=GetTempFileNameA(tmppath,NULL,0,newdir); -/* Windows 95, 98 return 0==id, while Windows 2000, XP return 0!=id */ - if (id) - { - sprintf(tmpstr,"%.4x.tmp",id & 0xffff); - sprintf(tmpstr1,"%x.tmp",id & 0xffff); - ok(lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr)==0 || - lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr1)==0, - "GetTempFileNameA returned '%s' which doesn't match '%s' or '%s'. id=%x\n", - newdir,tmpstr,tmpstr1,id); - ok(DeleteFileA(newdir),"Couldn't delete the temporary file we just created\n"); - } + sprintf(tmpstr,"%.4x.tmp",id & 0xffff); + sprintf(tmpstr1,"%x.tmp",id & 0xffff); + ok(lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr)==0 || + lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr1)==0, + "GetTempFileNameA returned '%s' which doesn't match '%s' or '%s'. id=%x\n", + newdir,tmpstr,tmpstr1,id); + ok(DeleteFileA(newdir),"Couldn't delete the temporary file we just created\n"); for(unique=0;unique<3;unique++) { /* Nonexistent path */ sprintf(invalid_dir, "%s\\%s",tmppath,"non_existent_dir_1jwj3y32nb3"); SetLastError(0xdeadbeef); ok(!GetTempFileNameA(invalid_dir,"tfn",unique,newdir),"GetTempFileNameA should have failed\n"); - ok(GetLastError()==ERROR_DIRECTORY || broken(GetLastError()==ERROR_PATH_NOT_FOUND)/*win98*/, - "got %d, expected ERROR_DIRECTORY\n", GetLastError()); + ok(GetLastError()==ERROR_DIRECTORY,"got %lu, expected ERROR_DIRECTORY\n", GetLastError()); /* Check return value for unique !=0 */ if(unique) { @@ -423,12 +416,12 @@ static void test_InitPathA(CHAR *newdir, CHAR *curDrive, CHAR *otherDrive) bRes = CreateDirectoryA(tmpstr,NULL); ok(!bRes && (GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == ERROR_ALREADY_EXISTS), - "CreateDirectoryA(\"%s\" should have failed (%d)\n", tmpstr, GetLastError()); + "CreateDirectoryA(\"%s\" should have failed (%ld)\n", tmpstr, GetLastError()); sprintf(tmpstr,"%c:\\", *curDrive); bRes = CreateDirectoryA(tmpstr,NULL); ok(!bRes && (GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == ERROR_ALREADY_EXISTS), - "CreateDirectoryA(\"%s\" should have failed (%d)\n", tmpstr, GetLastError()); + "CreateDirectoryA(\"%s\" should have failed (%ld)\n", tmpstr, GetLastError()); sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,SHORTFILE); hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL, CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL); @@ -467,7 +460,7 @@ static void test_CurrentDirectoryA(CHAR *origdir, CHAR *newdir) */ lstrcpyA(tmpstr,"aaaaaaa"); len1=GetCurrentDirectoryA(len,tmpstr); - ok(len1==len+1, "GetCurrentDirectoryA returned %d instead of %d\n",len1,len+1); + ok(len1==len+1, "GetCurrentDirectoryA returned %ld instead of %ld\n",len1,len+1); ok(lstrcmpiA(tmpstr,"aaaaaaa")==0, "GetCurrentDirectoryA should not have modified the buffer\n"); @@ -475,27 +468,27 @@ static void test_CurrentDirectoryA(CHAR *origdir, CHAR *newdir) SetLastError( 0xdeadbeef ); strcpy( buffer, "foo" ); len = GetCurrentDirectoryA( 32767, buffer ); - ok( len != 0 && len < MAX_PATH, "GetCurrentDirectoryA failed %u err %u\n", len, GetLastError() ); + ok( len != 0 && len < MAX_PATH, "GetCurrentDirectoryA failed %lu err %lu\n", len, GetLastError() ); if (len) ok( !strcmp( buffer, origdir ), "wrong result %s\n", buffer ); SetLastError( 0xdeadbeef ); strcpy( buffer, "foo" ); len = GetCurrentDirectoryA( 32768, buffer ); - ok( len != 0 && len < MAX_PATH, "GetCurrentDirectoryA failed %u err %u\n", len, GetLastError() ); + ok( len != 0 && len < MAX_PATH, "GetCurrentDirectoryA failed %lu err %lu\n", len, GetLastError() ); if (len) ok( !strcmp( buffer, origdir ), "wrong result %s\n", buffer ); SetLastError( 0xdeadbeef ); strcpy( buffer, "foo" ); len = GetCurrentDirectoryA( 65535, buffer ); - ok( (len != 0 && len < MAX_PATH) || broken(!len), /* nt4, win2k, xp */ "GetCurrentDirectoryA failed %u err %u\n", len, GetLastError() ); + ok( (len != 0 && len < MAX_PATH) || broken(!len), /* nt4, win2k, xp */ "GetCurrentDirectoryA failed %lu err %lu\n", len, GetLastError() ); if (len) ok( !strcmp( buffer, origdir ), "wrong result %s\n", buffer ); SetLastError( 0xdeadbeef ); strcpy( buffer, "foo" ); len = GetCurrentDirectoryA( 65536, buffer ); - ok( (len != 0 && len < MAX_PATH) || broken(!len), /* nt4 */ "GetCurrentDirectoryA failed %u err %u\n", len, GetLastError() ); + ok( (len != 0 && len < MAX_PATH), "GetCurrentDirectoryA failed %lu err %lu\n", len, GetLastError() ); if (len) ok( !strcmp( buffer, origdir ), "wrong result %s\n", buffer ); SetLastError( 0xdeadbeef ); strcpy( buffer, "foo" ); len = GetCurrentDirectoryA( 2 * 65536, buffer ); - ok( (len != 0 && len < MAX_PATH) || broken(!len), /* nt4 */ "GetCurrentDirectoryA failed %u err %u\n", len, GetLastError() ); + ok( (len != 0 && len < MAX_PATH), "GetCurrentDirectoryA failed %lu err %lu\n", len, GetLastError() ); if (len) ok( !strcmp( buffer, origdir ), "wrong result %s\n", buffer ); HeapFree( GetProcessHeap(), 0, buffer ); @@ -519,7 +512,7 @@ static void test_CurrentDirectoryA(CHAR *origdir, CHAR *newdir) /* Check that SetCurrentDirectory fails when a nonexistent dir is specified */ sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,NONDIR_SHORT); test_setdir(newdir,tmpstr,NULL,0,"check 3"); -/* Check that SetCurrentDirectory fails for a nonexistent lond directory */ +/* Check that SetCurrentDirectory fails for a nonexistent long directory */ sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,NONDIR_LONG); test_setdir(newdir,tmpstr,NULL,0,"check 4"); /* Check that SetCurrentDirectory passes with a long directory */ @@ -552,7 +545,7 @@ static void test_CurrentDirectoryA(CHAR *origdir, CHAR *newdir) /* Cleanup the mess we made while executing these tests */ static void test_CleanupPathA(CHAR *origdir, CHAR *curdir) { - CHAR tmpstr[MAX_PATH]; + CHAR tmpstr[MAX_PATH + 35]; sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,SHORTFILE); ok(DeleteFileA(tmpstr),"DeleteFileA failed\n"); sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,LONGFILE); @@ -581,14 +574,14 @@ static void test_ShortPathCase(const char *tmpdir, const char *dirname, sprintf(buf,"%s\\%s\\%s",tmpdir,dirname,filename); GetShortPathNameA(buf,shortbuf,sizeof(shortbuf)); hndl = CreateFileA(shortbuf,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL); - ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed (%d)\n",GetLastError()); + ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed (%ld)\n",GetLastError()); CloseHandle(hndl); /* Now for the real test */ for(i=0;i= len_with_null, "Expected >= %u, got %u\n", len_with_null, len); + ok(len >= len_with_null, "Expected >= %lu, got %lu\n", len_with_null, len); len = GetTempPathA(0, NULL); - ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len); + ok(len >= len_with_null, "Expected >= %lu, got %lu\n", len_with_null, len); /* The call above gave us the buffer size that Windows thinks is needed * so the next call should work @@ -1011,15 +966,15 @@ static void test_GetTempPathA(char* tmp_dir) /* The rest of the buffer remains untouched */ slen = len + 1; for(len++; len < sizeof(buf); len++) - ok(buf[len] == 'a', "expected 'a' at [%d], got 0x%x\n", len, buf[len]); + ok(buf[len] == 'a', "expected 'a' at [%ld], got 0x%x\n", len, buf[len]); /* When the buffer is not long enough it remains untouched */ memset(buf, 'a', sizeof(buf)); len = GetTempPathA(slen / 2, buf); ok(len == slen || broken(len == slen + 1) /* read the big comment above */ , - "expected %d, got %d\n", slen, len); - for(len = 0; len < sizeof(buf) / sizeof(buf[0]); len++) - ok(buf[len] == 'a', "expected 'a' at [%d], got 0x%x\n", len, buf[len]); + "expected %ld, got %ld\n", slen, len); + for(len = 0; len < ARRAY_SIZE(buf); len++) + ok(buf[len] == 'a', "expected 'a' at [%ld], got 0x%x\n", len, buf[len]); } static void test_GetTempPathW(char* tmp_dir) @@ -1029,7 +984,7 @@ static void test_GetTempPathW(char* tmp_dir) WCHAR tmp_dirW[MAX_PATH]; static const WCHAR fooW[] = {'f','o','o',0}; - MultiByteToWideChar(CP_ACP,0,tmp_dir,-1,tmp_dirW,sizeof(tmp_dirW)/sizeof(*tmp_dirW)); + MultiByteToWideChar(CP_ACP, 0, tmp_dir, -1, tmp_dirW, ARRAY_SIZE(tmp_dirW)); len_with_null = lstrlenW(tmp_dirW) + 1; /* This one is different from ANSI version: ANSI version doesn't @@ -1043,43 +998,38 @@ static void test_GetTempPathW(char* tmp_dir) lstrcpyW(buf, fooW); len = GetTempPathW(MAX_PATH, buf); - if (len == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) - { - win_skip("GetTempPathW is not available\n"); - return; - } ok(lstrcmpiW(buf, tmp_dirW) == 0, "GetTempPathW returned an incorrect temporary path\n"); ok(len == lstrlenW(buf), "returned length should be equal to the length of string\n"); lstrcpyW(buf, fooW); len = GetTempPathW(1, buf); ok(buf[0] == 0, "unicode version should truncate the buffer to zero size\n"); - ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len); + ok(len >= len_with_null, "Expected >= %lu, got %lu\n", len_with_null, len); len = GetTempPathW(0, NULL); - ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len); + ok(len >= len_with_null, "Expected >= %lu, got %lu\n", len_with_null, len); lstrcpyW(buf, fooW); len = GetTempPathW(len, buf); ok(lstrcmpiW(buf, tmp_dirW) == 0, "GetTempPathW returned an incorrect temporary path\n"); ok(len == lstrlenW(buf), "returned length should be equal to the length of string\n"); - for(len = 0; len < sizeof(buf) / sizeof(buf[0]); len++) + for(len = 0; len < ARRAY_SIZE(buf); len++) buf[len] = 'a'; len = GetTempPathW(len, buf); ok(lstrcmpiW(buf, tmp_dirW) == 0, "GetTempPathW returned an incorrect temporary path\n"); ok(len == lstrlenW(buf), "returned length should be equal to the length of string\n"); /* The rest of the buffer must be zeroed */ slen = len + 1; - for(len++; len < sizeof(buf) / sizeof(buf[0]); len++) - ok(buf[len] == '\0', "expected NULL at [%d], got 0x%x\n", len, buf[len]); + for(len++; len < ARRAY_SIZE(buf); len++) + ok(buf[len] == '\0', "expected NULL at [%ld], got 0x%x\n", len, buf[len]); /* When the buffer is not long enough the length passed is zeroed */ - for(len = 0; len < sizeof(buf) / sizeof(buf[0]); len++) + for(len = 0; len < ARRAY_SIZE(buf); len++) buf[len] = 'a'; len = GetTempPathW(slen / 2, buf); ok(len == slen || broken(len == slen + 1) /* read the big comment above */ , - "expected %d, got %d\n", slen, len); + "expected %ld, got %ld\n", slen, len); { /* In Windows 8 when TMP var points to a drive only (like C:) instead of a @@ -1095,9 +1045,9 @@ static void test_GetTempPathW(char* tmp_dir) } for(len = 0; len < slen / 2; len++) - ok(buf[len] == '\0', "expected NULL at [%d], got 0x%x\n", len, buf[len]); - for(; len < sizeof(buf) / sizeof(buf[0]); len++) - ok(buf[len] == 'a', "expected 'a' at [%d], got 0x%x\n", len, buf[len]); + ok(buf[len] == '\0', "expected NULL at [%ld], got 0x%x\n", len, buf[len]); + for(; len < ARRAY_SIZE(buf); len++) + ok(buf[len] == 'a', "expected 'a' at [%ld], got 0x%x\n", len, buf[len]); /* bogus application from bug 38220 passes the count value in sizeof(buffer) * instead the correct count of WCHAR, this test catches this case. */ @@ -1119,11 +1069,11 @@ static void test_GetTempPathW(char* tmp_dir) * to simplify testing we will test only until XP. */ for(; len < 32767; len++) - ok(long_buf[len] == '\0', "expected NULL at [%d], got 0x%x\n", len, long_buf[len]); + ok(long_buf[len] == '\0', "expected NULL at [%ld], got 0x%x\n", len, long_buf[len]); /* we will know skip the test that is in the middle of the OS difference by * incrementing len and then resume the test for the untouched part. */ for(len++; len < slen; len++) - ok(long_buf[len] == 0xcc, "expected 0xcc at [%d], got 0x%x\n", len, long_buf[len]); + ok(long_buf[len] == 0xcc, "expected 0xcc at [%ld], got 0x%x\n", len, long_buf[len]); HeapFree(GetProcessHeap(), 0, long_buf); } @@ -1193,17 +1143,14 @@ static void test_GetLongPathNameA(void) char temppath[MAX_PATH], temppath2[MAX_PATH]; HANDLE file; - if (!pGetLongPathNameA) - return; - GetTempPathA(MAX_PATH, tempfile); name = tempfile + strlen(tempfile); strcpy(name, "*"); SetLastError(0xdeadbeef); - length = pGetLongPathNameA(tempfile, temppath, MAX_PATH); + length = GetLongPathNameA(tempfile, temppath, MAX_PATH); ok(!length, "GetLongPathNameA should fail\n"); - ok(GetLastError() == ERROR_INVALID_NAME, "wrong error %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_NAME, "wrong error %ld\n", GetLastError()); strcpy(name, "longfilename.longext"); @@ -1212,7 +1159,7 @@ static void test_GetLongPathNameA(void) /* Test a normal path with a small buffer size */ memset(temppath, 0, MAX_PATH); - length = pGetLongPathNameA(tempfile, temppath, 4); + length = GetLongPathNameA(tempfile, temppath, 4); /* We have a failure so length should be the minimum plus the terminating '0' */ ok(length >= strlen(tempfile) + 1, "Wrong length\n"); ok(temppath[0] == 0, "Buffer should not have been touched\n"); @@ -1226,20 +1173,14 @@ static void test_GetLongPathNameA(void) explength = length + 4; SetLastError(0xdeadbeef); - length = pGetLongPathNameA(temppath2, NULL, 0); - if (length == 0 && GetLastError() == ERROR_BAD_NET_NAME) - { - win_skip("UNC syntax tests don't work on Win98/WinMe\n"); - DeleteFileA(tempfile); - return; - } - ok(length == explength, "Wrong length %d, expected %d\n", length, explength); + length = GetLongPathNameA(temppath2, NULL, 0); + ok(length == explength, "Wrong length %ld, expected %ld\n", length, explength); - length = pGetLongPathNameA(temppath2, NULL, MAX_PATH); - ok(length == explength, "Wrong length %d, expected %d\n", length, explength); + length = GetLongPathNameA(temppath2, NULL, MAX_PATH); + ok(length == explength, "Wrong length %ld, expected %ld\n", length, explength); - length = pGetLongPathNameA(temppath2, temppath, 4); - ok(length == explength, "Wrong length %d, expected %d\n", length, explength); + length = GetLongPathNameA(temppath2, temppath, 4); + ok(length == explength, "Wrong length %ld, expected %ld\n", length, explength); ok(temppath[0] == 0, "Buffer should not have been touched\n"); /* Now an UNC path with the computername */ @@ -1258,7 +1199,7 @@ static void test_GetLongPathNameA(void) /* Create a long syntax for reference */ memset(longpath, 0, MAX_PATH); - pGetLongPathNameA(tempfile, temppath, MAX_PATH); + GetLongPathNameA(tempfile, temppath, MAX_PATH); lstrcpyA(longpath, unc_prefix); longpath[lstrlenA(longpath)] = temppath[0]; lstrcatA(longpath, "$\\"); @@ -1266,7 +1207,7 @@ static void test_GetLongPathNameA(void) /* NULL test */ SetLastError(0xdeadbeef); - length = pGetLongPathNameA(unc_short, NULL, 0); + length = GetLongPathNameA(unc_short, NULL, 0); if (length == 0 && GetLastError() == ERROR_BAD_NETPATH) { /* Seen on Window XP Home */ @@ -1276,26 +1217,26 @@ static void test_GetLongPathNameA(void) } explength = lstrlenA(longpath) + 1; todo_wine - ok(length == explength, "Wrong length %d, expected %d\n", length, explength); + ok(length == explength, "Wrong length %ld, expected %ld\n", length, explength); - length = pGetLongPathNameA(unc_short, NULL, MAX_PATH); + length = GetLongPathNameA(unc_short, NULL, MAX_PATH); todo_wine - ok(length == explength, "Wrong length %d, expected %d\n", length, explength); + ok(length == explength, "Wrong length %ld, expected %ld\n", length, explength); memset(unc_long, 0, MAX_PATH); - length = pGetLongPathNameA(unc_short, unc_long, lstrlenA(unc_short)); + length = GetLongPathNameA(unc_short, unc_long, lstrlenA(unc_short)); /* length will include terminating '0' on failure */ todo_wine - ok(length == explength, "Wrong length %d, expected %d\n", length, explength); + ok(length == explength, "Wrong length %ld, expected %ld\n", length, explength); ok(unc_long[0] == 0, "Buffer should not have been touched\n"); memset(unc_long, 0, MAX_PATH); - length = pGetLongPathNameA(unc_short, unc_long, length); + length = GetLongPathNameA(unc_short, unc_long, length); /* length doesn't include terminating '0' on success */ explength--; todo_wine { - ok(length == explength, "Wrong length %d, expected %d\n", length, explength); + ok(length == explength, "Wrong length %ld, expected %ld\n", length, explength); ok(!lstrcmpiA(unc_long, longpath), "Expected (%s), got (%s)\n", longpath, unc_long); } @@ -1315,31 +1256,23 @@ static void test_GetLongPathNameW(void) static const WCHAR backslash[] = { '\\', 0}; static const WCHAR letterX[] = { 'X', 0}; - if (!pGetLongPathNameW) - return; - SetLastError(0xdeadbeef); - length = pGetLongPathNameW(NULL,NULL,0); - if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) - { - win_skip("GetLongPathNameW is not implemented\n"); - return; - } - ok(0==length,"GetLongPathNameW returned %d but expected 0\n",length); - ok(GetLastError()==ERROR_INVALID_PARAMETER,"GetLastError returned %d but expected ERROR_INVALID_PARAMETER\n",GetLastError()); + length = GetLongPathNameW(NULL,NULL,0); + ok(0==length,"GetLongPathNameW returned %ld but expected 0\n",length); + ok(GetLastError()==ERROR_INVALID_PARAMETER,"GetLastError returned %ld but expected ERROR_INVALID_PARAMETER\n",GetLastError()); SetLastError(0xdeadbeef); empty[0]=0; - length = pGetLongPathNameW(empty,NULL,0); - ok(0==length,"GetLongPathNameW returned %d but expected 0\n",length); - ok(GetLastError()==ERROR_PATH_NOT_FOUND,"GetLastError returned %d but expected ERROR_PATH_NOT_FOUND\n",GetLastError()); + length = GetLongPathNameW(empty,NULL,0); + ok(0==length,"GetLongPathNameW returned %ld but expected 0\n",length); + ok(GetLastError()==ERROR_PATH_NOT_FOUND,"GetLastError returned %ld but expected ERROR_PATH_NOT_FOUND\n",GetLastError()); /* Create a long path name. The path needs to exist for these tests to * succeed so we need the "\\?\" prefix when creating directories and * files. */ name[0] = 0; - while (lstrlenW(name) < (sizeof(name)/sizeof(WCHAR) - 1)) + while (lstrlenW(name) < (ARRAY_SIZE(name) - 1)) lstrcatW(name, letterX); GetTempPathW(MAX_PATH, tempdir); @@ -1349,7 +1282,7 @@ static void test_GetLongPathNameW(void) lstrcatW(shortpath, name); lstrcpyW(dirpath, shortpath); ret = CreateDirectoryW(shortpath, NULL); - ok(ret, "Could not create the temporary directory : %d\n", GetLastError()); + ok(ret, "Could not create the temporary directory : %ld\n", GetLastError()); lstrcatW(shortpath, backslash); lstrcatW(shortpath, name); @@ -1357,46 +1290,46 @@ static void test_GetLongPathNameW(void) /* No prefix */ SetLastError(0xdeadbeef); - length = pGetLongPathNameW(shortpath + 4, NULL, 0); - ok(length == 0, "Expected 0, got %d\n", length); + length = GetLongPathNameW(shortpath + 4, NULL, 0); + ok(length == 0, "Expected 0, got %ld\n", length); todo_wine ok(GetLastError() == ERROR_PATH_NOT_FOUND, - "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError()); + "Expected ERROR_PATH_NOT_FOUND, got %ld\n", GetLastError()); /* With prefix */ SetLastError(0xdeadbeef); - length = pGetLongPathNameW(shortpath, NULL, 0); + length = GetLongPathNameW(shortpath, NULL, 0); todo_wine { - ok(length == 0, "Expected 0, got %d\n", length); + ok(length == 0, "Expected 0, got %ld\n", length); ok(GetLastError() == ERROR_FILE_NOT_FOUND, - "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError()); + "Expected ERROR_PATH_NOT_FOUND, got %ld\n", GetLastError()); } file = CreateFileW(shortpath, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); ok(file != INVALID_HANDLE_VALUE, - "Could not create the temporary file : %d.\n", GetLastError()); + "Could not create the temporary file : %ld.\n", GetLastError()); CloseHandle(file); /* Path exists */ /* No prefix */ SetLastError(0xdeadbeef); - length = pGetLongPathNameW(shortpath + 4, NULL, 0); + length = GetLongPathNameW(shortpath + 4, NULL, 0); todo_wine { - ok(length == 0, "Expected 0, got %d\n", length); - ok(GetLastError() == ERROR_PATH_NOT_FOUND, "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError()); + ok(length == 0, "Expected 0, got %ld\n", length); + ok(GetLastError() == ERROR_PATH_NOT_FOUND, "Expected ERROR_PATH_NOT_FOUND, got %ld\n", GetLastError()); } /* With prefix */ - expanded = 4 + (pGetLongPathNameW(tempdir, NULL, 0) - 1) + lstrlenW(name) + 1 + lstrlenW(name) + 1; + expanded = 4 + (GetLongPathNameW(tempdir, NULL, 0) - 1) + lstrlenW(name) + 1 + lstrlenW(name) + 1; SetLastError(0xdeadbeef); - length = pGetLongPathNameW(shortpath, NULL, 0); - ok(length == expanded, "Expected %d, got %d\n", expanded, length); + length = GetLongPathNameW(shortpath, NULL, 0); + ok(length == expanded, "Expected %ld, got %ld\n", expanded, length); /* NULL buffer with length crashes on Windows */ if (0) - pGetLongPathNameW(shortpath, NULL, 20); + GetLongPathNameW(shortpath, NULL, 20); ok(DeleteFileW(shortpath), "Could not delete temporary file\n"); ok(RemoveDirectoryW(dirpath), "Could not delete temporary directory\n"); @@ -1416,19 +1349,13 @@ static void test_GetShortPathNameW(void) HANDLE file; int ret; - SetLastError(0xdeadbeef); GetTempPathW( MAX_PATH, tmppath ); - if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) - { - win_skip("GetTempPathW is not implemented\n"); - return; - } lstrcpyW( path, tmppath ); lstrcatW( path, test_path ); lstrcatW( path, backSlash ); ret = CreateDirectoryW( path, NULL ); - ok( ret, "Directory was not created. LastError = %d\n", GetLastError() ); + ok( ret, "Directory was not created. LastError = %ld\n", GetLastError() ); /* Starting a main part of test */ @@ -1438,7 +1365,7 @@ static void test_GetShortPathNameW(void) lstrcatW( path, test_path ); lstrcatW( path, backSlash ); short_path[0] = 0; - length = GetShortPathNameW( path, short_path, sizeof(short_path) / sizeof(*short_path) ); + length = GetShortPathNameW( path, short_path, ARRAY_SIZE( short_path )); ok( length, "GetShortPathNameW returned 0.\n" ); lstrcpyW( path, tmppath ); @@ -1455,7 +1382,7 @@ static void test_GetShortPathNameW(void) SetLastError(0xdeadbeef); length = GetShortPathNameW( short_path, path, 0 ); ok(!length, "GetShortPathNameW should fail\n"); - ok(GetLastError() == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError()); file = CreateFileW( short_path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); ok( file != INVALID_HANDLE_VALUE, "File was not created.\n" ); @@ -1469,14 +1396,14 @@ static void test_GetShortPathNameW(void) ok( file != INVALID_HANDLE_VALUE, "File was not created.\n" ); CloseHandle( file ); - length = GetShortPathNameW( path, short_path, sizeof(short_path)/sizeof(*short_path) ); - ok( length, "GetShortPathNameW failed: %u.\n", GetLastError() ); + length = GetShortPathNameW( path, short_path, ARRAY_SIZE( short_path )); + ok( length, "GetShortPathNameW failed: %lu.\n", GetLastError() ); lstrcpyW(ptr, wildW); SetLastError(0xdeadbeef); - length = GetShortPathNameW( path, short_path, sizeof(short_path)/sizeof(*short_path) ); + length = GetShortPathNameW( path, short_path, ARRAY_SIZE( short_path ) ); ok(!length, "GetShortPathNameW should fail\n"); - ok(GetLastError() == ERROR_INVALID_NAME, "wrong error %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_NAME, "wrong error %ld\n", GetLastError()); lstrcpyW(ptr, a_bcdeW); ret = DeleteFileW( path ); @@ -1497,7 +1424,7 @@ static void test_GetSystemDirectory(void) SetLastError(0xdeadbeef); res = GetSystemDirectoryA(NULL, 0); /* res includes the terminating Zero */ - ok(res > 0, "returned %d with %d (expected '>0')\n", res, GetLastError()); + ok(res > 0, "returned %ld with %ld (expected '>0')\n", res, GetLastError()); total = res; @@ -1507,11 +1434,8 @@ static void test_GetSystemDirectory(void) SetLastError(0xdeadbeef); res = GetSystemDirectoryA(NULL, total-1); - /* 95+NT: total (includes the terminating Zero) - 98+ME: 0 with ERROR_INVALID_PARAMETER */ - ok( (res == total) || (!res && (GetLastError() == ERROR_INVALID_PARAMETER)), - "returned %d with %d (expected '%d' or: '0' with " - "ERROR_INVALID_PARAMETER)\n", res, GetLastError(), total); + ok( res == total, "returned %lu with %lu (expected '%lu')\n", + res, GetLastError(), total ); if (total > MAX_PATH) return; @@ -1520,7 +1444,7 @@ static void test_GetSystemDirectory(void) res = GetSystemDirectoryA(buffer, total); /* res does not include the terminating Zero */ ok( (res == (total-1)) && (buffer[0]), - "returned %d with %d and '%s' (expected '%d' and a string)\n", + "returned %ld with %ld and '%s' (expected '%ld' and a string)\n", res, GetLastError(), buffer, total-1); buffer[0] = '\0'; @@ -1528,7 +1452,7 @@ static void test_GetSystemDirectory(void) res = GetSystemDirectoryA(buffer, total + 1); /* res does not include the terminating Zero */ ok( (res == (total-1)) && (buffer[0]), - "returned %d with %d and '%s' (expected '%d' and a string)\n", + "returned %ld with %ld and '%s' (expected '%ld' and a string)\n", res, GetLastError(), buffer, total-1); memset(buffer, '#', total + 1); @@ -1536,7 +1460,7 @@ static void test_GetSystemDirectory(void) SetLastError(0xdeadbeef); res = GetSystemDirectoryA(buffer, total-1); /* res includes the terminating Zero) */ - ok( res == total, "returned %d with %d and '%s' (expected '%d')\n", + ok( res == total, "returned %ld with %ld and '%s' (expected '%ld')\n", res, GetLastError(), buffer, total); memset(buffer, '#', total + 1); @@ -1544,7 +1468,7 @@ static void test_GetSystemDirectory(void) SetLastError(0xdeadbeef); res = GetSystemDirectoryA(buffer, total-2); /* res includes the terminating Zero) */ - ok( res == total, "returned %d with %d and '%s' (expected '%d')\n", + ok( res == total, "returned %ld with %ld and '%s' (expected '%ld')\n", res, GetLastError(), buffer, total); } @@ -1557,7 +1481,7 @@ static void test_GetWindowsDirectory(void) SetLastError(0xdeadbeef); res = GetWindowsDirectoryA(NULL, 0); /* res includes the terminating Zero */ - ok(res > 0, "returned %d with %d (expected '>0')\n", res, GetLastError()); + ok(res > 0, "returned %ld with %ld (expected '>0')\n", res, GetLastError()); total = res; /* this crashes on XP */ @@ -1566,11 +1490,8 @@ static void test_GetWindowsDirectory(void) SetLastError(0xdeadbeef); res = GetWindowsDirectoryA(NULL, total-1); - /* 95+NT: total (includes the terminating Zero) - 98+ME: 0 with ERROR_INVALID_PARAMETER */ - ok( (res == total) || (!res && (GetLastError() == ERROR_INVALID_PARAMETER)), - "returned %d with %d (expected '%d' or: '0' with " - "ERROR_INVALID_PARAMETER)\n", res, GetLastError(), total); + ok( res == total, "returned %lu with %lu (expected '%lu')\n", + res, GetLastError(), total ); if (total > MAX_PATH) return; @@ -1579,7 +1500,7 @@ static void test_GetWindowsDirectory(void) res = GetWindowsDirectoryA(buffer, total); /* res does not include the terminating Zero */ ok( (res == (total-1)) && (buffer[0]), - "returned %d with %d and '%s' (expected '%d' and a string)\n", + "returned %ld with %ld and '%s' (expected '%ld' and a string)\n", res, GetLastError(), buffer, total-1); buffer[0] = '\0'; @@ -1587,7 +1508,7 @@ static void test_GetWindowsDirectory(void) res = GetWindowsDirectoryA(buffer, total + 1); /* res does not include the terminating Zero */ ok( (res == (total-1)) && (buffer[0]), - "returned %d with %d and '%s' (expected '%d' and a string)\n", + "returned %ld with %ld and '%s' (expected '%ld' and a string)\n", res, GetLastError(), buffer, total-1); memset(buffer, '#', total + 1); @@ -1595,7 +1516,7 @@ static void test_GetWindowsDirectory(void) SetLastError(0xdeadbeef); res = GetWindowsDirectoryA(buffer, total-1); /* res includes the terminating Zero) */ - ok( res == total, "returned %d with %d and '%s' (expected '%d')\n", + ok( res == total, "returned %ld with %ld and '%s' (expected '%ld')\n", res, GetLastError(), buffer, total); memset(buffer, '#', total + 1); @@ -1603,7 +1524,7 @@ static void test_GetWindowsDirectory(void) SetLastError(0xdeadbeef); res = GetWindowsDirectoryA(buffer, total-2); /* res includes the terminating Zero) */ - ok( res == total, "returned %d with %d and '%s' (expected '%d')\n", + ok( res == total, "returned %ld with %ld and '%s' (expected '%ld')\n", res, GetLastError(), buffer, total); } @@ -1671,7 +1592,7 @@ static void test_drive_letter_case(void) memset(buf, 0, sizeof(buf)); SetLastError(0xdeadbeef); ret = GetWindowsDirectoryA(buf, sizeof(buf)); - ok(ret, "GetWindowsDirectory error %u\n", GetLastError()); + ok(ret, "GetWindowsDirectory error %lu\n", GetLastError()); ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret); ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]); ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]); @@ -1680,7 +1601,7 @@ static void test_drive_letter_case(void) buf[2] = '/'; SetLastError(0xdeadbeef); ret = GetFullPathNameA(buf + 2, sizeof(buf), buf, NULL); - ok(ret, "GetFullPathName error %u\n", GetLastError()); + ok(ret, "GetFullPathName error %lu\n", GetLastError()); ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret); ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]); ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]); @@ -1688,7 +1609,7 @@ static void test_drive_letter_case(void) memset(buf, 0, sizeof(buf)); SetLastError(0xdeadbeef); ret = GetSystemDirectoryA(buf, sizeof(buf)); - ok(ret, "GetSystemDirectory error %u\n", GetLastError()); + ok(ret, "GetSystemDirectory error %lu\n", GetLastError()); ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret); ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]); ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]); @@ -1696,7 +1617,7 @@ static void test_drive_letter_case(void) memset(buf, 0, sizeof(buf)); SetLastError(0xdeadbeef); ret = GetCurrentDirectoryA(sizeof(buf), buf); - ok(ret, "GetCurrentDirectory error %u\n", GetLastError()); + ok(ret, "GetCurrentDirectory error %lu\n", GetLastError()); ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret); ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]); ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]); @@ -1705,7 +1626,7 @@ static void test_drive_letter_case(void) memset(buf, 0, sizeof(buf)); SetLastError(0xdeadbeef); ret = GetTempPathA(sizeof(buf), buf); - ok(ret, "GetTempPath error %u\n", GetLastError()); + ok(ret, "GetTempPath error %lu\n", GetLastError()); ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret); if (buf[0]) { @@ -1716,7 +1637,7 @@ static void test_drive_letter_case(void) memset(buf, 0, sizeof(buf)); SetLastError(0xdeadbeef); ret = GetFullPathNameA(".", sizeof(buf), buf, NULL); - ok(ret, "GetFullPathName error %u\n", GetLastError()); + ok(ret, "GetFullPathName error %lu\n", GetLastError()); ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret); ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]); ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]); @@ -1724,21 +1645,18 @@ static void test_drive_letter_case(void) /* re-use the buffer returned by GetFullPathName */ SetLastError(0xdeadbeef); ret = GetShortPathNameA(buf, buf, sizeof(buf)); - ok(ret, "GetShortPathName error %u\n", GetLastError()); + ok(ret, "GetShortPathName error %lu\n", GetLastError()); ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret); ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]); ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]); - if (pGetLongPathNameA) - { - /* re-use the buffer returned by GetShortPathName */ - SetLastError(0xdeadbeef); - ret = pGetLongPathNameA(buf, buf, sizeof(buf)); - ok(ret, "GetLongPathNameA error %u\n", GetLastError()); - ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret); - ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]); - ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]); - } + /* re-use the buffer returned by GetShortPathName */ + SetLastError(0xdeadbeef); + ret = GetLongPathNameA(buf, buf, sizeof(buf)); + ok(ret, "GetLongPathNameA error %lu\n", GetLastError()); + ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret); + ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]); + ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]); #undef is_upper_case_letter } @@ -1768,11 +1686,11 @@ static void create_manifest_file(const char *filename, const char *manifest) MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH ); - GetTempPathW(sizeof(manifest_path)/sizeof(WCHAR), manifest_path); + GetTempPathW(ARRAY_SIZE(manifest_path), manifest_path); lstrcatW(manifest_path, path); file = CreateFileW(manifest_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError()); + ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %lu\n", GetLastError()); WriteFile(file, manifest, strlen(manifest), &size, NULL); CloseHandle(file); } @@ -1793,18 +1711,18 @@ static HANDLE test_create(const char *file) HANDLE handle; MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH); - GetTempPathW(sizeof(manifest_path)/sizeof(WCHAR), manifest_path); + GetTempPathW(ARRAY_SIZE(manifest_path), manifest_path); lstrcatW(manifest_path, path); memset(&actctx, 0, sizeof(ACTCTXW)); actctx.cbSize = sizeof(ACTCTXW); actctx.lpSource = manifest_path; - handle = pCreateActCtxW(&actctx); - ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %u\n", GetLastError()); + handle = CreateActCtxW(&actctx); + ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %lu\n", GetLastError()); - ok(actctx.cbSize == sizeof(actctx), "cbSize=%d\n", actctx.cbSize); - ok(actctx.dwFlags == 0, "dwFlags=%d\n", actctx.dwFlags); + ok(actctx.cbSize == sizeof(actctx), "cbSize=%ld\n", actctx.cbSize); + ok(actctx.dwFlags == 0, "dwFlags=%ld\n", actctx.dwFlags); ok(actctx.lpSource == manifest_path, "lpSource=%p\n", actctx.lpSource); ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture); ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId); @@ -1822,37 +1740,52 @@ static void test_SearchPathA(void) static const CHAR testdeprelA[] = "./testdep.dll"; static const CHAR kernel32A[] = "kernel32.dll"; static const CHAR fileA[] = ""; - CHAR pathA[MAX_PATH], buffA[MAX_PATH], path2A[MAX_PATH], path3A[MAX_PATH], curdirA[MAX_PATH]; + CHAR pathA[MAX_PATH + 13], buffA[MAX_PATH], path2A[MAX_PATH], path3A[MAX_PATH + 13], curdirA[MAX_PATH]; CHAR tmpdirA[MAX_PATH], *ptrA = NULL; ULONG_PTR cookie; HANDLE handle; BOOL bret; DWORD ret; - if (!pSearchPathA) - { - win_skip("SearchPathA isn't available\n"); - return; - } - - GetWindowsDirectoryA(pathA, sizeof(pathA)/sizeof(CHAR)); + GetWindowsDirectoryA(pathA, ARRAY_SIZE(pathA)); /* NULL filename */ SetLastError(0xdeadbeef); - ret = pSearchPathA(pathA, NULL, NULL, sizeof(buffA)/sizeof(CHAR), buffA, &ptrA); - ok(ret == 0, "Expected failure, got %d\n", ret); + ret = SearchPathA(pathA, NULL, NULL, ARRAY_SIZE(buffA), buffA, &ptrA); + ok(ret == 0, "Expected failure, got %ld\n", ret); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError()); + "Expected ERROR_INVALID_PARAMETER, got %lx\n", GetLastError()); /* empty filename */ SetLastError(0xdeadbeef); - ret = pSearchPathA(pathA, fileA, NULL, sizeof(buffA)/sizeof(CHAR), buffA, &ptrA); - ok(ret == 0, "Expected failure, got %d\n", ret); + ret = SearchPathA(pathA, fileA, NULL, ARRAY_SIZE(buffA), buffA, &ptrA); + ok(ret == 0, "Expected failure, got %ld\n", ret); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError()); + "Expected ERROR_INVALID_PARAMETER, got %lx\n", GetLastError()); - if (!pActivateActCtx) - return; + GetTempPathA(ARRAY_SIZE(pathA), pathA); + strcpy(path2A, pathA); + strcat(path2A, "testfile.ext.ext2"); + + handle = CreateFileA(path2A, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(handle != INVALID_HANDLE_VALUE, "Failed to create test file.\n"); + CloseHandle(handle); + + buffA[0] = 0; + ret = SearchPathA(pathA, "testfile.ext", NULL, ARRAY_SIZE(buffA), buffA, NULL); + ok(!ret, "Unexpected return value %lu.\n", ret); + + buffA[0] = 0; + ret = SearchPathA(pathA, "testfile.ext", ".ext2", ARRAY_SIZE(buffA), buffA, NULL); + ok(!ret, "Unexpected return value %lu.\n", ret); + + buffA[0] = 0; + ret = SearchPathA(pathA, "testfile.ext.ext2", NULL, ARRAY_SIZE(buffA), buffA, NULL); + ok(ret && ret == strlen(path2A), "got %ld\n", ret); + + DeleteFileA(path2A); + + GetWindowsDirectoryA(pathA, ARRAY_SIZE(pathA)); create_manifest_file("testdep1.manifest", manifest_dep); create_manifest_file("main.manifest", manifest_main); @@ -1862,61 +1795,62 @@ static void test_SearchPathA(void) delete_manifest_file("main.manifest"); /* search fails without active context */ - ret = pSearchPathA(NULL, testdepA, NULL, sizeof(buffA)/sizeof(CHAR), buffA, NULL); - ok(ret == 0, "got %d\n", ret); + ret = SearchPathA(NULL, testdepA, NULL, ARRAY_SIZE(buffA), buffA, NULL); + ok(ret == 0, "got %ld\n", ret); - ret = pSearchPathA(NULL, kernel32A, NULL, sizeof(path2A)/sizeof(CHAR), path2A, NULL); - ok(ret && ret == strlen(path2A), "got %d\n", ret); + ret = SearchPathA(NULL, kernel32A, NULL, ARRAY_SIZE(path2A), path2A, NULL); + ok(ret && ret == strlen(path2A), "got %ld\n", ret); - ret = pActivateActCtx(handle, &cookie); - ok(ret, "failed to activate context, %u\n", GetLastError()); + ret = ActivateActCtx(handle, &cookie); + ok(ret, "failed to activate context, %lu\n", GetLastError()); /* works when activated */ - ret = pSearchPathA(NULL, testdepA, NULL, sizeof(buffA)/sizeof(CHAR), buffA, NULL); - ok(ret && ret == strlen(buffA), "got %d\n", ret); + ret = SearchPathA(NULL, testdepA, NULL, ARRAY_SIZE(buffA), buffA, NULL); + ok(ret && ret == strlen(buffA), "got %ld\n", ret); - ret = pSearchPathA(NULL, "testdep.dll", ".ext", sizeof(buffA)/sizeof(CHAR), buffA, NULL); - ok(ret && ret == strlen(buffA), "got %d\n", ret); + ret = SearchPathA(NULL, "testdep.dll", ".ext", ARRAY_SIZE(buffA), buffA, NULL); + ok(ret && ret == strlen(buffA), "got %ld\n", ret); - ret = pSearchPathA(NULL, "testdep", ".dll", sizeof(buffA)/sizeof(CHAR), buffA, NULL); - ok(ret && ret == strlen(buffA), "got %d\n", ret); + ret = SearchPathA(NULL, "testdep", ".dll", ARRAY_SIZE(buffA), buffA, NULL); + ok(ret && ret == strlen(buffA), "got %ld\n", ret); - ret = pSearchPathA(NULL, "testdep", ".ext", sizeof(buffA)/sizeof(CHAR), buffA, NULL); - ok(!ret, "got %d\n", ret); + ret = SearchPathA(NULL, "testdep", ".ext", ARRAY_SIZE(buffA), buffA, NULL); + ok(!ret, "got %ld\n", ret); /* name contains path */ - ret = pSearchPathA(NULL, testdeprelA, NULL, sizeof(buffA)/sizeof(CHAR), buffA, NULL); - ok(!ret, "got %d\n", ret); + ret = SearchPathA(NULL, testdeprelA, NULL, ARRAY_SIZE(buffA), buffA, NULL); + ok(!ret, "got %ld\n", ret); /* fails with specified path that doesn't contain this file */ - ret = pSearchPathA(pathA, testdepA, NULL, sizeof(buffA)/sizeof(CHAR), buffA, NULL); - ok(!ret, "got %d\n", ret); + ret = SearchPathA(pathA, testdepA, NULL, ARRAY_SIZE(buffA), buffA, NULL); + ok(!ret, "got %ld\n", ret); /* path is redirected for wellknown names too */ - ret = pSearchPathA(NULL, kernel32A, NULL, sizeof(buffA)/sizeof(CHAR), buffA, NULL); - ok(ret && ret == strlen(buffA), "got %d\n", ret); + ret = SearchPathA(NULL, kernel32A, NULL, ARRAY_SIZE(buffA), buffA, NULL); + ok(ret && ret == strlen(buffA), "got %ld\n", ret); ok(strcmp(buffA, path2A), "got wrong path %s, %s\n", buffA, path2A); - ret = pDeactivateActCtx(0, cookie); - ok(ret, "failed to deactivate context, %u\n", GetLastError()); - pReleaseActCtx(handle); + ret = DeactivateActCtx(0, cookie); + ok(ret, "failed to deactivate context, %lu\n", GetLastError()); + ReleaseActCtx(handle); /* test the search path priority of the working directory */ GetTempPathA(sizeof(tmpdirA), tmpdirA); ret = GetCurrentDirectoryA(MAX_PATH, curdirA); ok(ret, "failed to obtain working directory.\n"); sprintf(pathA, "%s\\%s", tmpdirA, kernel32A); - ret = pSearchPathA(NULL, kernel32A, NULL, sizeof(path2A)/sizeof(CHAR), path2A, NULL); - ok(ret && ret == strlen(path2A), "got %d\n", ret); + ret = SearchPathA(NULL, kernel32A, NULL, ARRAY_SIZE(path2A), path2A, NULL); + ok(ret && ret == strlen(path2A), "got %ld\n", ret); bret = CopyFileA(path2A, pathA, FALSE); - ok(bret != 0, "failed to copy test executable to temp directory, %u\n", GetLastError()); - sprintf(path3A, "%s%s%s", curdirA, curdirA[strlen(curdirA)-1] != '\\' ? "\\" : "", kernel32A); + ok(bret != 0, "failed to copy test executable to temp directory, %lu\n", GetLastError()); + GetModuleFileNameA( GetModuleHandleA(0), path3A, sizeof(path3A) ); + strcpy( strrchr( path3A, '\\' ) + 1, kernel32A ); bret = CopyFileA(path2A, path3A, FALSE); - ok(bret != 0, "failed to copy test executable to launch directory, %u\n", GetLastError()); + ok(bret != 0, "failed to copy test executable to launch directory, %lu\n", GetLastError()); bret = SetCurrentDirectoryA(tmpdirA); ok(bret, "failed to change working directory\n"); - ret = pSearchPathA(NULL, kernel32A, ".exe", sizeof(buffA), buffA, NULL); - ok(ret && ret == strlen(buffA), "got %d\n", ret); + ret = SearchPathA(NULL, kernel32A, ".exe", sizeof(buffA), buffA, NULL); + ok(ret && ret == strlen(buffA), "got %ld\n", ret); ok(strcmp(buffA, path3A) == 0, "expected %s, got %s\n", path3A, buffA); bret = SetCurrentDirectoryA(curdirA); ok(bret, "failed to reset working directory\n"); @@ -1926,12 +1860,15 @@ static void test_SearchPathA(void) static void test_SearchPathW(void) { + static const WCHAR fileext2W[] = {'t','e','s','t','f','i','l','e','.','e','x','t','.','e','x','t','2',0}; + static const WCHAR fileextW[] = {'t','e','s','t','f','i','l','e','.','e','x','t',0}; static const WCHAR testdeprelW[] = {'.','/','t','e','s','t','d','e','p','.','d','l','l',0}; static const WCHAR testdepW[] = {'t','e','s','t','d','e','p','.','d','l','l',0}; static const WCHAR testdep1W[] = {'t','e','s','t','d','e','p',0}; static const WCHAR kernel32dllW[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0}; static const WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2',0}; static const WCHAR ole32W[] = {'o','l','e','3','2',0}; + static const WCHAR ext2W[] = {'.','e','x','t','2',0}; static const WCHAR extW[] = {'.','e','x','t',0}; static const WCHAR dllW[] = {'.','d','l','l',0}; static const WCHAR fileW[] = { 0 }; @@ -1941,29 +1878,44 @@ static void test_SearchPathW(void) HANDLE handle; DWORD ret; - if (!pSearchPathW) - { - win_skip("SearchPathW isn't available\n"); - return; - } + GetWindowsDirectoryW(pathW, ARRAY_SIZE(pathW)); -if (0) -{ - /* NULL filename, crashes on nt4 */ - pSearchPathW(pathW, NULL, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, &ptrW); -} - - GetWindowsDirectoryW(pathW, sizeof(pathW)/sizeof(WCHAR)); + /* NULL filename */ + ret = SearchPathW(pathW, NULL, NULL, ARRAY_SIZE(buffW), buffW, &ptrW); + ok(ret == 0, "Expected failure, got %ld\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %#lx\n", GetLastError()); /* empty filename */ SetLastError(0xdeadbeef); - ret = pSearchPathW(pathW, fileW, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, &ptrW); - ok(ret == 0, "Expected failure, got %d\n", ret); + ret = SearchPathW(pathW, fileW, NULL, ARRAY_SIZE(buffW), buffW, &ptrW); + ok(ret == 0, "Expected failure, got %ld\n", ret); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError()); + "Expected ERROR_INVALID_PARAMETER, got %lx\n", GetLastError()); - if (!pActivateActCtx) - return; + GetTempPathW(ARRAY_SIZE(pathW), pathW); + lstrcpyW(path2W, pathW); + lstrcatW(path2W, fileext2W); + + handle = CreateFileW(path2W, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(handle != INVALID_HANDLE_VALUE, "Failed to create test file.\n"); + CloseHandle(handle); + + buffW[0] = 0; + ret = SearchPathW(pathW, fileextW, NULL, ARRAY_SIZE(buffW), buffW, NULL); + ok(!ret, "Unexpected return value %lu.\n", ret); + + buffW[0] = 0; + ret = SearchPathW(pathW, fileextW, ext2W, ARRAY_SIZE(buffW), buffW, NULL); + ok(!ret, "Unexpected return value %lu.\n", ret); + + buffW[0] = 0; + ret = SearchPathW(pathW, fileext2W, NULL, ARRAY_SIZE(buffW), buffW, NULL); + ok(ret && ret == lstrlenW(path2W), "got %ld\n", ret); + + DeleteFileW(path2W); + + GetWindowsDirectoryW(pathW, ARRAY_SIZE(pathW)); create_manifest_file("testdep1.manifest", manifest_dep); create_manifest_file("main.manifest", manifest_main); @@ -1973,55 +1925,55 @@ if (0) delete_manifest_file("main.manifest"); /* search fails without active context */ - ret = pSearchPathW(NULL, testdepW, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, NULL); - ok(ret == 0, "got %d\n", ret); + ret = SearchPathW(NULL, testdepW, NULL, ARRAY_SIZE(buffW), buffW, NULL); + ok(ret == 0, "got %ld\n", ret); - ret = pSearchPathW(NULL, kernel32dllW, NULL, sizeof(path2W)/sizeof(WCHAR), path2W, NULL); - ok(ret && ret == lstrlenW(path2W), "got %d\n", ret); + ret = SearchPathW(NULL, kernel32dllW, NULL, ARRAY_SIZE(path2W), path2W, NULL); + ok(ret && ret == lstrlenW(path2W), "got %ld\n", ret); /* full path, name without 'dll' extension */ - GetSystemDirectoryW(pathW, sizeof(pathW)/sizeof(WCHAR)); - ret = pSearchPathW(pathW, kernel32W, NULL, sizeof(path2W)/sizeof(WCHAR), path2W, NULL); - ok(ret == 0, "got %d\n", ret); + GetSystemDirectoryW(pathW, ARRAY_SIZE(pathW)); + ret = SearchPathW(pathW, kernel32W, NULL, ARRAY_SIZE(path2W), path2W, NULL); + ok(ret == 0, "got %ld\n", ret); - GetWindowsDirectoryW(pathW, sizeof(pathW)/sizeof(WCHAR)); + GetWindowsDirectoryW(pathW, ARRAY_SIZE(pathW)); - ret = pActivateActCtx(handle, &cookie); - ok(ret, "failed to activate context, %u\n", GetLastError()); + ret = ActivateActCtx(handle, &cookie); + ok(ret, "failed to activate context, %lu\n", GetLastError()); /* works when activated */ - ret = pSearchPathW(NULL, testdepW, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, NULL); - ok(ret && ret == lstrlenW(buffW), "got %d\n", ret); + ret = SearchPathW(NULL, testdepW, NULL, ARRAY_SIZE(buffW), buffW, NULL); + ok(ret && ret == lstrlenW(buffW), "got %ld\n", ret); - ret = pSearchPathW(NULL, testdepW, extW, sizeof(buffW)/sizeof(WCHAR), buffW, NULL); - ok(ret && ret == lstrlenW(buffW), "got %d\n", ret); + ret = SearchPathW(NULL, testdepW, extW, ARRAY_SIZE(buffW), buffW, NULL); + ok(ret && ret == lstrlenW(buffW), "got %ld\n", ret); - ret = pSearchPathW(NULL, testdep1W, dllW, sizeof(buffW)/sizeof(WCHAR), buffW, NULL); - ok(ret && ret == lstrlenW(buffW), "got %d\n", ret); + ret = SearchPathW(NULL, testdep1W, dllW, ARRAY_SIZE(buffW), buffW, NULL); + ok(ret && ret == lstrlenW(buffW), "got %ld\n", ret); - ret = pSearchPathW(NULL, testdep1W, extW, sizeof(buffW)/sizeof(WCHAR), buffW, NULL); - ok(!ret, "got %d\n", ret); + ret = SearchPathW(NULL, testdep1W, extW, ARRAY_SIZE(buffW), buffW, NULL); + ok(!ret, "got %ld\n", ret); /* name contains path */ - ret = pSearchPathW(NULL, testdeprelW, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, NULL); - ok(!ret, "got %d\n", ret); + ret = SearchPathW(NULL, testdeprelW, NULL, ARRAY_SIZE(buffW), buffW, NULL); + ok(!ret, "got %ld\n", ret); /* fails with specified path that doesn't contain this file */ - ret = pSearchPathW(pathW, testdepW, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, NULL); - ok(!ret, "got %d\n", ret); + ret = SearchPathW(pathW, testdepW, NULL, ARRAY_SIZE(buffW), buffW, NULL); + ok(!ret, "got %ld\n", ret); /* path is redirected for wellknown names too, meaning it takes precedence over normal search order */ - ret = pSearchPathW(NULL, kernel32dllW, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, NULL); - ok(ret && ret == lstrlenW(buffW), "got %d\n", ret); + ret = SearchPathW(NULL, kernel32dllW, NULL, ARRAY_SIZE(buffW), buffW, NULL); + ok(ret && ret == lstrlenW(buffW), "got %ld\n", ret); ok(lstrcmpW(buffW, path2W), "got wrong path %s, %s\n", wine_dbgstr_w(buffW), wine_dbgstr_w(path2W)); /* path is built using on manifest file name */ - ret = pSearchPathW(NULL, ole32W, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, NULL); - ok(ret && ret == lstrlenW(buffW), "got %d\n", ret); + ret = SearchPathW(NULL, ole32W, NULL, ARRAY_SIZE(buffW), buffW, NULL); + ok(ret && ret == lstrlenW(buffW), "got %ld\n", ret); - ret = pDeactivateActCtx(0, cookie); - ok(ret, "failed to deactivate context, %u\n", GetLastError()); - pReleaseActCtx(handle); + ret = DeactivateActCtx(0, cookie); + ok(ret, "failed to deactivate context, %lu\n", GetLastError()); + ReleaseActCtx(handle); } static void test_GetFullPathNameA(void) @@ -2049,7 +2001,7 @@ static void test_GetFullPathNameA(void) {"", MAX_PATH, output, &filepart}, }; - for (i = 0; i < sizeof(invalid_parameters)/sizeof(invalid_parameters[0]); i++) + for (i = 0; i < ARRAY_SIZE(invalid_parameters); i++) { SetLastError(0xdeadbeef); strcpy(output, "deadbeef"); @@ -2058,12 +2010,12 @@ static void test_GetFullPathNameA(void) invalid_parameters[i].len, invalid_parameters[i].buffer, invalid_parameters[i].lastpart); - ok(!ret, "[%d] Expected GetFullPathNameA to return 0, got %u\n", i, ret); + ok(!ret, "[%d] Expected GetFullPathNameA to return 0, got %lu\n", i, ret); ok(!strcmp(output, "deadbeef"), "[%d] Expected the output buffer to be unchanged, got \"%s\"\n", i, output); ok(filepart == (char *)0xdeadbeef, "[%d] Expected output file part pointer to be untouched, got %p\n", i, filepart); ok(GetLastError() == 0xdeadbeef || GetLastError() == ERROR_INVALID_NAME, /* Win7 */ - "[%d] Expected GetLastError() to return 0xdeadbeef, got %u\n", + "[%d] Expected GetLastError() to return 0xdeadbeef, got %lu\n", i, GetLastError()); } @@ -2079,10 +2031,10 @@ static void test_GetFullPathNameA(void) { "c:\\\x83\x8f\x83\x43\x83\x93\\wine.c", "wine.c" }, { "c:\\demo\\\x97\xa0\x95\x5c", "\x97\xa0\x95\x5c" } }; - for (i = 0; i < sizeof(testset)/sizeof(testset[0]); i++) { + for (i = 0; i < ARRAY_SIZE(testset); i++) { ret = GetFullPathNameA(testset[i].input, sizeof(output), output, &filepart); - ok(ret, "[%d] GetFullPathName error %u\n", i, GetLastError()); + ok(ret, "[%d] GetFullPathName error %lu\n", i, GetLastError()); ok(!lstrcmpA(filepart, testset[i].expected), "[%d] expected %s got %s\n", i, testset[i].expected, filepart); } @@ -2119,15 +2071,7 @@ static void test_GetFullPathNameW(void) {emptyW, MAX_PATH, output, &filepart, 1}, }; - SetLastError(0xdeadbeef); - ret = GetFullPathNameW(NULL, 0, NULL, NULL); - if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) - { - win_skip("GetFullPathNameW is not available\n"); - return; - } - - for (i = 0; i < sizeof(invalid_parameters)/sizeof(invalid_parameters[0]); i++) + for (i = 0; i < ARRAY_SIZE(invalid_parameters); i++) { SetLastError(0xdeadbeef); lstrcpyW(output, deadbeefW); @@ -2136,37 +2080,37 @@ static void test_GetFullPathNameW(void) invalid_parameters[i].len, invalid_parameters[i].buffer, invalid_parameters[i].lastpart); - ok(!ret, "[%d] Expected GetFullPathNameW to return 0, got %u\n", i, ret); + ok(!ret, "[%d] Expected GetFullPathNameW to return 0, got %lu\n", i, ret); ok(!lstrcmpW(output, deadbeefW), "[%d] Expected the output buffer to be unchanged, got %s\n", i, wine_dbgstr_w(output)); ok(filepart == (WCHAR *)0xdeadbeef || (invalid_parameters[i].win7_expect && filepart == NULL), "[%d] Expected output file part pointer to be untouched, got %p\n", i, filepart); ok(GetLastError() == 0xdeadbeef || GetLastError() == ERROR_INVALID_NAME, /* Win7 */ - "[%d] Expected GetLastError() to return 0xdeadbeef, got %u\n", + "[%d] Expected GetLastError() to return 0xdeadbeef, got %lu\n", i, GetLastError()); } } static void init_pointers(void) { - HMODULE hKernel32 = GetModuleHandleA("kernel32.dll"); + HMODULE mod = GetModuleHandleA("kernel32.dll"); -#define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hKernel32, #f)) - MAKEFUNC(GetLongPathNameA); - MAKEFUNC(GetLongPathNameW); +#define MAKEFUNC(f) (p##f = (void*)GetProcAddress(mod, #f)) MAKEFUNC(NeedCurrentDirectoryForExePathA); MAKEFUNC(NeedCurrentDirectoryForExePathW); - MAKEFUNC(SearchPathA); - MAKEFUNC(SearchPathW); MAKEFUNC(SetSearchPathMode); - MAKEFUNC(ActivateActCtx); - MAKEFUNC(CreateActCtxW); - MAKEFUNC(DeactivateActCtx); - MAKEFUNC(GetCurrentActCtx); - MAKEFUNC(ReleaseActCtx); + MAKEFUNC(AddDllDirectory); + MAKEFUNC(RemoveDllDirectory); + MAKEFUNC(SetDllDirectoryW); + MAKEFUNC(SetDefaultDllDirectories); MAKEFUNC(CheckNameLegalDOS8Dot3W); MAKEFUNC(CheckNameLegalDOS8Dot3A); + mod = GetModuleHandleA("ntdll.dll"); + MAKEFUNC(LdrGetDllPath); + MAKEFUNC(RtlGetExePath); + MAKEFUNC(RtlGetSearchPath); + MAKEFUNC(RtlReleasePath); #undef MAKEFUNC } @@ -2177,70 +2121,68 @@ static void test_relative_path(void) int ret; WCHAR curdir[MAX_PATH]; - if (!pGetLongPathNameA) return; - GetCurrentDirectoryW(MAX_PATH, curdir); GetTempPathA(MAX_PATH, path); ret = SetCurrentDirectoryA(path); - ok(ret, "SetCurrentDirectory error %d\n", GetLastError()); + ok(ret, "SetCurrentDirectory error %ld\n", GetLastError()); ret = CreateDirectoryA("foo", NULL); - ok(ret, "CreateDirectory error %d\n", GetLastError()); + ok(ret, "CreateDirectory error %ld\n", GetLastError()); file = CreateFileA("foo\\file", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); ok(file != INVALID_HANDLE_VALUE, "failed to create temp file\n"); CloseHandle(file); ret = CreateDirectoryA("bar", NULL); - ok(ret, "CreateDirectory error %d\n", GetLastError()); + ok(ret, "CreateDirectory error %ld\n", GetLastError()); ret = SetCurrentDirectoryA("bar"); - ok(ret, "SetCurrentDirectory error %d\n", GetLastError()); + ok(ret, "SetCurrentDirectory error %ld\n", GetLastError()); ret = GetFileAttributesA("..\\foo\\file"); - ok(ret != INVALID_FILE_ATTRIBUTES, "GetFileAttributes error %d\n", GetLastError()); + ok(ret != INVALID_FILE_ATTRIBUTES, "GetFileAttributes error %ld\n", GetLastError()); strcpy(buf, "deadbeef"); - ret = pGetLongPathNameA(".", buf, MAX_PATH); - ok(ret, "GetLongPathName error %d\n", GetLastError()); + ret = GetLongPathNameA(".", buf, MAX_PATH); + ok(ret, "GetLongPathName error %ld\n", GetLastError()); ok(!strcmp(buf, "."), "expected ., got %s\n", buf); strcpy(buf, "deadbeef"); ret = GetShortPathNameA(".", buf, MAX_PATH); - ok(ret, "GetShortPathName error %d\n", GetLastError()); + ok(ret, "GetShortPathName error %ld\n", GetLastError()); ok(!strcmp(buf, "."), "expected ., got %s\n", buf); strcpy(buf, "deadbeef"); - ret = pGetLongPathNameA("..", buf, MAX_PATH); - ok(ret, "GetLongPathName error %d\n", GetLastError()); + ret = GetLongPathNameA("..", buf, MAX_PATH); + ok(ret, "GetLongPathName error %ld\n", GetLastError()); ok(!strcmp(buf, ".."), "expected .., got %s\n", buf); strcpy(buf, "deadbeef"); ret = GetShortPathNameA("..", buf, MAX_PATH); - ok(ret, "GetShortPathName error %d\n", GetLastError()); + ok(ret, "GetShortPathName error %ld\n", GetLastError()); ok(!strcmp(buf, ".."), "expected .., got %s\n", buf); strcpy(buf, "deadbeef"); - ret = pGetLongPathNameA("..\\foo\\file", buf, MAX_PATH); - ok(ret, "GetLongPathName error %d\n", GetLastError()); + ret = GetLongPathNameA("..\\foo\\file", buf, MAX_PATH); + ok(ret, "GetLongPathName error %ld\n", GetLastError()); ok(!strcmp(buf, "..\\foo\\file"), "expected ..\\foo\\file, got %s\n", buf); strcpy(buf, "deadbeef"); ret = GetShortPathNameA("..\\foo\\file", buf, MAX_PATH); - ok(ret, "GetShortPathName error %d\n", GetLastError()); + ok(ret, "GetShortPathName error %ld\n", GetLastError()); ok(!strcmp(buf, "..\\foo\\file"), "expected ..\\foo\\file, got %s\n", buf); strcpy(buf, "deadbeef"); - ret = pGetLongPathNameA(".\\..\\foo\\file", buf, MAX_PATH); - ok(ret, "GetLongPathName error %d\n", GetLastError()); + ret = GetLongPathNameA(".\\..\\foo\\file", buf, MAX_PATH); + ok(ret, "GetLongPathName error %ld\n", GetLastError()); ok(!strcmp(buf, ".\\..\\foo\\file"), "expected .\\..\\foo\\file, got %s\n", buf); strcpy(buf, "deadbeef"); ret = GetShortPathNameA(".\\..\\foo\\file", buf, MAX_PATH); - ok(ret, "GetShortPathName error %d\n", GetLastError()); + ok(ret, "GetShortPathName error %ld\n", GetLastError()); ok(!strcmp(buf, ".\\..\\foo\\file"), "expected .\\..\\foo\\file, got %s\n", buf); /* test double delimiters */ strcpy(buf, "deadbeef"); - ret = pGetLongPathNameA("..\\\\foo\\file", buf, MAX_PATH); - ok(ret, "GetLongPathName error %d\n", GetLastError()); + ret = GetLongPathNameA("..\\\\foo\\file", buf, MAX_PATH); + ok(ret, "GetLongPathName error %ld\n", GetLastError()); ok(!strcmp(buf, "..\\\\foo\\file"), "expected ..\\\\foo\\file, got %s\n", buf); strcpy(buf, "deadbeef"); ret = GetShortPathNameA("..\\\\foo\\file", buf, MAX_PATH); - ok(ret, "GetShortPathName error %d\n", GetLastError()); + ok(ret, "GetShortPathName error %ld\n", GetLastError()); ok(!strcmp(buf, "..\\\\foo\\file"), "expected ..\\\\foo\\file, got %s\n", buf); SetCurrentDirectoryA(".."); @@ -2300,7 +2242,7 @@ static void test_CheckNameLegalDOS8Dot3(void) br = pCheckNameLegalDOS8Dot3A("testtest.txt", NULL, 0, NULL, NULL); ok(br == FALSE, "CheckNameLegalDOS8Dot3A should have failed\n"); - for(i = 0; i < sizeof(cases)/sizeof(*cases); ++i){ + for(i = 0; i < ARRAY_SIZE(cases); ++i){ br = pCheckNameLegalDOS8Dot3W(cases[i].name, NULL, 0, &has_space, &is_legal); ok(br == TRUE, "CheckNameLegalDOS8Dot3W failed for %s\n", wine_dbgstr_w(cases[i].name)); ok(is_legal == cases[i].should_be_legal, "Got wrong legality for %s\n", wine_dbgstr_w(cases[i].name)); @@ -2347,43 +2289,43 @@ static void test_SetSearchPathMode(void) SetLastError( 0xdeadbeef ); ret = pSetSearchPathMode( 0 ); ok( !ret, "SetSearchPathMode succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); ret = pSetSearchPathMode( 0x80 ); ok( !ret, "SetSearchPathMode succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); ret = pSetSearchPathMode( BASE_SEARCH_PATH_PERMANENT ); ok( !ret, "SetSearchPathMode succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); ret = SearchPathA( NULL, "kernel32.dll", NULL, MAX_PATH, buf, NULL ); - ok( ret, "SearchPathA failed err %u\n", GetLastError() ); + ok( ret, "SearchPathA failed err %lu\n", GetLastError() ); GetCurrentDirectoryA( MAX_PATH, expect ); strcat( expect, "\\kernel32.dll" ); ok( !lstrcmpiA( buf, expect ), "found %s expected %s\n", buf, expect ); SetLastError( 0xdeadbeef ); ret = pSetSearchPathMode( BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE ); - ok( ret, "SetSearchPathMode failed err %u\n", GetLastError() ); + ok( ret, "SetSearchPathMode failed err %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); ret = SearchPathA( NULL, "kernel32.dll", NULL, MAX_PATH, buf, NULL ); - ok( ret, "SearchPathA failed err %u\n", GetLastError() ); + ok( ret, "SearchPathA failed err %lu\n", GetLastError() ); GetSystemDirectoryA( expect, MAX_PATH ); strcat( expect, "\\kernel32.dll" ); ok( !lstrcmpiA( buf, expect ), "found %s expected %s\n", buf, expect ); SetLastError( 0xdeadbeef ); ret = pSetSearchPathMode( BASE_SEARCH_PATH_DISABLE_SAFE_SEARCHMODE ); - ok( ret, "SetSearchPathMode failed err %u\n", GetLastError() ); + ok( ret, "SetSearchPathMode failed err %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); ret = SearchPathA( NULL, "kernel32.dll", NULL, MAX_PATH, buf, NULL ); - ok( ret, "SearchPathA failed err %u\n", GetLastError() ); + ok( ret, "SearchPathA failed err %lu\n", GetLastError() ); GetCurrentDirectoryA( MAX_PATH, expect ); strcat( expect, "\\kernel32.dll" ); ok( !lstrcmpiA( buf, expect ), "found %s expected %s\n", buf, expect ); @@ -2391,29 +2333,29 @@ static void test_SetSearchPathMode(void) SetLastError( 0xdeadbeef ); ret = pSetSearchPathMode( BASE_SEARCH_PATH_DISABLE_SAFE_SEARCHMODE | BASE_SEARCH_PATH_PERMANENT ); ok( !ret, "SetSearchPathMode succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); ret = pSetSearchPathMode( BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE | BASE_SEARCH_PATH_PERMANENT ); - ok( ret, "SetSearchPathMode failed err %u\n", GetLastError() ); + ok( ret, "SetSearchPathMode failed err %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); ret = pSetSearchPathMode( BASE_SEARCH_PATH_DISABLE_SAFE_SEARCHMODE ); ok( !ret, "SetSearchPathMode succeeded\n" ); - ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); ret = pSetSearchPathMode( BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE ); ok( !ret, "SetSearchPathMode succeeded\n" ); - ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); ret = pSetSearchPathMode( BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE | BASE_SEARCH_PATH_PERMANENT ); - ok( ret, "SetSearchPathMode failed err %u\n", GetLastError() ); + ok( ret, "SetSearchPathMode failed err %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); ret = SearchPathA( NULL, "kernel32.dll", NULL, MAX_PATH, buf, NULL ); - ok( ret, "SearchPathA failed err %u\n", GetLastError() ); + ok( ret, "SearchPathA failed err %lu\n", GetLastError() ); GetSystemDirectoryA( expect, MAX_PATH ); strcat( expect, "\\kernel32.dll" ); ok( !lstrcmpiA( buf, expect ), "found %s expected %s\n", buf, expect ); @@ -2423,20 +2365,338 @@ static void test_SetSearchPathMode(void) RemoveDirectoryA( dir ); } +static const WCHAR pathW[] = {'P','A','T','H',0}; + +static void build_search_path( WCHAR *buffer, UINT size, const WCHAR *module, const WCHAR *dlldir, BOOL safe ) +{ + WCHAR *p; + + if (module) lstrcpynW( buffer, module, size ); + else GetModuleFileNameW( NULL, buffer, size ); + if (!(p = wcsrchr( buffer, '\\' ))) return; + *p++ = ';'; + if (dlldir) + { + lstrcpyW( p, dlldir ); + p += lstrlenW( p ); + if (*dlldir) *p++ = ';'; + } + else if (!safe) + { + *p++ = '.'; + *p++ = ';'; + } + GetSystemDirectoryW( p, buffer + size - p ); + p = buffer + lstrlenW(buffer); + *p++ = ';'; + GetSystemDirectoryW( p, buffer + size - p ); + p = buffer + lstrlenW(buffer) - 2; /* remove "32" */ + *p++ = ';'; + GetWindowsDirectoryW( p, buffer + size - p ); + p = buffer + lstrlenW(buffer); + *p++ = ';'; + if (!dlldir && safe) + { + *p++ = '.'; + *p++ = ';'; + } + GetEnvironmentVariableW( pathW, p, buffer + size - p ); +} + +static BOOL path_equal( const WCHAR *path1, const WCHAR *path2 ) +{ + for (;;) + { + while (*path1 && towlower(*path1) == towlower(*path2)) { path1++; path2++; } + if (*path1 && *path1 != '\\' && *path1 != ';') return FALSE; + while (*path1 && (*path1 == '\\' || *path1 == ';')) path1++; + while (*path2 && (*path2 == '\\' || *path2 == ';')) path2++; + if (!*path1 || !*path2) return !*path1 && !*path2; + } +} + +static void test_RtlGetSearchPath(void) +{ + NTSTATUS ret; + WCHAR *path; + WCHAR buffer[2048], old_path[2048], dlldir[4]; + + if (!pRtlGetSearchPath) + { + win_skip( "RtlGetSearchPath isn't available\n" ); + return; + } + + GetEnvironmentVariableW( pathW, old_path, ARRAY_SIZE(old_path) ); + GetWindowsDirectoryW( buffer, ARRAY_SIZE(buffer) ); + lstrcpynW( dlldir, buffer, ARRAY_SIZE(dlldir) ); + + build_search_path( buffer, ARRAY_SIZE(buffer), NULL, NULL, TRUE ); + path = (WCHAR *)0xdeadbeef; + ret = pRtlGetSearchPath( &path ); + ok( !ret, "RtlGetSearchPath failed %lx\n", ret ); + ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); + pRtlReleasePath( path ); + + SetEnvironmentVariableA( "PATH", "foo" ); + build_search_path( buffer, ARRAY_SIZE(buffer), NULL, NULL, TRUE ); + path = (WCHAR *)0xdeadbeef; + ret = pRtlGetSearchPath( &path ); + ok( !ret, "RtlGetSearchPath failed %lx\n", ret ); + ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); + pRtlReleasePath( path ); + + if (pSetDllDirectoryW) + { + ok( pSetDllDirectoryW( dlldir ), "SetDllDirectoryW failed\n" ); + build_search_path( buffer, ARRAY_SIZE(buffer), NULL, NULL, TRUE ); + path = (WCHAR *)0xdeadbeef; + ret = pRtlGetSearchPath( &path ); + ok( !ret, "RtlGetSearchPath failed %lx\n", ret ); + ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); + pRtlReleasePath( path ); + pSetDllDirectoryW( NULL ); + } + + SetEnvironmentVariableW( pathW, old_path ); +} + +static void test_RtlGetExePath(void) +{ + static const WCHAR fooW[] = {'\\','f','o','o',0}; + static const WCHAR emptyW[1]; + NTSTATUS ret; + WCHAR *path; + WCHAR buffer[2048], old_path[2048], dlldir[4]; + + if (!pRtlGetExePath) + { + win_skip( "RtlGetExePath isn't available\n" ); + return; + } + + GetEnvironmentVariableW( pathW, old_path, ARRAY_SIZE(old_path) ); + GetWindowsDirectoryW( buffer, ARRAY_SIZE(buffer) ); + lstrcpynW( dlldir, buffer, ARRAY_SIZE(dlldir) ); + SetEnvironmentVariableA( "NoDefaultCurrentDirectoryInExePath", NULL ); + + build_search_path( buffer, ARRAY_SIZE(buffer), NULL, NULL, FALSE ); + path = (WCHAR *)0xdeadbeef; + ret = pRtlGetExePath( fooW, &path ); + ok( !ret, "RtlGetExePath failed %lx\n", ret ); + ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); + pRtlReleasePath( path ); + + build_search_path( buffer, ARRAY_SIZE(buffer), NULL, NULL, FALSE ); + path = (WCHAR *)0xdeadbeef; + ret = pRtlGetExePath( fooW + 1, &path ); + ok( !ret, "RtlGetExePath failed %lx\n", ret ); + ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); + pRtlReleasePath( path ); + + SetEnvironmentVariableA( "NoDefaultCurrentDirectoryInExePath", "yes" ); + + build_search_path( buffer, ARRAY_SIZE(buffer), NULL, NULL, FALSE ); + path = (WCHAR *)0xdeadbeef; + ret = pRtlGetExePath( fooW, &path ); + ok( !ret, "RtlGetExePath failed %lx\n", ret ); + ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); + pRtlReleasePath( path ); + + build_search_path( buffer, ARRAY_SIZE(buffer), NULL, emptyW, TRUE ); + path = (WCHAR *)0xdeadbeef; + ret = pRtlGetExePath( fooW + 1, &path ); + ok( !ret, "RtlGetExePath failed %lx\n", ret ); + ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); + pRtlReleasePath( path ); + + SetEnvironmentVariableA( "PATH", "foo" ); + build_search_path( buffer, ARRAY_SIZE(buffer), NULL, NULL, FALSE ); + path = (WCHAR *)0xdeadbeef; + ret = pRtlGetExePath( fooW, &path ); + ok( !ret, "RtlGetExePath failed %lx\n", ret ); + ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); + pRtlReleasePath( path ); + + if (pSetDllDirectoryW) + { + ok( pSetDllDirectoryW( dlldir ), "SetDllDirectoryW failed\n" ); + build_search_path( buffer, ARRAY_SIZE(buffer), NULL, NULL, FALSE ); + path = (WCHAR *)0xdeadbeef; + ret = pRtlGetExePath( fooW, &path ); + ok( !ret, "RtlGetExePath failed %lx\n", ret ); + ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); + pRtlReleasePath( path ); + pSetDllDirectoryW( NULL ); + } + + SetEnvironmentVariableW( pathW, old_path ); +} + +static void test_LdrGetDllPath(void) +{ + static const WCHAR fooW[] = {'f','o','o',0}; + NTSTATUS ret; + WCHAR *path, *unknown_ptr, *p; + WCHAR buffer[2048], old_path[2048], dlldir[4]; + + if (!pLdrGetDllPath) + { + win_skip( "LdrGetDllPath isn't available\n" ); + return; + } + GetEnvironmentVariableW( pathW, old_path, ARRAY_SIZE(old_path) ); + GetWindowsDirectoryW( buffer, ARRAY_SIZE(buffer) ); + lstrcpynW( dlldir, buffer, ARRAY_SIZE(dlldir) ); + + build_search_path( buffer, ARRAY_SIZE(buffer), NULL, NULL, TRUE ); + + path = unknown_ptr = (WCHAR *)0xdeadbeef; + ret = pLdrGetDllPath( 0, 0, &path, &unknown_ptr ); + ok( !ret, "LdrGetDllPath failed %lx\n", ret ); + ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); + ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); + pRtlReleasePath( path ); + + SetEnvironmentVariableA( "PATH", "foo" ); + build_search_path( buffer, ARRAY_SIZE(buffer), NULL, NULL, TRUE ); + ret = pLdrGetDllPath( 0, 0, &path, &unknown_ptr ); + ok( !ret, "LdrGetDllPath failed %lx\n", ret ); + ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); + ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); + pRtlReleasePath( path ); + + if (pSetDllDirectoryW) + { + ok( pSetDllDirectoryW( dlldir ), "SetDllDirectoryW failed\n" ); + build_search_path( buffer, ARRAY_SIZE(buffer), NULL, dlldir, TRUE ); + ret = pLdrGetDllPath( 0, 0, &path, &unknown_ptr ); + ok( !ret, "LdrGetDllPath failed %lx\n", ret ); + ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); + ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); + pRtlReleasePath( path ); + pSetDllDirectoryW( NULL ); + } + + ret = pLdrGetDllPath( 0, LOAD_LIBRARY_SEARCH_SYSTEM32, &path, &unknown_ptr ); + ok( !ret, "LdrGetDllPath failed %lx\n", ret ); + ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); + GetSystemDirectoryW( buffer, ARRAY_SIZE(buffer) ); + ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); + pRtlReleasePath( path ); + + ret = pLdrGetDllPath( 0, LOAD_LIBRARY_SEARCH_APPLICATION_DIR, &path, &unknown_ptr ); + ok( !ret, "LdrGetDllPath failed %lx\n", ret ); + ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); + GetModuleFileNameW( NULL, buffer, ARRAY_SIZE(buffer) ); + if ((p = wcsrchr( buffer, '\\' ))) *p = 0; + ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); + pRtlReleasePath( path ); + + ret = pLdrGetDllPath( fooW, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR, &path, &unknown_ptr ); + ok( ret == STATUS_INVALID_PARAMETER, "LdrGetDllPath failed %lx\n", ret ); + + lstrcpyW( buffer, L"\\\\?\\" ); + lstrcatW( buffer, dlldir ); + p = buffer + lstrlenW(buffer); + *p++ = '\\'; + lstrcpyW( p, fooW ); + ret = pLdrGetDllPath( buffer, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR, &path, &unknown_ptr ); + ok( !ret, "LdrGetDllPath failed %lx\n", ret ); + ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); + ok( !memcmp( path, L"\\\\?\\", 4 * sizeof(WCHAR) ) && path_equal( path + 4, dlldir ), + "got %s expected \\\\?\\%s\n", wine_dbgstr_w(path), wine_dbgstr_w(dlldir)); + pRtlReleasePath( path ); + + ret = pLdrGetDllPath( L"\\\\?\\c:\\test.dll", LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR, &path, &unknown_ptr ); + ok( !ret, "LdrGetDllPath failed %lx\n", ret ); + ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); + ok( !lstrcmpW( path, L"\\\\?\\c:" ), "got %s expected \\\\?\\c:\n", wine_dbgstr_w(path)); + pRtlReleasePath( path ); + + ret = pLdrGetDllPath( fooW, LOAD_WITH_ALTERED_SEARCH_PATH, &path, &unknown_ptr ); + ok( !ret, "LdrGetDllPath failed %lx\n", ret ); + ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); + build_search_path( buffer, ARRAY_SIZE(buffer), NULL, NULL, TRUE ); + ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); + pRtlReleasePath( path ); + + ret = pLdrGetDllPath( L"temp/foo", LOAD_WITH_ALTERED_SEARCH_PATH, &path, &unknown_ptr ); + ok( !ret, "LdrGetDllPath failed %lx\n", ret ); + ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); + build_search_path( buffer, ARRAY_SIZE(buffer), NULL, NULL, TRUE ); + ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); + pRtlReleasePath( path ); + + ret = pLdrGetDllPath( L".\\foo\\foobar", LOAD_WITH_ALTERED_SEARCH_PATH, &path, &unknown_ptr ); + ok( !ret, "LdrGetDllPath failed %lx\n", ret ); + ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); + build_search_path( buffer, ARRAY_SIZE(buffer), L".\\foo\\foobar", NULL, TRUE ); + ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); + pRtlReleasePath( path ); + + ret = pLdrGetDllPath( L"temp\\foo", LOAD_WITH_ALTERED_SEARCH_PATH, &path, &unknown_ptr ); + ok( !ret, "LdrGetDllPath failed %lx\n", ret ); + ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); + build_search_path( buffer, ARRAY_SIZE(buffer), L"temp\\foo", NULL, TRUE ); + ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); + pRtlReleasePath( path ); + + ret = pLdrGetDllPath( L"c:\\temp\\foo", LOAD_WITH_ALTERED_SEARCH_PATH, &path, &unknown_ptr ); + ok( !ret, "LdrGetDllPath failed %lx\n", ret ); + ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); + build_search_path( buffer, ARRAY_SIZE(buffer), L"c:\\temp\\foo", NULL, TRUE ); + ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); + pRtlReleasePath( path ); + + lstrcpyW( buffer, fooW ); + ret = pLdrGetDllPath( buffer, LOAD_WITH_ALTERED_SEARCH_PATH | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR, &path, &unknown_ptr ); + ok( ret == STATUS_INVALID_PARAMETER, "got %lx expected %lx\n", ret, STATUS_INVALID_PARAMETER ); + ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); + + lstrcpyW( buffer, dlldir ); + p = buffer + lstrlenW(buffer); + *p++ = '\\'; + lstrcpyW( p, fooW ); + ret = pLdrGetDllPath( buffer, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR, &path, &unknown_ptr ); + ok( !ret, "LdrGetDllPath failed %lx\n", ret ); + ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); + ok( path_equal( path, dlldir ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(dlldir)); + pRtlReleasePath( path ); + + if (pAddDllDirectory) + { + DLL_DIRECTORY_COOKIE cookie = pAddDllDirectory( dlldir ); + ok( !!cookie, "AddDllDirectory failed\n" ); + ret = pLdrGetDllPath( 0, LOAD_LIBRARY_SEARCH_USER_DIRS, &path, &unknown_ptr ); + ok( !ret, "LdrGetDllPath failed %lx\n", ret ); + ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); + ok( path_equal( path, dlldir ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(dlldir)); + pRtlReleasePath( path ); + pRemoveDllDirectory( cookie ); + } + + if (pSetDefaultDllDirectories) + { + pSetDefaultDllDirectories( LOAD_LIBRARY_SEARCH_SYSTEM32 ); + ret = pLdrGetDllPath( 0, 0, &path, &unknown_ptr ); + ok( !ret, "LdrGetDllPath failed %lx\n", ret ); + ok( !unknown_ptr, "unknown ptr %p\n", unknown_ptr ); + GetSystemDirectoryW( buffer, ARRAY_SIZE(buffer) ); + ok( path_equal( path, buffer ), "got %s expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(buffer)); + pRtlReleasePath( path ); + pSetDefaultDllDirectories( 0 ); + } + + SetEnvironmentVariableW( pathW, old_path ); +} + START_TEST(path) { CHAR origdir[MAX_PATH],curdir[MAX_PATH], curDrive, otherDrive; init_pointers(); - /* Report only once */ - if (!pGetLongPathNameA) - win_skip("GetLongPathNameA is not available\n"); - if (!pGetLongPathNameW) - win_skip("GetLongPathNameW is not available\n"); - if (!pActivateActCtx) - win_skip("Activation contexts not supported, some tests will be skipped\n"); - test_relative_path(); test_InitPathA(curdir, &curDrive, &otherDrive); test_CurrentDirectoryA(origdir,curdir); @@ -2457,4 +2717,7 @@ START_TEST(path) test_GetFullPathNameW(); test_CheckNameLegalDOS8Dot3(); test_SetSearchPathMode(); + test_RtlGetSearchPath(); + test_RtlGetExePath(); + test_LdrGetDllPath(); } diff --git a/modules/rostests/winetests/kernel32/pipe.c b/modules/rostests/winetests/kernel32/pipe.c index 66106ce5111..e450d1a68ec 100644 --- a/modules/rostests/winetests/kernel32/pipe.c +++ b/modules/rostests/winetests/kernel32/pipe.c @@ -30,15 +30,19 @@ #include "wine/test.h" #define PIPENAME "\\\\.\\PiPe\\tests_pipe.c" -#define PIPENAME_SPECIAL "\\\\.\\PiPe\\tests->pipe.c" #define NB_SERVER_LOOPS 8 static HANDLE alarm_event; static BOOL (WINAPI *pDuplicateTokenEx)(HANDLE,DWORD,LPSECURITY_ATTRIBUTES, SECURITY_IMPERSONATION_LEVEL,TOKEN_TYPE,PHANDLE); -static DWORD (WINAPI *pQueueUserAPC)(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData); static BOOL (WINAPI *pCancelIoEx)(HANDLE handle, LPOVERLAPPED lpOverlapped); +static BOOL (WINAPI *pCancelSynchronousIo)(HANDLE handle); +static BOOL (WINAPI *pGetNamedPipeClientProcessId)(HANDLE,ULONG*); +static BOOL (WINAPI *pGetNamedPipeServerProcessId)(HANDLE,ULONG*); +static BOOL (WINAPI *pGetNamedPipeClientSessionId)(HANDLE,ULONG*); +static BOOL (WINAPI *pGetNamedPipeServerSessionId)(HANDLE,ULONG*); +static BOOL (WINAPI *pGetOverlappedResultEx)(HANDLE,OVERLAPPED *,DWORD *,DWORD,BOOL); static BOOL user_apc_ran; static void CALLBACK user_apc(ULONG_PTR param) @@ -104,9 +108,9 @@ static BOOL RpcReadFile(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD rpcargs.args[4] = (ULONG_PTR)overlapped; thread = CreateThread(NULL, 0, rpcThreadMain, (void *)&rpcargs, 0, &threadId); - ok(thread != NULL, "CreateThread failed. %d\n", GetLastError()); + ok(thread != NULL, "CreateThread failed. %ld\n", GetLastError()); ret = WaitForSingleObject(thread, INFINITE); - ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed with %d.\n", GetLastError()); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed with %ld.\n", GetLastError()); CloseHandle(thread); SetLastError(rpcargs.lastError); @@ -117,15 +121,14 @@ static BOOL RpcReadFile(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD static void _test_not_signaled(unsigned line, HANDLE handle) { DWORD res = WaitForSingleObject(handle, 0); - disable_success_count - ok_(__FILE__,line)(res == WAIT_TIMEOUT, "WaitForSingleObject returned %u (%u)\n", res, GetLastError()); + ok_(__FILE__,line)(res == WAIT_TIMEOUT, "WaitForSingleObject returned %lu (%lu)\n", res, GetLastError()); } #define test_signaled(h) _test_signaled(__LINE__,h) static void _test_signaled(unsigned line, HANDLE handle) { DWORD res = WaitForSingleObject(handle, 0); - ok_(__FILE__,line)(res == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", res); + ok_(__FILE__,line)(res == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", res); } #define test_pipe_info(a,b,c,d,e) _test_pipe_info(__LINE__,a,b,c,d,e) @@ -136,10 +139,24 @@ static void _test_pipe_info(unsigned line, HANDLE pipe, DWORD ex_flags, DWORD ex res = GetNamedPipeInfo(pipe, &flags, &out_buf_size, &in_buf_size, &max_instances); ok_(__FILE__,line)(res, "GetNamedPipeInfo failed: %x\n", res); - ok_(__FILE__,line)(flags == ex_flags, "flags = %x, expected %x\n", flags, ex_flags); - ok_(__FILE__,line)(out_buf_size == ex_out_buf_size, "out_buf_size = %x, expected %u\n", out_buf_size, ex_out_buf_size); - ok_(__FILE__,line)(in_buf_size == ex_in_buf_size, "in_buf_size = %x, expected %u\n", in_buf_size, ex_in_buf_size); - ok_(__FILE__,line)(max_instances == ex_max_instances, "max_instances = %x, expected %u\n", max_instances, ex_max_instances); + ok_(__FILE__,line)(flags == ex_flags, "flags = %lx, expected %lx\n", flags, ex_flags); + ok_(__FILE__,line)(out_buf_size == ex_out_buf_size, "out_buf_size = %lx, expected %lu\n", out_buf_size, ex_out_buf_size); + ok_(__FILE__,line)(in_buf_size == ex_in_buf_size, "in_buf_size = %lx, expected %lu\n", in_buf_size, ex_in_buf_size); + ok_(__FILE__,line)(max_instances == ex_max_instances, "max_instances = %lx, expected %lu\n", max_instances, ex_max_instances); +} + +#define test_file_access(a,b) _test_file_access(__LINE__,a,b) +static void _test_file_access(unsigned line, HANDLE handle, DWORD expected_access) +{ + FILE_ACCESS_INFORMATION info; + IO_STATUS_BLOCK io; + NTSTATUS status; + + memset(&info, 0x11, sizeof(info)); + status = NtQueryInformationFile(handle, &io, &info, sizeof(info), FileAccessInformation); + ok_(__FILE__,line)(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08lx\n", status); + ok_(__FILE__,line)(info.AccessFlags == expected_access, "got access %08lx expected %08lx\n", + info.AccessFlags, expected_access); } static void test_CreateNamedPipe(int pipemode) @@ -164,7 +181,7 @@ static void test_CreateNamedPipe(int pipemode) /* Wait for nonexistent pipe */ ret = WaitNamedPipeA(PIPENAME, 2000); ok(ret == 0, "WaitNamedPipe returned %d for nonexistent pipe\n", ret); - ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError()); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError()); /* Bad parameter checks */ hnp = CreateNamedPipeA("not a named pipe", PIPE_ACCESS_DUPLEX, pipemode | PIPE_WAIT, @@ -211,26 +228,29 @@ static void test_CreateNamedPipe(int pipemode) ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); test_signaled(hnp); + test_file_access(hnp, SYNCHRONIZE | READ_CONTROL | FILE_WRITE_ATTRIBUTES + | FILE_READ_ATTRIBUTES | FILE_WRITE_PROPERTIES | FILE_READ_PROPERTIES + | FILE_APPEND_DATA | FILE_WRITE_DATA | FILE_READ_DATA); + ret = PeekNamedPipe(hnp, NULL, 0, NULL, &readden, NULL); - todo_wine - ok(!ret && GetLastError() == ERROR_BAD_PIPE, "PeekNamedPipe returned %x (%u)\n", + ok(!ret && GetLastError() == ERROR_BAD_PIPE, "PeekNamedPipe returned %x (%lu)\n", ret, GetLastError()); ret = WaitNamedPipeA(PIPENAME, 2000); - ok(ret, "WaitNamedPipe failed (%d)\n", GetLastError()); + ok(ret, "WaitNamedPipe failed (%ld)\n", GetLastError()); hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); - ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError()); + ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed (%ld)\n", GetLastError()); ok(!WaitNamedPipeA(PIPENAME, 100), "WaitNamedPipe succeeded\n"); - ok(GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError()); + ok(GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %lu\n", GetLastError()); /* Test ConnectNamedPipe() in both directions */ ok(!ConnectNamedPipe(hnp, NULL), "ConnectNamedPipe(server) succeeded\n"); - ok(GetLastError() == ERROR_PIPE_CONNECTED, "expected ERROR_PIPE_CONNECTED, got %u\n", GetLastError()); + ok(GetLastError() == ERROR_PIPE_CONNECTED, "expected ERROR_PIPE_CONNECTED, got %lu\n", GetLastError()); ok(!ConnectNamedPipe(hFile, NULL), "ConnectNamedPipe(client) succeeded\n"); - ok(GetLastError() == ERROR_INVALID_FUNCTION, "expected ERROR_INVALID_FUNCTION, got %u\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_FUNCTION, "expected ERROR_INVALID_FUNCTION, got %lu\n", GetLastError()); /* don't try to do i/o if one side couldn't be opened, as it hangs */ if (hFile != INVALID_HANDLE_VALUE) { @@ -241,14 +261,14 @@ static void test_CreateNamedPipe(int pipemode) ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile\n"); ok(written == sizeof(obuf), "write file len\n"); ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n"); - ok(readden == sizeof(obuf), "read got %d bytes\n", readden); + ok(readden == sizeof(obuf), "read got %ld bytes\n", readden); ok(memcmp(obuf, ibuf, written) == 0, "content check\n"); memset(ibuf, 0, sizeof(ibuf)); ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), "WriteFile\n"); ok(written == sizeof(obuf2), "write file len\n"); ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n"); - ok(readden == sizeof(obuf2), "read got %d bytes\n", readden); + ok(readden == sizeof(obuf2), "read got %ld bytes\n", readden); ok(memcmp(obuf2, ibuf, written) == 0, "content check\n"); /* Now the same again, but with an additional call to PeekNamedPipe */ @@ -256,32 +276,32 @@ static void test_CreateNamedPipe(int pipemode) ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile\n"); ok(written == sizeof(obuf), "write file len 1\n"); ok(PeekNamedPipe(hFile, NULL, 0, NULL, &avail, &left), "Peek\n"); - ok(avail == sizeof(obuf), "peek 1 got %d bytes\n", avail); + ok(avail == sizeof(obuf), "peek 1 got %ld bytes\n", avail); if (pipemode == PIPE_TYPE_BYTE) - ok(left == 0, "peek 1 got %d bytes left\n", left); + ok(left == 0, "peek 1 got %ld bytes left\n", left); else - ok(left == sizeof(obuf), "peek 1 got %d bytes left\n", left); + ok(left == sizeof(obuf), "peek 1 got %ld bytes left\n", left); ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n"); - ok(readden == sizeof(obuf), "read 1 got %d bytes\n", readden); + ok(readden == sizeof(obuf), "read 1 got %ld bytes\n", readden); ok(memcmp(obuf, ibuf, written) == 0, "content 1 check\n"); memset(ibuf, 0, sizeof(ibuf)); ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), "WriteFile\n"); ok(written == sizeof(obuf2), "write file len 2\n"); ok(PeekNamedPipe(hnp, NULL, 0, NULL, &avail, &left), "Peek\n"); - ok(avail == sizeof(obuf2), "peek 2 got %d bytes\n", avail); + ok(avail == sizeof(obuf2), "peek 2 got %ld bytes\n", avail); if (pipemode == PIPE_TYPE_BYTE) - ok(left == 0, "peek 2 got %d bytes left\n", left); + ok(left == 0, "peek 2 got %ld bytes left\n", left); else - ok(left == sizeof(obuf2), "peek 2 got %d bytes left\n", left); + ok(left == sizeof(obuf2), "peek 2 got %ld bytes left\n", left); ok(PeekNamedPipe(hnp, (LPVOID)1, 0, NULL, &avail, &left), "Peek\n"); - ok(avail == sizeof(obuf2), "peek 2 got %d bytes\n", avail); + ok(avail == sizeof(obuf2), "peek 2 got %ld bytes\n", avail); if (pipemode == PIPE_TYPE_BYTE) - ok(left == 0, "peek 2 got %d bytes left\n", left); + ok(left == 0, "peek 2 got %ld bytes left\n", left); else - ok(left == sizeof(obuf2), "peek 2 got %d bytes left\n", left); + ok(left == sizeof(obuf2), "peek 2 got %ld bytes left\n", left); ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n"); - ok(readden == sizeof(obuf2), "read 2 got %d bytes\n", readden); + ok(readden == sizeof(obuf2), "read 2 got %ld bytes\n", readden); ok(memcmp(obuf2, ibuf, written) == 0, "content 2 check\n"); /* Test how ReadFile behaves when the buffer is not big enough for the whole message */ @@ -289,39 +309,39 @@ static void test_CreateNamedPipe(int pipemode) ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), "WriteFile\n"); ok(written == sizeof(obuf2), "write file len\n"); ok(PeekNamedPipe(hFile, ibuf, 4, &readden, &avail, &left), "Peek\n"); - ok(readden == 4, "peek got %d bytes\n", readden); - ok(avail == sizeof(obuf2), "peek got %d bytes available\n", avail); + ok(readden == 4, "peek got %ld bytes\n", readden); + ok(avail == sizeof(obuf2), "peek got %ld bytes available\n", avail); if (pipemode == PIPE_TYPE_BYTE) - ok(left == -4, "peek got %d bytes left\n", left); + ok(left == -4, "peek got %ld bytes left\n", left); else - ok(left == sizeof(obuf2)-4, "peek got %d bytes left\n", left); + ok(left == sizeof(obuf2)-4, "peek got %ld bytes left\n", left); ok(ReadFile(hFile, ibuf, 4, &readden, NULL), "ReadFile\n"); - ok(readden == 4, "read got %d bytes\n", readden); + ok(readden == 4, "read got %ld bytes\n", readden); ok(ReadFile(hFile, ibuf + 4, sizeof(ibuf) - 4, &readden, NULL), "ReadFile\n"); - ok(readden == sizeof(obuf2) - 4, "read got %d bytes\n", readden); + ok(readden == sizeof(obuf2) - 4, "read got %ld bytes\n", readden); ok(memcmp(obuf2, ibuf, written) == 0, "content check\n"); memset(ibuf, 0, sizeof(ibuf)); ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile\n"); ok(written == sizeof(obuf), "write file len\n"); ok(PeekNamedPipe(hnp, ibuf, 4, &readden, &avail, &left), "Peek\n"); - ok(readden == 4, "peek got %d bytes\n", readden); - ok(avail == sizeof(obuf), "peek got %d bytes available\n", avail); + ok(readden == 4, "peek got %ld bytes\n", readden); + ok(avail == sizeof(obuf), "peek got %ld bytes available\n", avail); if (pipemode == PIPE_TYPE_BYTE) { - ok(left == -4, "peek got %d bytes left\n", left); + ok(left == -4, "peek got %ld bytes left\n", left); ok(ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile\n"); } else { - ok(left == sizeof(obuf)-4, "peek got %d bytes left\n", left); + ok(left == sizeof(obuf)-4, "peek got %ld bytes left\n", left); SetLastError(0xdeadbeef); ok(!ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile\n"); ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n"); } - ok(readden == 4, "read got %d bytes\n", readden); + ok(readden == 4, "read got %ld bytes\n", readden); ok(ReadFile(hnp, ibuf + 4, sizeof(ibuf) - 4, &readden, NULL), "ReadFile\n"); - ok(readden == sizeof(obuf) - 4, "read got %d bytes\n", readden); + ok(readden == sizeof(obuf) - 4, "read got %ld bytes\n", readden); ok(memcmp(obuf, ibuf, written) == 0, "content check\n"); /* Similar to above, but use a read buffer size small enough to read in three parts */ @@ -331,7 +351,7 @@ static void test_CreateNamedPipe(int pipemode) if (pipemode == PIPE_TYPE_BYTE) { ok(ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile\n"); - ok(readden == 4, "read got %d bytes\n", readden); + ok(readden == 4, "read got %ld bytes\n", readden); ok(ReadFile(hnp, ibuf + 4, 4, &readden, NULL), "ReadFile\n"); } else @@ -339,14 +359,14 @@ static void test_CreateNamedPipe(int pipemode) SetLastError(0xdeadbeef); ok(!ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile\n"); ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n"); - ok(readden == 4, "read got %d bytes\n", readden); + ok(readden == 4, "read got %ld bytes\n", readden); SetLastError(0xdeadbeef); ok(!ReadFile(hnp, ibuf + 4, 4, &readden, NULL), "ReadFile\n"); ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n"); } - ok(readden == 4, "read got %d bytes\n", readden); + ok(readden == 4, "read got %ld bytes\n", readden); ok(ReadFile(hnp, ibuf + 8, sizeof(ibuf) - 8, &readden, NULL), "ReadFile\n"); - ok(readden == sizeof(obuf2) - 8, "read got %d bytes\n", readden); + ok(readden == sizeof(obuf2) - 8, "read got %ld bytes\n", readden); ok(memcmp(obuf2, ibuf, written) == 0, "content check\n"); /* Test reading of multiple writes */ @@ -356,23 +376,23 @@ static void test_CreateNamedPipe(int pipemode) ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), " WriteFile3b\n"); ok(written == sizeof(obuf2), "write file len 3b\n"); ok(PeekNamedPipe(hFile, ibuf, 4, &readden, &avail, &left), "Peek3\n"); - ok(readden == 4, "peek3 got %d bytes\n", readden); + ok(readden == 4, "peek3 got %ld bytes\n", readden); if (pipemode == PIPE_TYPE_BYTE) - ok(left == -4, "peek3 got %d bytes left\n", left); + ok(left == -4, "peek3 got %ld bytes left\n", left); else - ok(left == sizeof(obuf)-4, "peek3 got %d bytes left\n", left); - ok(avail == sizeof(obuf) + sizeof(obuf2), "peek3 got %d bytes available\n", avail); + ok(left == sizeof(obuf)-4, "peek3 got %ld bytes left\n", left); + ok(avail == sizeof(obuf) + sizeof(obuf2), "peek3 got %ld bytes available\n", avail); ok(PeekNamedPipe(hFile, ibuf, sizeof(ibuf), &readden, &avail, &left), "Peek3\n"); if (pipemode == PIPE_TYPE_BYTE) { - ok(readden == sizeof(obuf) + sizeof(obuf2), "peek3 got %d bytes\n", readden); - ok(left == (DWORD) -(sizeof(obuf) + sizeof(obuf2)), "peek3 got %d bytes left\n", left); + ok(readden == sizeof(obuf) + sizeof(obuf2), "peek3 got %ld bytes\n", readden); + ok(left == (DWORD) -(sizeof(obuf) + sizeof(obuf2)), "peek3 got %ld bytes left\n", left); } else { - ok(readden == sizeof(obuf), "peek3 got %d bytes\n", readden); - ok(left == 0, "peek3 got %d bytes left\n", left); + ok(readden == sizeof(obuf), "peek3 got %ld bytes\n", readden); + ok(left == 0, "peek3 got %ld bytes left\n", left); } - ok(avail == sizeof(obuf) + sizeof(obuf2), "peek3 got %d bytes available\n", avail); + ok(avail == sizeof(obuf) + sizeof(obuf2), "peek3 got %ld bytes available\n", avail); pbuf = ibuf; ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "pipe content 3a check\n"); if (pipemode == PIPE_TYPE_BYTE && readden >= sizeof(obuf)+sizeof(obuf2)) { @@ -380,7 +400,7 @@ static void test_CreateNamedPipe(int pipemode) ok(memcmp(obuf2, pbuf, sizeof(obuf2)) == 0, "pipe content 3b check\n"); } ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n"); - ok(readden == sizeof(obuf) + sizeof(obuf2), "read 3 got %d bytes\n", readden); + ok(readden == sizeof(obuf) + sizeof(obuf2), "read 3 got %ld bytes\n", readden); pbuf = ibuf; ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 3a check\n"); pbuf += sizeof(obuf); @@ -393,23 +413,23 @@ static void test_CreateNamedPipe(int pipemode) ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), " WriteFile4b\n"); ok(written == sizeof(obuf2), "write file len 4b\n"); ok(PeekNamedPipe(hnp, ibuf, 4, &readden, &avail, &left), "Peek3\n"); - ok(readden == 4, "peek3 got %d bytes\n", readden); + ok(readden == 4, "peek3 got %ld bytes\n", readden); if (pipemode == PIPE_TYPE_BYTE) - ok(left == -4, "peek3 got %d bytes left\n", left); + ok(left == -4, "peek3 got %ld bytes left\n", left); else - ok(left == sizeof(obuf)-4, "peek3 got %d bytes left\n", left); - ok(avail == sizeof(obuf) + sizeof(obuf2), "peek3 got %d bytes available\n", avail); + ok(left == sizeof(obuf)-4, "peek3 got %ld bytes left\n", left); + ok(avail == sizeof(obuf) + sizeof(obuf2), "peek3 got %ld bytes available\n", avail); ok(PeekNamedPipe(hnp, ibuf, sizeof(ibuf), &readden, &avail, &left), "Peek4\n"); if (pipemode == PIPE_TYPE_BYTE) { - ok(readden == sizeof(obuf) + sizeof(obuf2), "peek4 got %d bytes\n", readden); - ok(left == (DWORD) -(sizeof(obuf) + sizeof(obuf2)), "peek4 got %d bytes left\n", left); + ok(readden == sizeof(obuf) + sizeof(obuf2), "peek4 got %ld bytes\n", readden); + ok(left == (DWORD) -(sizeof(obuf) + sizeof(obuf2)), "peek4 got %ld bytes left\n", left); } else { - ok(readden == sizeof(obuf), "peek4 got %d bytes\n", readden); - ok(left == 0, "peek4 got %d bytes left\n", left); + ok(readden == sizeof(obuf), "peek4 got %ld bytes\n", readden); + ok(left == 0, "peek4 got %ld bytes left\n", left); } - ok(avail == sizeof(obuf) + sizeof(obuf2), "peek4 got %d bytes available\n", avail); + ok(avail == sizeof(obuf) + sizeof(obuf2), "peek4 got %ld bytes available\n", avail); pbuf = ibuf; ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "pipe content 4a check\n"); if (pipemode == PIPE_TYPE_BYTE && readden >= sizeof(obuf)+sizeof(obuf2)) { @@ -418,10 +438,10 @@ static void test_CreateNamedPipe(int pipemode) } ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n"); if (pipemode == PIPE_TYPE_BYTE) { - ok(readden == sizeof(obuf) + sizeof(obuf2), "read 4 got %d bytes\n", readden); + ok(readden == sizeof(obuf) + sizeof(obuf2), "read 4 got %ld bytes\n", readden); } else { - ok(readden == sizeof(obuf), "read 4 got %d bytes\n", readden); + ok(readden == sizeof(obuf), "read 4 got %ld bytes\n", readden); } pbuf = ibuf; ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 4a check\n"); @@ -446,13 +466,13 @@ static void test_CreateNamedPipe(int pipemode) ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), " WriteFile5b\n"); ok(written == sizeof(obuf2), "write file len 3b\n"); ok(PeekNamedPipe(hFile, ibuf, sizeof(ibuf), &readden, &avail, &left), "Peek5\n"); - ok(readden == sizeof(obuf), "peek5 got %d bytes\n", readden); - ok(avail == sizeof(obuf) + sizeof(obuf2), "peek5 got %d bytes available\n", avail); - ok(left == 0, "peek5 got %d bytes left\n", left); + ok(readden == sizeof(obuf), "peek5 got %ld bytes\n", readden); + ok(avail == sizeof(obuf) + sizeof(obuf2), "peek5 got %ld bytes available\n", avail); + ok(left == 0, "peek5 got %ld bytes left\n", left); pbuf = ibuf; ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 5a check\n"); ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n"); - ok(readden == sizeof(obuf), "read 5 got %d bytes\n", readden); + ok(readden == sizeof(obuf), "read 5 got %ld bytes\n", readden); pbuf = ibuf; ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 5a check\n"); if (readden <= sizeof(obuf)) @@ -461,11 +481,11 @@ static void test_CreateNamedPipe(int pipemode) /* Multiple writes in the reverse direction */ /* the write of obuf2 from write4 should still be in the buffer */ ok(PeekNamedPipe(hnp, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek6a\n"); - ok(readden == sizeof(obuf2), "peek6a got %d bytes\n", readden); - ok(avail == sizeof(obuf2), "peek6a got %d bytes available\n", avail); + ok(readden == sizeof(obuf2), "peek6a got %ld bytes\n", readden); + ok(avail == sizeof(obuf2), "peek6a got %ld bytes available\n", avail); if (avail > 0) { ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n"); - ok(readden == sizeof(obuf2), "read 6a got %d bytes\n", readden); + ok(readden == sizeof(obuf2), "read 6a got %ld bytes\n", readden); pbuf = ibuf; ok(memcmp(obuf2, pbuf, sizeof(obuf2)) == 0, "content 6a check\n"); } @@ -475,13 +495,13 @@ static void test_CreateNamedPipe(int pipemode) ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), " WriteFile6b\n"); ok(written == sizeof(obuf2), "write file len 6b\n"); ok(PeekNamedPipe(hnp, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek6\n"); - ok(readden == sizeof(obuf), "peek6 got %d bytes\n", readden); + ok(readden == sizeof(obuf), "peek6 got %ld bytes\n", readden); - ok(avail == sizeof(obuf) + sizeof(obuf2), "peek6b got %d bytes available\n", avail); + ok(avail == sizeof(obuf) + sizeof(obuf2), "peek6b got %ld bytes available\n", avail); pbuf = ibuf; ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 6a check\n"); ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n"); - ok(readden == sizeof(obuf), "read 6b got %d bytes\n", readden); + ok(readden == sizeof(obuf), "read 6b got %ld bytes\n", readden); pbuf = ibuf; ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 6a check\n"); if (readden <= sizeof(obuf)) @@ -494,9 +514,9 @@ static void test_CreateNamedPipe(int pipemode) SetLastError(0xdeadbeef); ok(!ReadFile(hFile, ibuf, 4, &readden, NULL), "ReadFile 7\n"); ok(GetLastError() == ERROR_MORE_DATA, "wrong error 7\n"); - ok(readden == 4, "read got %d bytes 7\n", readden); + ok(readden == 4, "read got %ld bytes 7\n", readden); ok(ReadFile(hFile, ibuf + 4, sizeof(ibuf) - 4, &readden, NULL), "ReadFile 7\n"); - ok(readden == sizeof(obuf2) - 4, "read got %d bytes 7\n", readden); + ok(readden == sizeof(obuf2) - 4, "read got %ld bytes 7\n", readden); ok(memcmp(obuf2, ibuf, written) == 0, "content check 7\n"); memset(ibuf, 0, sizeof(ibuf)); @@ -505,9 +525,9 @@ static void test_CreateNamedPipe(int pipemode) SetLastError(0xdeadbeef); ok(!ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile 8\n"); ok(GetLastError() == ERROR_MORE_DATA, "wrong error 8\n"); - ok(readden == 4, "read got %d bytes 8\n", readden); + ok(readden == 4, "read got %ld bytes 8\n", readden); ok(ReadFile(hnp, ibuf + 4, sizeof(ibuf) - 4, &readden, NULL), "ReadFile 8\n"); - ok(readden == sizeof(obuf) - 4, "read got %d bytes 8\n", readden); + ok(readden == sizeof(obuf) - 4, "read got %ld bytes 8\n", readden); ok(memcmp(obuf, ibuf, written) == 0, "content check 8\n"); /* The following test shows that when doing a partial read of a message, the rest @@ -522,15 +542,15 @@ static void test_CreateNamedPipe(int pipemode) SetLastError(0xdeadbeef); ok(!ReadFile(hFile, ibuf, 4, &readden, NULL), "ReadFile 9\n"); ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n"); - ok(readden == 4, "read got %d bytes 9\n", readden); + ok(readden == 4, "read got %ld bytes 9\n", readden); SetLastError(0xdeadbeef); ret = RpcReadFile(hFile, ibuf + 4, 4, &readden, NULL); ok(!ret, "RpcReadFile 9\n"); ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n"); - ok(readden == 4, "read got %d bytes 9\n", readden); + ok(readden == 4, "read got %ld bytes 9\n", readden); ret = RpcReadFile(hFile, ibuf + 8, sizeof(ibuf), &readden, NULL); ok(ret, "RpcReadFile 9\n"); - ok(readden == sizeof(obuf) - 8, "read got %d bytes 9\n", readden); + ok(readden == sizeof(obuf) - 8, "read got %ld bytes 9\n", readden); ok(memcmp(obuf, ibuf, sizeof(obuf)) == 0, "content check 9\n"); if (readden <= sizeof(obuf) - 8) /* blocks forever if second part was already received */ { @@ -539,14 +559,14 @@ static void test_CreateNamedPipe(int pipemode) ret = RpcReadFile(hFile, ibuf, 4, &readden, NULL); ok(!ret, "RpcReadFile 9\n"); ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n"); - ok(readden == 4, "read got %d bytes 9\n", readden); + ok(readden == 4, "read got %ld bytes 9\n", readden); SetLastError(0xdeadbeef); ok(!ReadFile(hFile, ibuf + 4, 4, &readden, NULL), "ReadFile 9\n"); ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n"); - ok(readden == 4, "read got %d bytes 9\n", readden); + ok(readden == 4, "read got %ld bytes 9\n", readden); ret = RpcReadFile(hFile, ibuf + 8, sizeof(ibuf), &readden, NULL); ok(ret, "RpcReadFile 9\n"); - ok(readden == sizeof(obuf2) - 8, "read got %d bytes 9\n", readden); + ok(readden == sizeof(obuf2) - 8, "read got %ld bytes 9\n", readden); ok(memcmp(obuf2, ibuf, sizeof(obuf2)) == 0, "content check 9\n"); } @@ -559,15 +579,15 @@ static void test_CreateNamedPipe(int pipemode) SetLastError(0xdeadbeef); ok(!ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile 10\n"); ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n"); - ok(readden == 4, "read got %d bytes 10\n", readden); + ok(readden == 4, "read got %ld bytes 10\n", readden); SetLastError(0xdeadbeef); ret = RpcReadFile(hnp, ibuf + 4, 4, &readden, NULL); ok(!ret, "RpcReadFile 10\n"); ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n"); - ok(readden == 4, "read got %d bytes 10\n", readden); + ok(readden == 4, "read got %ld bytes 10\n", readden); ret = RpcReadFile(hnp, ibuf + 8, sizeof(ibuf), &readden, NULL); ok(ret, "RpcReadFile 10\n"); - ok(readden == sizeof(obuf2) - 8, "read got %d bytes 10\n", readden); + ok(readden == sizeof(obuf2) - 8, "read got %ld bytes 10\n", readden); ok(memcmp(obuf2, ibuf, sizeof(obuf2)) == 0, "content check 10\n"); if (readden <= sizeof(obuf2) - 8) /* blocks forever if second part was already received */ { @@ -576,14 +596,14 @@ static void test_CreateNamedPipe(int pipemode) ret = RpcReadFile(hnp, ibuf, 4, &readden, NULL); ok(!ret, "RpcReadFile 10\n"); ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n"); - ok(readden == 4, "read got %d bytes 10\n", readden); + ok(readden == 4, "read got %ld bytes 10\n", readden); SetLastError(0xdeadbeef); ok(!ReadFile(hnp, ibuf + 4, 4, &readden, NULL), "ReadFile 10\n"); ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n"); - ok(readden == 4, "read got %d bytes 10\n", readden); + ok(readden == 4, "read got %ld bytes 10\n", readden); ret = RpcReadFile(hnp, ibuf + 8, sizeof(ibuf), &readden, NULL); ok(ret, "RpcReadFile 10\n"); - ok(readden == sizeof(obuf) - 8, "read got %d bytes 10\n", readden); + ok(readden == sizeof(obuf) - 8, "read got %ld bytes 10\n", readden); ok(memcmp(obuf, ibuf, sizeof(obuf)) == 0, "content check 10\n"); } @@ -629,14 +649,49 @@ static void test_CreateNamedPipe(int pipemode) ok(CloseHandle(hnp), "CloseHandle\n"); - hnp = CreateNamedPipeA(PIPENAME_SPECIAL, PIPE_ACCESS_DUPLEX, pipemode | PIPE_WAIT, - /* nMaxInstances */ 1, - /* nOutBufSize */ 1024, - /* nInBufSize */ 1024, - /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT, - /* lpSecurityAttrib */ NULL); - ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe with special characters failed\n"); - ok(CloseHandle(hnp), "CloseHandle\n"); + hnp = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_INBOUND, pipemode | PIPE_WAIT, + 1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL); + ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); + test_signaled(hnp); + + test_file_access(hnp, SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_PROPERTIES + | FILE_READ_DATA); + + CloseHandle(hnp); + + hnp = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_OUTBOUND, pipemode | PIPE_WAIT, + 1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL); + ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); + test_signaled(hnp); + + test_file_access(hnp, SYNCHRONIZE | READ_CONTROL | FILE_WRITE_ATTRIBUTES + | FILE_WRITE_PROPERTIES | FILE_APPEND_DATA | FILE_WRITE_DATA); + + hFile = CreateFileA(PIPENAME, 0, 0, NULL, OPEN_EXISTING, 0, 0); + ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed: %lu\n", GetLastError()); + test_file_access(hFile, SYNCHRONIZE | FILE_READ_ATTRIBUTES); + CloseHandle(hFile); + + CloseHandle(hnp); + + hnp = CreateNamedPipeA("\\\\.\\pipe\\a<>*?|\"/b", PIPE_ACCESS_DUPLEX, + PIPE_TYPE_BYTE, 1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL); + ok(hnp != INVALID_HANDLE_VALUE, "failed to create pipe, error %lu\n", GetLastError()); + hFile = CreateFileA("\\\\.\\pipe\\a<>*?|\"/b", 0, 0, NULL, OPEN_EXISTING, 0, 0); + ok(hFile != INVALID_HANDLE_VALUE, "failed to open pipe, error %lu\n", GetLastError()); + CloseHandle(hFile); + CloseHandle(hnp); + + hnp = CreateNamedPipeA("\\\\.\\pipe\\trailingslash\\", PIPE_ACCESS_DUPLEX, + PIPE_TYPE_BYTE, 1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL); + ok(hnp != INVALID_HANDLE_VALUE, "failed to create pipe, error %lu\n", GetLastError()); + hFile = CreateFileA("\\\\.\\pipe\\trailingslash", 0, 0, NULL, OPEN_EXISTING, 0, 0); + ok(hFile == INVALID_HANDLE_VALUE, "expected opening pipe to fail\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %lu\n", GetLastError()); + hFile = CreateFileA("\\\\.\\pipe\\trailingslash\\", 0, 0, NULL, OPEN_EXISTING, 0, 0); + ok(hFile != INVALID_HANDLE_VALUE, "failed to open pipe, error %lu\n", GetLastError()); + CloseHandle(hFile); + CloseHandle(hnp); if (winetest_debug > 1) trace("test_CreateNamedPipe returning\n"); } @@ -738,43 +793,43 @@ static void test_ReadFile(void) server = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 1024, 1024, NMPWAIT_WAIT_FOREVER, NULL); - ok(server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with %u\n", GetLastError()); + ok(server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with %lu\n", GetLastError()); client = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); - ok(client != INVALID_HANDLE_VALUE, "CreateFile failed with %u\n", GetLastError()); + ok(client != INVALID_HANDLE_VALUE, "CreateFile failed with %lu\n", GetLastError()); ok(WriteFile(client, buf, sizeof(buf), &size, NULL), "WriteFile\n"); res = ReadFile(server, buf, 1, &size, NULL); - ok(!res && GetLastError() == ERROR_MORE_DATA, "ReadFile returned %x(%u)\n", res, GetLastError()); - ok(size == 1, "size = %u\n", size); + ok(!res && GetLastError() == ERROR_MORE_DATA, "ReadFile returned %x(%lu)\n", res, GetLastError()); + ok(size == 1, "size = %lu\n", size); /* pass both overlapped and ret read */ memset(&overlapped, 0, sizeof(overlapped)); res = ReadFile(server, buf, 1, &size, &overlapped); - ok(!res && GetLastError() == ERROR_MORE_DATA, "ReadFile returned %x(%u)\n", res, GetLastError()); - ok(size == 0, "size = %u\n", size); - ok((NTSTATUS)overlapped.Internal == STATUS_BUFFER_OVERFLOW, "Internal = %lx\n", overlapped.Internal); - ok(overlapped.InternalHigh == 1, "InternalHigh = %lx\n", overlapped.InternalHigh); + ok(!res && GetLastError() == ERROR_MORE_DATA, "ReadFile returned %x(%lu)\n", res, GetLastError()); + ok(size == 0, "size = %lu\n", size); + ok((NTSTATUS)overlapped.Internal == STATUS_BUFFER_OVERFLOW, "Internal = %Ix\n", overlapped.Internal); + ok(overlapped.InternalHigh == 1, "InternalHigh = %Ix\n", overlapped.InternalHigh); DisconnectNamedPipe(server); memset(&overlapped, 0, sizeof(overlapped)); overlapped.InternalHigh = 0xdeadbeef; res = ReadFile(server, buf, 1, &size, &overlapped); - ok(!res && GetLastError() == ERROR_PIPE_NOT_CONNECTED, "ReadFile returned %x(%u)\n", res, GetLastError()); - ok(size == 0, "size = %u\n", size); - ok(overlapped.Internal == STATUS_PENDING, "Internal = %lx\n", overlapped.Internal); - ok(overlapped.InternalHigh == 0xdeadbeef, "InternalHigh = %lx\n", overlapped.InternalHigh); + ok(!res && GetLastError() == ERROR_PIPE_NOT_CONNECTED, "ReadFile returned %x(%lu)\n", res, GetLastError()); + ok(size == 0, "size = %lu\n", size); + ok(overlapped.Internal == STATUS_PENDING, "Internal = %Ix\n", overlapped.Internal); + ok(overlapped.InternalHigh == 0xdeadbeef, "InternalHigh = %Ix\n", overlapped.InternalHigh); memset(&overlapped, 0, sizeof(overlapped)); overlapped.InternalHigh = 0xdeadbeef; res = WriteFile(server, buf, 1, &size, &overlapped); - ok(!res && GetLastError() == ERROR_PIPE_NOT_CONNECTED, "ReadFile returned %x(%u)\n", res, GetLastError()); - ok(size == 0, "size = %u\n", size); - ok(overlapped.Internal == STATUS_PENDING, "Internal = %lx\n", overlapped.Internal); - ok(overlapped.InternalHigh == 0xdeadbeef, "InternalHigh = %lx\n", overlapped.InternalHigh); + ok(!res && GetLastError() == ERROR_PIPE_NOT_CONNECTED, "ReadFile returned %x(%lu)\n", res, GetLastError()); + ok(size == 0, "size = %lu\n", size); + ok(overlapped.Internal == STATUS_PENDING, "Internal = %Ix\n", overlapped.Internal); + ok(overlapped.InternalHigh == 0xdeadbeef, "InternalHigh = %Ix\n", overlapped.InternalHigh); CloseHandle(server); CloseHandle(client); @@ -872,10 +927,11 @@ static DWORD CALLBACK serverThreadMain2(LPVOID arg) user_apc_ran = FALSE; - if (i == 0 && pQueueUserAPC) { + if (i == 0) + { if (winetest_debug > 1) trace("Queueing an user APC\n"); /* verify the pipe is non alerable */ - ret = pQueueUserAPC(&user_apc, GetCurrentThread(), 0); - ok(ret, "QueueUserAPC failed: %d\n", GetLastError()); + ret = QueueUserAPC(&user_apc, GetCurrentThread(), 0); + ok(ret, "QueueUserAPC failed: %ld\n", GetLastError()); } /* Wait for client to connect */ @@ -903,7 +959,7 @@ static DWORD CALLBACK serverThreadMain2(LPVOID arg) ok(user_apc_ran == FALSE, "UserAPC ran, pipe using alertable io mode\n"); - if (i == 0 && pQueueUserAPC) + if (i == 0) SleepEx(0, TRUE); /* get rid of apc */ /* Set up next echo server */ @@ -966,7 +1022,7 @@ static DWORD CALLBACK serverThreadMain3(LPVOID arg) if (winetest_debug > 1) trace("Server calling non-overlapped ConnectNamedPipe on overlapped pipe...\n"); success = ConnectNamedPipe(hnp, NULL); err = GetLastError(); - ok(success || (err == ERROR_PIPE_CONNECTED), "ConnectNamedPipe failed: %d\n", err); + ok(success || (err == ERROR_PIPE_CONNECTED), "ConnectNamedPipe failed: %ld\n", err); if (winetest_debug > 1) trace("ConnectNamedPipe operation complete.\n"); } else { if (winetest_debug > 1) trace("Server calling overlapped ConnectNamedPipe...\n"); @@ -981,7 +1037,7 @@ static DWORD CALLBACK serverThreadMain3(LPVOID arg) do { ret = WaitForSingleObjectEx(hEvent, INFINITE, TRUE); } while (ret == WAIT_IO_COMPLETION); - ok(ret == 0, "wait ConnectNamedPipe returned %x\n", ret); + ok(ret == 0, "wait ConnectNamedPipe returned %lx\n", ret); } success = GetOverlappedResult(hnp, &oOverlap, &dummy, letGORwait); if (!letGORwait && !letWFSOEwait && !success) { @@ -1009,7 +1065,7 @@ static DWORD CALLBACK serverThreadMain3(LPVOID arg) do { ret = WaitForSingleObjectEx(hEvent, INFINITE, TRUE); } while (ret == WAIT_IO_COMPLETION); - ok(ret == 0, "wait ReadFile returned %x\n", ret); + ok(ret == 0, "wait ReadFile returned %lx\n", ret); } success = GetOverlappedResult(hnp, &oOverlap, &readden, letGORwait); if (!letGORwait && !letWFSOEwait && !success) { @@ -1033,7 +1089,7 @@ static DWORD CALLBACK serverThreadMain3(LPVOID arg) do { ret = WaitForSingleObjectEx(hEvent, INFINITE, TRUE); } while (ret == WAIT_IO_COMPLETION); - ok(ret == 0, "wait WriteFile returned %x\n", ret); + ok(ret == 0, "wait WriteFile returned %lx\n", ret); } success = GetOverlappedResult(hnp, &oOverlap, &written, letGORwait); if (!letGORwait && !letWFSOEwait && !success) { @@ -1071,7 +1127,7 @@ static DWORD CALLBACK serverThreadMain4(LPVOID arg) ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); hcompletion = CreateIoCompletionPort(hnp, NULL, 12345, 1); - ok(hcompletion != NULL, "CreateIoCompletionPort failed, error=%i\n", GetLastError()); + ok(hcompletion != NULL, "CreateIoCompletionPort failed, error=%li\n", GetLastError()); for (i = 0; i < NB_SERVER_LOOPS; i++) { char buf[512]; @@ -1095,17 +1151,17 @@ static DWORD CALLBACK serverThreadMain4(LPVOID arg) success = ConnectNamedPipe(hnp, &oConnect); err = GetLastError(); ok(!success && (err == ERROR_IO_PENDING || err == ERROR_PIPE_CONNECTED), - "overlapped ConnectNamedPipe got %u err %u\n", success, err ); + "overlapped ConnectNamedPipe got %u err %lu\n", success, err ); if (!success && err == ERROR_IO_PENDING) { if (winetest_debug > 1) trace("ConnectNamedPipe GetQueuedCompletionStatus\n"); success = GetQueuedCompletionStatus(hcompletion, &dummy, &compkey, &oResult, 0); if (!success) { ok( GetLastError() == WAIT_TIMEOUT, - "ConnectNamedPipe GetQueuedCompletionStatus wrong error %u\n", GetLastError()); + "ConnectNamedPipe GetQueuedCompletionStatus wrong error %lu\n", GetLastError()); success = GetQueuedCompletionStatus(hcompletion, &dummy, &compkey, &oResult, 10000); } - ok(success, "ConnectNamedPipe GetQueuedCompletionStatus failed, errno=%i\n", GetLastError()); + ok(success, "ConnectNamedPipe GetQueuedCompletionStatus failed, errno=%li\n", GetLastError()); if (success) { ok(compkey == 12345, "got completion key %i instead of 12345\n", (int)compkey); @@ -1121,10 +1177,10 @@ static DWORD CALLBACK serverThreadMain4(LPVOID arg) success = ReadFile(hnp, buf, sizeof(buf), &readden, &oRead); if (winetest_debug > 1) trace("Server ReadFile returned...\n"); err = GetLastError(); - ok(success || err == ERROR_IO_PENDING, "overlapped ReadFile, err=%i\n", err); + ok(success || err == ERROR_IO_PENDING, "overlapped ReadFile, err=%li\n", err); success = GetQueuedCompletionStatus(hcompletion, &readden, &compkey, &oResult, 10000); - ok(success, "ReadFile GetQueuedCompletionStatus failed, errno=%i\n", GetLastError()); + ok(success, "ReadFile GetQueuedCompletionStatus failed, errno=%li\n", GetLastError()); if (success) { ok(compkey == 12345, "got completion key %i instead of 12345\n", (int)compkey); @@ -1136,10 +1192,10 @@ static DWORD CALLBACK serverThreadMain4(LPVOID arg) success = WriteFile(hnp, buf, readden, &written, &oWrite); if (winetest_debug > 1) trace("Server WriteFile returned...\n"); err = GetLastError(); - ok(success || err == ERROR_IO_PENDING, "overlapped WriteFile failed, err=%u\n", err); + ok(success || err == ERROR_IO_PENDING, "overlapped WriteFile failed, err=%lu\n", err); success = GetQueuedCompletionStatus(hcompletion, &written, &compkey, &oResult, 10000); - ok(success, "WriteFile GetQueuedCompletionStatus failed, errno=%i\n", GetLastError()); + ok(success, "WriteFile GetQueuedCompletionStatus failed, errno=%li\n", GetLastError()); if (success) { ok(compkey == 12345, "got completion key %i instead of 12345\n", (int)compkey); @@ -1157,8 +1213,8 @@ static DWORD CALLBACK serverThreadMain4(LPVOID arg) SetLastError(ERROR_SUCCESS); success = WriteFile(hnp, buf, readden, &written, &oWrite); err = GetLastError(); - todo_wine_if (!success && err == ERROR_PIPE_NOT_CONNECTED) ok(!success && err == ERROR_NO_DATA, - "overlapped WriteFile on disconnected pipe returned %u, err=%i\n", success, err); + ok(!success && err == ERROR_NO_DATA, + "overlapped WriteFile on disconnected pipe returned %u, err=%li\n", success, err); /* No completion status is queued on immediate error. */ SetLastError(ERROR_SUCCESS); @@ -1167,7 +1223,7 @@ static DWORD CALLBACK serverThreadMain4(LPVOID arg) &oResult, 0); err = GetLastError(); ok(!success && err == WAIT_TIMEOUT && !oResult, - "WriteFile GetQueuedCompletionStatus returned %u, err=%i, oResult %p\n", + "WriteFile GetQueuedCompletionStatus returned %u, err=%li, oResult %p\n", success, err, oResult); if (winetest_debug > 1) trace("Server reading from disconnected pipe...\n"); @@ -1176,7 +1232,7 @@ static DWORD CALLBACK serverThreadMain4(LPVOID arg) if (winetest_debug > 1) trace("Server ReadFile from disconnected pipe returned...\n"); err = GetLastError(); ok(!success && err == ERROR_BROKEN_PIPE, - "overlapped ReadFile on disconnected pipe returned %u, err=%i\n", success, err); + "overlapped ReadFile on disconnected pipe returned %u, err=%li\n", success, err); SetLastError(ERROR_SUCCESS); oResult = (OVERLAPPED *)0xdeadbeef; @@ -1184,19 +1240,19 @@ static DWORD CALLBACK serverThreadMain4(LPVOID arg) &oResult, 0); err = GetLastError(); ok(!success && err == WAIT_TIMEOUT && !oResult, - "ReadFile GetQueuedCompletionStatus returned %u, err=%i, oResult %p\n", + "ReadFile GetQueuedCompletionStatus returned %u, err=%li, oResult %p\n", success, err, oResult); /* finish this connection, wait for next one */ ok(FlushFileBuffers(hnp), "FlushFileBuffers\n"); success = DisconnectNamedPipe(hnp); - ok(success, "DisconnectNamedPipe failed, err %u\n", GetLastError()); + ok(success, "DisconnectNamedPipe failed, err %lu\n", GetLastError()); } ret = CloseHandle(hnp); - ok(ret, "CloseHandle named pipe failed, err=%i\n", GetLastError()); + ok(ret, "CloseHandle named pipe failed, err=%li\n", GetLastError()); ret = CloseHandle(hcompletion); - ok(ret, "CloseHandle completion failed, err=%i\n", GetLastError()); + ok(ret, "CloseHandle completion failed, err=%li\n", GetLastError()); return 0; } @@ -1252,7 +1308,7 @@ static DWORD CALLBACK serverThreadMain5(LPVOID arg) if (winetest_debug > 1) trace("Server calling ConnectNamedPipe...\n"); success = ConnectNamedPipe(hnp, NULL); err = GetLastError(); - ok(success || (err == ERROR_PIPE_CONNECTED), "ConnectNamedPipe failed: %d\n", err); + ok(success || (err == ERROR_PIPE_CONNECTED), "ConnectNamedPipe failed: %ld\n", err); if (winetest_debug > 1) trace("ConnectNamedPipe operation complete.\n"); /* Echo bytes once */ @@ -1263,7 +1319,7 @@ static DWORD CALLBACK serverThreadMain5(LPVOID arg) ResetEvent(hEvent); success = ReadFileEx(hnp, buf, sizeof(buf), &oOverlap, completion_routine); if (winetest_debug > 1) trace("Server ReadFileEx returned...\n"); - ok(success, "ReadFileEx failed, err=%i\n", GetLastError()); + ok(success, "ReadFileEx failed, err=%li\n", GetLastError()); ok(completion_called == 0, "completion routine called before ReadFileEx return\n"); if (winetest_debug > 1) trace("ReadFileEx returned.\n"); if (success) { @@ -1271,10 +1327,10 @@ static DWORD CALLBACK serverThreadMain5(LPVOID arg) do { ret = WaitForSingleObjectEx(hEvent, INFINITE, TRUE); } while (ret == WAIT_IO_COMPLETION); - ok(ret == 0, "wait ReadFileEx returned %x\n", ret); + ok(ret == 0, "wait ReadFileEx returned %lx\n", ret); } ok(completion_called == 1, "completion routine called %i times\n", completion_called); - ok(completion_errorcode == ERROR_SUCCESS, "completion routine got error %d\n", completion_errorcode); + ok(completion_errorcode == ERROR_SUCCESS, "completion routine got error %ld\n", completion_errorcode); ok(completion_num_bytes != 0, "read 0 bytes\n"); ok(completion_lpoverlapped == &oOverlap, "got wrong overlapped pointer %p\n", completion_lpoverlapped); readden = completion_num_bytes; @@ -1285,7 +1341,7 @@ static DWORD CALLBACK serverThreadMain5(LPVOID arg) ResetEvent(hEvent); success = WriteFileEx(hnp, buf, readden, &oOverlap, completion_routine); if (winetest_debug > 1) trace("Server WriteFileEx returned...\n"); - ok(success, "WriteFileEx failed, err=%i\n", GetLastError()); + ok(success, "WriteFileEx failed, err=%li\n", GetLastError()); ok(completion_called == 0, "completion routine called before ReadFileEx return\n"); if (winetest_debug > 1) trace("overlapped WriteFile returned.\n"); if (success) { @@ -1293,12 +1349,12 @@ static DWORD CALLBACK serverThreadMain5(LPVOID arg) do { ret = WaitForSingleObjectEx(hEvent, INFINITE, TRUE); } while (ret == WAIT_IO_COMPLETION); - ok(ret == 0, "wait WriteFileEx returned %x\n", ret); + ok(ret == 0, "wait WriteFileEx returned %lx\n", ret); } if (winetest_debug > 1) trace("Server done writing.\n"); ok(completion_called == 1, "completion routine called %i times\n", completion_called); - ok(completion_errorcode == ERROR_SUCCESS, "completion routine got error %d\n", completion_errorcode); - ok(completion_num_bytes == readden, "read %i bytes wrote %i\n", readden, completion_num_bytes); + ok(completion_errorcode == ERROR_SUCCESS, "completion routine got error %ld\n", completion_errorcode); + ok(completion_num_bytes == readden, "read %li bytes wrote %li\n", readden, completion_num_bytes); ok(completion_lpoverlapped == &oOverlap, "got wrong overlapped pointer %p\n", completion_lpoverlapped); /* finish this connection, wait for next one */ @@ -1308,11 +1364,11 @@ static DWORD CALLBACK serverThreadMain5(LPVOID arg) return 0; } -static void exercizeServer(const char *pipename, HANDLE serverThread) +static void exerciseServer(const char *pipename, HANDLE serverThread) { int i; - if (winetest_debug > 1) trace("exercizeServer starting\n"); + if (winetest_debug > 1) trace("exerciseServer starting\n"); for (i = 0; i < NB_SERVER_LOOPS; i++) { HANDLE hFile=INVALID_HANDLE_VALUE; static const char obuf[] = "Bit Bucket"; @@ -1355,7 +1411,7 @@ static void exercizeServer(const char *pipename, HANDLE serverThread) ok(WaitForSingleObject(serverThread,INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject\n"); CloseHandle(hnp); - if (winetest_debug > 1) trace("exercizeServer returning\n"); + if (winetest_debug > 1) trace("exerciseServer returning\n"); } static void test_NamedPipe_2(void) @@ -1370,7 +1426,7 @@ static void test_NamedPipe_2(void) alarm_event = CreateEventW( NULL, TRUE, FALSE, NULL ); SetLastError(0xdeadbeef); alarmThread = CreateThread(NULL, 0, alarmThreadMain, (void *) 20000, 0, &alarmThreadId); - ok(alarmThread != NULL, "CreateThread failed: %d\n", GetLastError()); + ok(alarmThread != NULL, "CreateThread failed: %ld\n", GetLastError()); /* The servers we're about to exercise do try to clean up carefully, * but to reduce the chance of a test failure due to a pipe handle @@ -1380,32 +1436,32 @@ static void test_NamedPipe_2(void) /* Try server #1 */ SetLastError(0xdeadbeef); serverThread = CreateThread(NULL, 0, serverThreadMain1, (void *)8, 0, &serverThreadId); - ok(serverThread != NULL, "CreateThread failed: %d\n", GetLastError()); - exercizeServer(PIPENAME "serverThreadMain1", serverThread); + ok(serverThread != NULL, "CreateThread failed: %ld\n", GetLastError()); + exerciseServer(PIPENAME "serverThreadMain1", serverThread); /* Try server #2 */ SetLastError(0xdeadbeef); serverThread = CreateThread(NULL, 0, serverThreadMain2, 0, 0, &serverThreadId); - ok(serverThread != NULL, "CreateThread failed: %d\n", GetLastError()); - exercizeServer(PIPENAME "serverThreadMain2", serverThread); + ok(serverThread != NULL, "CreateThread failed: %ld\n", GetLastError()); + exerciseServer(PIPENAME "serverThreadMain2", serverThread); /* Try server #3 */ SetLastError(0xdeadbeef); serverThread = CreateThread(NULL, 0, serverThreadMain3, 0, 0, &serverThreadId); - ok(serverThread != NULL, "CreateThread failed: %d\n", GetLastError()); - exercizeServer(PIPENAME "serverThreadMain3", serverThread); + ok(serverThread != NULL, "CreateThread failed: %ld\n", GetLastError()); + exerciseServer(PIPENAME "serverThreadMain3", serverThread); /* Try server #4 */ SetLastError(0xdeadbeef); serverThread = CreateThread(NULL, 0, serverThreadMain4, 0, 0, &serverThreadId); - ok(serverThread != NULL, "CreateThread failed: %d\n", GetLastError()); - exercizeServer(PIPENAME "serverThreadMain4", serverThread); + ok(serverThread != NULL, "CreateThread failed: %ld\n", GetLastError()); + exerciseServer(PIPENAME "serverThreadMain4", serverThread); /* Try server #5 */ SetLastError(0xdeadbeef); serverThread = CreateThread(NULL, 0, serverThreadMain5, 0, 0, &serverThreadId); - ok(serverThread != NULL, "CreateThread failed: %d\n", GetLastError()); - exercizeServer(PIPENAME "serverThreadMain5", serverThread); + ok(serverThread != NULL, "CreateThread failed: %ld\n", GetLastError()); + exerciseServer(PIPENAME "serverThreadMain5", serverThread); ok(SetEvent( alarm_event ), "SetEvent\n"); CloseHandle( alarm_event ); @@ -1456,6 +1512,11 @@ static int test_DisconnectNamedPipe(void) ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe while messages waiting\n"); ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL) == 0 && GetLastError() == ERROR_PIPE_NOT_CONNECTED, "WriteFile to disconnected pipe\n"); + ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL) == 0 + && GetLastError() == ERROR_PIPE_NOT_CONNECTED, "WriteFile to disconnected pipe\n"); + ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL) == 0 + && GetLastError() == ERROR_PIPE_NOT_CONNECTED, + "ReadFile from disconnected pipe with bytes waiting\n"); ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL) == 0 && GetLastError() == ERROR_PIPE_NOT_CONNECTED, "ReadFile from disconnected pipe with bytes waiting\n"); @@ -1463,15 +1524,13 @@ static int test_DisconnectNamedPipe(void) ok(!DisconnectNamedPipe(hnp) && GetLastError() == ERROR_PIPE_NOT_CONNECTED, "DisconnectNamedPipe worked twice\n"); ret = WaitForSingleObject(hFile, 0); - ok(ret == WAIT_TIMEOUT, "WaitForSingleObject returned %X\n", ret); + ok(ret == WAIT_TIMEOUT, "WaitForSingleObject returned %lX\n", ret); ret = PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL); - todo_wine - ok(!ret && GetLastError() == ERROR_PIPE_NOT_CONNECTED, "PeekNamedPipe returned %x (%u)\n", + ok(!ret && GetLastError() == ERROR_PIPE_NOT_CONNECTED, "PeekNamedPipe returned %lx (%lu)\n", ret, GetLastError()); ret = PeekNamedPipe(hnp, NULL, 0, NULL, &readden, NULL); - todo_wine - ok(!ret && GetLastError() == ERROR_BAD_PIPE, "PeekNamedPipe returned %x (%u)\n", + ok(!ret && GetLastError() == ERROR_BAD_PIPE, "PeekNamedPipe returned %lx (%lu)\n", ret, GetLastError()); ok(CloseHandle(hFile), "CloseHandle\n"); } @@ -1491,8 +1550,7 @@ static void test_CreatePipe(void) char readbuf[32]; user_apc_ran = FALSE; - if (pQueueUserAPC) - ok(pQueueUserAPC(user_apc, GetCurrentThread(), 0), "couldn't create user apc\n"); + ok(QueueUserAPC(user_apc, GetCurrentThread(), 0), "couldn't create user apc\n"); pipe_attr.nLength = sizeof(SECURITY_ATTRIBUTES); pipe_attr.bInheritHandle = TRUE; @@ -1500,22 +1558,27 @@ static void test_CreatePipe(void) ok(CreatePipe(&piperead, &pipewrite, &pipe_attr, 0) != 0, "CreatePipe failed\n"); test_pipe_info(piperead, FILE_PIPE_SERVER_END, 4096, 4096, 1); test_pipe_info(pipewrite, 0, 4096, 4096, 1); + test_file_access(piperead, SYNCHRONIZE | READ_CONTROL | FILE_WRITE_ATTRIBUTES + | FILE_READ_ATTRIBUTES | FILE_READ_PROPERTIES | FILE_READ_DATA); + test_file_access(pipewrite, SYNCHRONIZE | READ_CONTROL | FILE_WRITE_ATTRIBUTES + | FILE_READ_ATTRIBUTES | FILE_WRITE_PROPERTIES | FILE_APPEND_DATA + | FILE_WRITE_DATA); ok(WriteFile(pipewrite,PIPENAME,sizeof(PIPENAME), &written, NULL), "Write to anonymous pipe failed\n"); - ok(written == sizeof(PIPENAME), "Write to anonymous pipe wrote %d bytes\n", written); + ok(written == sizeof(PIPENAME), "Write to anonymous pipe wrote %ld bytes\n", written); ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL), "Read from non empty pipe failed\n"); - ok(read == sizeof(PIPENAME), "Read from anonymous pipe got %d bytes\n", read); + ok(read == sizeof(PIPENAME), "Read from anonymous pipe got %ld bytes\n", read); ok(CloseHandle(pipewrite), "CloseHandle for the write pipe failed\n"); ok(CloseHandle(piperead), "CloseHandle for the read pipe failed\n"); /* Now write another chunk*/ ok(CreatePipe(&piperead, &pipewrite, &pipe_attr, 0) != 0, "CreatePipe failed\n"); ok(WriteFile(pipewrite,PIPENAME,sizeof(PIPENAME), &written, NULL), "Write to anonymous pipe failed\n"); - ok(written == sizeof(PIPENAME), "Write to anonymous pipe wrote %d bytes\n", written); + ok(written == sizeof(PIPENAME), "Write to anonymous pipe wrote %ld bytes\n", written); /* and close the write end, read should still succeed*/ ok(CloseHandle(pipewrite), "CloseHandle for the Write Pipe failed\n"); ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL), "Read from broken pipe with pending data failed\n"); - ok(read == sizeof(PIPENAME), "Read from anonymous pipe got %d bytes\n", read); + ok(read == sizeof(PIPENAME), "Read from anonymous pipe got %ld bytes\n", read); /* But now we need to get informed that the pipe is closed */ ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL) == 0, "Broken pipe not detected\n"); ok(CloseHandle(piperead), "CloseHandle for the read pipe failed\n"); @@ -1526,13 +1589,13 @@ static void test_CreatePipe(void) for (i = 0; i < size; i++) buffer[i] = i; 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); + ok(written == size, "Write to anonymous pipe wrote %ld bytes\n", written); /* and close the write end, read should still succeed*/ ok(CloseHandle(pipewrite), "CloseHandle for the Write Pipe failed\n"); memset( buffer, 0, size ); ok(ReadFile(piperead, buffer, size, &read, NULL), "Read from broken pipe with pending data failed\n"); - ok(read == size, "Read from anonymous pipe got %d bytes\n", read); - for (i = 0; i < size; i++) ok( buffer[i] == (BYTE)i, "invalid data %x at %x\n", buffer[i], i ); + ok(read == size, "Read from anonymous pipe got %ld bytes\n", read); + for (i = 0; i < size; i++) ok( buffer[i] == (BYTE)i, "invalid data %x at %lx\n", buffer[i], i ); /* But now we need to get informed that the pipe is closed */ ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL) == 0, "Broken pipe not detected\n"); ok(CloseHandle(piperead), "CloseHandle for the read pipe failed\n"); @@ -1559,107 +1622,107 @@ static void test_CloseHandle(void) hpipe = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL); - ok(hpipe != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with %u\n", GetLastError()); + ok(hpipe != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with %lu\n", GetLastError()); hfile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); - ok(hfile != INVALID_HANDLE_VALUE, "CreateFile failed with %u\n", GetLastError()); + ok(hfile != INVALID_HANDLE_VALUE, "CreateFile failed with %lu\n", GetLastError()); numbytes = 0xdeadbeef; ret = WriteFile(hpipe, testdata, sizeof(testdata), &numbytes, NULL); - ok(ret, "WriteFile failed with %u\n", GetLastError()); - ok(numbytes == sizeof(testdata), "expected sizeof(testdata), got %u\n", numbytes); + ok(ret, "WriteFile failed with %lu\n", GetLastError()); + ok(numbytes == sizeof(testdata), "expected sizeof(testdata), got %lu\n", numbytes); numbytes = 0xdeadbeef; ret = PeekNamedPipe(hfile, NULL, 0, NULL, &numbytes, NULL); - ok(ret, "PeekNamedPipe failed with %u\n", GetLastError()); - ok(numbytes == sizeof(testdata), "expected sizeof(testdata), got %u\n", numbytes); + ok(ret, "PeekNamedPipe failed with %lu\n", GetLastError()); + ok(numbytes == sizeof(testdata), "expected sizeof(testdata), got %lu\n", numbytes); ret = CloseHandle(hpipe); - ok(ret, "CloseHandle failed with %u\n", GetLastError()); + ok(ret, "CloseHandle failed with %lu\n", GetLastError()); numbytes = 0xdeadbeef; memset(buffer, 0, sizeof(buffer)); ret = ReadFile(hfile, buffer, 0, &numbytes, NULL); - ok(ret, "ReadFile failed with %u\n", GetLastError()); - ok(numbytes == 0, "expected 0, got %u\n", numbytes); + ok(ret, "ReadFile failed with %lu\n", GetLastError()); + ok(numbytes == 0, "expected 0, got %lu\n", numbytes); numbytes = 0xdeadbeef; ret = PeekNamedPipe(hfile, NULL, 0, NULL, &numbytes, NULL); - ok(ret, "PeekNamedPipe failed with %u\n", GetLastError()); - ok(numbytes == sizeof(testdata), "expected sizeof(testdata), got %u\n", numbytes); + ok(ret, "PeekNamedPipe failed with %lu\n", GetLastError()); + ok(numbytes == sizeof(testdata), "expected sizeof(testdata), got %lu\n", numbytes); numbytes = 0xdeadbeef; memset(buffer, 0, sizeof(buffer)); ret = ReadFile(hfile, buffer, sizeof(buffer), &numbytes, NULL); - ok(ret, "ReadFile failed with %u\n", GetLastError()); - ok(numbytes == sizeof(testdata), "expected sizeof(testdata), got %u\n", numbytes); + ok(ret, "ReadFile failed with %lu\n", GetLastError()); + ok(numbytes == sizeof(testdata), "expected sizeof(testdata), got %lu\n", numbytes); ret = GetNamedPipeHandleStateA(hfile, &state, NULL, NULL, NULL, NULL, 0); - ok(ret, "GetNamedPipeHandleState failed with %u\n", GetLastError()); + ok(ret, "GetNamedPipeHandleState failed with %lu\n", GetLastError()); state = PIPE_READMODE_MESSAGE | PIPE_WAIT; ret = SetNamedPipeHandleState(hfile, &state, NULL, NULL); - ok(ret, "SetNamedPipeHandleState failed with %u\n", GetLastError()); + ok(ret, "SetNamedPipeHandleState failed with %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = ReadFile(hfile, buffer, 0, &numbytes, NULL); ok(!ret, "ReadFile unexpectedly succeeded\n"); - ok(GetLastError() == ERROR_BROKEN_PIPE, "expected ERROR_BROKEN_PIPE, got %u\n", GetLastError()); + ok(GetLastError() == ERROR_BROKEN_PIPE, "expected ERROR_BROKEN_PIPE, got %lu\n", GetLastError()); numbytes = 0xdeadbeef; ret = PeekNamedPipe(hfile, NULL, 0, NULL, &numbytes, NULL); - ok(!ret && GetLastError() == ERROR_BROKEN_PIPE, "PeekNamedPipe returned %x (%u)\n", + ok(!ret && GetLastError() == ERROR_BROKEN_PIPE, "PeekNamedPipe returned %x (%lu)\n", ret, GetLastError()); - ok(numbytes == 0xdeadbeef, "numbytes = %u\n", numbytes); + ok(numbytes == 0xdeadbeef, "numbytes = %lu\n", numbytes); SetLastError(0xdeadbeef); ret = WriteFile(hfile, testdata, sizeof(testdata), &numbytes, NULL); ok(!ret, "WriteFile unexpectedly succeeded\n"); - todo_wine ok(GetLastError() == ERROR_NO_DATA, "expected ERROR_NO_DATA, got %u\n", GetLastError()); + ok(GetLastError() == ERROR_NO_DATA, "expected ERROR_NO_DATA, got %lu\n", GetLastError()); CloseHandle(hfile); hpipe = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL); - ok(hpipe != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with %u\n", GetLastError()); + ok(hpipe != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with %lu\n", GetLastError()); hfile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); - ok(hfile != INVALID_HANDLE_VALUE, "CreateFile failed with %u\n", GetLastError()); + ok(hfile != INVALID_HANDLE_VALUE, "CreateFile failed with %lu\n", GetLastError()); numbytes = 0xdeadbeef; ret = WriteFile(hpipe, testdata, 0, &numbytes, NULL); - ok(ret, "WriteFile failed with %u\n", GetLastError()); - ok(numbytes == 0, "expected 0, got %u\n", numbytes); + ok(ret, "WriteFile failed with %lu\n", GetLastError()); + ok(numbytes == 0, "expected 0, got %lu\n", numbytes); ret = CloseHandle(hpipe); - ok(ret, "CloseHandle failed with %u\n", GetLastError()); + ok(ret, "CloseHandle failed with %lu\n", GetLastError()); numbytes = 0xdeadbeef; memset(buffer, 0, sizeof(buffer)); ret = ReadFile(hfile, buffer, sizeof(buffer), &numbytes, NULL); - ok(ret, "ReadFile failed with %u\n", GetLastError()); - ok(numbytes == 0, "expected 0, got %u\n", numbytes); + ok(ret, "ReadFile failed with %lu\n", GetLastError()); + ok(numbytes == 0, "expected 0, got %lu\n", numbytes); SetLastError(0xdeadbeef); ret = ReadFile(hfile, buffer, 0, &numbytes, NULL); ok(!ret, "ReadFile unexpectedly succeeded\n"); - ok(GetLastError() == ERROR_BROKEN_PIPE, "expected ERROR_BROKEN_PIPE, got %u\n", GetLastError()); + ok(GetLastError() == ERROR_BROKEN_PIPE, "expected ERROR_BROKEN_PIPE, got %lu\n", GetLastError()); ret = GetNamedPipeHandleStateA(hfile, &state, NULL, NULL, NULL, NULL, 0); - ok(ret, "GetNamedPipeHandleState failed with %u\n", GetLastError()); + ok(ret, "GetNamedPipeHandleState failed with %lu\n", GetLastError()); state = PIPE_READMODE_MESSAGE | PIPE_WAIT; ret = SetNamedPipeHandleState(hfile, &state, NULL, NULL); - ok(ret, "SetNamedPipeHandleState failed with %u\n", GetLastError()); + ok(ret, "SetNamedPipeHandleState failed with %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = ReadFile(hfile, buffer, 0, &numbytes, NULL); ok(!ret, "ReadFile unexpectedly succeeded\n"); - ok(GetLastError() == ERROR_BROKEN_PIPE, "expected ERROR_BROKEN_PIPE, got %u\n", GetLastError()); + ok(GetLastError() == ERROR_BROKEN_PIPE, "expected ERROR_BROKEN_PIPE, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WriteFile(hfile, testdata, sizeof(testdata), &numbytes, NULL); ok(!ret, "WriteFile unexpectedly succeeded\n"); - todo_wine ok(GetLastError() == ERROR_NO_DATA, "expected ERROR_NO_DATA, got %u\n", GetLastError()); + ok(GetLastError() == ERROR_NO_DATA, "expected ERROR_NO_DATA, got %lu\n", GetLastError()); CloseHandle(hfile); @@ -1668,108 +1731,108 @@ static void test_CloseHandle(void) hpipe = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL); - ok(hpipe != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with %u\n", GetLastError()); + ok(hpipe != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with %lu\n", GetLastError()); hfile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); - ok(hfile != INVALID_HANDLE_VALUE, "CreateFile failed with %u\n", GetLastError()); + ok(hfile != INVALID_HANDLE_VALUE, "CreateFile failed with %lu\n", GetLastError()); numbytes = 0xdeadbeef; ret = WriteFile(hfile, testdata, sizeof(testdata), &numbytes, NULL); - ok(ret, "WriteFile failed with %u\n", GetLastError()); - ok(numbytes == sizeof(testdata), "expected sizeof(testdata), got %u\n", numbytes); + ok(ret, "WriteFile failed with %lu\n", GetLastError()); + ok(numbytes == sizeof(testdata), "expected sizeof(testdata), got %lu\n", numbytes); numbytes = 0xdeadbeef; ret = PeekNamedPipe(hpipe, NULL, 0, NULL, &numbytes, NULL); - ok(ret, "PeekNamedPipe failed with %u\n", GetLastError()); - ok(numbytes == sizeof(testdata), "expected sizeof(testdata), got %u\n", numbytes); + ok(ret, "PeekNamedPipe failed with %lu\n", GetLastError()); + ok(numbytes == sizeof(testdata), "expected sizeof(testdata), got %lu\n", numbytes); ret = CloseHandle(hfile); - ok(ret, "CloseHandle failed with %u\n", GetLastError()); + ok(ret, "CloseHandle failed with %lu\n", GetLastError()); numbytes = 0xdeadbeef; memset(buffer, 0, sizeof(buffer)); ret = ReadFile(hpipe, buffer, 0, &numbytes, NULL); ok(ret || GetLastError() == ERROR_MORE_DATA /* >= Win 8 */, - "ReadFile failed with %u\n", GetLastError()); - ok(numbytes == 0, "expected 0, got %u\n", numbytes); + "ReadFile failed with %lu\n", GetLastError()); + ok(numbytes == 0, "expected 0, got %lu\n", numbytes); numbytes = 0xdeadbeef; ret = PeekNamedPipe(hpipe, NULL, 0, NULL, &numbytes, NULL); - ok(ret, "PeekNamedPipe failed with %u\n", GetLastError()); - ok(numbytes == sizeof(testdata), "expected sizeof(testdata), got %u\n", numbytes); + ok(ret, "PeekNamedPipe failed with %lu\n", GetLastError()); + ok(numbytes == sizeof(testdata), "expected sizeof(testdata), got %lu\n", numbytes); numbytes = 0xdeadbeef; memset(buffer, 0, sizeof(buffer)); ret = ReadFile(hpipe, buffer, sizeof(buffer), &numbytes, NULL); - ok(ret, "ReadFile failed with %u\n", GetLastError()); - ok(numbytes == sizeof(testdata), "expected sizeof(testdata), got %u\n", numbytes); + ok(ret, "ReadFile failed with %lu\n", GetLastError()); + ok(numbytes == sizeof(testdata), "expected sizeof(testdata), got %lu\n", numbytes); ret = GetNamedPipeHandleStateA(hpipe, &state, NULL, NULL, NULL, NULL, 0); - ok(ret, "GetNamedPipeHandleState failed with %u\n", GetLastError()); + ok(ret, "GetNamedPipeHandleState failed with %lu\n", GetLastError()); state = PIPE_READMODE_MESSAGE | PIPE_WAIT; ret = SetNamedPipeHandleState(hpipe, &state, NULL, NULL); - ok(ret, "SetNamedPipeHandleState failed with %u\n", GetLastError()); + ok(ret, "SetNamedPipeHandleState failed with %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = ReadFile(hpipe, buffer, 0, &numbytes, NULL); ok(!ret, "ReadFile unexpectedly succeeded\n"); - ok(GetLastError() == ERROR_BROKEN_PIPE, "expected ERROR_BROKEN_PIPE, got %u\n", GetLastError()); + ok(GetLastError() == ERROR_BROKEN_PIPE, "expected ERROR_BROKEN_PIPE, got %lu\n", GetLastError()); numbytes = 0xdeadbeef; ret = PeekNamedPipe(hpipe, NULL, 0, NULL, &numbytes, NULL); - ok(!ret && GetLastError() == ERROR_BROKEN_PIPE, "PeekNamedPipe returned %x (%u)\n", + ok(!ret && GetLastError() == ERROR_BROKEN_PIPE, "PeekNamedPipe returned %x (%lu)\n", ret, GetLastError()); - ok(numbytes == 0xdeadbeef, "numbytes = %u\n", numbytes); + ok(numbytes == 0xdeadbeef, "numbytes = %lu\n", numbytes); SetLastError(0xdeadbeef); ret = WriteFile(hpipe, testdata, sizeof(testdata), &numbytes, NULL); ok(!ret, "WriteFile unexpectedly succeeded\n"); - todo_wine ok(GetLastError() == ERROR_NO_DATA, "expected ERROR_NO_DATA, got %u\n", GetLastError()); + ok(GetLastError() == ERROR_NO_DATA, "expected ERROR_NO_DATA, got %lu\n", GetLastError()); CloseHandle(hpipe); hpipe = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL); - ok(hpipe != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with %u\n", GetLastError()); + ok(hpipe != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with %lu\n", GetLastError()); hfile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); - ok(hfile != INVALID_HANDLE_VALUE, "CreateFile failed with %u\n", GetLastError()); + ok(hfile != INVALID_HANDLE_VALUE, "CreateFile failed with %lu\n", GetLastError()); numbytes = 0xdeadbeef; ret = WriteFile(hfile, testdata, 0, &numbytes, NULL); - ok(ret, "WriteFile failed with %u\n", GetLastError()); - ok(numbytes == 0, "expected 0, got %u\n", numbytes); + ok(ret, "WriteFile failed with %lu\n", GetLastError()); + ok(numbytes == 0, "expected 0, got %lu\n", numbytes); ret = CloseHandle(hfile); - ok(ret, "CloseHandle failed with %u\n", GetLastError()); + ok(ret, "CloseHandle failed with %lu\n", GetLastError()); numbytes = 0xdeadbeef; memset(buffer, 0, sizeof(buffer)); ret = ReadFile(hpipe, buffer, sizeof(buffer), &numbytes, NULL); - ok(ret, "ReadFile failed with %u\n", GetLastError()); - ok(numbytes == 0, "expected 0, got %u\n", numbytes); + ok(ret, "ReadFile failed with %lu\n", GetLastError()); + ok(numbytes == 0, "expected 0, got %lu\n", numbytes); SetLastError(0xdeadbeef); ret = ReadFile(hpipe, buffer, 0, &numbytes, NULL); ok(!ret, "ReadFile unexpectedly succeeded\n"); - ok(GetLastError() == ERROR_BROKEN_PIPE, "expected ERROR_BROKEN_PIPE, got %u\n", GetLastError()); + ok(GetLastError() == ERROR_BROKEN_PIPE, "expected ERROR_BROKEN_PIPE, got %lu\n", GetLastError()); ret = GetNamedPipeHandleStateA(hpipe, &state, NULL, NULL, NULL, NULL, 0); - ok(ret, "GetNamedPipeHandleState failed with %u\n", GetLastError()); + ok(ret, "GetNamedPipeHandleState failed with %lu\n", GetLastError()); state = PIPE_READMODE_MESSAGE | PIPE_WAIT; ret = SetNamedPipeHandleState(hpipe, &state, NULL, NULL); - ok(ret, "SetNamedPipeHandleState failed with %u\n", GetLastError()); + ok(ret, "SetNamedPipeHandleState failed with %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = ReadFile(hpipe, buffer, 0, &numbytes, NULL); ok(!ret, "ReadFile unexpectedly succeeded\n"); - ok(GetLastError() == ERROR_BROKEN_PIPE, "expected ERROR_BROKEN_PIPE, got %u\n", GetLastError()); + ok(GetLastError() == ERROR_BROKEN_PIPE, "expected ERROR_BROKEN_PIPE, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = WriteFile(hpipe, testdata, sizeof(testdata), &numbytes, NULL); ok(!ret, "WriteFile unexpectedly succeeded\n"); - todo_wine ok(GetLastError() == ERROR_NO_DATA, "expected ERROR_NO_DATA, got %u\n", GetLastError()); + ok(GetLastError() == ERROR_NO_DATA, "expected ERROR_NO_DATA, got %lu\n", GetLastError()); CloseHandle(hpipe); } @@ -1800,10 +1863,10 @@ static DWORD CALLBACK named_pipe_client_func(LPVOID p) /* modify the token so we can tell if the pipe impersonation * token reverts to the process token */ ret = AdjustTokenPrivileges(params->token, TRUE, NULL, 0, NULL, NULL); - ok(ret, "AdjustTokenPrivileges failed with error %d\n", GetLastError()); + ok(ret, "AdjustTokenPrivileges failed with error %ld\n", GetLastError()); } ret = SetThreadToken(NULL, params->token); - ok(ret, "SetThreadToken failed with error %d\n", GetLastError()); + ok(ret, "SetThreadToken failed with error %ld\n", GetLastError()); } else { @@ -1811,40 +1874,40 @@ static DWORD CALLBACK named_pipe_client_func(LPVOID p) HANDLE process_token; ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES, &process_token); - ok(ret, "OpenProcessToken failed with error %d\n", GetLastError()); + ok(ret, "OpenProcessToken failed with error %ld\n", GetLastError()); ret = GetTokenInformation(process_token, TokenPrivileges, NULL, 0, &Size); - ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetTokenInformation(TokenPrivileges) failed with %d\n", GetLastError()); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetTokenInformation(TokenPrivileges) failed with %ld\n", GetLastError()); Privileges = HeapAlloc(GetProcessHeap(), 0, Size); ret = GetTokenInformation(process_token, TokenPrivileges, Privileges, Size, &Size); - ok(ret, "GetTokenInformation(TokenPrivileges) failed with %d\n", GetLastError()); + ok(ret, "GetTokenInformation(TokenPrivileges) failed with %ld\n", GetLastError()); ret = AdjustTokenPrivileges(process_token, TRUE, NULL, 0, NULL, NULL); - ok(ret, "AdjustTokenPrivileges failed with error %d\n", GetLastError()); + ok(ret, "AdjustTokenPrivileges failed with error %ld\n", GetLastError()); CloseHandle(process_token); } pipe = CreateFileA(PIPE_NAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, params->security_flags, NULL); - ok(pipe != INVALID_HANDLE_VALUE, "CreateFile for pipe failed with error %d\n", GetLastError()); + ok(pipe != INVALID_HANDLE_VALUE, "CreateFile for pipe failed with error %ld\n", GetLastError()); ret = WriteFile(pipe, message, sizeof(message), &bytes_written, NULL); - ok(ret, "WriteFile failed with error %d\n", GetLastError()); + ok(ret, "WriteFile failed with error %ld\n", GetLastError()); ret = ReadFile(pipe, &dummy, sizeof(dummy), &bytes_read, NULL); - ok(ret, "ReadFile failed with error %d\n", GetLastError()); + ok(ret, "ReadFile failed with error %ld\n", GetLastError()); if (params->token) { if (params->revert) { ret = RevertToSelf(); - ok(ret, "RevertToSelf failed with error %d\n", GetLastError()); + ok(ret, "RevertToSelf failed with error %ld\n", GetLastError()); } else { ret = AdjustTokenPrivileges(params->token, TRUE, NULL, 0, NULL, NULL); - ok(ret, "AdjustTokenPrivileges failed with error %d\n", GetLastError()); + ok(ret, "AdjustTokenPrivileges failed with error %ld\n", GetLastError()); } } else @@ -1852,10 +1915,10 @@ static DWORD CALLBACK named_pipe_client_func(LPVOID p) HANDLE process_token; ret = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &process_token); - ok(ret, "OpenProcessToken failed with error %d\n", GetLastError()); + ok(ret, "OpenProcessToken failed with error %ld\n", GetLastError()); ret = AdjustTokenPrivileges(process_token, FALSE, Privileges, 0, NULL, NULL); - ok(ret, "AdjustTokenPrivileges failed with error %d\n", GetLastError()); + ok(ret, "AdjustTokenPrivileges failed with error %ld\n", GetLastError()); HeapFree(GetProcessHeap(), 0, Privileges); @@ -1863,10 +1926,10 @@ static DWORD CALLBACK named_pipe_client_func(LPVOID p) } ret = WriteFile(pipe, message, sizeof(message), &bytes_written, NULL); - ok(ret, "WriteFile failed with error %d\n", GetLastError()); + ok(ret, "WriteFile failed with error %ld\n", GetLastError()); ret = ReadFile(pipe, &dummy, sizeof(dummy), &bytes_read, NULL); - ok(ret, "ReadFile failed with error %d\n", GetLastError()); + ok(ret, "ReadFile failed with error %ld\n", GetLastError()); CloseHandle(pipe); @@ -1880,10 +1943,10 @@ static HANDLE make_impersonation_token(DWORD Access, SECURITY_IMPERSONATION_LEVE BOOL ret; ret = OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE, &ProcessToken); - ok(ret, "OpenProcessToken failed with error %d\n", GetLastError()); + ok(ret, "OpenProcessToken failed with error %ld\n", GetLastError()); ret = pDuplicateTokenEx(ProcessToken, Access, NULL, ImpersonationLevel, TokenImpersonation, &Token); - ok(ret, "DuplicateToken failed with error %d\n", GetLastError()); + ok(ret, "DuplicateToken failed with error %ld\n", GetLastError()); CloseHandle(ProcessToken); @@ -1907,37 +1970,37 @@ static void test_ImpersonateNamedPipeClient(HANDLE hClientToken, DWORD security_ DWORD size; hPipeServer = CreateNamedPipeA(PIPE_NAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 100, 100, NMPWAIT_USE_DEFAULT_WAIT, NULL); - ok(hPipeServer != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with error %d\n", GetLastError()); + ok(hPipeServer != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with error %ld\n", GetLastError()); params.security_flags = security_flags; params.token = hClientToken; params.revert = revert; hThread = CreateThread(NULL, 0, named_pipe_client_func, ¶ms, 0, &dwTid); - ok(hThread != NULL, "CreateThread failed with error %d\n", GetLastError()); + ok(hThread != NULL, "CreateThread failed with error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = ImpersonateNamedPipeClient(hPipeServer); error = GetLastError(); ok(ret /* win2k3 */ || (error == ERROR_CANNOT_IMPERSONATE), - "ImpersonateNamedPipeClient should have failed with ERROR_CANNOT_IMPERSONATE instead of %d\n", GetLastError()); + "ImpersonateNamedPipeClient should have failed with ERROR_CANNOT_IMPERSONATE instead of %ld\n", GetLastError()); ret = ConnectNamedPipe(hPipeServer, NULL); - ok(ret || (GetLastError() == ERROR_PIPE_CONNECTED), "ConnectNamedPipe failed with error %d\n", GetLastError()); + ok(ret || (GetLastError() == ERROR_PIPE_CONNECTED), "ConnectNamedPipe failed with error %ld\n", GetLastError()); ret = ReadFile(hPipeServer, buffer, sizeof(buffer), &dwBytesRead, NULL); - ok(ret, "ReadFile failed with error %d\n", GetLastError()); + ok(ret, "ReadFile failed with error %ld\n", GetLastError()); ret = ImpersonateNamedPipeClient(hPipeServer); - ok(ret, "ImpersonateNamedPipeClient failed with error %d\n", GetLastError()); + ok(ret, "ImpersonateNamedPipeClient failed with error %ld\n", GetLastError()); ret = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken); - ok(ret, "OpenThreadToken failed with error %d\n", GetLastError()); + ok(ret, "OpenThreadToken failed with error %ld\n", GetLastError()); (*test_func)(0, hToken); ImpersonationLevel = 0xdeadbeef; /* to avoid false positives */ ret = GetTokenInformation(hToken, TokenImpersonationLevel, &ImpersonationLevel, sizeof(ImpersonationLevel), &size); - ok(ret, "GetTokenInformation(TokenImpersonationLevel) failed with error %d\n", GetLastError()); + ok(ret, "GetTokenInformation(TokenImpersonationLevel) failed with error %ld\n", GetLastError()); ok(ImpersonationLevel == SecurityImpersonation, "ImpersonationLevel should have been SecurityImpersonation(%d) instead of %d\n", SecurityImpersonation, ImpersonationLevel); CloseHandle(hToken); @@ -1945,16 +2008,16 @@ static void test_ImpersonateNamedPipeClient(HANDLE hClientToken, DWORD security_ RevertToSelf(); ret = WriteFile(hPipeServer, &dummy, sizeof(dummy), &dwBytesWritten, NULL); - ok(ret, "WriteFile failed with error %d\n", GetLastError()); + ok(ret, "WriteFile failed with error %ld\n", GetLastError()); ret = ReadFile(hPipeServer, buffer, sizeof(buffer), &dwBytesRead, NULL); - ok(ret, "ReadFile failed with error %d\n", GetLastError()); + ok(ret, "ReadFile failed with error %ld\n", GetLastError()); ret = ImpersonateNamedPipeClient(hPipeServer); - ok(ret, "ImpersonateNamedPipeClient failed with error %d\n", GetLastError()); + ok(ret, "ImpersonateNamedPipeClient failed with error %ld\n", GetLastError()); ret = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken); - ok(ret, "OpenThreadToken failed with error %d\n", GetLastError()); + ok(ret, "OpenThreadToken failed with error %ld\n", GetLastError()); (*test_func)(1, hToken); @@ -1963,12 +2026,12 @@ static void test_ImpersonateNamedPipeClient(HANDLE hClientToken, DWORD security_ RevertToSelf(); ret = WriteFile(hPipeServer, &dummy, sizeof(dummy), &dwBytesWritten, NULL); - ok(ret, "WriteFile failed with error %d\n", GetLastError()); + ok(ret, "WriteFile failed with error %ld\n", GetLastError()); WaitForSingleObject(hThread, INFINITE); ret = ImpersonateNamedPipeClient(hPipeServer); - ok(ret, "ImpersonateNamedPipeClient failed with error %d\n", GetLastError()); + ok(ret, "ImpersonateNamedPipeClient failed with error %ld\n", GetLastError()); RevertToSelf(); @@ -2034,7 +2097,7 @@ static void test_no_sqos_no_token(int call_index, HANDLE hToken) case 0: priv_count = get_privilege_count(hToken); todo_wine - ok(priv_count == 0, "privilege count should have been 0 instead of %d\n", priv_count); + ok(priv_count == 0, "privilege count should have been 0 instead of %ld\n", priv_count); break; case 1: priv_count = get_privilege_count(hToken); @@ -2116,7 +2179,7 @@ static void test_no_sqos_revert(int call_index, HANDLE hToken) case 0: priv_count = get_privilege_count(hToken); todo_wine - ok(priv_count == 0, "privilege count should have been 0 instead of %d\n", priv_count); + ok(priv_count == 0, "privilege count should have been 0 instead of %ld\n", priv_count); break; case 1: priv_count = get_privilege_count(hToken); @@ -2293,7 +2356,7 @@ static void test_overlapped(void) Sleep(1); ret = WriteFile(pipe, "x", 1, &num, NULL); - ok(ret, "WriteFile failed with error %d\n", GetLastError()); + ok(ret, "WriteFile failed with error %ld\n", GetLastError()); WaitForSingleObject(thread, INFINITE); CloseHandle(pipe); @@ -2309,29 +2372,29 @@ static void test_overlapped_error(void) BOOL ret; event = CreateEventA(NULL, TRUE, FALSE, NULL); - ok(event != NULL, "CreateEventA failed with %u\n", GetLastError()); + ok(event != NULL, "CreateEventA failed with %lu\n", GetLastError()); pipe = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 1024, 1024, NMPWAIT_WAIT_FOREVER, NULL); - ok(pipe != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with %u\n", GetLastError()); + ok(pipe != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with %lu\n", GetLastError()); memset(&overlapped, 0, sizeof(overlapped)); overlapped.hEvent = event; ret = ConnectNamedPipe(pipe, &overlapped); err = GetLastError(); ok(ret == FALSE, "ConnectNamedPipe succeeded\n"); - ok(err == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %u\n", err); + ok(err == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %lu\n", err); file = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); - ok(file != INVALID_HANDLE_VALUE, "CreateFile failed with %u\n", GetLastError()); + ok(file != INVALID_HANDLE_VALUE, "CreateFile failed with %lu\n", GetLastError()); numbytes = 0xdeadbeef; ret = GetOverlappedResult(pipe, &overlapped, &numbytes, TRUE); ok(ret == TRUE, "GetOverlappedResult failed\n"); - ok(numbytes == 0, "expected 0, got %u\n", numbytes); - ok(overlapped.Internal == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08lx\n", overlapped.Internal); + ok(numbytes == 0, "expected 0, got %lu\n", numbytes); + ok(overlapped.Internal == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08Ix\n", overlapped.Internal); CloseHandle(file); CloseHandle(pipe); @@ -2339,19 +2402,19 @@ static void test_overlapped_error(void) pipe = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 1024, 1024, NMPWAIT_WAIT_FOREVER, NULL); - ok(pipe != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with %u\n", GetLastError()); + ok(pipe != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with %lu\n", GetLastError()); file = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); - ok(file != INVALID_HANDLE_VALUE, "CreateFile failed with %u\n", GetLastError()); + ok(file != INVALID_HANDLE_VALUE, "CreateFile failed with %lu\n", GetLastError()); memset(&overlapped, 0, sizeof(overlapped)); overlapped.hEvent = event; ret = ConnectNamedPipe(pipe, &overlapped); err = GetLastError(); ok(ret == FALSE, "ConnectNamedPipe succeeded\n"); - ok(err == ERROR_PIPE_CONNECTED, "expected ERROR_PIPE_CONNECTED, got %u\n", err); - ok(overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %08lx\n", overlapped.Internal); + ok(err == ERROR_PIPE_CONNECTED, "expected ERROR_PIPE_CONNECTED, got %lu\n", err); + ok(overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %08Ix\n", overlapped.Internal); CloseHandle(file); CloseHandle(pipe); @@ -2375,31 +2438,30 @@ static void test_NamedPipeHandleState(void) /* lpSecurityAttrib */ NULL); ok(server != INVALID_HANDLE_VALUE, "cf failed\n"); ret = GetNamedPipeHandleStateA(server, NULL, NULL, NULL, NULL, NULL, 0); - ok(ret, "GetNamedPipeHandleState failed: %d\n", GetLastError()); + ok(ret, "GetNamedPipeHandleState failed: %ld\n", GetLastError()); ret = GetNamedPipeHandleStateA(server, &state, &instances, NULL, NULL, NULL, 0); - ok(ret, "GetNamedPipeHandleState failed: %d\n", GetLastError()); + ok(ret, "GetNamedPipeHandleState failed: %ld\n", GetLastError()); if (ret) { - ok(state == 0, "unexpected state %08x\n", state); - ok(instances == 1, "expected 1 instances, got %d\n", instances); + ok(state == 0, "unexpected state %08lx\n", state); + ok(instances == 1, "expected 1 instances, got %ld\n", instances); } /* Some parameters have no meaning, and therefore can't be retrieved, * on a local pipe. */ SetLastError(0xdeadbeef); - ret = GetNamedPipeHandleStateA(server, &state, &instances, - &maxCollectionCount, &collectDataTimeout, userName, - sizeof(userName) / sizeof(userName[0])); + ret = GetNamedPipeHandleStateA(server, &state, &instances, &maxCollectionCount, + &collectDataTimeout, userName, ARRAY_SIZE(userName)); todo_wine ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); /* A byte-mode pipe server can't be changed to message mode. */ state = PIPE_READMODE_MESSAGE; SetLastError(0xdeadbeef); ret = SetNamedPipeHandleState(server, &state, NULL, NULL); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); client = CreateFileA(PIPENAME, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); @@ -2407,13 +2469,13 @@ static void test_NamedPipeHandleState(void) state = PIPE_READMODE_BYTE; ret = SetNamedPipeHandleState(client, &state, NULL, NULL); - ok(ret, "SetNamedPipeHandleState failed: %d\n", GetLastError()); + ok(ret, "SetNamedPipeHandleState failed: %ld\n", GetLastError()); /* A byte-mode pipe client can't be changed to message mode, either. */ state = PIPE_READMODE_MESSAGE; SetLastError(0xdeadbeef); ret = SetNamedPipeHandleState(server, &state, NULL, NULL); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); CloseHandle(client); CloseHandle(server); @@ -2427,21 +2489,21 @@ static void test_NamedPipeHandleState(void) /* lpSecurityAttrib */ NULL); ok(server != INVALID_HANDLE_VALUE, "cf failed\n"); ret = GetNamedPipeHandleStateA(server, NULL, NULL, NULL, NULL, NULL, 0); - ok(ret, "GetNamedPipeHandleState failed: %d\n", GetLastError()); + ok(ret, "GetNamedPipeHandleState failed: %ld\n", GetLastError()); ret = GetNamedPipeHandleStateA(server, &state, &instances, NULL, NULL, NULL, 0); - ok(ret, "GetNamedPipeHandleState failed: %d\n", GetLastError()); + ok(ret, "GetNamedPipeHandleState failed: %ld\n", GetLastError()); if (ret) { - ok(state == 0, "unexpected state %08x\n", state); - ok(instances == 1, "expected 1 instances, got %d\n", instances); + ok(state == 0, "unexpected state %08lx\n", state); + ok(instances == 1, "expected 1 instances, got %ld\n", instances); } /* In contrast to byte-mode pipes, a message-mode pipe server can be * changed to byte mode. */ state = PIPE_READMODE_BYTE; ret = SetNamedPipeHandleState(server, &state, NULL, NULL); - ok(ret, "SetNamedPipeHandleState failed: %d\n", GetLastError()); + ok(ret, "SetNamedPipeHandleState failed: %ld\n", GetLastError()); client = CreateFileA(PIPENAME, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); @@ -2449,12 +2511,12 @@ static void test_NamedPipeHandleState(void) state = PIPE_READMODE_MESSAGE; ret = SetNamedPipeHandleState(client, &state, NULL, NULL); - ok(ret, "SetNamedPipeHandleState failed: %d\n", GetLastError()); + ok(ret, "SetNamedPipeHandleState failed: %ld\n", GetLastError()); /* A message-mode pipe client can also be changed to byte mode. */ state = PIPE_READMODE_BYTE; ret = SetNamedPipeHandleState(client, &state, NULL, NULL); - ok(ret, "SetNamedPipeHandleState failed: %d\n", GetLastError()); + ok(ret, "SetNamedPipeHandleState failed: %ld\n", GetLastError()); CloseHandle(client); CloseHandle(server); @@ -2546,37 +2608,37 @@ static void test_readfileex_pending(void) ret = ConnectNamedPipe(server, &overlapped); err = GetLastError(); ok(ret == FALSE, "ConnectNamedPipe succeeded\n"); - ok(err == ERROR_IO_PENDING, "ConnectNamedPipe set error %i\n", err); + ok(err == ERROR_IO_PENDING, "ConnectNamedPipe set error %li\n", err); wait = WaitForSingleObject(event, 0); - ok(wait == WAIT_TIMEOUT, "WaitForSingleObject returned %x\n", wait); + ok(wait == WAIT_TIMEOUT, "WaitForSingleObject returned %lx\n", wait); client = CreateFileA(PIPENAME, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); ok(client != INVALID_HANDLE_VALUE, "cf failed\n"); wait = WaitForSingleObject(event, 0); - ok(wait == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", wait); + ok(wait == WAIT_OBJECT_0, "WaitForSingleObject returned %lx\n", wait); /* Start a read that can't complete immediately. */ completion_called = 0; ResetEvent(event); ret = ReadFileEx(server, read_buf, sizeof(read_buf), &overlapped, completion_routine); - ok(ret == TRUE, "ReadFileEx failed, err=%i\n", GetLastError()); + ok(ret == TRUE, "ReadFileEx failed, err=%li\n", GetLastError()); ok(completion_called == 0, "completion routine called before ReadFileEx returned\n"); ret = WriteFile(client, test_string, strlen(test_string), &num_bytes, NULL); ok(ret == TRUE, "WriteFile failed\n"); - ok(num_bytes == strlen(test_string), "only %i bytes written\n", num_bytes); + ok(num_bytes == strlen(test_string), "only %li bytes written\n", num_bytes); ok(completion_called == 0, "completion routine called during WriteFile\n"); wait = WaitForSingleObjectEx(event, 0, TRUE); - ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait); + ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %lx\n", wait); ok(completion_called == 1, "completion not called after writing pipe\n"); - ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode); - ok(completion_num_bytes == strlen(test_string), "ReadFileEx returned only %d bytes\n", completion_num_bytes); + ok(completion_errorcode == 0, "completion called with error %lx\n", completion_errorcode); + ok(completion_num_bytes == strlen(test_string), "ReadFileEx returned only %ld bytes\n", completion_num_bytes); ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n"); ok(!memcmp(test_string, read_buf, strlen(test_string)), "ReadFileEx read wrong bytes\n"); @@ -2597,16 +2659,16 @@ static void test_readfileex_pending(void) /* write couldn't complete immediately, presumably the pipe is full */ break; - ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", wait); + ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObject returned %lx\n", wait); - ok(ret == TRUE, "WriteFileEx failed, err=%i\n", err); - ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode); + ok(ret == TRUE, "WriteFileEx failed, err=%li\n", err); + ok(completion_errorcode == 0, "completion called with error %lx\n", completion_errorcode); ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n"); } - ok(ret == TRUE, "WriteFileEx failed, err=%i\n", err); + ok(ret == TRUE, "WriteFileEx failed, err=%li\n", err); ok(completion_called == 0, "completion routine called but wait timed out\n"); - ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode); + ok(completion_errorcode == 0, "completion called with error %lx\n", completion_errorcode); ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n"); /* free up some space in the pipe */ @@ -2619,23 +2681,23 @@ static void test_readfileex_pending(void) wait = WaitForSingleObjectEx(event, 0, TRUE); ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0 || wait == WAIT_TIMEOUT, - "WaitForSingleObject returned %x\n", wait); + "WaitForSingleObject returned %lx\n", wait); if (wait != WAIT_TIMEOUT) break; } ok(completion_called == 1, "completion routine not called\n"); - ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode); + ok(completion_errorcode == 0, "completion called with error %lx\n", completion_errorcode); ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n"); num_bytes = 0xdeadbeef; SetLastError(0xdeadbeef); ret = ReadFile(INVALID_HANDLE_VALUE, read_buf, 0, &num_bytes, NULL); ok(!ret, "ReadFile should fail\n"); - ok(GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError()); - ok(num_bytes == 0, "expected 0, got %u\n", num_bytes); + ok(GetLastError() == ERROR_INVALID_HANDLE, "wrong error %lu\n", GetLastError()); + ok(num_bytes == 0, "expected 0, got %lu\n", num_bytes); - S(U(overlapped)).Offset = 0; - S(U(overlapped)).OffsetHigh = 0; + overlapped.Offset = 0; + overlapped.OffsetHigh = 0; overlapped.Internal = -1; overlapped.InternalHigh = -1; overlapped.hEvent = event; @@ -2643,31 +2705,31 @@ static void test_readfileex_pending(void) SetLastError(0xdeadbeef); ret = ReadFile(server, read_buf, 0, &num_bytes, &overlapped); ok(!ret, "ReadFile should fail\n"); - ok(GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %d\n", GetLastError()); - ok(num_bytes == 0, "bytes %u\n", num_bytes); - ok((NTSTATUS)overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %#lx\n", overlapped.Internal); - ok(overlapped.InternalHigh == -1, "expected -1, got %lu\n", overlapped.InternalHigh); + ok(GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %ld\n", GetLastError()); + ok(num_bytes == 0, "bytes %lu\n", num_bytes); + ok((NTSTATUS)overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %#Ix\n", overlapped.Internal); + ok(overlapped.InternalHigh == -1, "expected -1, got %Iu\n", overlapped.InternalHigh); wait = WaitForSingleObject(event, 100); - ok(wait == WAIT_TIMEOUT, "WaitForSingleObject returned %x\n", wait); + ok(wait == WAIT_TIMEOUT, "WaitForSingleObject returned %lx\n", wait); num_bytes = 0xdeadbeef; ret = WriteFile(client, test_string, 1, &num_bytes, NULL); ok(ret, "WriteFile failed\n"); - ok(num_bytes == 1, "bytes %u\n", num_bytes); + ok(num_bytes == 1, "bytes %lu\n", num_bytes); wait = WaitForSingleObject(event, 100); - ok(wait == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", wait); + ok(wait == WAIT_OBJECT_0, "WaitForSingleObject returned %lx\n", wait); - ok(num_bytes == 1, "bytes %u\n", num_bytes); - ok((NTSTATUS)overlapped.Internal == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#lx\n", overlapped.Internal); - ok(overlapped.InternalHigh == 0, "expected 0, got %lu\n", overlapped.InternalHigh); + ok(num_bytes == 1, "bytes %lu\n", num_bytes); + ok((NTSTATUS)overlapped.Internal == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#Ix\n", overlapped.Internal); + ok(overlapped.InternalHigh == 0, "expected 0, got %Iu\n", overlapped.InternalHigh); /* read the pending byte and clear the pipe */ num_bytes = 0xdeadbeef; ret = ReadFile(server, read_buf, 1, &num_bytes, &overlapped); ok(ret, "ReadFile failed\n"); - ok(num_bytes == 1, "bytes %u\n", num_bytes); + ok(num_bytes == 1, "bytes %lu\n", num_bytes); CloseHandle(client); CloseHandle(server); @@ -2678,35 +2740,35 @@ static void test_readfileex_pending(void) static void _test_peek_pipe(unsigned line, HANDLE pipe, DWORD expected_read, DWORD expected_avail, DWORD expected_message_length) { DWORD bytes_read = 0xdeadbeed, avail = 0xdeadbeef, left = 0xdeadbeed; - char buf[4000]; + char buf[12000]; FILE_PIPE_PEEK_BUFFER *peek_buf = (void*)buf; IO_STATUS_BLOCK io; NTSTATUS status; BOOL r; r = PeekNamedPipe(pipe, buf, sizeof(buf), &bytes_read, &avail, &left); - ok_(__FILE__,line)(r, "PeekNamedPipe failed: %u\n", GetLastError()); - ok_(__FILE__,line)(bytes_read == expected_read, "bytes_read = %u, expected %u\n", bytes_read, expected_read); - ok_(__FILE__,line)(avail == expected_avail, "avail = %u, expected %u\n", avail, expected_avail); - ok_(__FILE__,line)(left == expected_message_length - expected_read, "left = %d, expected %d\n", + ok_(__FILE__,line)(r, "PeekNamedPipe failed: %lu\n", GetLastError()); + ok_(__FILE__,line)(bytes_read == expected_read, "bytes_read = %lu, expected %lu\n", bytes_read, expected_read); + ok_(__FILE__,line)(avail == expected_avail, "avail = %lu, expected %lu\n", avail, expected_avail); + ok_(__FILE__,line)(left == expected_message_length - expected_read, "left = %ld, expected %ld\n", left, expected_message_length - expected_read); status = NtFsControlFile(pipe, 0, NULL, NULL, &io, FSCTL_PIPE_PEEK, NULL, 0, buf, sizeof(buf)); - ok_(__FILE__,line)(!status || status == STATUS_PENDING, "NtFsControlFile(FSCTL_PIPE_PEEK) failed: %x\n", status); + ok_(__FILE__,line)(!status || status == STATUS_PENDING, "NtFsControlFile(FSCTL_PIPE_PEEK) failed: %lx\n", status); ok_(__FILE__,line)(io.Information == FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[expected_read]), - "io.Information = %lu\n", io.Information); - ok_(__FILE__,line)(peek_buf->ReadDataAvailable == expected_avail, "ReadDataAvailable = %u, expected %u\n", + "io.Information = %Iu\n", io.Information); + ok_(__FILE__,line)(peek_buf->ReadDataAvailable == expected_avail, "ReadDataAvailable = %lu, expected %lu\n", peek_buf->ReadDataAvailable, expected_avail); - ok_(__FILE__,line)(peek_buf->MessageLength == expected_message_length, "MessageLength = %u, expected %u\n", + ok_(__FILE__,line)(peek_buf->MessageLength == expected_message_length, "MessageLength = %lu, expected %lu\n", peek_buf->MessageLength, expected_message_length); if (expected_read) { r = PeekNamedPipe(pipe, buf, 1, &bytes_read, &avail, &left); - ok_(__FILE__,line)(r, "PeekNamedPipe failed: %u\n", GetLastError()); - ok_(__FILE__,line)(bytes_read == 1, "bytes_read = %u, expected %u\n", bytes_read, expected_read); - ok_(__FILE__,line)(avail == expected_avail, "avail = %u, expected %u\n", avail, expected_avail); - ok_(__FILE__,line)(left == expected_message_length-1, "left = %d, expected %d\n", left, expected_message_length-1); + ok_(__FILE__,line)(r, "PeekNamedPipe failed: %lu\n", GetLastError()); + ok_(__FILE__,line)(bytes_read == 1, "bytes_read = %lu, expected %lu\n", bytes_read, expected_read); + ok_(__FILE__,line)(avail == expected_avail, "avail = %lu, expected %lu\n", avail, expected_avail); + ok_(__FILE__,line)(left == expected_message_length-1, "left = %ld, expected %ld\n", left, expected_message_length-1); } } @@ -2721,22 +2783,22 @@ static void _overlapped_read_sync(unsigned line, HANDLE reader, void *buf, DWORD overlapped.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); res = ReadFile(reader, buf, buf_size, &read_bytes, &overlapped); if (partial_read) - ok_(__FILE__,line)(!res && GetLastError() == ERROR_MORE_DATA, "ReadFile returned: %x (%u)\n", res, GetLastError()); + ok_(__FILE__,line)(!res && GetLastError() == ERROR_MORE_DATA, "ReadFile returned: %x (%lu)\n", res, GetLastError()); else - ok_(__FILE__,line)(res, "ReadFile failed: %u\n", GetLastError()); + ok_(__FILE__,line)(res, "ReadFile failed: %lu\n", GetLastError()); if(partial_read) - ok_(__FILE__,line)(!read_bytes, "read_bytes %u expected 0\n", read_bytes); + ok_(__FILE__,line)(!read_bytes, "read_bytes %lu expected 0\n", read_bytes); else - ok_(__FILE__,line)(read_bytes == expected_result, "read_bytes %u expected %u\n", read_bytes, expected_result); + ok_(__FILE__,line)(read_bytes == expected_result, "read_bytes %lu expected %lu\n", read_bytes, expected_result); read_bytes = 0xdeadbeef; res = GetOverlappedResult(reader, &overlapped, &read_bytes, FALSE); if (partial_read) ok_(__FILE__,line)(!res && GetLastError() == ERROR_MORE_DATA, - "GetOverlappedResult returned: %x (%u)\n", res, GetLastError()); + "GetOverlappedResult returned: %x (%lu)\n", res, GetLastError()); else - ok_(__FILE__,line)(res, "GetOverlappedResult failed: %u\n", GetLastError()); - ok_(__FILE__,line)(read_bytes == expected_result, "read_bytes %u expected %u\n", read_bytes, expected_result); + ok_(__FILE__,line)(res, "GetOverlappedResult failed: %lu\n", GetLastError()); + ok_(__FILE__,line)(read_bytes == expected_result, "read_bytes %lu expected %lu\n", read_bytes, expected_result); CloseHandle(overlapped.hEvent); } @@ -2749,8 +2811,8 @@ static void _overlapped_read_async(unsigned line, HANDLE reader, void *buf, DWOR memset(overlapped, 0, sizeof(*overlapped)); overlapped->hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); res = ReadFile(reader, buf, buf_size, &read_bytes, overlapped); - ok_(__FILE__,line)(!res && GetLastError() == ERROR_IO_PENDING, "ReadFile returned %x(%u)\n", res, GetLastError()); - ok_(__FILE__,line)(!read_bytes, "read_bytes %u expected 0\n", read_bytes); + ok_(__FILE__,line)(!res && GetLastError() == ERROR_IO_PENDING, "ReadFile returned %x(%lu)\n", res, GetLastError()); + ok_(__FILE__,line)(!read_bytes, "read_bytes %lu expected 0\n", read_bytes); _test_not_signaled(line, overlapped->hEvent); } @@ -2765,13 +2827,13 @@ static void _overlapped_write_sync(unsigned line, HANDLE writer, void *buf, DWOR memset(&overlapped, 0, sizeof(overlapped)); overlapped.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); res = WriteFile(writer, buf, size, &written_bytes, &overlapped); - ok_(__FILE__,line)(res, "WriteFile returned %x(%u)\n", res, GetLastError()); - ok_(__FILE__,line)(written_bytes == size, "WriteFile returned written_bytes = %u\n", written_bytes); + ok_(__FILE__,line)(res, "WriteFile returned %x(%lu)\n", res, GetLastError()); + ok_(__FILE__,line)(written_bytes == size, "WriteFile returned written_bytes = %lu\n", written_bytes); written_bytes = 0xdeadbeef; res = GetOverlappedResult(writer, &overlapped, &written_bytes, FALSE); - ok_(__FILE__,line)(res, "GetOverlappedResult failed: %u\n", GetLastError()); - ok_(__FILE__,line)(written_bytes == size, "GetOverlappedResult returned written_bytes %u expected %u\n", written_bytes, size); + ok_(__FILE__,line)(res, "GetOverlappedResult failed: %lu\n", GetLastError()); + ok_(__FILE__,line)(written_bytes == size, "GetOverlappedResult returned written_bytes %lu expected %lu\n", written_bytes, size); CloseHandle(overlapped.hEvent); } @@ -2785,10 +2847,8 @@ static void _overlapped_write_async(unsigned line, HANDLE writer, void *buf, DWO memset(overlapped, 0, sizeof(*overlapped)); overlapped->hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); res = WriteFile(writer, buf, size, &written_bytes, overlapped); - disable_success_count - ok_(__FILE__,line)(!res && GetLastError() == ERROR_IO_PENDING, "WriteFile returned %x(%u)\n", res, GetLastError()); - disable_success_count - ok_(__FILE__,line)(!written_bytes, "written_bytes = %u\n", written_bytes); + ok_(__FILE__,line)(!res && GetLastError() == ERROR_IO_PENDING, "WriteFile returned %x(%lu)\n", res, GetLastError()); + ok_(__FILE__,line)(!written_bytes, "written_bytes = %lu\n", written_bytes); _test_not_signaled(line, overlapped->hEvent); } @@ -2799,7 +2859,7 @@ static void _test_flush_sync(unsigned line, HANDLE pipe) BOOL res; res = FlushFileBuffers(pipe); - ok_(__FILE__,line)(res, "FlushFileBuffers failed: %u\n", GetLastError()); + ok_(__FILE__,line)(res, "FlushFileBuffers failed: %lu\n", GetLastError()); } static DWORD expected_flush_error; @@ -2810,9 +2870,15 @@ static DWORD CALLBACK flush_proc(HANDLE pipe) res = FlushFileBuffers(pipe); if (expected_flush_error == ERROR_SUCCESS) - ok(res, "FlushFileBuffers failed: %u\n", GetLastError()); + { + ok(res, "FlushFileBuffers failed: %lu\n", GetLastError()); + } else - todo_wine ok(!res && GetLastError() == expected_flush_error, "FlushFileBuffers failed: %u\n", GetLastError()); + { + ok(!res, "FlushFileBuffers should have failed\n"); + ok(GetLastError() == expected_flush_error, + "FlushFileBuffers set error %lu, expected %lu\n", GetLastError(), expected_flush_error); + } return 0; } @@ -2824,7 +2890,7 @@ static HANDLE _test_flush_async(unsigned line, HANDLE pipe, DWORD error) expected_flush_error = error; thread = CreateThread(NULL, 0, flush_proc, pipe, 0, &tid); - ok_(__FILE__,line)(thread != NULL, "CreateThread failed: %u\n", GetLastError()); + ok_(__FILE__,line)(thread != NULL, "CreateThread failed: %lu\n", GetLastError()); Sleep(50); _test_not_signaled(line, thread); @@ -2835,7 +2901,7 @@ static HANDLE _test_flush_async(unsigned line, HANDLE pipe, DWORD error) static void _test_flush_done(unsigned line, HANDLE thread) { DWORD res = WaitForSingleObject(thread, 1000); - ok_(__FILE__,line)(res == WAIT_OBJECT_0, "WaitForSingleObject returned %u (%u)\n", res, GetLastError()); + ok_(__FILE__,line)(res == WAIT_OBJECT_0, "WaitForSingleObject returned %lu (%lu)\n", res, GetLastError()); CloseHandle(thread); } @@ -2849,10 +2915,10 @@ static void _test_overlapped_result(unsigned line, HANDLE handle, OVERLAPPED *ov res = GetOverlappedResult(handle, overlapped, &result, FALSE); if (partial_read) - ok_(__FILE__,line)(!res && GetLastError() == ERROR_MORE_DATA, "GetOverlappedResult returned: %x (%u)\n", res, GetLastError()); + ok_(__FILE__,line)(!res && GetLastError() == ERROR_MORE_DATA, "GetOverlappedResult returned: %x (%lu)\n", res, GetLastError()); else - ok_(__FILE__,line)(res, "GetOverlappedResult failed: %u\n", GetLastError()); - ok_(__FILE__,line)(result == expected_result, "read_bytes = %u, expected %u\n", result, expected_result); + ok_(__FILE__,line)(res, "GetOverlappedResult failed: %lu\n", GetLastError()); + ok_(__FILE__,line)(result == expected_result, "read_bytes = %lu, expected %lu\n", result, expected_result); CloseHandle(overlapped->hEvent); } @@ -2865,9 +2931,9 @@ static void _test_overlapped_failure(unsigned line, HANDLE handle, OVERLAPPED *o _test_signaled(line, overlapped->hEvent); res = GetOverlappedResult(handle, overlapped, &result, FALSE); - ok_(__FILE__,line)(!res && GetLastError() == error, "GetOverlappedResult returned: %x (%u), expected error %u\n", + ok_(__FILE__,line)(!res && GetLastError() == error, "GetOverlappedResult returned: %x (%lu), expected error %lu\n", res, GetLastError(), error); - ok_(__FILE__,line)(!result, "result = %u\n", result); + ok_(__FILE__,line)(!result, "result = %lu\n", result); CloseHandle(overlapped->hEvent); } @@ -2877,7 +2943,7 @@ static void _cancel_overlapped(unsigned line, HANDLE handle, OVERLAPPED *overlap BOOL res; res = pCancelIoEx(handle, overlapped); - ok_(__FILE__,line)(res, "CancelIoEx failed: %u\n", GetLastError()); + ok_(__FILE__,line)(res, "CancelIoEx failed: %lu\n", GetLastError()); _test_overlapped_failure(line, handle, overlapped, ERROR_OPERATION_ABORTED); } @@ -2887,6 +2953,7 @@ static void test_blocking_rw(HANDLE writer, HANDLE reader, DWORD buf_size, BOOL OVERLAPPED read_overlapped, read_overlapped2, write_overlapped, write_overlapped2; char buf[10000], read_buf[10000]; HANDLE flush_thread; + BOOL res; memset(buf, 0xaa, sizeof(buf)); @@ -2898,39 +2965,53 @@ static void test_blocking_rw(HANDLE writer, HANDLE reader, DWORD buf_size, BOOL /* write more data than needed for read */ overlapped_write_sync(writer, buf, 4000); test_overlapped_result(reader, &read_overlapped, 1000, msg_read); + test_peek_pipe(reader, 3000, 3000, msg_mode ? 3000 : 0); /* test pending write with overlapped event */ overlapped_write_async(writer, buf, buf_size, &write_overlapped); + test_peek_pipe(reader, 3000 + (msg_mode ? 0 : buf_size), 3000 + buf_size, msg_mode ? 3000 : 0); /* write one more byte */ overlapped_write_async(writer, buf, 1, &write_overlapped2); flush_thread = test_flush_async(writer, ERROR_SUCCESS); test_not_signaled(write_overlapped.hEvent); + test_peek_pipe(reader, 3000 + (msg_mode ? 0 : buf_size + 1), 3000 + buf_size + 1, + msg_mode ? 3000 : 0); /* empty write will not block */ overlapped_write_sync(writer, buf, 0); test_not_signaled(write_overlapped.hEvent); test_not_signaled(write_overlapped2.hEvent); + test_peek_pipe(reader, 3000 + (msg_mode ? 0 : buf_size + 1), 3000 + buf_size + 1, + msg_mode ? 3000 : 0); /* read remaining data from the first write */ overlapped_read_sync(reader, read_buf, 3000, 3000, FALSE); test_overlapped_result(writer, &write_overlapped, buf_size, FALSE); test_not_signaled(write_overlapped2.hEvent); test_not_signaled(flush_thread); + test_peek_pipe(reader, buf_size + (msg_mode ? 0 : 1), buf_size + 1, msg_mode ? buf_size : 0); /* read one byte so that the next write fits the buffer */ overlapped_read_sync(reader, read_buf, 1, 1, msg_read); test_overlapped_result(writer, &write_overlapped2, 1, FALSE); + test_peek_pipe(reader, buf_size + (msg_mode ? -1 : 0), buf_size, msg_mode ? buf_size - 1 : 0); /* read the whole buffer */ overlapped_read_sync(reader, read_buf, buf_size, buf_size-msg_read, FALSE); + test_peek_pipe(reader, msg_read ? 1 : 0, msg_read ? 1 : 0, msg_read ? 1 : 0); if(msg_read) + { overlapped_read_sync(reader, read_buf, 1000, 1, FALSE); + test_peek_pipe(reader, 0, 0, 0); + } - if(msg_mode) { + if(msg_mode) + { /* we still have an empty message in queue */ overlapped_read_sync(reader, read_buf, 1000, 0, FALSE); + test_peek_pipe(reader, 0, 0, 0); } test_flush_done(flush_thread); @@ -2942,23 +3023,29 @@ static void test_blocking_rw(HANDLE writer, HANDLE reader, DWORD buf_size, BOOL overlapped_write_sync(writer, buf, 1); test_overlapped_result(reader, &read_overlapped, 0, msg_read); test_overlapped_result(reader, &read_overlapped2, 1, FALSE); + test_peek_pipe(reader, 0, 0, 0); /* write a message larger than buffer */ overlapped_write_async(writer, buf, buf_size+2000, &write_overlapped); + test_peek_pipe(reader, buf_size + 2000, buf_size + 2000, msg_mode ? buf_size + 2000 : 0); /* read so that pending write is still larger than the buffer */ overlapped_read_sync(reader, read_buf, 1999, 1999, msg_read); test_not_signaled(write_overlapped.hEvent); + test_peek_pipe(reader, buf_size + 1, buf_size + 1, msg_mode ? buf_size + 1 : 0); /* read one more byte */ overlapped_read_sync(reader, read_buf, 1, 1, msg_read); test_overlapped_result(writer, &write_overlapped, buf_size+2000, FALSE); + test_peek_pipe(reader, buf_size, buf_size, msg_mode ? buf_size : 0); /* read remaining data */ overlapped_read_sync(reader, read_buf, buf_size+1, buf_size, FALSE); + test_peek_pipe(reader, 0, 0, 0); /* simple pass of empty message */ overlapped_write_sync(writer, buf, 0); + test_peek_pipe(reader, 0, 0, 0); if(msg_mode) overlapped_read_sync(reader, read_buf, 1, 0, FALSE); @@ -3000,30 +3087,88 @@ static void test_blocking_rw(HANDLE writer, HANDLE reader, DWORD buf_size, BOOL overlapped_write_sync(writer, buf, 1); test_overlapped_result(reader, &read_overlapped, 1, FALSE); + /* Test that canceling the same operation twice gives a sensible error */ + SetLastError(0xdeadbeef); + overlapped_read_async(reader, read_buf, 1, &read_overlapped2); + res = pCancelIoEx(reader, &read_overlapped2); + ok(res, "CancelIoEx failed with error %ld\n", GetLastError()); + res = pCancelIoEx(reader, &read_overlapped2); + ok(!res, "CancelIOEx succeeded unexpectedly\n"); + ok(GetLastError() == ERROR_NOT_FOUND, + "In CancelIoEx failure, expected ERROR_NOT_FOUND, got %ld\n", GetLastError()); + test_overlapped_failure(reader, &read_overlapped2, ERROR_OPERATION_ABORTED); + /* make two async writes, cancel the first one and make sure that we read from the second one */ overlapped_write_async(writer, buf, buf_size+2000, &write_overlapped); overlapped_write_async(writer, buf, 1, &write_overlapped2); + test_peek_pipe(reader, buf_size + 2000 + (msg_mode ? 0 : 1), + buf_size + 2001, msg_mode ? buf_size + 2000 : 0); cancel_overlapped(writer, &write_overlapped); + test_peek_pipe(reader, 1, 1, msg_mode ? 1 : 0); overlapped_read_sync(reader, read_buf, 1000, 1, FALSE); test_overlapped_result(writer, &write_overlapped2, 1, FALSE); + test_peek_pipe(reader, 0, 0, 0); - /* same as above, but parially read written data before canceling */ + /* same as above, but partially read written data before canceling */ overlapped_write_async(writer, buf, buf_size+2000, &write_overlapped); overlapped_write_async(writer, buf, 1, &write_overlapped2); + test_peek_pipe(reader, buf_size + 2000 + (msg_mode ? 0 : 1), + buf_size + 2001, msg_mode ? buf_size + 2000 : 0); overlapped_read_sync(reader, read_buf, 10, 10, msg_read); test_not_signaled(write_overlapped.hEvent); cancel_overlapped(writer, &write_overlapped); + test_peek_pipe(reader, 1, 1, msg_mode ? 1 : 0); overlapped_read_sync(reader, read_buf, 1000, 1, FALSE); test_overlapped_result(writer, &write_overlapped2, 1, FALSE); + test_peek_pipe(reader, 0, 0, 0); /* empty queue by canceling write and make sure that flush is signaled */ overlapped_write_async(writer, buf, buf_size+2000, &write_overlapped); flush_thread = test_flush_async(writer, ERROR_SUCCESS); test_not_signaled(flush_thread); cancel_overlapped(writer, &write_overlapped); + test_peek_pipe(reader, 0, 0, 0); test_flush_done(flush_thread); } +#define overlapped_transact(a,b,c,d,e,f) _overlapped_transact(__LINE__,a,b,c,d,e,f) +static void _overlapped_transact(unsigned line, HANDLE caller, void *write_buf, DWORD write_size, + void *read_buf, DWORD read_size, OVERLAPPED *overlapped) +{ + BOOL res; + + memset(overlapped, 0, sizeof(*overlapped)); + overlapped->hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + res = TransactNamedPipe(caller, write_buf, write_size, read_buf, read_size, NULL, overlapped); + ok_(__FILE__,line)(!res && GetLastError() == ERROR_IO_PENDING, + "TransactNamedPipe returned: %x(%lu)\n", res, GetLastError()); +} + +#define overlapped_transact_failure(a,b,c,d,e,f) _overlapped_transact_failure(__LINE__,a,b,c,d,e,f) +static void _overlapped_transact_failure(unsigned line, HANDLE caller, void *write_buf, DWORD write_size, + void *read_buf, DWORD read_size, DWORD expected_error) +{ + OVERLAPPED overlapped; + BOOL res; + + memset(&overlapped, 0, sizeof(overlapped)); + overlapped.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + res = TransactNamedPipe(caller, write_buf, write_size, read_buf, read_size, NULL, &overlapped); + ok_(__FILE__,line)(!res, "TransactNamedPipe succeeded\n"); + + if (GetLastError() == ERROR_IO_PENDING) /* win8+ */ + { + _test_overlapped_failure(line, caller, &overlapped, expected_error); + } + else + { + ok_(__FILE__,line)(GetLastError() == expected_error, + "TransactNamedPipe returned error %lu, expected %lu\n", + GetLastError(), expected_error); + CloseHandle(overlapped.hEvent); + } +} + static void child_process_write_pipe(HANDLE pipe) { OVERLAPPED overlapped; @@ -3044,9 +3189,9 @@ static HANDLE create_writepipe_process(HANDLE pipe) BOOL res; winetest_get_mainargs(&argv); - sprintf(buf, "\"%s\" pipe writepipe %lx", argv[0], (UINT_PTR)pipe); + sprintf(buf, "\"%s\" pipe writepipe %Ix", argv[0], (UINT_PTR)pipe); res = CreateProcessA(NULL, buf, NULL, NULL, TRUE, 0L, NULL, NULL, &si, &info); - ok(res, "CreateProcess failed: %u\n", GetLastError()); + ok(res, "CreateProcess failed: %lu\n", GetLastError()); CloseHandle(info.hThread); return info.hProcess; @@ -3061,21 +3206,21 @@ static void create_overlapped_pipe(DWORD mode, HANDLE *client, HANDLE *server) *server = CreateNamedPipeA(PIPENAME, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX, PIPE_WAIT | mode, 1, 5000, 6000, NMPWAIT_USE_DEFAULT_WAIT, NULL); - ok(&server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %u\n", GetLastError()); + ok(*server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %lu\n", GetLastError()); test_signaled(*server); memset(&overlapped, 0, sizeof(overlapped)); overlapped.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); res = ConnectNamedPipe(*server, &overlapped); - ok(!res && GetLastError() == ERROR_IO_PENDING, "WriteFile returned %x(%u)\n", res, GetLastError()); + ok(!res && GetLastError() == ERROR_IO_PENDING, "WriteFile returned %x(%lu)\n", res, GetLastError()); test_not_signaled(*server); test_not_signaled(overlapped.hEvent); *client = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, &sec_attr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); - ok(*server != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError()); + ok(*client != INVALID_HANDLE_VALUE, "CreateFile failed: %lu\n", GetLastError()); res = SetNamedPipeHandleState(*client, &read_mode, NULL, NULL); - ok(res, "SetNamedPipeHandleState failed: %u\n", GetLastError()); + ok(res, "SetNamedPipeHandleState failed: %lu\n", GetLastError()); test_signaled(*client); test_not_signaled(*server); @@ -3108,6 +3253,7 @@ static void test_overlapped_transport(BOOL msg_mode, BOOL msg_read_mode) CloseHandle(server); /* close client with pending writes */ + memset(buf, 0xaa, sizeof(buf)); create_overlapped_pipe(create_flags, &client, &server); overlapped_write_async(server, buf, 7000, &overlapped); flush = test_flush_async(server, ERROR_BROKEN_PIPE); @@ -3131,7 +3277,7 @@ static void test_overlapped_transport(BOOL msg_mode, BOOL msg_read_mode) overlapped_write_async(server, buf, 7000, &overlapped2); flush = test_flush_async(client, ERROR_PIPE_NOT_CONNECTED); res = DisconnectNamedPipe(server); - ok(res, "DisconnectNamedPipe failed: %u\n", GetLastError()); + ok(res, "DisconnectNamedPipe failed: %lu\n", GetLastError()); test_overlapped_failure(client, &overlapped, ERROR_PIPE_NOT_CONNECTED); test_overlapped_failure(client, &overlapped2, ERROR_PIPE_NOT_CONNECTED); test_flush_done(flush); @@ -3144,12 +3290,12 @@ static void test_overlapped_transport(BOOL msg_mode, BOOL msg_read_mode) /* successfully read part of write that is pending in child process */ res = ReadFile(server, buf, 10, &read_bytes, NULL); if(!msg_read_mode) - ok(res, "ReadFile failed: %u\n", GetLastError()); + ok(res, "ReadFile failed: %lu\n", GetLastError()); else - ok(!res && GetLastError() == ERROR_MORE_DATA, "ReadFile returned: %x %u\n", res, GetLastError()); - ok(read_bytes == 10, "read_bytes = %u\n", read_bytes); + ok(!res && GetLastError() == ERROR_MORE_DATA, "ReadFile returned: %x %lu\n", res, GetLastError()); + ok(read_bytes == 10, "read_bytes = %lu\n", read_bytes); TerminateProcess(process, 0); - winetest_wait_child_process(process); + wait_child_process(process); /* after terminating process, there is no pending write and pipe buffer is empty */ overlapped_read_async(server, buf, 10, &overlapped); overlapped_write_sync(client, buf, 1); @@ -3159,34 +3305,1071 @@ static void test_overlapped_transport(BOOL msg_mode, BOOL msg_read_mode) CloseHandle(client); } +static void test_transact(HANDLE caller, HANDLE callee, DWORD write_buf_size, DWORD read_buf_size) +{ + OVERLAPPED overlapped, overlapped2, read_overlapped, write_overlapped; + char buf[10000], read_buf[10000]; + + memset(buf, 0xaa, sizeof(buf)); + + /* simple transact call */ + overlapped_transact(caller, (BYTE*)"abc", 3, read_buf, 100, &overlapped); + overlapped_write_sync(callee, (BYTE*)"test", 4); + test_overlapped_result(caller, &overlapped, 4, FALSE); + ok(!memcmp(read_buf, "test", 4), "unexpected read_buf\n"); + overlapped_read_sync(callee, read_buf, 1000, 3, FALSE); + ok(!memcmp(read_buf, "abc", 3), "unexpected read_buf\n"); + + /* transact fails if there is already data in read buffer */ + overlapped_write_sync(callee, buf, 1); + overlapped_transact_failure(caller, buf, 2, read_buf, 1, ERROR_PIPE_BUSY); + overlapped_read_sync(caller, read_buf, 1000, 1, FALSE); + + /* transact doesn't block on write */ + overlapped_write_async(caller, buf, write_buf_size+2000, &write_overlapped); + overlapped_transact(caller, buf, 2, read_buf, 1, &overlapped); + test_not_signaled(overlapped.hEvent); + overlapped_write_sync(callee, buf, 1); + test_overlapped_result(caller, &overlapped, 1, FALSE); + overlapped_read_sync(callee, read_buf, sizeof(read_buf), write_buf_size+2000, FALSE); + test_overlapped_result(caller, &write_overlapped, write_buf_size+2000, FALSE); + overlapped_read_sync(callee, read_buf, sizeof(read_buf), 2, FALSE); + + /* transact with already pending read */ + overlapped_read_async(callee, read_buf, 10, &read_overlapped); + overlapped_transact(caller, buf, 5, read_buf, 6, &overlapped); + test_overlapped_result(callee, &read_overlapped, 5, FALSE); + test_not_signaled(overlapped.hEvent); + overlapped_write_sync(callee, buf, 10); + test_overlapped_result(caller, &overlapped, 6, TRUE); + overlapped_read_sync(caller, read_buf, sizeof(read_buf), 4, FALSE); + + /* 0-size messages */ + overlapped_transact(caller, buf, 5, read_buf, 0, &overlapped); + overlapped_read_sync(callee, read_buf, sizeof(read_buf), 5, FALSE); + overlapped_write_sync(callee, buf, 0); + test_overlapped_result(caller, &overlapped, 0, FALSE); + + overlapped_transact(caller, buf, 0, read_buf, 0, &overlapped); + overlapped_read_sync(callee, read_buf, sizeof(read_buf), 0, FALSE); + test_not_signaled(overlapped.hEvent); + overlapped_write_sync(callee, buf, 0); + test_overlapped_result(caller, &overlapped, 0, FALSE); + + /* reply transact with another transact */ + overlapped_transact(caller, buf, 3, read_buf, 100, &overlapped); + overlapped_read_sync(callee, read_buf, 1000, 3, FALSE); + overlapped_transact(callee, buf, 4, read_buf, 100, &overlapped2); + test_overlapped_result(caller, &overlapped, 4, FALSE); + overlapped_write_sync(caller, buf, 1); + test_overlapped_result(caller, &overlapped2, 1, FALSE); + + if (!pCancelIoEx) return; + + /* cancel keeps written data */ + overlapped_write_async(caller, buf, write_buf_size+2000, &write_overlapped); + overlapped_transact(caller, buf, 2, read_buf, 1, &overlapped); + test_not_signaled(overlapped.hEvent); + cancel_overlapped(caller, &overlapped); + overlapped_read_sync(callee, read_buf, sizeof(read_buf), write_buf_size+2000, FALSE); + test_overlapped_result(caller, &write_overlapped, write_buf_size+2000, FALSE); + overlapped_read_sync(callee, read_buf, sizeof(read_buf), 2, FALSE); +} + +static void test_TransactNamedPipe(void) +{ + HANDLE client, server; + BYTE buf[10]; + + create_overlapped_pipe(PIPE_TYPE_BYTE, &client, &server); + overlapped_transact_failure(client, buf, 2, buf, 1, ERROR_BAD_PIPE); + CloseHandle(client); + CloseHandle(server); + + create_overlapped_pipe(PIPE_TYPE_MESSAGE | PIPE_READMODE_BYTE, &client, &server); + overlapped_transact_failure(client, buf, 2, buf, 1, ERROR_BAD_PIPE); + CloseHandle(client); + CloseHandle(server); + + trace("testing server->client transaction...\n"); + create_overlapped_pipe(PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, &client, &server); + test_transact(server, client, 5000, 6000); + CloseHandle(client); + CloseHandle(server); + + trace("testing client->server transaction...\n"); + create_overlapped_pipe(PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, &client, &server); + test_transact(client, server, 6000, 5000); + CloseHandle(client); + CloseHandle(server); +} + +static HANDLE create_overlapped_server( OVERLAPPED *overlapped ) +{ + HANDLE pipe; + BOOL ret; + + pipe = CreateNamedPipeA(PIPENAME, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX, PIPE_READMODE_BYTE | PIPE_WAIT, + 1, 5000, 6000, NMPWAIT_USE_DEFAULT_WAIT, NULL); + ok(pipe != INVALID_HANDLE_VALUE, "got %lu\n", GetLastError()); + ret = ConnectNamedPipe(pipe, overlapped); + ok(!ret && GetLastError() == ERROR_IO_PENDING, "got %lu\n", GetLastError()); + return pipe; +} + +static void child_process_check_pid(DWORD server_pid) +{ + DWORD current = GetProcessId(GetCurrentProcess()); + HANDLE pipe; + ULONG pid; + BOOL ret; + + pipe = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + ok(pipe != INVALID_HANDLE_VALUE, "got %lu\n", GetLastError()); + + pid = 0; + ret = pGetNamedPipeClientProcessId(pipe, &pid); + ok(ret, "got %lu\n", GetLastError()); + ok(pid == current, "got %04lx\n", pid); + + pid = 0; + ret = pGetNamedPipeServerProcessId(pipe, &pid); + ok(ret, "got %lu\n", GetLastError()); + ok(pid == server_pid, "got %04lx expected %04lx\n", pid, server_pid); + CloseHandle(pipe); +} + +static HANDLE create_check_id_process(const char *verb, DWORD id) +{ + STARTUPINFOA si = {sizeof(si)}; + PROCESS_INFORMATION info; + char **argv, buf[MAX_PATH]; + BOOL ret; + + winetest_get_mainargs(&argv); + sprintf(buf, "\"%s\" pipe %s %lx", argv[0], verb, id); + ret = CreateProcessA(NULL, buf, NULL, NULL, TRUE, 0, NULL, NULL, &si, &info); + ok(ret, "got %lu\n", GetLastError()); + CloseHandle(info.hThread); + return info.hProcess; +} + +static void test_namedpipe_process_id(void) +{ + HANDLE client, server, process; + DWORD current = GetProcessId(GetCurrentProcess()); + OVERLAPPED overlapped; + ULONG pid; + BOOL ret; + +#if defined(__REACTOS__) && DLL_EXPORT_VERSION >= 0x600 + /* FIXME: GetNamedPipeClientProcessId is a STUB on ReactOS. */ + if (is_reactos() || !pGetNamedPipeClientProcessId) +#else + if (!pGetNamedPipeClientProcessId) +#endif + { + win_skip("GetNamedPipeClientProcessId not available\n"); + return; + } + + create_overlapped_pipe(PIPE_TYPE_BYTE, &client, &server); + + SetLastError(0xdeadbeef); + ret = pGetNamedPipeClientProcessId(server, NULL); + ok(!ret, "success\n"); + todo_wine ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %lu\n", GetLastError()); + + pid = 0; + ret = pGetNamedPipeClientProcessId(server, &pid); + ok(ret, "got %lu\n", GetLastError()); + ok(pid == current, "got %04lx expected %04lx\n", pid, current); + + pid = 0; + ret = pGetNamedPipeClientProcessId(client, &pid); + ok(ret, "got %lu\n", GetLastError()); + ok(pid == current, "got %04lx expected %04lx\n", pid, current); + + SetLastError(0xdeadbeef); + ret = pGetNamedPipeServerProcessId(server, NULL); + ok(!ret, "success\n"); + todo_wine ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %lu\n", GetLastError()); + + pid = 0; + ret = pGetNamedPipeServerProcessId(client, &pid); + ok(ret, "got %lu\n", GetLastError()); + ok(pid == current, "got %04lx expected %04lx\n", pid, current); + + pid = 0; + ret = pGetNamedPipeServerProcessId(server, &pid); + ok(ret, "got %lu\n", GetLastError()); + ok(pid == current, "got %04lx expected %04lx\n", pid, current); + + /* closed client handle */ + CloseHandle(client); + pid = 0; + ret = pGetNamedPipeClientProcessId(server, &pid); + ok(ret, "got %lu\n", GetLastError()); + ok(pid == current, "got %04lx expected %04lx\n", pid, current); + + pid = 0; + ret = pGetNamedPipeServerProcessId(server, &pid); + ok(ret, "got %lu\n", GetLastError()); + ok(pid == current, "got %04lx expected %04lx\n", pid, current); + CloseHandle(server); + + /* disconnected server */ + create_overlapped_pipe(PIPE_TYPE_BYTE, &client, &server); + DisconnectNamedPipe(server); + + SetLastError(0xdeadbeef); + ret = pGetNamedPipeClientProcessId(server, &pid); + todo_wine ok(!ret, "success\n"); + todo_wine ok(GetLastError() == ERROR_NOT_FOUND, "got %lu\n", GetLastError()); + + pid = 0; + ret = pGetNamedPipeServerProcessId(server, &pid); + ok(ret, "got %lu\n", GetLastError()); + ok(pid == current, "got %04lx expected %04lx\n", pid, current); + + SetLastError(0xdeadbeef); + ret = pGetNamedPipeClientProcessId(client, &pid); + todo_wine ok(!ret, "success\n"); + todo_wine ok(GetLastError() == ERROR_PIPE_NOT_CONNECTED, "got %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = pGetNamedPipeServerProcessId(client, &pid); + todo_wine ok(!ret, "success\n"); + todo_wine ok(GetLastError() == ERROR_PIPE_NOT_CONNECTED, "got %lu\n", GetLastError()); + CloseHandle(client); + CloseHandle(server); + + /* closed server handle */ + create_overlapped_pipe(PIPE_TYPE_BYTE, &client, &server); + CloseHandle(server); + + pid = 0; + ret = pGetNamedPipeClientProcessId(client, &pid); + ok(ret, "got %lu\n", GetLastError()); + ok(pid == current, "got %04lx expected %04lx\n", pid, current); + + pid = 0; + ret = pGetNamedPipeServerProcessId(client, &pid); + ok(ret, "got %lu\n", GetLastError()); + ok(pid == current, "got %04lx expected %04lx\n", pid, current); + CloseHandle(client); + + /* different process */ + memset(&overlapped, 0, sizeof(overlapped)); + overlapped.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + server = create_overlapped_server( &overlapped ); + ok(server != INVALID_HANDLE_VALUE, "got %lu\n", GetLastError()); + + process = create_check_id_process("checkpid", GetProcessId(GetCurrentProcess())); + wait_child_process(process); + + CloseHandle(overlapped.hEvent); + CloseHandle(process); + CloseHandle(server); +} + +static void child_process_check_session_id(DWORD server_id) +{ + DWORD current; + HANDLE pipe; + ULONG id; + BOOL ret; + + ProcessIdToSessionId(GetProcessId(GetCurrentProcess()), ¤t); + + pipe = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + ok(pipe != INVALID_HANDLE_VALUE, "got %lu\n", GetLastError()); + + id = 0; + ret = pGetNamedPipeClientSessionId(pipe, &id); + ok(ret, "got %lu\n", GetLastError()); + ok(id == current, "got %04lx\n", id); + + id = 0; + ret = pGetNamedPipeServerSessionId(pipe, &id); + ok(ret, "got %lu\n", GetLastError()); + ok(id == server_id, "got %04lx expected %04lx\n", id, server_id); + CloseHandle(pipe); +} + +static void test_namedpipe_session_id(void) +{ + HANDLE client, server, process; + OVERLAPPED overlapped; + DWORD current; + ULONG id; + BOOL ret; + +#if defined(__REACTOS__) && DLL_EXPORT_VERSION >= 0x600 + /* FIXME: GetNamedPipeClientSessionId is a STUB on ReactOS. */ + if (is_reactos() || !pGetNamedPipeClientSessionId) +#else + if (!pGetNamedPipeClientSessionId) +#endif + { + win_skip("GetNamedPipeClientSessionId not available\n"); + return; + } + + ProcessIdToSessionId(GetProcessId(GetCurrentProcess()), ¤t); + + create_overlapped_pipe(PIPE_TYPE_BYTE, &client, &server); + + if (0) /* crashes on recent Windows */ + { + SetLastError(0xdeadbeef); + ret = pGetNamedPipeClientSessionId(server, NULL); + ok(!ret, "success\n"); + } + + id = 0; + ret = pGetNamedPipeClientSessionId(server, &id); + ok(ret, "got %lu\n", GetLastError()); + ok(id == current, "got %lu expected %lu\n", id, current); + + id = 0; + ret = pGetNamedPipeClientSessionId(client, &id); + ok(ret, "got %lu\n", GetLastError()); + ok(id == current, "got %lu expected %lu\n", id, current); + + SetLastError(0xdeadbeef); + ret = pGetNamedPipeServerSessionId(server, NULL); + ok(!ret, "success\n"); + todo_wine ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %lu\n", GetLastError()); + + id = 0; + ret = pGetNamedPipeServerSessionId(client, &id); + ok(ret, "got %lu\n", GetLastError()); + ok(id == current, "got %lu expected %lu\n", id, current); + + id = 0; + ret = pGetNamedPipeServerSessionId(server, &id); + ok(ret, "got %lu\n", GetLastError()); + ok(id == current, "got %lu expected %lu\n", id, current); + + /* closed client handle */ + CloseHandle(client); + + id = 0; + ret = pGetNamedPipeClientSessionId(server, &id); + ok(ret, "got %lu\n", GetLastError()); + ok(id == current, "got %04lx expected %04lx\n", id, current); + + id = 0; + ret = pGetNamedPipeServerSessionId(server, &id); + ok(ret, "got %lu\n", GetLastError()); + ok(id == current, "got %04lx expected %04lx\n", id, current); + CloseHandle(server); + + /* disconnected server */ + create_overlapped_pipe(PIPE_TYPE_BYTE, &client, &server); + DisconnectNamedPipe(server); + + SetLastError(0xdeadbeef); + ret = pGetNamedPipeClientSessionId(server, &id); + todo_wine ok(!ret, "success\n"); + todo_wine ok(GetLastError() == ERROR_NOT_FOUND, "got %lu\n", GetLastError()); + + id = 0; + ret = pGetNamedPipeServerSessionId(server, &id); + ok(ret, "got %lu\n", GetLastError()); + ok(id == current, "got %04lx expected %04lx\n", id, current); + + SetLastError(0xdeadbeef); + ret = pGetNamedPipeClientSessionId(client, &id); + todo_wine ok(!ret, "success\n"); + todo_wine ok(GetLastError() == ERROR_PIPE_NOT_CONNECTED, "got %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = pGetNamedPipeServerSessionId(client, &id); + todo_wine ok(!ret, "success\n"); + todo_wine ok(GetLastError() == ERROR_PIPE_NOT_CONNECTED, "got %lu\n", GetLastError()); + CloseHandle(client); + CloseHandle(server); + + /* closed server handle */ + create_overlapped_pipe(PIPE_TYPE_BYTE, &client, &server); + CloseHandle(server); + + id = 0; + ret = pGetNamedPipeClientSessionId(client, &id); + ok(ret, "got %lu\n", GetLastError()); + ok(id == current, "got %04lx expected %04lx\n", id, current); + + id = 0; + ret = pGetNamedPipeServerSessionId(client, &id); + ok(ret, "got %lu\n", GetLastError()); + ok(id == current, "got %04lx expected %04lx\n", id, current); + CloseHandle(client); + + /* different process */ + memset(&overlapped, 0, sizeof(overlapped)); + overlapped.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + server = create_overlapped_server( &overlapped ); + ok(server != INVALID_HANDLE_VALUE, "got %lu\n", GetLastError()); + + process = create_check_id_process("checksessionid", current); + wait_child_process(process); + + CloseHandle(overlapped.hEvent); + CloseHandle(process); + CloseHandle(server); +} + +static void test_multiple_instances(void) +{ + HANDLE server[4], client; + int i; + BOOL ret; + OVERLAPPED ov; + + if(!pCancelIoEx) + { + win_skip("Skipping multiple instance tests on too old Windows\n"); + return; + } + + for (i = 0; i < ARRAY_SIZE(server); i++) + { + server[i] = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_READMODE_BYTE | PIPE_WAIT, ARRAY_SIZE(server), 1024, 1024, + NMPWAIT_USE_DEFAULT_WAIT, NULL); + ok(server[i] != INVALID_HANDLE_VALUE, "got invalid handle\n"); + } + + client = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(client != INVALID_HANDLE_VALUE, "got invalid handle\n"); + + /* Show that this has connected to server[0] not any other one */ + + memset(&ov, 0, sizeof(ov)); + ret = ConnectNamedPipe(server[2], &ov); + ok(ret == FALSE, "got %d\n", ret); + ok(GetLastError() == ERROR_IO_PENDING, "got %ld\n", GetLastError()); + + memset(&ov, 0, sizeof(ov)); + ret = ConnectNamedPipe(server[0], &ov); + ok(ret == FALSE, "got %d\n", ret); + ok(GetLastError() == ERROR_PIPE_CONNECTED, "got %ld\n", GetLastError()); + + CloseHandle(client); + + /* The next connected server is server[1], doesn't matter that server[2] has pending listeners */ + + client = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(client != INVALID_HANDLE_VALUE, "got invalid handle\n"); + + memset(&ov, 0, sizeof(ov)); + ret = ConnectNamedPipe(server[2], &ov); + ok(ret == FALSE, "got %d\n", ret); + ok(GetLastError() == ERROR_IO_PENDING, "got %ld\n", GetLastError()); + + memset(&ov, 0, sizeof(ov)); + ret = ConnectNamedPipe(server[1], &ov); + ok(ret == FALSE, "got %d\n", ret); + ok(GetLastError() == ERROR_PIPE_CONNECTED, "got %ld\n", GetLastError()); + + CloseHandle(client); + + /* server[2] is connected next */ + + client = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(client != INVALID_HANDLE_VALUE, "got invalid handle\n"); + + memset(&ov, 0, sizeof(ov)); + ret = ConnectNamedPipe(server[2], &ov); + ok(ret == FALSE, "got %d\n", ret); + ok(GetLastError() == ERROR_PIPE_CONNECTED, "got %ld\n", GetLastError()); + + CloseHandle(client); + + /* Disconnect in order server[0] and server[2] */ + + DisconnectNamedPipe(server[0]); + DisconnectNamedPipe(server[2]); + + /* Put into listening state server[2] and server[0] */ + + memset(&ov, 0, sizeof(ov)); + ret = ConnectNamedPipe(server[2], &ov); + ok(ret == FALSE, "got %d\n", ret); + ok(GetLastError() == ERROR_IO_PENDING, "got %ld\n", GetLastError()); + + memset(&ov, 0, sizeof(ov)); + ret = ConnectNamedPipe(server[0], &ov); + ok(ret == FALSE, "got %d\n", ret); + ok(GetLastError() == ERROR_IO_PENDING, "got %ld\n", GetLastError()); + + /* server[3] is connected next */ + + client = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(client != INVALID_HANDLE_VALUE, "got invalid handle\n"); + + memset(&ov, 0, sizeof(ov)); + ret = ConnectNamedPipe(server[3], &ov); + ok(ret == FALSE, "got %d\n", ret); + ok(GetLastError() == ERROR_PIPE_CONNECTED, "got %ld\n", GetLastError()); + + CloseHandle(client); + + /* server[2], which stasted listening first, will be connected next */ + + client = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(client != INVALID_HANDLE_VALUE, "got invalid handle\n"); + + memset(&ov, 0, sizeof(ov)); + ret = ConnectNamedPipe(server[2], &ov); + ok(ret == FALSE, "got %d\n", ret); + ok(GetLastError() == ERROR_PIPE_CONNECTED, "got %ld\n", GetLastError()); + + memset(&ov, 0, sizeof(ov)); + ret = ConnectNamedPipe(server[0], &ov); + ok(ret == FALSE, "got %d\n", ret); + ok(GetLastError() == ERROR_IO_PENDING, "got %ld\n", GetLastError()); + + CloseHandle(client); + + /* Finally server[0] is connected */ + + client = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(client != INVALID_HANDLE_VALUE, "got invalid handle\n"); + + memset(&ov, 0, sizeof(ov)); + ret = ConnectNamedPipe(server[0], &ov); + ok(ret == FALSE, "got %d\n", ret); + ok(GetLastError() == ERROR_PIPE_CONNECTED, "got %ld\n", GetLastError()); + + CloseHandle(client); + + /* No more listening pipes available */ + DisconnectNamedPipe(server[0]); + client = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(client == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PIPE_BUSY, "got %p(%lu)\n", client, GetLastError()); + + for (i = 0; i < ARRAY_SIZE(server); i++) + { + DisconnectNamedPipe(server[i]); + CloseHandle(server[i]); + } +} + +static DWORD WINAPI wait_pipe_proc(void *arg) +{ + BOOL ret; + ret = WaitNamedPipeA(PIPENAME, 1000); + ok(ret, "WaitNamedPipe failed (%lu)\n", GetLastError()); + return 0; +} + +static HANDLE async_wait_pipe(void) +{ + HANDLE thread; + BOOL ret; + + thread = CreateThread(NULL, 0, wait_pipe_proc, NULL, 0, NULL); + ok(thread != NULL, "CreateThread failed: %lu\n", GetLastError()); + + ret = WaitNamedPipeA(PIPENAME, 1); + ok(!ret && GetLastError() == ERROR_SEM_TIMEOUT, "WaitNamedPipe failed %x(%lu)\n", ret, GetLastError()); + + return thread; +} + +static void test_wait_pipe(void) +{ + HANDLE server[2], client, wait; + OVERLAPPED ov; + DWORD res; + BOOL ret; + + ret = WaitNamedPipeA(PIPENAME, 0); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, "WaitNamedPipe failed %x(%lu)\n", ret, GetLastError()); + + server[0] = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_READMODE_BYTE | PIPE_WAIT, ARRAY_SIZE(server), 1024, 1024, + NMPWAIT_USE_DEFAULT_WAIT, NULL); + ok(server[0] != INVALID_HANDLE_VALUE, "got invalid handle\n"); + + ret = WaitNamedPipeA(PIPENAME, 1); + ok(ret, "WaitNamedPipe failed (%lu)\n", GetLastError()); + + client = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(client != INVALID_HANDLE_VALUE, "got invalid handle\n"); + + /* Creating a new pipe server wakes waiters */ + wait = async_wait_pipe(); + server[1] = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_READMODE_BYTE | PIPE_WAIT, ARRAY_SIZE(server), 1024, 1024, + NMPWAIT_USE_DEFAULT_WAIT, NULL); + ok(server[1] != INVALID_HANDLE_VALUE, "got invalid handle\n"); + + res = WaitForSingleObject(wait, 100); + ok(res == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", res); + + CloseHandle(wait); + CloseHandle(server[1]); + + CloseHandle(client); + ret = DisconnectNamedPipe(server[0]); + ok(ret, "DisconnectNamedPipe failed (%lu)\n", GetLastError()); + + /* Putting pipe server into waiting listening state wakes waiters */ + wait = async_wait_pipe(); + memset(&ov, 0, sizeof(ov)); + ov.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + ret = ConnectNamedPipe(server[0], &ov); + ok(ret == FALSE, "got %d\n", ret); + ok(GetLastError() == ERROR_IO_PENDING, "got %ld\n", GetLastError()); + + res = WaitForSingleObject(wait, 100); + ok(res == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", res); + CloseHandle(server[0]); + + res = WaitForSingleObject(ov.hEvent, 0); + ok(res == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", res); + CloseHandle(ov.hEvent); +} + +static void test_nowait(DWORD pipe_type) +{ + HANDLE piperead, pipewrite, file; + OVERLAPPED ol, ol2; + DWORD read, write; + char readbuf[32768]; + static const char teststring[] = "bits"; + + /* CreateNamedPipe with PIPE_NOWAIT, and read from empty pipe */ + piperead = CreateNamedPipeA(PIPENAME, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX, + /* dwPipeMode */ pipe_type | PIPE_NOWAIT, + /* nMaxInstances */ 1, + /* nOutBufSize */ 512, + /* nInBufSize */ 512, + /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT, + /* lpSecurityAttrib */ NULL); + ok(piperead != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); + pipewrite = CreateFileA(PIPENAME, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(pipewrite != INVALID_HANDLE_VALUE, "CreateFileA failed\n"); + memset(&ol, 0, sizeof(ol)); + ol.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + SetLastError(0xdeadbeef); + ok(ReadFile(piperead, readbuf, sizeof(readbuf), &read, &ol) == FALSE, "ReadFile should fail\n"); + ok(GetLastError() == ERROR_NO_DATA, "got %ld should be ERROR_NO_DATA\n", GetLastError()); + if (GetLastError() == ERROR_IO_PENDING) + CancelIo(piperead); + + /* test a small write/read */ + ok(WriteFile(pipewrite, teststring, sizeof(teststring), &write, NULL), "WriteFile should succeed\n"); + ok(ReadFile(piperead, readbuf, sizeof(readbuf), &read, &ol), "ReadFile should succeed\n"); + ok(read == write, "read/write bytes should match\n"); + ok(CloseHandle(ol.hEvent), "CloseHandle for the event failed\n"); + ok(CloseHandle(pipewrite), "CloseHandle for the write pipe failed\n"); + ok(CloseHandle(piperead), "CloseHandle for the read pipe failed\n"); + + + /* create write side with PIPE_NOWAIT, read side PIPE_WAIT, and test writes */ + pipewrite = CreateNamedPipeA(PIPENAME, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX, + /* dwPipeMode */ pipe_type | PIPE_NOWAIT, + /* nMaxInstances */ 1, + /* nOutBufSize */ 512, + /* nInBufSize */ 512, + /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT, + /* lpSecurityAttrib */ NULL); + ok(pipewrite != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); + piperead = CreateFileA(PIPENAME, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); + ok(piperead != INVALID_HANDLE_VALUE, "CreateFileA failed\n"); + memset(&ol, 0, sizeof(ol)); + ol.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + memset(&ol2, 0, sizeof(ol2)); + ol2.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + + /* write one byte larger than the buffer size, should fail */ + SetLastError(0xdeadbeef); + ok(WriteFile(pipewrite, readbuf, 513, &write, &ol), "WriteFile should succeed\n"); + /* WriteFile only documents that 'write < sizeof(readbuf)' for this case, but Windows + * doesn't seem to do partial writes ('write == 0' always) + */ + ok(write < sizeof(readbuf), "WriteFile should fail to write the whole buffer\n"); + ok(write == 0, "WriteFile doesn't do partial writes here\n"); + if (GetLastError() == ERROR_IO_PENDING) + CancelIo(piperead); + + /* overlapped read of 32768, non-blocking write of 512 */ + SetLastError(0xdeadbeef); + ok(ReadFile(piperead, readbuf, sizeof(readbuf), &read, &ol2) == FALSE, "ReadFile should fail\n"); + ok(GetLastError() == ERROR_IO_PENDING, "got %ld should be ERROR_IO_PENDING\n", GetLastError()); + ok(WriteFile(pipewrite, teststring, sizeof(teststring), &write, &ol), "WriteFile should succeed\n"); + ok(write == sizeof(teststring), "got %ld\n", write); + ok(GetOverlappedResult(piperead, &ol2, &read, FALSE), "GetOverlappedResult should succeed\n"); + ok(read == sizeof(teststring), "got %ld\n", read); + if (GetOverlappedResult(piperead, &ol2, &read, FALSE) == FALSE) + CancelIo(piperead); + + /* overlapped read of 32768, non-blocking write of 513 */ + SetLastError(0xdeadbeef); + ok(ReadFile(piperead, readbuf, sizeof(readbuf), &read, &ol2) == FALSE, "ReadFile should fail\n"); + ok(GetLastError() == ERROR_IO_PENDING, "got %ld should be ERROR_IO_PENDING\n", GetLastError()); + ok(WriteFile(pipewrite, readbuf, 513, &write, &ol), "WriteFile should succeed\n"); + ok(write == 513, "got %ld, write should be %d\n", write, 513); + ok(GetOverlappedResult(piperead, &ol2, &read, FALSE), "GetOverlappedResult should succeed\n"); + ok(read == 513, "got %ld, read should be %d\n", read, 513); + if (GetOverlappedResult(piperead, &ol2, &read, FALSE) == FALSE) + CancelIo(piperead); + + /* overlapped read of 1 byte, non-blocking write of 513 bytes */ + SetLastError(0xdeadbeef); + ok(ReadFile(piperead, readbuf, 1, &read, &ol2) == FALSE, "ReadFile should fail\n"); + ok(GetLastError() == ERROR_IO_PENDING, "got %ld should be ERROR_IO_PENDING\n", GetLastError()); + ok(WriteFile(pipewrite, readbuf, 513, &write, &ol), "WriteFile should succeed\n"); + ok(write == 513, "got %ld, write should be %d\n", write, 513); + ok(GetOverlappedResult(piperead, &ol2, &read, FALSE), "GetOverlappedResult should succeed\n"); + ok(read == 1, "got %ld, read should be %d\n", read, 1); + if (GetOverlappedResult(piperead, &ol2, &read, FALSE) == FALSE) + CancelIo(piperead); + /* read the remaining 512 bytes */ + SetLastError(0xdeadbeef); + ok(ReadFile(piperead, readbuf, sizeof(readbuf), &read, &ol2), "ReadFile should succeed\n"); + ok(read == 512, "got %ld, write should be %d\n", write, 512); + if (GetOverlappedResult(piperead, &ol2, &read, FALSE) == FALSE) + CancelIo(piperead); + + /* overlapped read of 1 byte, non-blocking write of 514 bytes */ + SetLastError(0xdeadbeef); + ok(ReadFile(piperead, readbuf, 1, &read, &ol2) == FALSE, "ReadFile should fail\n"); + ok(GetLastError() == ERROR_IO_PENDING, "got %ld should be ERROR_IO_PENDING\n", GetLastError()); + ok(WriteFile(pipewrite, readbuf, 514, &write, &ol), "WriteFile should succeed\n"); + if (pipe_type == PIPE_TYPE_MESSAGE) + { + todo_wine + ok(write == 0, "got %ld\n", write); + todo_wine + ok(!GetOverlappedResult(piperead, &ol2, &read, FALSE), "GetOverlappedResult should fail\n"); + todo_wine + ok(GetLastError() == ERROR_IO_INCOMPLETE, "got %ld should be ERROR_IO_PENDING\n", GetLastError()); + todo_wine + ok(read == 0, "got %ld, read should be %d\n", read, 1); + } + else + { + ok(write == 1, "got %ld\n", write); + ok(GetOverlappedResult(piperead, &ol2, &read, FALSE), "GetOverlappedResult should fail\n"); + ok(read == 1, "got %ld, read should be %d\n", read, 1); + } + if (GetOverlappedResult(piperead, &ol2, &read, FALSE) == FALSE) + CancelIo(piperead); + + /* write the exact buffer size, should succeed */ + SetLastError(0xdeadbeef); + ok(WriteFile(pipewrite, readbuf, 512, &write, &ol), "WriteFile should succeed\n"); + ok(write == 512, "WriteFile should write the whole buffer\n"); + if (GetLastError() == ERROR_IO_PENDING) + CancelIo(piperead); + + ok(CloseHandle(ol.hEvent), "CloseHandle for the event failed\n"); + ok(CloseHandle(ol2.hEvent), "CloseHandle for the event failed\n"); + ok(CloseHandle(pipewrite), "CloseHandle for the write pipe failed\n"); + ok(CloseHandle(piperead), "CloseHandle for the read pipe failed\n"); + + + /* CreateNamedPipe with PIPE_NOWAIT, test ConnectNamedPipe */ + pipewrite = CreateNamedPipeA(PIPENAME, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX, + /* dwPipeMode */ pipe_type | PIPE_NOWAIT, + /* nMaxInstances */ 1, + /* nOutBufSize */ 512, + /* nInBufSize */ 512, + /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT, + /* lpSecurityAttrib */ NULL); + ok(pipewrite != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); + memset(&ol, 0, sizeof(ol)); + ol.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + SetLastError(0xdeadbeef); + ok(ConnectNamedPipe(pipewrite, &ol) == FALSE, "ConnectNamedPipe should fail\n"); + ok(GetLastError() == ERROR_PIPE_LISTENING, "got %ld should be ERROR_PIPE_LISTENING\n", GetLastError()); + if (GetLastError() == ERROR_IO_PENDING) + CancelIo(pipewrite); + + /* connect and disconnect, then test ConnectNamedPipe again */ + file = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed\n"); + ok(CloseHandle(file), "CloseHandle failed\n"); + SetLastError(0xdeadbeef); + ok(ConnectNamedPipe(pipewrite,&ol) == FALSE, "ConnectNamedPipe should fail\n"); + ok(GetLastError() == ERROR_NO_DATA, "got %ld should be ERROR_NO_DATA\n", GetLastError()); + if (GetLastError() == ERROR_IO_PENDING) + CancelIo(pipewrite); + + /* call DisconnectNamedPipe and test ConnectNamedPipe again */ + ok(DisconnectNamedPipe(pipewrite) == TRUE, "DisconnectNamedPipe should succeed\n"); + SetLastError(0xdeadbeef); + ok(ConnectNamedPipe(pipewrite,&ol) == FALSE, "ConnectNamedPipe should fail\n"); + ok(GetLastError() == ERROR_PIPE_LISTENING, "got %ld should be ERROR_PIPE_LISTENING\n", GetLastError()); + if (GetLastError() == ERROR_IO_PENDING) + CancelIo(pipewrite); + ok(CloseHandle(ol.hEvent), "CloseHandle for the event failed\n"); + ok(CloseHandle(pipewrite), "CloseHandle for the write pipe failed\n"); +} + +static void test_GetOverlappedResultEx(void) +{ + HANDLE client, server; + OVERLAPPED ovl; + char buffer[8000]; + DWORD ret_size; + BOOL ret; + + if (!pGetOverlappedResultEx) + { + win_skip("GetOverlappedResultEx() is not available\n"); + return; + } + + create_overlapped_pipe(PIPE_TYPE_BYTE, &client, &server); + + overlapped_write_async(client, buffer, sizeof(buffer), &ovl); + + user_apc_ran = FALSE; + QueueUserAPC(user_apc, GetCurrentThread(), 0); + + SetLastError(0xdeadbeef); + ret = pGetOverlappedResultEx(client, &ovl, &ret_size, 0, FALSE); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_IO_INCOMPLETE, "wrong error %lu\n", GetLastError()); + ok(!user_apc_ran, "APC should not have run\n"); + + SetLastError(0xdeadbeef); + ret = pGetOverlappedResultEx(client, &ovl, &ret_size, 0, TRUE); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_IO_INCOMPLETE, "wrong error %lu\n", GetLastError()); + ok(!user_apc_ran, "APC should not have run\n"); + + SetLastError(0xdeadbeef); + ret = pGetOverlappedResultEx(client, &ovl, &ret_size, 10, FALSE); + ok(!ret, "expected failure\n"); + ok(GetLastError() == WAIT_TIMEOUT, "wrong error %lu\n", GetLastError()); + ok(!user_apc_ran, "APC should not have run\n"); + + SetLastError(0xdeadbeef); + ret = pGetOverlappedResultEx(client, &ovl, &ret_size, 10, TRUE); + ok(!ret, "expected failure\n"); + ok(GetLastError() == WAIT_IO_COMPLETION, "wrong error %lu\n", GetLastError()); + ok(user_apc_ran, "APC should have run\n"); + + CloseHandle(ovl.hEvent); + + CloseHandle(client); + CloseHandle(server); +} + +static void child_process_exit_process_async(DWORD parent_pid, HANDLE parent_pipe) +{ + OVERLAPPED overlapped = {0}; + static char buffer[1]; + HANDLE parent, pipe; + BOOL ret; + + parent = OpenProcess(PROCESS_DUP_HANDLE, FALSE, parent_pid); + ok(!!parent, "got parent %p\n", parent); + + ret = DuplicateHandle(parent, parent_pipe, GetCurrentProcess(), &pipe, 0, + FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + ok(ret, "got error %lu\n", GetLastError()); + + overlapped.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + + ret = ReadFile(pipe, buffer, sizeof(buffer), NULL, &overlapped); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_IO_PENDING, "got error %lu\n", GetLastError()); + + /* exit without closing the pipe handle */ +} + +static void test_exit_process_async(void) +{ + HANDLE client, server, port; + OVERLAPPED *overlapped; + PROCESS_INFORMATION pi; + STARTUPINFOA si = {0}; + char cmdline[300]; + ULONG_PTR key; + char **argv; + DWORD size; + BOOL ret; + + winetest_get_mainargs(&argv); + + create_overlapped_pipe(PIPE_TYPE_BYTE, &client, &server); + port = CreateIoCompletionPort(client, NULL, 123, 0); + + sprintf(cmdline, "%s pipe exit_process_async %lx %p", argv[0], GetCurrentProcessId(), client); + ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + ok(ret, "got error %lu\n", GetLastError()); + ret = WaitForSingleObject(pi.hProcess, 1000); + ok(!ret, "wait timed out\n"); + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + + key = 0xdeadbeef; + size = 0xdeadbeef; + ret = GetQueuedCompletionStatus(port, &size, &key, &overlapped, 1000); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_OPERATION_ABORTED, "got error %lu\n", GetLastError()); + ok(!size, "got size %lu\n", size); + ok(key == 123, "got key %Iu\n", key); + + CloseHandle(port); + CloseHandle(server); +} + +static DWORD CALLBACK synchronousIoThreadMain(void *arg) +{ + HANDLE pipe; + BOOL ret; + + pipe = arg; + SetLastError(0xdeadbeef); + ret = ConnectNamedPipe(pipe, NULL); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_OPERATION_ABORTED, "got error %lu\n", GetLastError()); + return 0; +} + +static DWORD CALLBACK synchronousIoThreadMain2(void *arg) +{ + OVERLAPPED ov; + HANDLE pipe; + BOOL ret; + + pipe = arg; + memset(&ov, 0, sizeof(ov)); + ov.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + SetLastError(0xdeadbeef); + ret = ConnectNamedPipe(pipe, &ov); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_IO_PENDING, "got error %lu\n", GetLastError()); + ret = WaitForSingleObject(ov.hEvent, 1000); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", ret); + CloseHandle(ov.hEvent); + return 0; +} + +static void test_CancelSynchronousIo(void) +{ + BOOL res; + DWORD wait; + HANDLE file; + HANDLE pipe; + HANDLE thread; + + /* bogus values */ + SetLastError(0xdeadbeef); + res = pCancelSynchronousIo((HANDLE)0xdeadbeef); + ok(!res, "CancelSynchronousIo succeeded unexpectedly\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE, + "In CancelSynchronousIo failure, expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError()); + + SetLastError(0xdeadbeef); + res = pCancelSynchronousIo(GetCurrentThread()); + ok(!res, "CancelSynchronousIo succeeded unexpectedly\n"); + ok(GetLastError() == ERROR_NOT_FOUND, + "In CancelSynchronousIo failure, expected ERROR_NOT_FOUND, got %ld\n", GetLastError()); + + /* synchronous i/o */ + pipe = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + 1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL); + ok(pipe != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with %lu\n", GetLastError()); + thread = CreateThread(NULL, 0, synchronousIoThreadMain, pipe, 0, NULL); + /* wait for I/O to start, which transitions the pipe handle from signaled to nonsignaled state. */ + while ((wait = WaitForSingleObject(pipe, 0)) == WAIT_OBJECT_0) Sleep(1); + ok(wait == WAIT_TIMEOUT, "WaitForSingleObject returned %lu (error %lu)\n", wait, GetLastError()); + SetLastError(0xdeadbeef); + res = pCancelSynchronousIo(thread); + ok(res, "CancelSynchronousIo failed with error %ld\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, + "In CancelSynchronousIo failure, expected 0xdeadbeef got %ld\n", GetLastError()); + wait = WaitForSingleObject(thread, 1000); + ok(wait == WAIT_OBJECT_0, "WaitForSingleObject returned %lx\n", wait); + CloseHandle(thread); + CloseHandle(pipe); + + /* asynchronous i/o */ + pipe = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + 1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL); + ok(pipe != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with %lu\n", GetLastError()); + thread = CreateThread(NULL, 0, synchronousIoThreadMain2, pipe, 0, NULL); + /* wait for I/O to start, which transitions the pipe handle from signaled to nonsignaled state. */ + while ((wait = WaitForSingleObject(pipe, 0)) == WAIT_OBJECT_0) Sleep(1); + ok(wait == WAIT_TIMEOUT, "WaitForSingleObject returned %lu (error %lu)\n", wait, GetLastError()); + SetLastError(0xdeadbeef); + res = pCancelSynchronousIo(thread); + ok(!res, "CancelSynchronousIo succeeded unexpectedly\n"); + ok(GetLastError() == ERROR_NOT_FOUND, + "In CancelSynchronousIo failure, expected ERROR_NOT_FOUND, got %ld\n", GetLastError()); + file = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "CreateFile failed (%ld)\n", GetLastError()); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + CloseHandle(file); + CloseHandle(pipe); +} + START_TEST(pipe) { char **argv; int argc; HMODULE hmod; -#if defined(__REACTOS__) && defined(_M_AMD64) - if (!winetest_interactive) - { - skip("ROSTESTS-370: Skipping kernel32_winetest:pipe because it hangs on Windows Server 2003 x64-Testbot. Set winetest_interactive to run it anyway.\n"); - return; - } -#endif - hmod = GetModuleHandleA("advapi32.dll"); pDuplicateTokenEx = (void *) GetProcAddress(hmod, "DuplicateTokenEx"); hmod = GetModuleHandleA("kernel32.dll"); - pQueueUserAPC = (void *) GetProcAddress(hmod, "QueueUserAPC"); pCancelIoEx = (void *) GetProcAddress(hmod, "CancelIoEx"); + pCancelSynchronousIo = (void *) GetProcAddress(hmod, "CancelSynchronousIo"); + pGetNamedPipeClientProcessId = (void *) GetProcAddress(hmod, "GetNamedPipeClientProcessId"); + pGetNamedPipeServerProcessId = (void *) GetProcAddress(hmod, "GetNamedPipeServerProcessId"); + pGetNamedPipeClientSessionId = (void *) GetProcAddress(hmod, "GetNamedPipeClientSessionId"); + pGetNamedPipeServerSessionId = (void *) GetProcAddress(hmod, "GetNamedPipeServerSessionId"); + pGetOverlappedResultEx = (void *)GetProcAddress(hmod, "GetOverlappedResultEx"); argc = winetest_get_mainargs(&argv); - if (argc > 3 && !strcmp(argv[2], "writepipe")) + if (argc > 3) { - UINT_PTR handle; - sscanf(argv[3], "%lx", &handle); - child_process_write_pipe((HANDLE)handle); - return; + if (!strcmp(argv[2], "writepipe")) + { + ULONG handle; + sscanf(argv[3], "%lx", &handle); + child_process_write_pipe(ULongToHandle(handle)); + return; + } + if (!strcmp(argv[2], "checkpid")) + { + DWORD pid = GetProcessId(GetCurrentProcess()); + sscanf(argv[3], "%lx", &pid); + child_process_check_pid(pid); + return; + } + if (!strcmp(argv[2], "checksessionid")) + { + DWORD id; + ProcessIdToSessionId(GetProcessId(GetCurrentProcess()), &id); + sscanf(argv[3], "%lx", &id); + child_process_check_session_id(id); + return; + } + if (!strcmp(argv[2], "exit_process_async")) + { + HANDLE handle; + DWORD pid; + sscanf(argv[3], "%lx", &pid); + sscanf(argv[4], "%p", &handle); + child_process_exit_process_async(pid, handle); + return; + } } if (test_DisconnectNamedPipe()) @@ -3207,4 +4390,20 @@ START_TEST(pipe) test_overlapped_transport(TRUE, FALSE); test_overlapped_transport(TRUE, TRUE); test_overlapped_transport(FALSE, FALSE); + test_TransactNamedPipe(); + test_namedpipe_process_id(); + test_namedpipe_session_id(); + test_multiple_instances(); + test_wait_pipe(); + test_nowait(PIPE_TYPE_BYTE); + test_nowait(PIPE_TYPE_MESSAGE); + test_GetOverlappedResultEx(); +#ifdef __REACTOS__ + if (is_reactos() || GetNTVersion() <= _WIN32_WINNT_WS03) { + skip("These next tests crash or hang on ReactOS and Windows Server 2003.\n"); + return; + } +#endif + test_exit_process_async(); + test_CancelSynchronousIo(); } diff --git a/modules/rostests/winetests/kernel32/power.c b/modules/rostests/winetests/kernel32/power.c new file mode 100644 index 00000000000..900362a4a45 --- /dev/null +++ b/modules/rostests/winetests/kernel32/power.c @@ -0,0 +1,83 @@ +/* + * Unit tests for power management functions + * + * Copyright (c) 2019 Alex Henrie + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "wine/test.h" + +void test_GetSystemPowerStatus(void) +{ + SYSTEM_POWER_STATUS ps; + BOOL ret; + BYTE capacity_flags, expected_capacity_flags; + + if (0) /* crashes */ + GetSystemPowerStatus(NULL); + + memset(&ps, 0x23, sizeof(ps)); + ret = GetSystemPowerStatus(&ps); + ok(ret == TRUE, "expected TRUE\n"); + + if (ps.BatteryFlag == BATTERY_FLAG_UNKNOWN) + { + skip("GetSystemPowerStatus not implemented or not working\n"); + return; + } + else if (ps.BatteryFlag != BATTERY_FLAG_NO_BATTERY) + { + trace("battery detected\n"); + expected_capacity_flags = 0; + if (ps.BatteryLifePercent > 66) + expected_capacity_flags |= BATTERY_FLAG_HIGH; + if (ps.BatteryLifePercent < 33) + expected_capacity_flags |= BATTERY_FLAG_LOW; + if (ps.BatteryLifePercent < 5) + expected_capacity_flags |= BATTERY_FLAG_CRITICAL; + capacity_flags = (ps.BatteryFlag & ~BATTERY_FLAG_CHARGING); + ok(capacity_flags == expected_capacity_flags, + "expected %u%%-charged battery to have capacity flags 0x%02x, got 0x%02x\n", + ps.BatteryLifePercent, expected_capacity_flags, capacity_flags); + ok(ps.BatteryLifeTime <= ps.BatteryFullLifeTime, + "expected BatteryLifeTime %lu to be less than or equal to BatteryFullLifeTime %lu\n", + ps.BatteryLifeTime, ps.BatteryFullLifeTime); + if (ps.BatteryFlag & BATTERY_FLAG_CHARGING) + { + ok(ps.BatteryLifeTime == BATTERY_LIFE_UNKNOWN, + "expected BatteryLifeTime to be -1 when charging, got %lu\n", ps.BatteryLifeTime); + ok(ps.BatteryFullLifeTime == BATTERY_LIFE_UNKNOWN, + "expected BatteryFullLifeTime to be -1 when charging, got %lu\n", ps.BatteryFullLifeTime); + } + } + else + { + trace("no battery detected\n"); + ok(ps.ACLineStatus == AC_LINE_ONLINE, + "expected ACLineStatus to be 1, got %u\n", ps.ACLineStatus); + ok(ps.BatteryLifePercent == BATTERY_PERCENTAGE_UNKNOWN, + "expected BatteryLifePercent to be -1, got %u\n", ps.BatteryLifePercent); + ok(ps.BatteryLifeTime == BATTERY_LIFE_UNKNOWN, + "expected BatteryLifeTime to be -1, got %lu\n", ps.BatteryLifeTime); + ok(ps.BatteryFullLifeTime == BATTERY_LIFE_UNKNOWN, + "expected BatteryFullLifeTime to be -1, got %lu\n", ps.BatteryFullLifeTime); + } +} + +START_TEST(power) +{ + test_GetSystemPowerStatus(); +} diff --git a/modules/rostests/winetests/kernel32/process.c b/modules/rostests/winetests/kernel32/process.c index 359725e383a..eaf2824832d 100644 --- a/modules/rostests/winetests/kernel32/process.c +++ b/modules/rostests/winetests/kernel32/process.c @@ -36,8 +36,10 @@ #include "tlhelp32.h" #include "wine/test.h" - -#include "winnt.h" +#include "wine/heap.h" +#ifdef __REACTOS__ +#include "winehacks.h" +#endif /* PROCESS_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */ #define PROCESS_ALL_ACCESS_NT4 (PROCESS_ALL_ACCESS & ~0xf000) @@ -48,7 +50,7 @@ do { \ int value = (actual); \ ok((expected) == value, "Expected " #actual " to be %d (" #expected ") is %d\n", \ - (expected), value); \ + (int)(expected), value); \ } while (0) #define expect_eq_s(expected, actual) \ do { \ @@ -67,12 +69,12 @@ static HINSTANCE hkernel32, hntdll; static void (WINAPI *pGetNativeSystemInfo)(LPSYSTEM_INFO); static BOOL (WINAPI *pGetSystemRegistryQuota)(PDWORD, PDWORD); static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL); -static LPVOID (WINAPI *pVirtualAllocEx)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD); -static BOOL (WINAPI *pVirtualFreeEx)(HANDLE, LPVOID, SIZE_T, DWORD); +static BOOL (WINAPI *pIsWow64Process2)(HANDLE, USHORT *, USHORT *); static BOOL (WINAPI *pQueryFullProcessImageNameA)(HANDLE hProcess, DWORD dwFlags, LPSTR lpExeName, PDWORD lpdwSize); static BOOL (WINAPI *pQueryFullProcessImageNameW)(HANDLE hProcess, DWORD dwFlags, LPWSTR lpExeName, PDWORD lpdwSize); static DWORD (WINAPI *pK32GetProcessImageFileNameA)(HANDLE,LPSTR,DWORD); static HANDLE (WINAPI *pCreateJobObjectW)(LPSECURITY_ATTRIBUTES sa, LPCWSTR name); +static HANDLE (WINAPI *pOpenJobObjectA)(DWORD access, BOOL inherit, LPCSTR name); static BOOL (WINAPI *pAssignProcessToJobObject)(HANDLE job, HANDLE process); static BOOL (WINAPI *pIsProcessInJob)(HANDLE process, HANDLE job, PBOOL result); static BOOL (WINAPI *pTerminateJobObject)(HANDLE job, UINT exit_code); @@ -81,7 +83,8 @@ static BOOL (WINAPI *pSetInformationJobObject)(HANDLE job, JOBOBJECTINFOCLASS static HANDLE (WINAPI *pCreateIoCompletionPort)(HANDLE file, HANDLE existing_port, ULONG_PTR key, DWORD threads); static BOOL (WINAPI *pGetNumaProcessorNode)(UCHAR, PUCHAR); static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG); -static BOOL (WINAPI *pProcessIdToSessionId)(DWORD,DWORD*); +static NTSTATUS (WINAPI *pNtQueryInformationThread)(HANDLE, THREADINFOCLASS, PVOID, ULONG, PULONG); +static NTSTATUS (WINAPI *pNtQuerySystemInformationEx)(SYSTEM_INFORMATION_CLASS, void*, ULONG, void*, ULONG, ULONG*); static DWORD (WINAPI *pWTSGetActiveConsoleSessionId)(void); static HANDLE (WINAPI *pCreateToolhelp32Snapshot)(DWORD, DWORD); static BOOL (WINAPI *pProcess32First)(HANDLE, PROCESSENTRY32*); @@ -90,10 +93,13 @@ static BOOL (WINAPI *pThread32First)(HANDLE, THREADENTRY32*); static BOOL (WINAPI *pThread32Next)(HANDLE, THREADENTRY32*); static BOOL (WINAPI *pGetLogicalProcessorInformationEx)(LOGICAL_PROCESSOR_RELATIONSHIP,SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*,DWORD*); static SIZE_T (WINAPI *pGetLargePageMinimum)(void); +static BOOL (WINAPI *pGetSystemCpuSetInformation)(SYSTEM_CPU_SET_INFORMATION*,ULONG,ULONG*,HANDLE,ULONG); static BOOL (WINAPI *pInitializeProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD, SIZE_T*); static BOOL (WINAPI *pUpdateProcThreadAttribute)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD_PTR, void *,SIZE_T,void*,SIZE_T*); static void (WINAPI *pDeleteProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*); static DWORD (WINAPI *pGetActiveProcessorCount)(WORD); +static DWORD (WINAPI *pGetMaximumProcessorCount)(WORD); +static BOOL (WINAPI *pGetProcessInformation)(HANDLE,PROCESS_INFORMATION_CLASS,void*,DWORD); /* ############################### */ static char base[MAX_PATH]; @@ -205,6 +211,21 @@ static WCHAR* decodeW(const char* str) return ptr; } +static void wait_and_close_child_process(PROCESS_INFORMATION *pi) +{ + wait_child_process(pi->hProcess); + CloseHandle(pi->hThread); + CloseHandle(pi->hProcess); +} + +static void reload_child_info(const char* resfile) +{ + /* This forces the profile functions to reload the resource file + * after the child process has modified it. + */ + WritePrivateProfileStringA(NULL, NULL, NULL, resfile); +} + /****************************************************************** * init * @@ -220,7 +241,7 @@ static BOOL init(void) myARGC = winetest_get_mainargs( &myARGV ); if (!GetCurrentDirectoryA(sizeof(base), base)) return FALSE; - strcpy(selfname, myARGV[0]); + GetModuleFileNameA( 0, selfname, sizeof(selfname) ); /* Strip the path of selfname */ if ((p = strrchr(selfname, '\\')) != NULL) exename = p + 1; @@ -232,16 +253,18 @@ static BOOL init(void) hntdll = GetModuleHandleA("ntdll.dll"); pNtQueryInformationProcess = (void *)GetProcAddress(hntdll, "NtQueryInformationProcess"); + pNtQueryInformationThread = (void *)GetProcAddress(hntdll, "NtQueryInformationThread"); + pNtQuerySystemInformationEx = (void *)GetProcAddress(hntdll, "NtQuerySystemInformationEx"); pGetNativeSystemInfo = (void *) GetProcAddress(hkernel32, "GetNativeSystemInfo"); pGetSystemRegistryQuota = (void *) GetProcAddress(hkernel32, "GetSystemRegistryQuota"); pIsWow64Process = (void *) GetProcAddress(hkernel32, "IsWow64Process"); - pVirtualAllocEx = (void *) GetProcAddress(hkernel32, "VirtualAllocEx"); - pVirtualFreeEx = (void *) GetProcAddress(hkernel32, "VirtualFreeEx"); + pIsWow64Process2 = (void *) GetProcAddress(hkernel32, "IsWow64Process2"); pQueryFullProcessImageNameA = (void *) GetProcAddress(hkernel32, "QueryFullProcessImageNameA"); pQueryFullProcessImageNameW = (void *) GetProcAddress(hkernel32, "QueryFullProcessImageNameW"); pK32GetProcessImageFileNameA = (void *) GetProcAddress(hkernel32, "K32GetProcessImageFileNameA"); pCreateJobObjectW = (void *)GetProcAddress(hkernel32, "CreateJobObjectW"); + pOpenJobObjectA = (void *)GetProcAddress(hkernel32, "OpenJobObjectA"); pAssignProcessToJobObject = (void *)GetProcAddress(hkernel32, "AssignProcessToJobObject"); pIsProcessInJob = (void *)GetProcAddress(hkernel32, "IsProcessInJob"); pTerminateJobObject = (void *)GetProcAddress(hkernel32, "TerminateJobObject"); @@ -249,7 +272,6 @@ static BOOL init(void) pSetInformationJobObject = (void *)GetProcAddress(hkernel32, "SetInformationJobObject"); pCreateIoCompletionPort = (void *)GetProcAddress(hkernel32, "CreateIoCompletionPort"); pGetNumaProcessorNode = (void *)GetProcAddress(hkernel32, "GetNumaProcessorNode"); - pProcessIdToSessionId = (void *)GetProcAddress(hkernel32, "ProcessIdToSessionId"); pWTSGetActiveConsoleSessionId = (void *)GetProcAddress(hkernel32, "WTSGetActiveConsoleSessionId"); pCreateToolhelp32Snapshot = (void *)GetProcAddress(hkernel32, "CreateToolhelp32Snapshot"); pProcess32First = (void *)GetProcAddress(hkernel32, "Process32First"); @@ -258,10 +280,13 @@ static BOOL init(void) pThread32Next = (void *)GetProcAddress(hkernel32, "Thread32Next"); pGetLogicalProcessorInformationEx = (void *)GetProcAddress(hkernel32, "GetLogicalProcessorInformationEx"); pGetLargePageMinimum = (void *)GetProcAddress(hkernel32, "GetLargePageMinimum"); + pGetSystemCpuSetInformation = (void *)GetProcAddress(hkernel32, "GetSystemCpuSetInformation"); pInitializeProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "InitializeProcThreadAttributeList"); pUpdateProcThreadAttribute = (void *)GetProcAddress(hkernel32, "UpdateProcThreadAttribute"); pDeleteProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "DeleteProcThreadAttributeList"); pGetActiveProcessorCount = (void *)GetProcAddress(hkernel32, "GetActiveProcessorCount"); + pGetMaximumProcessorCount = (void *)GetProcAddress(hkernel32, "GetMaximumProcessorCount"); + pGetProcessInformation = (void *)GetProcAddress(hkernel32, "GetProcessInformation"); return TRUE; } @@ -285,9 +310,9 @@ static void get_file_name(char* buf) * static void childPrintf * */ -static void __WINE_PRINTF_ATTR(2,3) childPrintf(HANDLE h, const char* fmt, ...) +static void WINAPIV __WINE_PRINTF_ATTR(2,3) childPrintf(HANDLE h, const char* fmt, ...) { - va_list valist; + va_list valist; char buffer[1024+4*MAX_LISTED_ENV_VAR]; DWORD w; @@ -297,6 +322,56 @@ static void __WINE_PRINTF_ATTR(2,3) childPrintf(HANDLE h, const char* fmt, ...) WriteFile(h, buffer, strlen(buffer), &w, NULL); } +/* bits 0..1 contains FILE_TYPE_{UNKNOWN, CHAR, PIPE, DISK} */ +#if defined(__REACTOS__) && defined(_WIN64) +/* This appears to be what HATTR_NULL resolves to on Windows x64 for native (not WoW) processes. + * It may be: + * HATTR_NULL (x86) | HATTR_INVALID | 0x01 */ +#define HATTR_NULL 0x0d /* NULL handle value */ +#else +#define HATTR_NULL 0x08 /* NULL handle value */ +#endif +#define HATTR_INVALID 0x04 /* INVALID_HANDLE_VALUE */ +#define HATTR_TYPE 0x0c /* valid handle, with type set */ +#define HATTR_UNTOUCHED 0x10 /* Identify fields untouched by GetStartupInfoW */ +#define HATTR_INHERIT 0x20 /* inheritance flag set */ +#define HATTR_PROTECT 0x40 /* protect from close flag set */ +#define HATTR_DANGLING 0x80 /* a pseudo value to show that the handle value has been copied but not inherited */ + +#define HANDLE_UNTOUCHEDW (HANDLE)(DWORD_PTR)(0x5050505050505050ull) + +static unsigned encode_handle_attributes(HANDLE h) +{ + DWORD dw; + unsigned result; + + if (h == NULL) + result = HATTR_NULL; + else if (h == INVALID_HANDLE_VALUE) + result = HATTR_INVALID; + else if (h == HANDLE_UNTOUCHEDW) + result = HATTR_UNTOUCHED; + else + { + result = HATTR_TYPE; + dw = GetFileType(h); + if (dw == FILE_TYPE_CHAR || dw == FILE_TYPE_DISK || dw == FILE_TYPE_PIPE) + { + DWORD info; + if (GetHandleInformation(h, &info)) + { + if (info & HANDLE_FLAG_INHERIT) + result |= HATTR_INHERIT; + if (info & HANDLE_FLAG_PROTECT_FROM_CLOSE) + result |= HATTR_PROTECT; + } + } + else + dw = FILE_TYPE_UNKNOWN; + result |= dw; + } + return result; +} /****************************************************************** * doChild @@ -321,40 +396,48 @@ static void doChild(const char* file, const char* option) if (hFile == INVALID_HANDLE_VALUE) return; /* output of startup info (Ansi) */ + memset(&siA, 0xA0, sizeof(siA)); GetStartupInfoA(&siA); childPrintf(hFile, - "[StartupInfoA]\ncb=%08u\nlpDesktop=%s\nlpTitle=%s\n" - "dwX=%u\ndwY=%u\ndwXSize=%u\ndwYSize=%u\n" - "dwXCountChars=%u\ndwYCountChars=%u\ndwFillAttribute=%u\n" - "dwFlags=%u\nwShowWindow=%u\n" - "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n", + "[StartupInfoA]\ncb=%08lu\nlpDesktop=%s\nlpTitle=%s\n" + "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n" + "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n" + "dwFlags=%lu\nwShowWindow=%u\n" + "hStdInput=%Iu\nhStdOutput=%Iu\nhStdError=%Iu\n" + "hStdInputEncode=%u\nhStdOutputEncode=%u\nhStdErrorEncode=%u\n\n", siA.cb, encodeA(siA.lpDesktop), encodeA(siA.lpTitle), siA.dwX, siA.dwY, siA.dwXSize, siA.dwYSize, siA.dwXCountChars, siA.dwYCountChars, siA.dwFillAttribute, siA.dwFlags, siA.wShowWindow, - (DWORD_PTR)siA.hStdInput, (DWORD_PTR)siA.hStdOutput, (DWORD_PTR)siA.hStdError); + (DWORD_PTR)siA.hStdInput, (DWORD_PTR)siA.hStdOutput, (DWORD_PTR)siA.hStdError, + encode_handle_attributes(siA.hStdInput), encode_handle_attributes(siA.hStdOutput), + encode_handle_attributes(siA.hStdError)); /* check the console handles in the TEB */ - childPrintf(hFile, "[TEB]\nhStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n", + childPrintf(hFile, + "[TEB]\nhStdInput=%Iu\nhStdOutput=%Iu\nhStdError=%Iu\n" + "hStdInputEncode=%u\nhStdOutputEncode=%u\nhStdErrorEncode=%u\n\n", (DWORD_PTR)params->hStdInput, (DWORD_PTR)params->hStdOutput, - (DWORD_PTR)params->hStdError); + (DWORD_PTR)params->hStdError, + encode_handle_attributes(params->hStdInput), encode_handle_attributes(params->hStdOutput), + encode_handle_attributes(params->hStdError)); - /* since GetStartupInfoW is only implemented in win2k, - * zero out before calling so we can notice the difference - */ - memset(&siW, 0, sizeof(siW)); + memset(&siW, 0x50, sizeof(siW)); GetStartupInfoW(&siW); childPrintf(hFile, - "[StartupInfoW]\ncb=%08u\nlpDesktop=%s\nlpTitle=%s\n" - "dwX=%u\ndwY=%u\ndwXSize=%u\ndwYSize=%u\n" - "dwXCountChars=%u\ndwYCountChars=%u\ndwFillAttribute=%u\n" - "dwFlags=%u\nwShowWindow=%u\n" - "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n", + "[StartupInfoW]\ncb=%08lu\nlpDesktop=%s\nlpTitle=%s\n" + "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n" + "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n" + "dwFlags=%lu\nwShowWindow=%u\n" + "hStdInput=%Iu\nhStdOutput=%Iu\nhStdError=%Iu\n" + "hStdInputEncode=%u\nhStdOutputEncode=%u\nhStdErrorEncode=%u\n\n", siW.cb, encodeW(siW.lpDesktop), encodeW(siW.lpTitle), siW.dwX, siW.dwY, siW.dwXSize, siW.dwYSize, siW.dwXCountChars, siW.dwYCountChars, siW.dwFillAttribute, siW.dwFlags, siW.wShowWindow, - (DWORD_PTR)siW.hStdInput, (DWORD_PTR)siW.hStdOutput, (DWORD_PTR)siW.hStdError); + (DWORD_PTR)siW.hStdInput, (DWORD_PTR)siW.hStdOutput, (DWORD_PTR)siW.hStdError, + encode_handle_attributes(siW.hStdInput), encode_handle_attributes(siW.hStdOutput), + encode_handle_attributes(siW.hStdError)); /* Arguments */ childPrintf(hFile, "[Arguments]\nargcA=%d\n", myARGC); @@ -367,7 +450,7 @@ static void doChild(const char* file, const char* option) /* output toolhelp information */ snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError()); + ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %lu\n", GetLastError()); memset(&pe, 0, sizeof(pe)); pe.dwSize = sizeof(pe); if (pProcess32First(snapshot, &pe)) @@ -376,11 +459,13 @@ static void doChild(const char* file, const char* option) if (!pProcess32Next(snapshot, &pe)) break; } CloseHandle(snapshot); +#if !defined(__REACTOS__) || !defined(_WIN64) // This doesn't work on x86_64, all Windows versions. ok(pe.th32ProcessID == GetCurrentProcessId(), "failed to find current process in snapshot\n"); +#endif childPrintf(hFile, - "[Toolhelp]\ncntUsage=%u\nth32DefaultHeapID=%lu\n" - "th32ModuleID=%u\ncntThreads=%u\nth32ParentProcessID=%u\n" - "pcPriClassBase=%u\ndwFlags=%u\nszExeFile=%s\n\n", + "[Toolhelp]\ncntUsage=%lu\nth32DefaultHeapID=%Iu\n" + "th32ModuleID=%lu\ncntThreads=%lu\nth32ParentProcessID=%lu\n" + "pcPriClassBase=%lu\ndwFlags=%lu\nszExeFile=%s\n\n", pe.cntUsage, pe.th32DefaultHeapID, pe.th32ModuleID, pe.cntThreads, pe.th32ParentProcessID, pe.pcPriClassBase, pe.dwFlags, encodeA(pe.szExeFile)); @@ -427,7 +512,7 @@ static void doChild(const char* file, const char* option) childPrintf(hFile, "[Misc]\n"); if (GetCurrentDirectoryA(sizeof(bufA), bufA)) childPrintf(hFile, "CurrDirA=%s\n", encodeA(bufA)); - if (GetCurrentDirectoryW(sizeof(bufW) / sizeof(bufW[0]), bufW)) + if (GetCurrentDirectoryW(ARRAY_SIZE(bufW), bufW)) childPrintf(hFile, "CurrDirW=%s\n", encodeW(bufW)); childPrintf(hFile, "\n"); @@ -451,9 +536,9 @@ static void doChild(const char* file, const char* option) childPrintf(hFile, "InputCP=%d\nOutputCP=%d\n", GetConsoleCP(), GetConsoleOutputCP()); if (GetConsoleMode(hConIn, &modeIn)) - childPrintf(hFile, "InputMode=%u\n", modeIn); + childPrintf(hFile, "InputMode=%lu\n", modeIn); if (GetConsoleMode(hConOut, &modeOut)) - childPrintf(hFile, "OutputMode=%u\n", modeOut); + childPrintf(hFile, "OutputMode=%lu\n", modeOut); /* now that we have written all relevant information, let's change it */ SetLastError(0xdeadbeef); @@ -469,13 +554,13 @@ static void doChild(const char* file, const char* option) } ret = SetConsoleMode(hConIn, modeIn ^ 1); - ok( ret, "Setting mode (%d)\n", GetLastError()); + ok( ret, "Setting mode (%ld)\n", GetLastError()); ret = SetConsoleMode(hConOut, modeOut ^ 1); - ok( ret, "Setting mode (%d)\n", GetLastError()); - sbi.dwCursorPosition.X ^= 1; - sbi.dwCursorPosition.Y ^= 1; + ok( ret, "Setting mode (%ld)\n", GetLastError()); + sbi.dwCursorPosition.X = !sbi.dwCursorPosition.X; + sbi.dwCursorPosition.Y = !sbi.dwCursorPosition.Y; ret = SetConsoleCursorPosition(hConOut, sbi.dwCursorPosition); - ok( ret, "Setting cursor position (%d)\n", GetLastError()); + ok( ret, "Setting cursor position (%ld)\n", GetLastError()); } if (option && strcmp(option, "stdhandle") == 0) { @@ -527,31 +612,12 @@ static WCHAR* getChildStringW(const char* sect, const char* key) 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...) - */ -static int wtstrcasecmp(const char* p1, const char* p2) -{ - char c1, c2; - - c1 = c2 = '@'; - while (c1 == c2 && c1) - { - c1 = *p1++; c2 = *p2++; - if (c1 != c2) - { - c1 = toupper(c1); c2 = toupper(c2); - } - } - return c1 - c2; -} - static int strCmp(const char* s1, const char* s2, BOOL sensitive) { if (!s1 && !s2) return 0; if (!s2) return -1; if (!s1) return 1; - return (sensitive) ? strcmp(s1, s2) : wtstrcasecmp(s1, s2); + return (sensitive) ? strcmp(s1, s2) : strcasecmp(s1, s2); } static void ok_child_string( int line, const char *sect, const char *key, @@ -594,14 +660,21 @@ static void ok_child_int( int line, const char *sect, const char *key, UINT expe ok_(__FILE__, line)( result == expect, "%s:%s expected %u, but got %u\n", sect, key, expect, result ); } +static void ok_child_hexint( int line, const char *sect, const char *key, UINT expect, UINT is_broken ) +{ + UINT result = GetPrivateProfileIntA( sect, key, !expect, resfile ); + ok_(__FILE__, line)( result == expect || broken( is_broken && result == is_broken ), "%s:%s expected %#x, but got %#x\n", sect, key, expect, result ); +} + #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 ) #define okChildInt(sect, key, expect) ok_child_int(__LINE__, (sect), (key), (expect)) +#define okChildHexInt(sect, key, expect, is_broken) ok_child_hexint(__LINE__, (sect), (key), (expect), (is_broken)) static void test_Startup(void) { - char buffer[MAX_PATH]; + char buffer[2 * MAX_PATH + 25]; PROCESS_INFORMATION info; STARTUPINFOA startup,si; char *result; @@ -616,15 +689,11 @@ static void test_Startup(void) startup.wShowWindow = SW_SHOWNORMAL; get_file_name(resfile); - sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); + sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); - /* 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); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info); + reload_child_info(resfile); GetStartupInfoA(&si); okChildInt("StartupInfoA", "cb", startup.cb); okChildString("StartupInfoA", "lpDesktop", si.lpDesktop); @@ -656,15 +725,11 @@ static void test_Startup(void) startup.dwFillAttribute = 0xA55A; get_file_name(resfile); - sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); + sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); - /* 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); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info); + reload_child_info(resfile); okChildInt("StartupInfoA", "cb", startup.cb); okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop); okChildString("StartupInfoA", "lpTitle", startup.lpTitle); @@ -696,15 +761,11 @@ static void test_Startup(void) startup.dwFillAttribute = 0xA55A; get_file_name(resfile); - sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); + sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); - /* 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); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info); + reload_child_info(resfile); okChildInt("StartupInfoA", "cb", startup.cb); okChildString("StartupInfoA", "lpDesktop", si.lpDesktop); okChildString("StartupInfoA", "lpTitle", startup.lpTitle); @@ -736,15 +797,11 @@ static void test_Startup(void) startup.dwFillAttribute = 0xA55A; get_file_name(resfile); - sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); + sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); - /* 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); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info); + reload_child_info(resfile); okChildInt("StartupInfoA", "cb", startup.cb); okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop); okChildString("StartupInfoA", "lpTitle", startup.lpTitle); @@ -776,15 +833,11 @@ static void test_Startup(void) startup.dwFillAttribute = 0xA55A; get_file_name(resfile); - sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); + sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); - /* 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); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info); + reload_child_info(resfile); okChildInt("StartupInfoA", "cb", startup.cb); okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop); result = getChildString( "StartupInfoA", "lpTitle" ); @@ -818,15 +871,11 @@ static void test_Startup(void) startup.dwFillAttribute = 0xA55A; get_file_name(resfile); - sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); + sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); - /* 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); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info); + reload_child_info(resfile); okChildInt("StartupInfoA", "cb", startup.cb); okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop); okChildString("StartupInfoA", "lpTitle", startup.lpTitle); @@ -858,15 +907,11 @@ static void test_Startup(void) startup.dwFillAttribute = 0xA55A; get_file_name(resfile); - sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); + sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); - /* 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); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info); + reload_child_info(resfile); okChildInt("StartupInfoA", "cb", startup.cb); okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop); okChildString("StartupInfoA", "lpTitle", startup.lpTitle); @@ -887,28 +932,46 @@ static void test_Startup(void) static void test_CommandLine(void) { - char buffer[MAX_PATH], fullpath[MAX_PATH], *lpFilePart, *p; - char buffer2[MAX_PATH]; + char buffer[2 * MAX_PATH + 65], fullpath[MAX_PATH], *lpFilePart, *p; + char buffer2[MAX_PATH + 44]; PROCESS_INFORMATION info; STARTUPINFOA startup; BOOL ret; + LPWSTR cmdline, cmdline_backup; memset(&startup, 0, sizeof(startup)); startup.cb = sizeof(startup); startup.dwFlags = STARTF_USESHOWWINDOW; startup.wShowWindow = SW_SHOWNORMAL; - /* the basics */ - get_file_name(resfile); - sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" \"C:\\Program Files\\my nice app.exe\"", selfname, resfile); - ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); - /* 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); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + /* failure case */ + strcpy(buffer, "\"t:\\NotADir\\NotAFile.exe\""); + memset(&info, 0xa, sizeof(info)); + ok(!CreateProcessA(buffer, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess unexpectedly succeeded\n"); + /* Check that the effective STARTUPINFOA parameters are not modified */ + ok(startup.cb == sizeof(startup), "unexpected cb %ld\n", startup.cb); + ok(startup.lpDesktop == NULL, "lpDesktop is not NULL\n"); + ok(startup.lpTitle == NULL, "lpTitle is not NULL\n"); + ok(startup.dwFlags == STARTF_USESHOWWINDOW, "unexpected dwFlags %04lx\n", startup.dwFlags); + ok(startup.wShowWindow == SW_SHOWNORMAL, "unexpected wShowWindow %d\n", startup.wShowWindow); + ok(!info.hProcess, "unexpected hProcess %p\n", info.hProcess); + ok(!info.hThread, "unexpected hThread %p\n", info.hThread); + ok(!info.dwProcessId, "unexpected dwProcessId %04lx\n", info.dwProcessId); + ok(!info.dwThreadId, "unexpected dwThreadId %04lx\n", info.dwThreadId); + /* the basics; not getting confused by the leading and trailing " */ + get_file_name(resfile); + sprintf(buffer, "\"%s\" process dump \"%s\" \"C:\\Program Files\\my nice app.exe\"", selfname, resfile); + ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); + /* Check that the effective STARTUPINFOA parameters are not modified */ + ok(startup.cb == sizeof(startup), "unexpected cb %ld\n", startup.cb); + ok(startup.lpDesktop == NULL, "lpDesktop is not NULL\n"); + ok(startup.lpTitle == NULL, "lpTitle is not NULL\n"); + ok(startup.dwFlags == STARTF_USESHOWWINDOW, "unexpected dwFlags %04lx\n", startup.dwFlags); + ok(startup.wShowWindow == SW_SHOWNORMAL, "unexpected wShowWindow %d\n", startup.wShowWindow); + wait_and_close_child_process(&info); + + reload_child_info(resfile); okChildInt("Arguments", "argcA", 5); okChildString("Arguments", "argvA4", "C:\\Program Files\\my nice app.exe"); okChildString("Arguments", "argvA5", NULL); @@ -916,22 +979,13 @@ static void test_CommandLine(void) release_memory(); DeleteFileA(resfile); - memset(&startup, 0, sizeof(startup)); - startup.cb = sizeof(startup); - startup.dwFlags = STARTF_USESHOWWINDOW; - startup.wShowWindow = SW_SHOWNORMAL; - - /* from François */ + /* test main()'s quotes handling */ get_file_name(resfile); - sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", selfname, resfile); + sprintf(buffer, "\"%s\" process dump \"%s\" \"a\\\"b\\\\\" c\\\" d", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); - /* 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); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info); + reload_child_info(resfile); okChildInt("Arguments", "argcA", 7); okChildString("Arguments", "argvA4", "a\"b\\"); okChildString("Arguments", "argvA5", "c\""); @@ -941,58 +995,56 @@ static void test_CommandLine(void) release_memory(); DeleteFileA(resfile); - /* Test for Bug1330 to show that XP doesn't change '/' to '\\' in argv[0]*/ + GetFullPathNameA(selfname, MAX_PATH, fullpath, &lpFilePart); + assert ( lpFilePart != 0); + *(lpFilePart -1 ) = 0; + SetCurrentDirectoryA( fullpath ); + + /* Test for Bug1330 to show that XP doesn't change '/' to '\\' in argv[0] + * and " escaping. + */ get_file_name(resfile); /* Use exename to avoid buffer containing things like 'C:' */ - sprintf(buffer, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename, resfile); + sprintf(buffer, "./%s process dump \"%s\" \"\"\"\"", 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()); - /* 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); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + ok(ret, "CreateProcess (%s) failed : %ld\n", buffer, GetLastError()); + wait_and_close_child_process(&info); + + reload_child_info(resfile); sprintf(buffer, "./%s", exename); + okChildInt("Arguments", "argcA", 5); okChildString("Arguments", "argvA0", buffer); + okChildString("Arguments", "argvA4", "\""); + okChildString("Arguments", "argvA5", NULL); release_memory(); DeleteFileA(resfile); get_file_name(resfile); /* Use exename to avoid buffer containing things like 'C:' */ - sprintf(buffer, ".\\%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename, resfile); + sprintf(buffer, ".\\%s process dump \"%s\"", 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()); - /* 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); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + ok(ret, "CreateProcess (%s) failed : %ld\n", buffer, GetLastError()); + wait_and_close_child_process(&info); + + reload_child_info(resfile); sprintf(buffer, ".\\%s", exename); okChildString("Arguments", "argvA0", buffer); release_memory(); DeleteFileA(resfile); get_file_name(resfile); - 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 tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", p, exename, resfile); - else sprintf(buffer, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename, resfile); + if (p) sprintf(buffer, "..%s/%s process dump \"%s\"", p, exename, resfile); + else sprintf(buffer, "./%s process dump \"%s\"", 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()); - /* 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); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + ok(ret, "CreateProcess (%s) failed : %ld\n", buffer, GetLastError()); + wait_and_close_child_process(&info); + + reload_child_info(resfile); if (p) sprintf(buffer, "..%s/%s", p, exename); else sprintf(buffer, "./%s", exename); okChildString("Arguments", "argvA0", buffer); @@ -1008,22 +1060,19 @@ static void test_CommandLine(void) /* 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 dump \"%s\" \"a\\\"b\\\\\" c\\\" d", resfile); + sprintf(buffer2, "dummy process dump \"%s\"", 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); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); - sprintf(buffer, "tests/process.c dump %s", resfile); + ok(ret, "CreateProcess (%s) failed : %ld\n", buffer, GetLastError()); + wait_and_close_child_process(&info); + + reload_child_info(resfile); okChildString("Arguments", "argvA0", "dummy"); okChildString("Arguments", "CommandLineA", buffer2); okChildStringWA("Arguments", "CommandLineW", buffer2); release_memory(); DeleteFileA(resfile); + SetCurrentDirectoryA( base ); if (0) /* Test crashes on NT-based Windows. */ { @@ -1032,7 +1081,7 @@ static void test_CommandLine(void) ret = CreateProcessA(NULL, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); ok(!ret, "CreateProcessA unexpectedly succeeded\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); } buffer[0] = '\0'; @@ -1044,7 +1093,7 @@ static void test_CommandLine(void) ok(GetLastError() == ERROR_PATH_NOT_FOUND || broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* Win9x/WinME */ || broken(GetLastError() == ERROR_ACCESS_DENIED) /* Win98 */, - "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError()); + "Expected ERROR_PATH_NOT_FOUND, got %ld\n", GetLastError()); buffer2[0] = '\0'; @@ -1055,7 +1104,7 @@ static void test_CommandLine(void) ok(GetLastError() == ERROR_PATH_NOT_FOUND || broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* Win9x/WinME */ || broken(GetLastError() == ERROR_ACCESS_DENIED) /* Win98 */, - "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError()); + "Expected ERROR_PATH_NOT_FOUND, got %ld\n", GetLastError()); /* Test empty command line parameter. */ SetLastError(0xdeadbeef); @@ -1065,7 +1114,7 @@ static void test_CommandLine(void) GetLastError() == ERROR_PATH_NOT_FOUND /* NT4 */ || GetLastError() == ERROR_BAD_PATHNAME /* Win98 */ || GetLastError() == ERROR_INVALID_PARAMETER /* Win7 */, - "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError()); strcpy(buffer, "doesnotexist.exe"); strcpy(buffer2, "does not exist.exe"); @@ -1074,28 +1123,38 @@ static void test_CommandLine(void) SetLastError(0xdeadbeef); ret = CreateProcessA(buffer, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); ok(!ret, "CreateProcessA unexpectedly succeeded\n"); - ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = CreateProcessA(buffer2, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); ok(!ret, "CreateProcessA unexpectedly succeeded\n"); - ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError()); /* Test nonexistent command line parameter. */ SetLastError(0xdeadbeef); ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); ok(!ret, "CreateProcessA unexpectedly succeeded\n"); - ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = CreateProcessA(NULL, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); ok(!ret, "CreateProcessA unexpectedly succeeded\n"); - ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError()); + + /* Test whether GetCommandLineW reads directly from TEB or from a cached address */ + cmdline = GetCommandLineW(); + ok(cmdline == NtCurrentTeb()->Peb->ProcessParameters->CommandLine.Buffer, "Expected address from TEB, got %p\n", cmdline); + + cmdline_backup = cmdline; + NtCurrentTeb()->Peb->ProcessParameters->CommandLine.Buffer = NULL; + cmdline = GetCommandLineW(); + ok(cmdline == cmdline_backup, "Expected cached address from TEB, got %p\n", cmdline); + NtCurrentTeb()->Peb->ProcessParameters->CommandLine.Buffer = cmdline_backup; } static void test_Directory(void) { - char buffer[MAX_PATH]; + char buffer[2 * MAX_PATH + 25]; PROCESS_INFORMATION info; STARTUPINFOA startup; char windir[MAX_PATH]; @@ -1108,16 +1167,12 @@ static void test_Directory(void) /* the basics */ get_file_name(resfile); - sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); + sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile); GetWindowsDirectoryA( windir, sizeof(windir) ); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, windir, &startup, &info), "CreateProcess\n"); - /* 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); - CloseHandle(info.hThread); - CloseHandle(info.hProcess); + wait_and_close_child_process(&info); + reload_child_info(resfile); okChildIString("Misc", "CurrDirA", windir); release_memory(); DeleteFileA(resfile); @@ -1133,42 +1188,36 @@ static void test_Directory(void) memset(&info, 0, sizeof(info)); ok(!CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0L, NULL, "non\\existent\\directory", &startup, &info), "CreateProcess\n"); - ok(GetLastError() == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %ld\n", GetLastError()); ok(!TerminateProcess(info.hProcess, 0), "Child process should not exist\n"); } static void test_Toolhelp(void) { - char buffer[MAX_PATH]; +#if defined(__REACTOS__) && defined(_WIN64) + skip("test_Toolhelp() times out on x86_64.\n"); +#else + char buffer[2 * MAX_PATH + 27]; STARTUPINFOA startup; PROCESS_INFORMATION info; HANDLE process, thread, snapshot; + DWORD nested_pid; PROCESSENTRY32 pe; THREADENTRY32 te; DWORD ret; int i; -#if defined(__REACTOS__) && defined(_M_AMD64) - if (!winetest_interactive) - { - skip("ROSTESTS-372: Skipping test in kernel32_winetest:process test_Toolhelp because it leaves a process behind on Windows Server 2003 x64-Testbot. Set winetest_interactive to run it anyway.\n"); - //return; - } -#endif - memset(&startup, 0, sizeof(startup)); startup.cb = sizeof(startup); startup.dwFlags = STARTF_USESHOWWINDOW; startup.wShowWindow = SW_SHOWNORMAL; get_file_name(resfile); - sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); + sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n"); - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - CloseHandle(info.hProcess); - CloseHandle(info.hThread); + wait_and_close_child_process(&info); - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); + reload_child_info(resfile); okChildInt("Toolhelp", "cntUsage", 0); okChildInt("Toolhelp", "th32DefaultHeapID", 0); okChildInt("Toolhelp", "th32ModuleID", 0); @@ -1179,35 +1228,23 @@ static void test_Toolhelp(void) release_memory(); DeleteFileA(resfile); -#if defined(__REACTOS__) && defined(_M_AMD64) - if (!winetest_interactive) - { - skip("ROSTESTS-371: Skipping kernel32_winetest:sync test_apc_deadlock because it fails on Windows Server 2003 x64-Testbot. Set winetest_interactive to run it anyway.\n"); - } - else - { -#endif - get_file_name(resfile); - sprintf(buffer, "\"%s\" tests/process.c nested \"%s\"", selfname, resfile); + sprintf(buffer, "\"%s\" process nested \"%s\"", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n"); - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); + wait_child_process(info.hProcess); process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, info.dwProcessId); - ok(process != NULL, "OpenProcess failed %u\n", GetLastError()); + ok(process != NULL, "OpenProcess failed %lu\n", GetLastError()); CloseHandle(process); CloseHandle(info.hProcess); CloseHandle(info.hThread); -#if defined(__REACTOS__) && defined(_M_AMD64) - } -#endif for (i = 0; i < 20; i++) { SetLastError(0xdeadbeef); process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, info.dwProcessId); - ok(process || GetLastError() == ERROR_INVALID_PARAMETER, "OpenProcess failed %u\n", GetLastError()); + ok(process || GetLastError() == ERROR_INVALID_PARAMETER, "OpenProcess failed %lu\n", GetLastError()); if (!process) break; CloseHandle(process); Sleep(100); @@ -1215,23 +1252,30 @@ static void test_Toolhelp(void) /* The following test fails randomly on some Windows versions, but Gothic 2 depends on it */ ok(i < 20 || broken(i == 20), "process object not released\n"); + /* Look for the nested process by pid */ + reload_child_info(resfile); + nested_pid = GetPrivateProfileIntA("Nested", "Pid", 0, resfile); + DeleteFileA(resfile); + snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError()); + ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %lu\n", GetLastError()); memset(&pe, 0, sizeof(pe)); pe.dwSize = sizeof(pe); if (pProcess32First(snapshot, &pe)) { - while (pe.th32ParentProcessID != info.dwProcessId) + while (pe.th32ProcessID != nested_pid) if (!pProcess32Next(snapshot, &pe)) break; } CloseHandle(snapshot); - ok(pe.th32ParentProcessID == info.dwProcessId, "failed to find nested child process\n"); + ok(pe.th32ProcessID == nested_pid, "failed to find nested child process\n"); + ok(pe.th32ParentProcessID == info.dwProcessId, "nested child process has parent %lu instead of %lu\n", pe.th32ParentProcessID, info.dwProcessId); + ok(stricmp(pe.szExeFile, exename) == 0, "nested executable is %s instead of %s\n", pe.szExeFile, exename); process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, pe.th32ProcessID); - ok(process != NULL, "OpenProcess failed %u\n", GetLastError()); + ok(process != NULL, "OpenProcess failed %lu\n", GetLastError()); snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); - ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError()); + ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %lu\n", GetLastError()); memset(&te, 0, sizeof(te)); te.dwSize = sizeof(te); if (pThread32First(snapshot, &te)) @@ -1243,15 +1287,15 @@ static void test_Toolhelp(void) ok(te.th32OwnerProcessID == pe.th32ProcessID, "failed to find suspended thread\n"); thread = OpenThread(THREAD_ALL_ACCESS_NT4, FALSE, te.th32ThreadID); - ok(thread != NULL, "OpenThread failed %u\n", GetLastError()); + ok(thread != NULL, "OpenThread failed %lu\n", GetLastError()); ret = ResumeThread(thread); - ok(ret == 1, "expected 1, got %u\n", ret); + ok(ret == 1, "expected 1, got %lu\n", ret); CloseHandle(thread); - ok(WaitForSingleObject(process, 30000) == WAIT_OBJECT_0, "Child process termination\n"); + wait_child_process(process); CloseHandle(process); - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); + reload_child_info(resfile); okChildInt("Toolhelp", "cntUsage", 0); okChildInt("Toolhelp", "th32DefaultHeapID", 0); okChildInt("Toolhelp", "th32ModuleID", 0); @@ -1261,6 +1305,7 @@ static void test_Toolhelp(void) release_memory(); DeleteFileA(resfile); +#endif } static BOOL is_str_env_drive_dir(const char* str) @@ -1328,7 +1373,7 @@ static void cmpEnvironment(const char* gesA) static void test_Environment(void) { - char buffer[MAX_PATH]; + char buffer[2 * MAX_PATH + 25]; PROCESS_INFORMATION info; STARTUPINFOA startup; char *child_env; @@ -1345,13 +1390,11 @@ static void test_Environment(void) /* the basics */ get_file_name(resfile); - sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); + sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); - /* 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); + wait_and_close_child_process(&info); + reload_child_info(resfile); env = GetEnvironmentStringsA(); cmpEnvironment(env); release_memory(); @@ -1364,7 +1407,7 @@ static void test_Environment(void) /* the basics */ get_file_name(resfile); - sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); + sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile); child_env_len = 0; ptr = env; @@ -1388,14 +1431,12 @@ static void test_Environment(void) strcpy(ptr, "BAR=FOOBAR"); ptr += strlen(ptr) + 1; /* copy all existing variables except: - * - WINELOADER * - PATH (already set above) * - the directory definitions (=[A-Z]:=) */ for (ptr2 = env; *ptr2; ptr2 += strlen(ptr2) + 1) { if (strncmp(ptr2, "PATH=", 5) != 0 && - strncmp(ptr2, "WINELOADER=", 11) != 0 && !is_str_env_drive_dir(ptr2)) { strcpy(ptr, ptr2); @@ -1404,11 +1445,9 @@ static void test_Environment(void) } *ptr = '\0'; ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, child_env, NULL, &startup, &info), "CreateProcess\n"); - /* 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); + wait_and_close_child_process(&info); + reload_child_info(resfile); cmpEnvironment(child_env); HeapFree(GetProcessHeap(), 0, child_env); @@ -1419,7 +1458,7 @@ static void test_Environment(void) static void test_SuspendFlag(void) { - char buffer[MAX_PATH]; + char buffer[2 * MAX_PATH + 25]; PROCESS_INFORMATION info; STARTUPINFOA startup, us; DWORD exit_status; @@ -1432,21 +1471,19 @@ static void test_SuspendFlag(void) startup.wShowWindow = SW_SHOWNORMAL; get_file_name(resfile); - sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); + sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &info), "CreateProcess\n"); ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n"); - Sleep(1000); + Sleep(100); ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n"); ok(ResumeThread(info.hThread) == 1, "Resuming thread\n"); - /* 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); + wait_and_close_child_process(&info); GetStartupInfoA(&us); + reload_child_info(resfile); okChildInt("StartupInfoA", "cb", startup.cb); okChildString("StartupInfoA", "lpDesktop", us.lpDesktop); result = getChildString( "StartupInfoA", "lpTitle" ); @@ -1467,7 +1504,7 @@ static void test_SuspendFlag(void) static void test_DebuggingFlag(void) { - char buffer[MAX_PATH]; + char buffer[2 * MAX_PATH + 25]; void *processbase = NULL; PROCESS_INFORMATION info; STARTUPINFOA startup, us; @@ -1482,7 +1519,7 @@ static void test_DebuggingFlag(void) startup.wShowWindow = SW_SHOWNORMAL; get_file_name(resfile); - sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); + sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n"); /* get all startup events up to the entry point break exception */ @@ -1493,7 +1530,7 @@ static void test_DebuggingFlag(void) if (!dbg) { ok(de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT, - "first event: %d\n", de.dwDebugEventCode); + "first event: %ld\n", de.dwDebugEventCode); processbase = de.u.CreateProcessInfo.lpBaseOfImage; } if (de.dwDebugEventCode != EXCEPTION_DEBUG_EVENT) dbg++; @@ -1502,13 +1539,11 @@ static void test_DebuggingFlag(void) } while (de.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT); ok(dbg, "I have seen a debug event\n"); - /* 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); + wait_and_close_child_process(&info); GetStartupInfoA(&us); + reload_child_info(resfile); okChildInt("StartupInfoA", "cb", startup.cb); okChildString("StartupInfoA", "lpDesktop", us.lpDesktop); result = getChildString( "StartupInfoA", "lpTitle" ); @@ -1527,14 +1562,9 @@ static void test_DebuggingFlag(void) DeleteFileA(resfile); } -static BOOL is_console(HANDLE h) -{ - return h != INVALID_HANDLE_VALUE && ((ULONG_PTR)h & 3) == 3; -} - static void test_Console(void) { - char buffer[MAX_PATH]; + char buffer[2 * MAX_PATH + 35]; PROCESS_INFORMATION info; STARTUPINFOA startup, us; SECURITY_ATTRIBUTES sa; @@ -1561,8 +1591,13 @@ static void test_Console(void) startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0); /* first, we need to be sure we're attached to a console */ - if (!is_console(startup.hStdInput) || !is_console(startup.hStdOutput)) + if (startup.hStdInput == INVALID_HANDLE_VALUE || startup.hStdOutput == INVALID_HANDLE_VALUE) { + /* this fails either when this test process is run detached from console + * (unlikely, as this very process must be explicitly created with detached flag), + * or is attached to a Wine's shell-no-window kind of console (if the later, detach from it) + */ + FreeConsole(); /* we're not attached to a console, let's do it */ AllocConsole(); startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0); @@ -1580,14 +1615,11 @@ static void test_Console(void) cpOut = GetConsoleOutputCP(); get_file_name(resfile); - sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" console", selfname, resfile); + sprintf(buffer, "\"%s\" process dump \"%s\" console", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &info), "CreateProcess\n"); + wait_and_close_child_process(&info); - /* 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); - + reload_child_info(resfile); /* now get the modification the child has made, and resets parents expected values */ ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbiC), "Getting sb info\n"); ok(GetConsoleMode(startup.hStdInput, &modeInC), "Getting console in mode\n"); @@ -1596,6 +1628,10 @@ static void test_Console(void) SetConsoleMode(startup.hStdInput, modeIn); SetConsoleMode(startup.hStdOutput, modeOut); + /* don't test flag that is changed at startup if WINETEST_COLOR is set */ + modeOut = (modeOut & ~ENABLE_VIRTUAL_TERMINAL_PROCESSING) | + (modeOutC & ENABLE_VIRTUAL_TERMINAL_PROCESSING); + cpInC = GetConsoleCP(); cpOutC = GetConsoleOutputCP(); @@ -1604,7 +1640,7 @@ static void test_Console(void) ok(!SetConsoleCP(0), "Shouldn't succeed\n"); ok(GetLastError()==ERROR_INVALID_PARAMETER || broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */ - "GetLastError: expecting %u got %u\n", + "GetLastError: expecting %u got %lu\n", ERROR_INVALID_PARAMETER, GetLastError()); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) run_tests = FALSE; @@ -1614,7 +1650,7 @@ static void test_Console(void) ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n"); ok(GetLastError()==ERROR_INVALID_PARAMETER || broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */ - "GetLastError: expecting %u got %u\n", + "GetLastError: expecting %u got %lu\n", ERROR_INVALID_PARAMETER, GetLastError()); SetConsoleCP(cpIn); @@ -1659,16 +1695,14 @@ static void test_Console(void) 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); + ok(cpInC == 1252, "Wrong console CP (expected 1252 got %ld/%ld)\n", cpInC, cpIn); + ok(cpOutC == 1252, "Wrong console-SB CP (expected 1252 got %ld/%ld)\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); - ok(sbiC.dwCursorPosition.Y == (sbi.dwCursorPosition.Y ^ 1), "Wrong cursor position\n"); release_memory(); DeleteFileA(resfile); @@ -1694,14 +1728,14 @@ static void test_Console(void) startup.hStdError = hChildOutInh; get_file_name(resfile); - sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" stdhandle", selfname, resfile); + sprintf(buffer, "\"%s\" process dump \"%s\" stdhandle", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n"); ok(CloseHandle(hChildInInh), "Closing handle\n"); ok(CloseHandle(hChildOutInh), "Closing handle\n"); msg_len = strlen(msg) + 1; ok(WriteFile(hParentOut, msg, msg_len, &w, NULL), "Writing to child\n"); - ok(w == msg_len, "Should have written %u bytes, actually wrote %u\n", msg_len, w); + ok(w == msg_len, "Should have written %u bytes, actually wrote %lu\n", msg_len, w); memset(buffer, 0, sizeof(buffer)); ok(ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL), "Reading from child\n"); ok(strcmp(buffer, msg) == 0, "Should have received '%s'\n", msg); @@ -1709,11 +1743,9 @@ static void test_Console(void) /* the child may also send the final "n tests executed" string, so read it to avoid a deadlock */ ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL); - /* 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); + wait_and_close_child_process(&info); + reload_child_info(resfile); okChildString("StdHandle", "msg", msg); release_memory(); @@ -1722,7 +1754,7 @@ static void test_Console(void) static void test_ExitCode(void) { - char buffer[MAX_PATH]; + char buffer[2 * MAX_PATH + 35]; PROCESS_INFORMATION info; STARTUPINFOA startup; DWORD code; @@ -1734,14 +1766,13 @@ static void test_ExitCode(void) startup.wShowWindow = SW_SHOWNORMAL; get_file_name(resfile); - sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" exit_code", selfname, resfile); + sprintf(buffer, "\"%s\" process dump \"%s\" exit_code", selfname, resfile); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info), "CreateProcess\n"); - /* wait for child to terminate */ + /* not wait_child_process() because of the exit code */ 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); + reload_child_info(resfile); ok(GetExitCodeProcess(info.hProcess, &code), "Getting exit code\n"); okChildInt("ExitCode", "value", code); @@ -1757,18 +1788,12 @@ static void test_OpenProcess(void) SIZE_T dummy, read_bytes; BOOL ret; - /* not exported in all windows versions */ - if ((!pVirtualAllocEx) || (!pVirtualFreeEx)) { - win_skip("VirtualAllocEx not found\n"); - return; - } - /* without PROCESS_VM_OPERATION */ hproc = OpenProcess(PROCESS_ALL_ACCESS_NT4 & ~PROCESS_VM_OPERATION, FALSE, GetCurrentProcessId()); - ok(hproc != NULL, "OpenProcess error %d\n", GetLastError()); + ok(hproc != NULL, "OpenProcess error %ld\n", GetLastError()); SetLastError(0xdeadbeef); - addr1 = pVirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS); + addr1 = VirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS); ok(!addr1, "VirtualAllocEx should fail\n"); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { /* Win9x */ @@ -1776,35 +1801,35 @@ static void test_OpenProcess(void) win_skip("VirtualAllocEx not implemented\n"); return; } - ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError()); + ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %ld\n", GetLastError()); read_bytes = 0xdeadbeef; SetLastError(0xdeadbeef); ret = ReadProcessMemory(hproc, test_OpenProcess, &dummy, sizeof(dummy), &read_bytes); - ok(ret, "ReadProcessMemory error %d\n", GetLastError()); - ok(read_bytes == sizeof(dummy), "wrong read bytes %ld\n", read_bytes); + ok(ret, "ReadProcessMemory error %ld\n", GetLastError()); + ok(read_bytes == sizeof(dummy), "wrong read bytes %Id\n", read_bytes); CloseHandle(hproc); hproc = OpenProcess(PROCESS_VM_OPERATION, FALSE, GetCurrentProcessId()); - ok(hproc != NULL, "OpenProcess error %d\n", GetLastError()); + ok(hproc != NULL, "OpenProcess error %ld\n", GetLastError()); - addr1 = pVirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS); - ok(addr1 != NULL, "VirtualAllocEx error %d\n", GetLastError()); + addr1 = VirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS); + ok(addr1 != NULL, "VirtualAllocEx error %ld\n", GetLastError()); /* without PROCESS_QUERY_INFORMATION */ SetLastError(0xdeadbeef); ok(!VirtualQueryEx(hproc, addr1, &info, sizeof(info)), "VirtualQueryEx without PROCESS_QUERY_INFORMATION rights should fail\n"); - ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError()); + ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %ld\n", GetLastError()); /* without PROCESS_VM_READ */ read_bytes = 0xdeadbeef; SetLastError(0xdeadbeef); ok(!ReadProcessMemory(hproc, addr1, &dummy, sizeof(dummy), &read_bytes), "ReadProcessMemory without PROCESS_VM_READ rights should fail\n"); - ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError()); - ok(read_bytes == 0, "wrong read bytes %ld\n", read_bytes); + ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %ld\n", GetLastError()); + ok(read_bytes == 0, "wrong read bytes %Id\n", read_bytes); CloseHandle(hproc); @@ -1812,23 +1837,23 @@ static void test_OpenProcess(void) memset(&info, 0xcc, sizeof(info)); read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info)); - ok(read_bytes == sizeof(info), "VirtualQueryEx error %d\n", GetLastError()); + ok(read_bytes == sizeof(info), "VirtualQueryEx error %ld\n", GetLastError()); ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1); ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1); - ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect); - ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize); - ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State); + ok(info.AllocationProtect == PAGE_NOACCESS, "%lx != PAGE_NOACCESS\n", info.AllocationProtect); + ok(info.RegionSize == 0x10000, "%Ix != 0x10000\n", info.RegionSize); + ok(info.State == MEM_RESERVE, "%lx != MEM_RESERVE\n", info.State); /* NT reports Protect == 0 for a not committed memory block */ ok(info.Protect == 0 /* NT */ || info.Protect == PAGE_NOACCESS, /* Win9x */ - "%x != PAGE_NOACCESS\n", info.Protect); - ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type); + "%lx != PAGE_NOACCESS\n", info.Protect); + ok(info.Type == MEM_PRIVATE, "%lx != MEM_PRIVATE\n", info.Type); SetLastError(0xdeadbeef); - ok(!pVirtualFreeEx(hproc, addr1, 0, MEM_RELEASE), + ok(!VirtualFreeEx(hproc, addr1, 0, MEM_RELEASE), "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n"); - ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError()); + ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %ld\n", GetLastError()); CloseHandle(hproc); @@ -1840,22 +1865,22 @@ static void test_OpenProcess(void) read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info)); if (read_bytes) /* win8 */ { - ok(read_bytes == sizeof(info), "VirtualQueryEx error %d\n", GetLastError()); + ok(read_bytes == sizeof(info), "VirtualQueryEx error %ld\n", GetLastError()); ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1); ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1); - ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect); - ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize); - ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State); - ok(info.Protect == 0, "%x != PAGE_NOACCESS\n", info.Protect); - ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type); + ok(info.AllocationProtect == PAGE_NOACCESS, "%lx != PAGE_NOACCESS\n", info.AllocationProtect); + ok(info.RegionSize == 0x10000, "%Ix != 0x10000\n", info.RegionSize); + ok(info.State == MEM_RESERVE, "%lx != MEM_RESERVE\n", info.State); + ok(info.Protect == 0, "%lx != PAGE_NOACCESS\n", info.Protect); + ok(info.Type == MEM_PRIVATE, "%lx != MEM_PRIVATE\n", info.Type); } else /* before win8 */ - ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError()); + ok(broken(GetLastError() == ERROR_ACCESS_DENIED), "wrong error %ld\n", GetLastError()); SetLastError(0xdeadbeef); - ok(!pVirtualFreeEx(hproc, addr1, 0, MEM_RELEASE), + ok(!VirtualFreeEx(hproc, addr1, 0, MEM_RELEASE), "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n"); - ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError()); + ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %ld\n", GetLastError()); CloseHandle(hproc); } @@ -1872,11 +1897,11 @@ static void test_GetProcessVersion(void) SetLastError(0xdeadbeef); ret = GetProcessVersion(0); - ok(ret, "GetProcessVersion error %u\n", GetLastError()); + ok(ret, "GetProcessVersion error %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = GetProcessVersion(GetCurrentProcessId()); - ok(ret, "GetProcessVersion error %u\n", GetLastError()); + ok(ret, "GetProcessVersion error %lu\n", GetLastError()); memset(&si, 0, sizeof(si)); si.cb = sizeof(si); @@ -1884,15 +1909,15 @@ static void test_GetProcessVersion(void) si.wShowWindow = SW_HIDE; SetLastError(0xdeadbeef); ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); - ok(ret, "CreateProcess error %u\n", GetLastError()); + ok(ret, "CreateProcess error %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = GetProcessVersion(pi.dwProcessId); - ok(ret, "GetProcessVersion error %u\n", GetLastError()); + ok(ret, "GetProcessVersion error %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = TerminateProcess(pi.hProcess, 0); - ok(ret, "TerminateProcess error %u\n", GetLastError()); + ok(ret, "TerminateProcess error %lu\n", GetLastError()); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); @@ -1914,7 +1939,7 @@ static void test_GetProcessImageFileNameA(void) SetLastError(0xdeadbeef); rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), NULL, 0); ok(!rc && GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "K32GetProcessImageFileNameA(no buffer): returned %u, le=%u\n", rc, GetLastError()); + "K32GetProcessImageFileNameA(no buffer): returned %lu, le=%lu\n", rc, GetLastError()); *process = '\0'; rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), process, sizeof(process)); @@ -1954,7 +1979,7 @@ static void test_QueryFullProcessImageNameA(void) *module = '\0'; SetLastError(0); /* old Windows don't reset it on success */ size = GetModuleFileNameA(NULL, module, sizeof(module)); - ok(size && GetLastError() != ERROR_INSUFFICIENT_BUFFER, "GetModuleFileName failed: %u le=%u\n", size, GetLastError()); + ok(size && GetLastError() != ERROR_INSUFFICIENT_BUFFER, "GetModuleFileName failed: %lu le=%lu\n", size, GetLastError()); /* get the buffer length without \0 terminator */ length = sizeof(buf); @@ -1984,9 +2009,9 @@ static void test_QueryFullProcessImageNameA(void) expect_eq_d(4, size); expect_eq_s(INIT_STR, buf); - /* this is a difference between the ascii and the unicode version + /* this is a difference between the ansi and the unicode version * the unicode version crashes when the size is big enough to hold - * the result while the ascii version throws an error + * the result while the ansi version throws an error */ size = 1024; expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL, &size)); @@ -2001,6 +2026,7 @@ static void test_QueryFullProcessImageNameW(void) WCHAR deviceW[] = {'\\','D', 'e','v','i','c','e',0}; WCHAR buf[1024]; DWORD size, len; + DWORD flags; if (!pQueryFullProcessImageNameW) { @@ -2011,14 +2037,14 @@ static void test_QueryFullProcessImageNameW(void) ok(GetModuleFileNameW(NULL, module_name, 1024), "GetModuleFileNameW(NULL, ...) failed\n"); /* GetCurrentProcess pseudo-handle */ - size = sizeof(buf) / sizeof(buf[0]); + size = ARRAY_SIZE(buf); expect_eq_d(TRUE, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf, &size)); expect_eq_d(lstrlenW(buf), size); expect_eq_ws_i(buf, module_name); hSelf = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId()); /* Real handle */ - size = sizeof(buf) / sizeof(buf[0]); + size = ARRAY_SIZE(buf); expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size)); expect_eq_d(lstrlenW(buf), size); expect_eq_ws_i(buf, module_name); @@ -2054,9 +2080,36 @@ static void test_QueryFullProcessImageNameW(void) expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError()); expect_eq_ws_i(module_name, buf); /* buffer not changed */ + /* Invalid flags - a few arbitrary values only */ + for (flags = 2; flags <= 15; ++flags) + { + size = ARRAY_SIZE(buf); + SetLastError(0xdeadbeef); + *(DWORD*)buf = 0x13579acf; + todo_wine + { + expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, flags, buf, &size)); + expect_eq_d((DWORD)ARRAY_SIZE(buf), size); /* size not changed */ + expect_eq_d(ERROR_INVALID_PARAMETER, GetLastError()); + expect_eq_d(0x13579acf, *(DWORD*)buf); /* buffer not changed */ + } + } + for (flags = 16; flags != 0; flags <<= 1) + { + size = ARRAY_SIZE(buf); + SetLastError(0xdeadbeef); + *(DWORD*)buf = 0x13579acf; + todo_wine + { + expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, flags, buf, &size)); + expect_eq_d((DWORD)ARRAY_SIZE(buf), size); /* size not changed */ + expect_eq_d(ERROR_INVALID_PARAMETER, GetLastError()); + expect_eq_d(0x13579acf, *(DWORD*)buf); /* buffer not changed */ + } + } /* native path */ - size = sizeof(buf) / sizeof(buf[0]); + size = ARRAY_SIZE(buf); expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, PROCESS_NAME_NATIVE, buf, &size)); expect_eq_d(lstrlenW(buf), size); ok(buf[0] == '\\', "NT path should begin with '\\'\n"); @@ -2064,10 +2117,10 @@ static void test_QueryFullProcessImageNameW(void) module_name[2] = '\0'; *device = '\0'; - size = QueryDosDeviceW(module_name, device, sizeof(device)/sizeof(device[0])); - ok(size, "QueryDosDeviceW failed: le=%u\n", GetLastError()); + size = QueryDosDeviceW(module_name, device, ARRAY_SIZE(device)); + ok(size, "QueryDosDeviceW failed: le=%lu\n", GetLastError()); len = lstrlenW(device); - ok(size >= len+2, "expected %d to be greater than %d+2 = strlen(%s)\n", size, len, wine_dbgstr_w(device)); + ok(size >= len+2, "expected %ld to be greater than %ld+2 = strlen(%s)\n", size, len, wine_dbgstr_w(device)); if (size >= lstrlenW(buf)) { @@ -2095,25 +2148,25 @@ static void test_Handles(void) 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() ); + ok( ret, "GetExitCodeProcess failed err %lu\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() ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %lu\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() ); + ok( ret, "GetExitCodeProcess failed err %lu\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() ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %lu\n", GetLastError() ); #endif handle = GetStdHandle( STD_ERROR_HANDLE ); @@ -2141,7 +2194,7 @@ static void test_IsWow64Process(void) if (!pIsWow64Process) { - skip("IsWow64Process is not available\n"); + win_skip("IsWow64Process is not available\n"); return; } @@ -2186,10 +2239,123 @@ static void test_IsWow64Process(void) } } +static void test_IsWow64Process2(void) +{ + PROCESS_INFORMATION pi; + STARTUPINFOA si; + BOOL ret, is_wow64; + USHORT machine, native_machine; + static char cmdline[] = "C:\\Program Files\\Internet Explorer\\iexplore.exe"; + static char cmdline_wow64[] = "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe"; +#ifdef __i386__ + USHORT expect_native = IMAGE_FILE_MACHINE_I386; +#elif defined __x86_64__ + USHORT expect_native = IMAGE_FILE_MACHINE_AMD64; +#elif defined __arm__ + USHORT expect_native = IMAGE_FILE_MACHINE_ARMNT; +#elif defined __aarch64__ + USHORT expect_native = IMAGE_FILE_MACHINE_ARM64; +#else + USHORT expect_native = 0; +#endif + + if (!pIsWow64Process2) + { + win_skip("IsWow64Process2 is not available\n"); + return; + } + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + SetLastError(0xdeadbeef); + ret = CreateProcessA(cmdline_wow64, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi); + if (ret) + { + SetLastError(0xdeadbeef); + machine = native_machine = 0xdead; + ret = pIsWow64Process2(pi.hProcess, &machine, &native_machine); + ok(ret, "IsWow64Process2 error %lu\n", GetLastError()); + +#if defined(__i386__) || defined(__x86_64__) + ok(machine == IMAGE_FILE_MACHINE_I386, "got %#x\n", machine); + ok( native_machine == IMAGE_FILE_MACHINE_AMD64 || + native_machine == IMAGE_FILE_MACHINE_ARM64, "got %#x\n", native_machine); + expect_native = native_machine; +#else + skip("not supported architecture\n"); +#endif + ret = TerminateProcess(pi.hProcess, 0); + ok(ret, "TerminateProcess error\n"); + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + SetLastError(0xdeadbeef); + ret = CreateProcessA(cmdline, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi); + ok(ret, "CreateProcess error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = pIsWow64Process(pi.hProcess, &is_wow64); + ok(ret, "IsWow64Process error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + machine = native_machine = 0xdead; + ret = pIsWow64Process2(pi.hProcess, &machine, &native_machine); + ok(ret, "IsWow64Process2 error %lu\n", GetLastError()); + + ok(machine == IMAGE_FILE_MACHINE_UNKNOWN, "got %#x\n", machine); + ok(native_machine == expect_native, "got %#x\n", native_machine); + + SetLastError(0xdeadbeef); + machine = 0xdead; + ret = pIsWow64Process2(pi.hProcess, &machine, NULL); + ok(ret, "IsWow64Process2 error %lu\n", GetLastError()); + ok(machine == IMAGE_FILE_MACHINE_UNKNOWN, "got %#x\n", machine); + + ret = TerminateProcess(pi.hProcess, 0); + ok(ret, "TerminateProcess error\n"); + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + + SetLastError(0xdeadbeef); + ret = pIsWow64Process(GetCurrentProcess(), &is_wow64); + ok(ret, "IsWow64Process error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + machine = native_machine = 0xdead; + ret = pIsWow64Process2(GetCurrentProcess(), &machine, &native_machine); + ok(ret, "IsWow64Process2 error %lu\n", GetLastError()); + + if (is_wow64) + { + ok(machine == IMAGE_FILE_MACHINE_I386, "got %#x\n", machine); + ok(native_machine == expect_native, "got %#x\n", native_machine); + } + else + { + ok(machine == IMAGE_FILE_MACHINE_UNKNOWN, "got %#x\n", machine); + ok(native_machine == expect_native, "got %#x\n", native_machine); + } + + SetLastError(0xdeadbeef); + machine = 0xdead; + ret = pIsWow64Process2(GetCurrentProcess(), &machine, NULL); + ok(ret, "IsWow64Process2 error %lu\n", GetLastError()); + if (is_wow64) + ok(machine == IMAGE_FILE_MACHINE_I386, "got %#x\n", machine); + else + ok(machine == IMAGE_FILE_MACHINE_UNKNOWN, "got %#x\n", machine); +} + static void test_SystemInfo(void) { SYSTEM_INFO si, nsi; BOOL is_wow64; + USHORT machine, native_machine; if (!pGetNativeSystemInfo) { @@ -2203,27 +2369,49 @@ static void test_SystemInfo(void) pGetNativeSystemInfo(&nsi); if (is_wow64) { - if (S(U(si)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) + if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) { - ok(S(U(nsi)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64, + ok(nsi.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64, "Expected PROCESSOR_ARCHITECTURE_AMD64, got %d\n", - S(U(nsi)).wProcessorArchitecture); - ok(nsi.dwProcessorType == PROCESSOR_AMD_X8664, - "Expected PROCESSOR_AMD_X8664, got %d\n", - nsi.dwProcessorType); + nsi.wProcessorArchitecture); + if (pIsWow64Process2 && pIsWow64Process2(GetCurrentProcess(), &machine, &native_machine) && + native_machine == IMAGE_FILE_MACHINE_ARM64) + { + ok(nsi.dwProcessorType == PROCESSOR_INTEL_PENTIUM, "got %ld\n", nsi.dwProcessorType); + ok(nsi.wProcessorLevel == 15, "got %d\n", nsi.wProcessorLevel); + ok(nsi.wProcessorRevision == 0x40a, "got %d\n", nsi.wProcessorRevision); + } + else ok(nsi.dwProcessorType == PROCESSOR_AMD_X8664, "got %ld\n", nsi.dwProcessorType); } } else { - ok(S(U(si)).wProcessorArchitecture == S(U(nsi)).wProcessorArchitecture, + ok(si.wProcessorArchitecture == nsi.wProcessorArchitecture, "Expected no difference for wProcessorArchitecture, got %d and %d\n", - S(U(si)).wProcessorArchitecture, S(U(nsi)).wProcessorArchitecture); + si.wProcessorArchitecture, nsi.wProcessorArchitecture); ok(si.dwProcessorType == nsi.dwProcessorType, - "Expected no difference for dwProcessorType, got %d and %d\n", + "Expected no difference for dwProcessorType, got %ld and %ld\n", si.dwProcessorType, nsi.dwProcessorType); } } +static void test_ProcessorCount(void) +{ + DWORD active, maximum; + + if (!pGetActiveProcessorCount || !pGetMaximumProcessorCount) + { + win_skip("GetActiveProcessorCount or GetMaximumProcessorCount is not available\n"); + return; + } + + active = pGetActiveProcessorCount(ALL_PROCESSOR_GROUPS); + maximum = pGetMaximumProcessorCount(ALL_PROCESSOR_GROUPS); + ok(active <= maximum, + "Number of active processors %li is greater than maximum number of processors %li\n", + active, maximum); +} + static void test_RegistryQuota(void) { BOOL ret; @@ -2264,26 +2452,26 @@ static void test_TerminateProcess(void) si.cb = sizeof(si); SetLastError(0xdeadbeef); ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi); - ok(ret, "CreateProcess error %u\n", GetLastError()); + ok(ret, "CreateProcess error %lu\n", GetLastError()); SetLastError(0xdeadbeef); thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret); - ok(thread != 0, "CreateRemoteThread error %d\n", GetLastError()); + ok(thread != 0, "CreateRemoteThread error %ld\n", GetLastError()); /* create a not closed thread handle duplicate in the target process */ SetLastError(0xdeadbeef); ret = DuplicateHandle(GetCurrentProcess(), thread, pi.hProcess, &dummy, 0, FALSE, DUPLICATE_SAME_ACCESS); - ok(ret, "DuplicateHandle error %u\n", GetLastError()); + ok(ret, "DuplicateHandle error %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = TerminateThread(thread, 0); - ok(ret, "TerminateThread error %u\n", GetLastError()); + ok(ret, "TerminateThread error %lu\n", GetLastError()); CloseHandle(thread); SetLastError(0xdeadbeef); ret = TerminateProcess(pi.hProcess, 0); - ok(ret, "TerminateProcess error %u\n", GetLastError()); + ok(ret, "TerminateProcess error %lu\n", GetLastError()); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); @@ -2296,23 +2484,29 @@ static void test_DuplicateHandle(void) DWORD info; BOOL r; +#if defined(__REACTOS__) && defined(_WIN64) + if (is_reactos()) { + ok(FALSE, "FIXME: test_DuplicateHandle() deadlocks on ReactOS x64!\n"); + return; + } +#endif r = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &out, 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); - ok(r, "DuplicateHandle error %u\n", GetLastError()); + ok(r, "DuplicateHandle error %lu\n", GetLastError()); r = GetHandleInformation(out, &info); - ok(r, "GetHandleInformation error %u\n", GetLastError()); - ok(info == 0, "info = %x\n", info); + ok(r, "GetHandleInformation error %lu\n", GetLastError()); + ok(info == 0, "info = %lx\n", info); ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n"); CloseHandle(out); r = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &out, 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); - ok(r, "DuplicateHandle error %u\n", GetLastError()); + ok(r, "DuplicateHandle error %lu\n", GetLastError()); r = GetHandleInformation(out, &info); - ok(r, "GetHandleInformation error %u\n", GetLastError()); - ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info); + ok(r, "GetHandleInformation error %lu\n", GetLastError()); + ok(info == HANDLE_FLAG_INHERIT, "info = %lx\n", info); ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n"); CloseHandle(out); @@ -2327,31 +2521,31 @@ static void test_DuplicateHandle(void) r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out, 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); - ok(r, "DuplicateHandle error %u\n", GetLastError()); + ok(r, "DuplicateHandle error %lu\n", GetLastError()); ok(f == out, "f != out\n"); r = GetHandleInformation(out, &info); - ok(r, "GetHandleInformation error %u\n", GetLastError()); - ok(info == 0, "info = %x\n", info); + ok(r, "GetHandleInformation error %lu\n", GetLastError()); + ok(info == 0, "info = %lx\n", info); r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out, 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); - ok(r, "DuplicateHandle error %u\n", GetLastError()); + ok(r, "DuplicateHandle error %lu\n", GetLastError()); ok(f == out, "f != out\n"); r = GetHandleInformation(out, &info); - ok(r, "GetHandleInformation error %u\n", GetLastError()); - ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info); + ok(r, "GetHandleInformation error %lu\n", GetLastError()); + ok(info == HANDLE_FLAG_INHERIT, "info = %lx\n", info); r = SetHandleInformation(f, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE); - ok(r, "SetHandleInformation error %u\n", GetLastError()); + ok(r, "SetHandleInformation error %lu\n", GetLastError()); r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out, 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); - ok(r, "DuplicateHandle error %u\n", GetLastError()); + ok(r, "DuplicateHandle error %lu\n", GetLastError()); ok(f != out, "f == out\n"); r = GetHandleInformation(out, &info); - ok(r, "GetHandleInformation error %u\n", GetLastError()); - ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info); + ok(r, "GetHandleInformation error %lu\n", GetLastError()); + ok(info == HANDLE_FLAG_INHERIT, "info = %lx\n", info); r = SetHandleInformation(f, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0); - ok(r, "SetHandleInformation error %u\n", GetLastError()); + ok(r, "SetHandleInformation error %lu\n", GetLastError()); /* Test if DuplicateHandle allocates first free handle */ if (f > out) @@ -2366,23 +2560,58 @@ static void test_DuplicateHandle(void) CloseHandle(fmin); r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out, 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); - ok(r, "DuplicateHandle error %u\n", GetLastError()); + ok(r, "DuplicateHandle error %lu\n", GetLastError()); ok(f == out, "f != out\n"); CloseHandle(out); DeleteFileA(file_name); f = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); - if (!is_console(f)) - { - skip("DuplicateHandle on console handle\n"); - CloseHandle(f); - return; - } - + ok(f != INVALID_HANDLE_VALUE, "Failed to open CONIN$ %lu\n", GetLastError()); r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out, 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); - ok(r, "DuplicateHandle error %u\n", GetLastError()); - todo_wine ok(f != out, "f == out\n"); + ok(r, "DuplicateHandle error %lu\n", GetLastError()); + ok(f == out || broken(/* Win7 */ (((ULONG_PTR)f & 3) == 3) && (f != out)), "f != out\n"); + CloseHandle(out); + + /* Test DUPLICATE_SAME_ATTRIBUTES */ + f = CreateFileA("NUL", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); + ok(f != INVALID_HANDLE_VALUE, "Failed to open NUL %lu\n", GetLastError()); + r = GetHandleInformation(f, &info); + ok(r && info == 0, "Unexpected info %lx\n", info); + + r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out, + 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES); + ok(r, "DuplicateHandle error %lu\n", GetLastError()); + r = GetHandleInformation(out, &info); + ok(r && info == 0, "Unexpected info %lx\n", info); + CloseHandle(out); + + r = SetHandleInformation(f, HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE, + HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE); + ok(r, "SetHandleInformation error %lu\n", GetLastError()); + info = 0xdeabeef; + r = GetHandleInformation(f, &info); + ok(r && info == (HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE), "Unexpected info %lx\n", info); + ok(r, "SetHandleInformation error %lu\n", GetLastError()); + r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out, + 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES); + ok(r, "DuplicateHandle error %lu\n", GetLastError()); + info = 0xdeabeef; + r = GetHandleInformation(out, &info); + ok(r && info == (HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE), "Unexpected info %lx\n", info); + r = SetHandleInformation(out, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0); + ok(r, "SetHandleInformation error %lu\n", GetLastError()); + CloseHandle(out); + r = SetHandleInformation(f, HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE, 0); + ok(r, "SetHandleInformation error %lu\n", GetLastError()); + CloseHandle(f); + + r = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &out, + 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES); + ok(r, "DuplicateHandle error %lu\n", GetLastError()); + info = 0xdeabeef; + r = GetHandleInformation(out, &info); + ok(r && info == 0, "Unexpected info %lx\n", info); CloseHandle(out); } @@ -2396,10 +2625,10 @@ static void _test_completion(int line, HANDLE port, DWORD ekey, ULONG_PTR evalue ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, wait); - ok_(__FILE__, line)(ret, "GetQueuedCompletionStatus: %x\n", GetLastError()); + ok_(__FILE__, line)(ret, "GetQueuedCompletionStatus: %lx\n", GetLastError()); if (ret) { - ok_(__FILE__, line)(key == ekey, "unexpected key %x\n", key); + ok_(__FILE__, line)(key == ekey, "unexpected key %lx\n", key); ok_(__FILE__, line)(value == evalue, "unexpected value %p\n", (void *)value); ok_(__FILE__, line)(overlapped == (LPOVERLAPPED)eoverlapped, "unexpected overlapped %p\n", overlapped); } @@ -2409,77 +2638,61 @@ static void _test_completion(int line, HANDLE port, DWORD ekey, ULONG_PTR evalue static void _create_process(int line, const char *command, LPPROCESS_INFORMATION pi) { BOOL ret; - char buffer[MAX_PATH]; + char buffer[MAX_PATH + 19]; STARTUPINFOA si = {0}; - sprintf(buffer, "\"%s\" tests/process.c %s", selfname, command); + sprintf(buffer, "\"%s\" process %s", selfname, command); ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, pi); - ok_(__FILE__, line)(ret, "CreateProcess error %u\n", GetLastError()); + ok_(__FILE__, line)(ret, "CreateProcess error %lu\n", GetLastError()); } #define test_assigned_proc(job, ...) _test_assigned_proc(__LINE__, job, __VA_ARGS__) -static void _test_assigned_proc(int line, HANDLE job, int expected_count, ...) +static void _test_assigned_proc(int line, HANDLE job, unsigned int count, ...) { char buf[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + sizeof(ULONG_PTR) * 20]; - PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list = (JOBOBJECT_BASIC_PROCESS_ID_LIST *)buf; - DWORD ret_len, pid; + JOBOBJECT_BASIC_PROCESS_ID_LIST *list = (JOBOBJECT_BASIC_PROCESS_ID_LIST *)buf; + unsigned int i, pid; va_list valist; - int n; + DWORD size; BOOL ret; memset(buf, 0, sizeof(buf)); - ret = pQueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, sizeof(buf), &ret_len); - ok_(__FILE__, line)(ret, "QueryInformationJobObject error %u\n", GetLastError()); - if (ret) - { - todo_wine_if(expected_count) - ok_(__FILE__, line)(expected_count == pid_list->NumberOfAssignedProcesses, - "Expected NumberOfAssignedProcesses to be %d (expected_count) is %d\n", - expected_count, pid_list->NumberOfAssignedProcesses); - todo_wine_if(expected_count) - ok_(__FILE__, line)(expected_count == pid_list->NumberOfProcessIdsInList, - "Expected NumberOfProcessIdsInList to be %d (expected_count) is %d\n", - expected_count, pid_list->NumberOfProcessIdsInList); + ret = pQueryInformationJobObject(job, JobObjectBasicProcessIdList, list, sizeof(buf), &size); + ok_(__FILE__, line)(ret, "failed to get process id list, error %lu\n", GetLastError()); - va_start(valist, expected_count); - for (n = 0; n < min(expected_count, pid_list->NumberOfProcessIdsInList); ++n) - { - pid = va_arg(valist, DWORD); - ok_(__FILE__, line)(pid == pid_list->ProcessIdList[n], - "Expected pid_list->ProcessIdList[%d] to be %x is %lx\n", - n, pid, pid_list->ProcessIdList[n]); - } - va_end(valist); + ok_(__FILE__, line)(list->NumberOfAssignedProcesses == count, + "expected %u assigned processes, got %lu\n", count, list->NumberOfAssignedProcesses); + ok_(__FILE__, line)(list->NumberOfProcessIdsInList == count, + "expected %u process IDs, got %lu\n", count, list->NumberOfProcessIdsInList); + + va_start(valist, count); + for (i = 0; i < min(count, list->NumberOfProcessIdsInList); ++i) + { + pid = va_arg(valist, unsigned int); + ok_(__FILE__, line)(pid == list->ProcessIdList[i], + "wrong pid %u: expected %#04x, got %#04Ix\n", i, pid, list->ProcessIdList[i]); } + va_end(valist); } -#define test_accounting(job, total_proc, active_proc, terminated_proc) _test_accounting(__LINE__, job, total_proc, active_proc, terminated_proc) -static void _test_accounting(int line, HANDLE job, int total_proc, int active_proc, int terminated_proc) +#define test_accounting(a, b, c, d) _test_accounting(__LINE__, a, b, c, d) +static void _test_accounting(int line, HANDLE job, unsigned int total, unsigned int active, unsigned int terminated) { - JOBOBJECT_BASIC_ACCOUNTING_INFORMATION basic_accounting; - DWORD ret_len; + JOBOBJECT_BASIC_ACCOUNTING_INFORMATION info; + DWORD size; BOOL ret; - memset(&basic_accounting, 0, sizeof(basic_accounting)); - ret = pQueryInformationJobObject(job, JobObjectBasicAccountingInformation, &basic_accounting, sizeof(basic_accounting), &ret_len); - ok_(__FILE__, line)(ret, "QueryInformationJobObject error %u\n", GetLastError()); - if (ret) - { - /* Not going to check process times or page faults */ + memset(&info, 0, sizeof(info)); + ret = pQueryInformationJobObject(job, JobObjectBasicAccountingInformation, &info, sizeof(info), &size); + ok_(__FILE__, line)(ret, "failed to get accounting information, error %lu\n", GetLastError()); - todo_wine_if(total_proc) - ok_(__FILE__, line)(total_proc == basic_accounting.TotalProcesses, - "Expected basic_accounting.TotalProcesses to be %d (total_proc) is %d\n", - total_proc, basic_accounting.TotalProcesses); - todo_wine_if(active_proc) - ok_(__FILE__, line)(active_proc == basic_accounting.ActiveProcesses, - "Expected basic_accounting.ActiveProcesses to be %d (active_proc) is %d\n", - active_proc, basic_accounting.ActiveProcesses); - ok_(__FILE__, line)(terminated_proc == basic_accounting.TotalTerminatedProcesses, - "Expected basic_accounting.TotalTerminatedProcesses to be %d (terminated_proc) is %d\n", - terminated_proc, basic_accounting.TotalTerminatedProcesses); - } + ok_(__FILE__, line)(info.TotalProcesses == total, + "expected %u total processes, got %lu\n", total, info.TotalProcesses); + ok_(__FILE__, line)(info.ActiveProcesses == active, + "expected %u active processes, got %lu\n", active, info.ActiveProcesses); + ok_(__FILE__, line)(info.TotalTerminatedProcesses == terminated, + "expected %u terminated processes, got %lu\n", terminated, info.TotalTerminatedProcesses); } static void test_IsProcessInJob(void) @@ -2487,7 +2700,6 @@ static void test_IsProcessInJob(void) HANDLE job, job2; PROCESS_INFORMATION pi; BOOL ret, out; - DWORD dwret; if (!pIsProcessInJob) { @@ -2496,65 +2708,67 @@ static void test_IsProcessInJob(void) } job = pCreateJobObjectW(NULL, NULL); - ok(job != NULL, "CreateJobObject error %u\n", GetLastError()); + ok(job != NULL, "CreateJobObject error %lu\n", GetLastError()); job2 = pCreateJobObjectW(NULL, NULL); - ok(job2 != NULL, "CreateJobObject error %u\n", GetLastError()); + ok(job2 != NULL, "CreateJobObject error %lu\n", GetLastError()); create_process("wait", &pi); out = TRUE; ret = pIsProcessInJob(pi.hProcess, job, &out); - ok(ret, "IsProcessInJob error %u\n", GetLastError()); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); ok(!out, "IsProcessInJob returned out=%u\n", out); test_assigned_proc(job, 0); test_accounting(job, 0, 0, 0); out = TRUE; ret = pIsProcessInJob(pi.hProcess, job2, &out); - ok(ret, "IsProcessInJob error %u\n", GetLastError()); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); ok(!out, "IsProcessInJob returned out=%u\n", out); test_assigned_proc(job2, 0); test_accounting(job2, 0, 0, 0); - out = TRUE; - ret = pIsProcessInJob(pi.hProcess, NULL, &out); - ok(ret, "IsProcessInJob error %u\n", GetLastError()); - ok(!out, "IsProcessInJob returned out=%u\n", out); - ret = pAssignProcessToJobObject(job, pi.hProcess); - ok(ret, "AssignProcessToJobObject error %u\n", GetLastError()); + ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError()); out = FALSE; ret = pIsProcessInJob(pi.hProcess, job, &out); - ok(ret, "IsProcessInJob error %u\n", GetLastError()); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); ok(out, "IsProcessInJob returned out=%u\n", out); test_assigned_proc(job, 1, pi.dwProcessId); test_accounting(job, 1, 1, 0); out = TRUE; ret = pIsProcessInJob(pi.hProcess, job2, &out); - ok(ret, "IsProcessInJob error %u\n", GetLastError()); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); ok(!out, "IsProcessInJob returned out=%u\n", out); test_assigned_proc(job2, 0); test_accounting(job2, 0, 0, 0); out = FALSE; ret = pIsProcessInJob(pi.hProcess, NULL, &out); - ok(ret, "IsProcessInJob error %u\n", GetLastError()); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); ok(out, "IsProcessInJob returned out=%u\n", out); TerminateProcess(pi.hProcess, 0); - - dwret = WaitForSingleObject(pi.hProcess, 1000); - ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); + wait_child_process(pi.hProcess); out = FALSE; ret = pIsProcessInJob(pi.hProcess, job, &out); - ok(ret, "IsProcessInJob error %u\n", GetLastError()); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); ok(out, "IsProcessInJob returned out=%u\n", out); +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_WIN8) { + test_assigned_proc(job, 1); + test_accounting(job, 1, 1, 0); + } else { +#endif test_assigned_proc(job, 0); test_accounting(job, 1, 0, 0); +#ifdef __REACTOS__ + } +#endif CloseHandle(pi.hProcess); CloseHandle(pi.hThread); @@ -2570,39 +2784,38 @@ static void test_TerminateJobObject(void) DWORD dwret; job = pCreateJobObjectW(NULL, NULL); - ok(job != NULL, "CreateJobObject error %u\n", GetLastError()); + ok(job != NULL, "CreateJobObject error %lu\n", GetLastError()); test_assigned_proc(job, 0); test_accounting(job, 0, 0, 0); create_process("wait", &pi); ret = pAssignProcessToJobObject(job, pi.hProcess); - ok(ret, "AssignProcessToJobObject error %u\n", GetLastError()); + ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError()); test_assigned_proc(job, 1, pi.dwProcessId); test_accounting(job, 1, 1, 0); ret = pTerminateJobObject(job, 123); - ok(ret, "TerminateJobObject error %u\n", GetLastError()); + ok(ret, "TerminateJobObject error %lu\n", GetLastError()); + /* not wait_child_process() because of the exit code */ dwret = WaitForSingleObject(pi.hProcess, 1000); - ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); + ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", dwret); if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0); test_assigned_proc(job, 0); test_accounting(job, 1, 0, 0); ret = GetExitCodeProcess(pi.hProcess, &dwret); - ok(ret, "GetExitCodeProcess error %u\n", GetLastError()); - ok(dwret == 123 || broken(dwret == 0) || broken(dwret == 259) /* randomly fails on Win 2000 / XP */, - "wrong exitcode %u\n", dwret); + ok(ret, "GetExitCodeProcess error %lu\n", GetLastError()); + ok(dwret == 123 || broken(dwret == 0) /* randomly fails on Win 2000 / XP */, + "wrong exitcode %lu\n", dwret); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); /* Test adding an already terminated process to a job object */ create_process("exit", &pi); - - dwret = WaitForSingleObject(pi.hProcess, 1000); - ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); + wait_child_process(pi.hProcess); SetLastError(0xdeadbeef); ret = pAssignProcessToJobObject(job, pi.hProcess); @@ -2623,31 +2836,35 @@ static void test_QueryInformationJobObject(void) PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list = (JOBOBJECT_BASIC_PROCESS_ID_LIST *)buf; JOBOBJECT_EXTENDED_LIMIT_INFORMATION ext_limit_info; JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit_info = &ext_limit_info.BasicLimitInformation; - DWORD dwret, ret_len; + JOBOBJECT_BASIC_ACCOUNTING_INFORMATION basic_accounting_info; + DWORD ret_len; PROCESS_INFORMATION pi[2]; - HANDLE job; + char buffer[50]; + HANDLE job, sem; BOOL ret; job = pCreateJobObjectW(NULL, NULL); - ok(job != NULL, "CreateJobObject error %u\n", GetLastError()); + ok(job != NULL, "CreateJobObject error %lu\n", GetLastError()); /* Only active processes are returned */ - create_process("exit", &pi[0]); - ret = pAssignProcessToJobObject(job, pi[0].hProcess); - ok(ret, "AssignProcessToJobObject error %u\n", GetLastError()); - dwret = WaitForSingleObject(pi[0].hProcess, 1000); - ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); + sprintf(buffer, "sync kernel32-process-%lx", GetCurrentProcessId()); + sem = CreateSemaphoreA(NULL, 0, 1, buffer + 5); + ok(sem != NULL, "CreateSemaphoreA failed le=%lu\n", GetLastError()); + create_process(buffer, &pi[0]); - CloseHandle(pi[0].hProcess); - CloseHandle(pi[0].hThread); + ret = pAssignProcessToJobObject(job, pi[0].hProcess); + ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError()); + + ReleaseSemaphore(sem, 1, NULL); + wait_and_close_child_process(&pi[0]); create_process("wait", &pi[0]); ret = pAssignProcessToJobObject(job, pi[0].hProcess); - ok(ret, "AssignProcessToJobObject error %u\n", GetLastError()); + ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError()); create_process("wait", &pi[1]); ret = pAssignProcessToJobObject(job, pi[1].hProcess); - ok(ret, "AssignProcessToJobObject error %u\n", GetLastError()); + ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = QueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, @@ -2661,21 +2878,17 @@ static void test_QueryInformationJobObject(void) pid_list->NumberOfProcessIdsInList = 42; ret = QueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList[1]), &ret_len); - todo_wine ok(!ret, "QueryInformationJobObject expected failure\n"); - todo_wine expect_eq_d(ERROR_MORE_DATA, GetLastError()); if (ret) { - todo_wine expect_eq_d(42, pid_list->NumberOfAssignedProcesses); - todo_wine expect_eq_d(42, pid_list->NumberOfProcessIdsInList); } memset(buf, 0, sizeof(buf)); ret = pQueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, sizeof(buf), &ret_len); - ok(ret, "QueryInformationJobObject error %u\n", GetLastError()); + ok(ret, "QueryInformationJobObject error %lu\n", GetLastError()); if(ret) { if (pid_list->NumberOfAssignedProcesses == 3) /* Win 8 */ @@ -2684,17 +2897,12 @@ static void test_QueryInformationJobObject(void) { ULONG_PTR *list = pid_list->ProcessIdList; - todo_wine ok(ret_len == FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList[2]), - "QueryInformationJobObject returned ret_len=%u\n", ret_len); + "QueryInformationJobObject returned ret_len=%lu\n", ret_len); - todo_wine expect_eq_d(2, pid_list->NumberOfAssignedProcesses); - todo_wine expect_eq_d(2, pid_list->NumberOfProcessIdsInList); - todo_wine expect_eq_d(pi[0].dwProcessId, list[0]); - todo_wine expect_eq_d(pi[1].dwProcessId, list[1]); } } @@ -2709,8 +2917,8 @@ static void test_QueryInformationJobObject(void) memset(basic_limit_info, 0x11, sizeof(*basic_limit_info)); ret = pQueryInformationJobObject(job, JobObjectBasicLimitInformation, basic_limit_info, sizeof(*basic_limit_info), &ret_len); - ok(ret, "QueryInformationJobObject error %u\n", GetLastError()); - ok(ret_len == sizeof(*basic_limit_info), "QueryInformationJobObject returned ret_len=%u\n", ret_len); + ok(ret, "QueryInformationJobObject error %lu\n", GetLastError()); + ok(ret_len == sizeof(*basic_limit_info), "QueryInformationJobObject returned ret_len=%lu\n", ret_len); expect_eq_d(0, basic_limit_info->LimitFlags); /* test JobObjectExtendedLimitInformation */ @@ -2723,10 +2931,22 @@ static void test_QueryInformationJobObject(void) memset(&ext_limit_info, 0x11, sizeof(ext_limit_info)); ret = pQueryInformationJobObject(job, JobObjectExtendedLimitInformation, &ext_limit_info, sizeof(ext_limit_info), &ret_len); - ok(ret, "QueryInformationJobObject error %u\n", GetLastError()); - ok(ret_len == sizeof(ext_limit_info), "QueryInformationJobObject returned ret_len=%u\n", ret_len); + ok(ret, "QueryInformationJobObject error %lu\n", GetLastError()); + ok(ret_len == sizeof(ext_limit_info), "QueryInformationJobObject returned ret_len=%lu\n", ret_len); expect_eq_d(0, basic_limit_info->LimitFlags); + /* test JobObjectBasicAccountingInformation */ + ret = pQueryInformationJobObject(job, JobObjectBasicAccountingInformation, &basic_accounting_info, + sizeof(basic_accounting_info), &ret_len); + ok(ret, "QueryInformationJobObject error %lu\n", GetLastError()); + ok(ret_len == sizeof(basic_accounting_info), "QueryInformationJobObject returned ret_len=%lu\n", ret_len); + expect_eq_d(3, basic_accounting_info.TotalProcesses); +#if defined(__REACTOS__) + ok(basic_accounting_info.ActiveProcesses == 2 || broken(basic_accounting_info.ActiveProcesses == 3) /* Win8+ */, "Expected %d == %d\n", basic_accounting_info.ActiveProcesses, 2); +#else + expect_eq_d(2, basic_accounting_info.ActiveProcesses); +#endif + TerminateProcess(pi[0].hProcess, 0); CloseHandle(pi[0].hProcess); CloseHandle(pi[0].hThread); @@ -2741,34 +2961,43 @@ static void test_QueryInformationJobObject(void) static void test_CompletionPort(void) { JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info; - PROCESS_INFORMATION pi; + PROCESS_INFORMATION pi, pi2; HANDLE job, port; - DWORD dwret; BOOL ret; job = pCreateJobObjectW(NULL, NULL); - ok(job != NULL, "CreateJobObject error %u\n", GetLastError()); + ok(job != NULL, "CreateJobObject error %lu\n", GetLastError()); + + create_process("wait", &pi2); + ret = pAssignProcessToJobObject(job, pi2.hProcess); + ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError()); port = pCreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); - ok(port != NULL, "CreateIoCompletionPort error %u\n", GetLastError()); + ok(port != NULL, "CreateIoCompletionPort error %lu\n", GetLastError()); port_info.CompletionKey = job; port_info.CompletionPort = port; ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info)); - ok(ret, "SetInformationJobObject error %u\n", GetLastError()); + ok(ret, "SetInformationJobObject error %lu\n", GetLastError()); create_process("wait", &pi); ret = pAssignProcessToJobObject(job, pi.hProcess); - ok(ret, "AssignProcessToJobObject error %u\n", GetLastError()); + ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError()); + test_completion(port, JOB_OBJECT_MSG_NEW_PROCESS, (DWORD_PTR)job, pi2.dwProcessId, 0); test_completion(port, JOB_OBJECT_MSG_NEW_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0); TerminateProcess(pi.hProcess, 0); - dwret = WaitForSingleObject(pi.hProcess, 1000); - ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); + wait_child_process(pi.hProcess); test_completion(port, JOB_OBJECT_MSG_EXIT_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0); + TerminateProcess(pi2.hProcess, 0); + wait_child_process(pi2.hProcess); + CloseHandle(pi2.hProcess); + CloseHandle(pi2.hThread); + + test_completion(port, JOB_OBJECT_MSG_EXIT_PROCESS, (DWORD_PTR)job, pi2.dwProcessId, 0); test_completion(port, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO, (DWORD_PTR)job, 0, 100); CloseHandle(pi.hProcess); @@ -2786,7 +3015,7 @@ static void test_KillOnJobClose(void) BOOL ret; job = pCreateJobObjectW(NULL, NULL); - ok(job != NULL, "CreateJobObject error %u\n", GetLastError()); + ok(job != NULL, "CreateJobObject error %lu\n", GetLastError()); limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info)); @@ -2795,21 +3024,22 @@ static void test_KillOnJobClose(void) win_skip("Kill on job close limit not available\n"); return; } - ok(ret, "SetInformationJobObject error %u\n", GetLastError()); + ok(ret, "SetInformationJobObject error %lu\n", GetLastError()); test_assigned_proc(job, 0); test_accounting(job, 0, 0, 0); create_process("wait", &pi); ret = pAssignProcessToJobObject(job, pi.hProcess); - ok(ret, "AssignProcessToJobObject error %u\n", GetLastError()); + ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError()); test_assigned_proc(job, 1, pi.dwProcessId); test_accounting(job, 1, 1, 0); CloseHandle(job); + /* not wait_child_process() for the kill */ dwret = WaitForSingleObject(pi.hProcess, 1000); - ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); + ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", dwret); if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0); CloseHandle(pi.hProcess); @@ -2818,42 +3048,36 @@ static void test_KillOnJobClose(void) static void test_WaitForJobObject(void) { - HANDLE job; + HANDLE job, sem; + char buffer[50]; PROCESS_INFORMATION pi; BOOL ret; DWORD dwret; /* test waiting for a job object when the process is killed */ job = pCreateJobObjectW(NULL, NULL); - ok(job != NULL, "CreateJobObject error %u\n", GetLastError()); + ok(job != NULL, "CreateJobObject error %lu\n", GetLastError()); dwret = WaitForSingleObject(job, 100); - ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret); + ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", dwret); create_process("wait", &pi); ret = pAssignProcessToJobObject(job, pi.hProcess); - ok(ret, "AssignProcessToJobObject error %u\n", GetLastError()); + ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError()); dwret = WaitForSingleObject(job, 100); - ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret); + ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", dwret); ret = pTerminateJobObject(job, 123); - ok(ret, "TerminateJobObject error %u\n", GetLastError()); + ok(ret, "TerminateJobObject error %lu\n", GetLastError()); dwret = WaitForSingleObject(job, 500); ok(dwret == WAIT_OBJECT_0 || broken(dwret == WAIT_TIMEOUT), - "WaitForSingleObject returned %u\n", dwret); + "WaitForSingleObject returned %lu\n", dwret); if (dwret == WAIT_TIMEOUT) /* Win 2000/XP */ { -#ifdef __REACTOS__ - if (!ret) - { - ok(0, "HACK: Killing process to speed up the test\n"); - TerminateProcess(pi.hProcess, 0); - } -#endif CloseHandle(pi.hProcess); CloseHandle(pi.hThread); CloseHandle(job); @@ -2863,7 +3087,7 @@ static void test_WaitForJobObject(void) /* the object is not reset immediately */ dwret = WaitForSingleObject(job, 100); - ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); + ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", dwret); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); @@ -2872,13 +3096,13 @@ static void test_WaitForJobObject(void) create_process("wait", &pi); ret = pAssignProcessToJobObject(job, pi.hProcess); - ok(ret, "AssignProcessToJobObject error %u\n", GetLastError()); + ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError()); dwret = WaitForSingleObject(job, 100); - ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); + ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", dwret); ret = pTerminateJobObject(job, 123); - ok(ret, "TerminateJobObject error %u\n", GetLastError()); + ok(ret, "TerminateJobObject error %lu\n", GetLastError()); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); @@ -2887,22 +3111,26 @@ static void test_WaitForJobObject(void) /* repeat the test, but this time the process terminates properly */ job = pCreateJobObjectW(NULL, NULL); - ok(job != NULL, "CreateJobObject error %u\n", GetLastError()); + ok(job != NULL, "CreateJobObject error %lu\n", GetLastError()); dwret = WaitForSingleObject(job, 100); - ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret); + ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", dwret); - create_process("exit", &pi); + sprintf(buffer, "sync kernel32-process-%lx", GetCurrentProcessId()); + sem = CreateSemaphoreA(NULL, 0, 1, buffer + 5); + ok(sem != NULL, "CreateSemaphoreA failed le=%lu\n", GetLastError()); + create_process(buffer, &pi); ret = pAssignProcessToJobObject(job, pi.hProcess); - ok(ret, "AssignProcessToJobObject error %u\n", GetLastError()); + ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError()); + ReleaseSemaphore(sem, 1, NULL); dwret = WaitForSingleObject(job, 100); - ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret); + ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", dwret); - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); + wait_and_close_child_process(&pi); CloseHandle(job); + CloseHandle(sem); } static HANDLE test_AddSelfToJob(void) @@ -2911,10 +3139,10 @@ static HANDLE test_AddSelfToJob(void) BOOL ret; job = pCreateJobObjectW(NULL, NULL); - ok(job != NULL, "CreateJobObject error %u\n", GetLastError()); + ok(job != NULL, "CreateJobObject error %lu\n", GetLastError()); ret = pAssignProcessToJobObject(job, GetCurrentProcess()); - ok(ret, "AssignProcessToJobObject error %u\n", GetLastError()); + ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError()); test_assigned_proc(job, 1, GetCurrentProcessId()); test_accounting(job, 1, 1, 0); @@ -2923,10 +3151,7 @@ static HANDLE test_AddSelfToJob(void) static void test_jobInheritance(HANDLE job) { - char buffer[MAX_PATH]; PROCESS_INFORMATION pi; - STARTUPINFOA si = {0}; - DWORD dwret; BOOL ret, out; if (!pIsProcessInJob) @@ -2935,33 +3160,26 @@ static void test_jobInheritance(HANDLE job) return; } - sprintf(buffer, "\"%s\" tests/process.c %s", selfname, "exit"); - - ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); - ok(ret, "CreateProcessA error %u\n", GetLastError()); + create_process("exit", &pi); out = FALSE; ret = pIsProcessInJob(pi.hProcess, job, &out); - ok(ret, "IsProcessInJob error %u\n", GetLastError()); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); ok(out, "IsProcessInJob returned out=%u\n", out); test_assigned_proc(job, 2, GetCurrentProcessId(), pi.dwProcessId); test_accounting(job, 2, 2, 0); - dwret = WaitForSingleObject(pi.hProcess, 1000); - ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); - - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); + wait_and_close_child_process(&pi); } -static void test_BreakawayOk(HANDLE job) +static void test_BreakawayOk(HANDLE parent_job) { JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info; PROCESS_INFORMATION pi; STARTUPINFOA si = {0}; - char buffer[MAX_PATH]; - BOOL ret, out; - DWORD dwret; + char buffer[MAX_PATH + 23]; + BOOL ret, out, nested_jobs; + HANDLE job; if (!pIsProcessInJob) { @@ -2969,135 +3187,460 @@ static void test_BreakawayOk(HANDLE job) return; } - sprintf(buffer, "\"%s\" tests/process.c %s", selfname, "exit"); + job = pCreateJobObjectW(NULL, NULL); + ok(!!job, "CreateJobObjectW error %lu\n", GetLastError()); + ret = pAssignProcessToJobObject(job, GetCurrentProcess()); + ok(ret || broken(!ret && GetLastError() == ERROR_ACCESS_DENIED) /* before Win 8. */, + "AssignProcessToJobObject error %lu\n", GetLastError()); + nested_jobs = ret; + if (!ret) + win_skip("Nested jobs are not supported.\n"); + + sprintf(buffer, "\"%s\" process exit", selfname); ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi); ok(!ret, "CreateProcessA expected failure\n"); expect_eq_d(ERROR_ACCESS_DENIED, GetLastError()); - test_assigned_proc(job, 1, GetCurrentProcessId()); - test_accounting(job, 2, 1, 0); if (ret) { TerminateProcess(pi.hProcess, 0); + wait_and_close_child_process(&pi); + } - dwret = WaitForSingleObject(pi.hProcess, 1000); - ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); + if (nested_jobs) + { + test_assigned_proc(job, 1, GetCurrentProcessId()); + test_accounting(job, 1, 1, 0); - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); + limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK; + ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info)); + ok(ret, "SetInformationJobObject error %lu\n", GetLastError()); + + sprintf(buffer, "\"%s\" process exit", selfname); + ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi); + ok(ret, "CreateProcessA error %lu\n", GetLastError()); + + ret = pIsProcessInJob(pi.hProcess, job, &out); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); + ok(!out, "IsProcessInJob returned out=%u\n", out); + + ret = pIsProcessInJob(pi.hProcess, parent_job, &out); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); + ok(out, "IsProcessInJob returned out=%u\n", out); + + TerminateProcess(pi.hProcess, 0); + wait_and_close_child_process(&pi); } limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK; - ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info)); - ok(ret, "SetInformationJobObject error %u\n", GetLastError()); + ret = pSetInformationJobObject(parent_job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info)); + ok(ret, "SetInformationJobObject error %lu\n", GetLastError()); ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi); - ok(ret, "CreateProcessA error %u\n", GetLastError()); + ok(ret, "CreateProcessA error %lu\n", GetLastError()); ret = pIsProcessInJob(pi.hProcess, job, &out); - ok(ret, "IsProcessInJob error %u\n", GetLastError()); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); ok(!out, "IsProcessInJob returned out=%u\n", out); - test_assigned_proc(job, 1, GetCurrentProcessId()); - test_accounting(job, 2, 1, 0); + if (nested_jobs) + { + test_assigned_proc(job, 1, GetCurrentProcessId()); + test_accounting(job, 1, 1, 0); + } - dwret = WaitForSingleObject(pi.hProcess, 1000); - ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); + ret = pIsProcessInJob(pi.hProcess, parent_job, &out); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); + ok(!out, "IsProcessInJob returned out=%u\n", out); - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); + wait_and_close_child_process(&pi); limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK; ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info)); - ok(ret, "SetInformationJobObject error %u\n", GetLastError()); + ok(ret, "SetInformationJobObject error %lu\n", GetLastError()); ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); - ok(ret, "CreateProcess error %u\n", GetLastError()); + ok(ret, "CreateProcess error %lu\n", GetLastError()); ret = pIsProcessInJob(pi.hProcess, job, &out); - ok(ret, "IsProcessInJob error %u\n", GetLastError()); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); ok(!out, "IsProcessInJob returned out=%u\n", out); - test_assigned_proc(job, 1, GetCurrentProcessId()); - test_accounting(job, 2, 1, 0); + if (nested_jobs) + { + test_assigned_proc(job, 1, GetCurrentProcessId()); + test_accounting(job, 1, 1, 0); + } - dwret = WaitForSingleObject(pi.hProcess, 1000); - ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); - - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); + wait_and_close_child_process(&pi); /* unset breakaway ok */ limit_info.BasicLimitInformation.LimitFlags = 0; ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info)); - ok(ret, "SetInformationJobObject error %u\n", GetLastError()); + ok(ret, "SetInformationJobObject error %lu\n", GetLastError()); } -static void test_StartupNoConsole(void) +/* copy an executable, but changing its subsystem */ +static void copy_change_subsystem(const char* in, const char* out, DWORD subsyst) { -#ifndef _WIN64 - char buffer[MAX_PATH]; - STARTUPINFOA startup; - PROCESS_INFORMATION info; + BOOL ret; + HANDLE hFile, hMap; + void* mapping; + IMAGE_NT_HEADERS *nthdr; - memset(&startup, 0, sizeof(startup)); - startup.cb = sizeof(startup); - startup.dwFlags = STARTF_USESHOWWINDOW; - startup.wShowWindow = SW_SHOWNORMAL; - get_file_name(resfile); - sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); - ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, - &info), "CreateProcess\n"); - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); - okChildInt("StartupInfoA", "hStdInput", (UINT)INVALID_HANDLE_VALUE); - okChildInt("StartupInfoA", "hStdOutput", (UINT)INVALID_HANDLE_VALUE); - okChildInt("StartupInfoA", "hStdError", (UINT)INVALID_HANDLE_VALUE); - okChildInt("TEB", "hStdInput", 0); - okChildInt("TEB", "hStdOutput", 0); - okChildInt("TEB", "hStdError", 0); - release_memory(); - DeleteFileA(resfile); -#endif + ret = CopyFileA(in, out, FALSE); + ok(ret, "Failed to copy executable %s in %s (%lu)\n", in, out, GetLastError()); + + hFile = CreateFileA(out, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + ok(hFile != INVALID_HANDLE_VALUE, "Couldn't open file %s (%lu)\n", out, GetLastError()); + hMap = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0, NULL); + ok(hMap != NULL, "Couldn't create map (%lu)\n", GetLastError()); + mapping = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0); + ok(mapping != NULL, "Couldn't map (%lu)\n", GetLastError()); + nthdr = RtlImageNtHeader(mapping); + ok(nthdr != NULL, "Cannot get NT headers out of %s\n", out); + if (nthdr) nthdr->OptionalHeader.Subsystem = subsyst; + ret = UnmapViewOfFile(mapping); + ok(ret, "Couldn't unmap (%lu)\n", GetLastError()); + CloseHandle(hMap); + CloseHandle(hFile); } -static void test_DetachConsoleHandles(void) +#define H_CONSOLE 0 +#define H_DISK 1 +#define H_CHAR 2 +#define H_PIPE 3 +#define H_NULL 4 +#define H_INVALID 5 +#define H_DEVIL 6 /* unassigned handle */ + +#define ARG_STD 0x80000000 +#define ARG_STARTUPINFO 0x00000000 +#define ARG_CP_INHERIT 0x40000000 +#define ARG_HANDLE_INHERIT 0x20000000 +#define ARG_HANDLE_PROTECT 0x10000000 +#define ARG_HANDLE_MASK (~0xff000000) + +static BOOL check_run_child(const char *exec, DWORD flags, BOOL cp_inherit, + STARTUPINFOA *si) { -#ifndef _WIN64 - char buffer[MAX_PATH]; - STARTUPINFOA startup; PROCESS_INFORMATION info; - UINT result; + char buffer[2 * MAX_PATH + 64]; + DWORD exit_code; + BOOL res; + DWORD ret; - memset(&startup, 0, sizeof(startup)); - startup.cb = sizeof(startup); - startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES; - startup.wShowWindow = SW_SHOWNORMAL; - startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE); - startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); - startup.hStdError = GetStdHandle(STD_ERROR_HANDLE); get_file_name(resfile); - sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); - ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, - &info), "CreateProcess\n"); - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); + sprintf(buffer, "\"%s\" process dump \"%s\"", exec, resfile); - result = GetPrivateProfileIntA("StartupInfoA", "hStdInput", 0, resfile); - ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result); - result = GetPrivateProfileIntA("StartupInfoA", "hStdOutput", 0, resfile); - ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result); - result = GetPrivateProfileIntA("StartupInfoA", "hStdError", 0, resfile); - ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result); - result = GetPrivateProfileIntA("TEB", "hStdInput", 0, resfile); - ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result); - result = GetPrivateProfileIntA("TEB", "hStdOutput", 0, resfile); - ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result); - result = GetPrivateProfileIntA("TEB", "hStdError", 0, resfile); - ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result); + res = CreateProcessA(NULL, buffer, NULL, NULL, cp_inherit, flags, NULL, NULL, si, &info); + ok(res, "CreateProcess failed: %lu %s\n", GetLastError(), buffer); + CloseHandle(info.hThread); + ret = WaitForSingleObject(info.hProcess, 30000); + ok(ret == WAIT_OBJECT_0, "Could not wait for the child process: %ld le=%lu\n", + ret, GetLastError()); + res = GetExitCodeProcess(info.hProcess, &exit_code); + ok(res && exit_code == 0, "Couldn't get exit_code\n"); + CloseHandle(info.hProcess); + return res; +} - release_memory(); - DeleteFileA(resfile); +static char std_handle_file[MAX_PATH]; + +static BOOL build_startupinfo( STARTUPINFOA *startup, unsigned args, HANDLE hstd[2] ) +{ + SECURITY_ATTRIBUTES inherit_sa = { sizeof(inherit_sa), NULL, TRUE }; + SECURITY_ATTRIBUTES *psa; + BOOL ret, needs_close = FALSE; + + psa = (args & ARG_HANDLE_INHERIT) ? &inherit_sa : NULL; + + memset(startup, 0, sizeof(*startup)); + startup->cb = sizeof(*startup); + + switch (args & ARG_HANDLE_MASK) + { + case H_CONSOLE: + hstd[0] = CreateFileA("CONIN$", GENERIC_READ, 0, psa, OPEN_EXISTING, 0, 0); + ok(hstd[0] != INVALID_HANDLE_VALUE, "Couldn't create input to console\n"); + hstd[1] = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, psa, OPEN_EXISTING, 0, 0); + ok(hstd[1] != INVALID_HANDLE_VALUE, "Couldn't create input to console\n"); + needs_close = TRUE; + break; + case H_DISK: + hstd[0] = CreateFileA(std_handle_file, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, psa, OPEN_EXISTING, 0, 0); + ok(hstd[0] != INVALID_HANDLE_VALUE, "Couldn't create input to file %s\n", std_handle_file); + hstd[1] = CreateFileA(std_handle_file, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, psa, OPEN_EXISTING, 0, 0); + ok(hstd[1] != INVALID_HANDLE_VALUE, "Couldn't create input to file %s\n", std_handle_file); + needs_close = TRUE; + break; + case H_CHAR: + hstd[0] = CreateFileA("NUL", GENERIC_READ, 0, psa, OPEN_EXISTING, 0, 0); + ok(hstd[0] != INVALID_HANDLE_VALUE, "Couldn't create input to NUL\n"); + hstd[1] = CreateFileA("NUL", GENERIC_READ|GENERIC_WRITE, 0, psa, OPEN_EXISTING, 0, 0); + ok(hstd[1] != INVALID_HANDLE_VALUE, "Couldn't create input to NUL\n"); + needs_close = TRUE; + break; + case H_PIPE: + ret = CreatePipe(&hstd[0], &hstd[1], psa, 0); + ok(ret, "Couldn't create anon pipe\n"); + needs_close = TRUE; + break; + case H_NULL: + hstd[0] = hstd[1] = NULL; + break; + case H_INVALID: + hstd[0] = hstd[1] = INVALID_HANDLE_VALUE; + break; + case H_DEVIL: + hstd[0] = (HANDLE)(ULONG_PTR)0x066600; + hstd[1] = (HANDLE)(ULONG_PTR)0x066610; + break; + default: + ok(0, "Unsupported handle type %x\n", args & ARG_HANDLE_MASK); + return FALSE; + } + if ((args & ARG_HANDLE_PROTECT) && needs_close) + { + ret = SetHandleInformation(hstd[0], HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE); + ok(ret, "Couldn't set inherit flag to hstd[0]\n"); + ret = SetHandleInformation(hstd[1], HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE); + ok(ret, "Couldn't set inherit flag to hstd[1]\n"); + } + + if (args & ARG_STD) + { + SetStdHandle(STD_INPUT_HANDLE, hstd[0]); + SetStdHandle(STD_OUTPUT_HANDLE, hstd[1]); + } + else /* through startup info */ + { + startup->dwFlags |= STARTF_USESTDHANDLES; + startup->hStdInput = hstd[0]; + startup->hStdOutput = hstd[1]; + } + return needs_close; +} + +struct std_handle_test +{ + /* input */ + unsigned args; + /* output */ + DWORD expected; + DWORD is_broken; /* Win7 broken file types */ +}; + +static void test_StdHandleInheritance(void) +{ + HANDLE hsavestd[3]; + static char guiexec[MAX_PATH]; + static char cuiexec[MAX_PATH]; + char **argv; + BOOL ret; + int i, j; + + static const struct std_handle_test + nothing_cui[] = + { + /* all others handles type behave as H_DISK */ +/* 0*/ {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, + + /* all others handles type behave as H_DISK */ + {ARG_STARTUPINFO | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + {ARG_STD | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, + + /* all others handles type behave as H_DISK */ + {ARG_STARTUPINFO | H_DISK, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, +/* 5*/ {ARG_STD | H_DISK, HATTR_TYPE | FILE_TYPE_DISK}, + + /* all others handles type behave as H_DISK */ + {ARG_STARTUPINFO | ARG_HANDLE_PROTECT | H_DISK, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + {ARG_STD | ARG_HANDLE_PROTECT | H_DISK, HATTR_TYPE | HATTR_PROTECT | FILE_TYPE_DISK}, + + /* all others handles type behave as H_DISK */ + {ARG_STARTUPINFO | ARG_CP_INHERIT | H_DISK, HATTR_DANGLING, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + {ARG_STD | ARG_CP_INHERIT | H_DISK, HATTR_DANGLING}, + + /* all others handles type behave as H_DISK */ +/*10*/ {ARG_STARTUPINFO | H_DEVIL, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + {ARG_STD | H_DEVIL, HATTR_NULL}, + {ARG_STARTUPINFO | H_INVALID, HATTR_NULL, .is_broken = HATTR_INVALID}, + {ARG_STD | H_INVALID, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + {ARG_STARTUPINFO | H_NULL, HATTR_NULL, .is_broken = HATTR_INVALID}, +/*15*/ {ARG_STD | H_NULL, HATTR_NULL, .is_broken = HATTR_INVALID}, + }, + nothing_gui[] = + { + /* testing all types because of discrepancies */ +/* 0*/ {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, + {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_PIPE, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_PIPE}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_PIPE, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_PIPE}, + {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CHAR, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_CHAR}, +/* 5*/ {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CHAR, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_CHAR}, + {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + + /* all others handles type behave as H_DISK */ + {ARG_STARTUPINFO | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + {ARG_STD | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL}, + + /* all others handles type behave as H_DISK */ +/*10*/ {ARG_STARTUPINFO | ARG_CP_INHERIT | H_DISK, HATTR_DANGLING}, + {ARG_STD | ARG_CP_INHERIT | H_DISK, HATTR_DANGLING}, + + /* all others handles type behave as H_DISK */ + {ARG_STARTUPINFO | H_DISK, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + {ARG_STD | H_DISK, HATTR_NULL}, + + {ARG_STARTUPINFO | H_DEVIL, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, +/*15*/ {ARG_STD | H_DEVIL, HATTR_NULL}, + {ARG_STARTUPINFO | H_INVALID, HATTR_NULL, .is_broken = HATTR_INVALID}, + {ARG_STD | H_INVALID, HATTR_NULL}, + {ARG_STARTUPINFO | H_NULL, HATTR_NULL}, + {ARG_STD | H_NULL, HATTR_NULL}, + }, + detached_cui[] = + { + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL}, + {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_CHAR, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + /* all others handles type behave as H_DISK */ + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL}, + {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, + }, + detached_gui[] = + { + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL}, + {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + /* all others handles type behave as H_DISK */ + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL}, + {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, + }; + static const struct + { + DWORD cp_flags; + BOOL use_cui; + const struct std_handle_test* tests; + size_t count; + const char* descr; + } + tests[] = + { +#define X(d, cg, s) {(d), (cg), s, ARRAY_SIZE(s), #s} + X(0, TRUE, nothing_cui), + X(0, FALSE, nothing_gui), + X(DETACHED_PROCESS, TRUE, detached_cui), + X(DETACHED_PROCESS, FALSE, detached_gui), +#undef X + }; + +#ifdef __REACTOS__ + if (is_reactos()) { + ok(FALSE, "FIXME: These std handle tests on ReactOS confuses rosautotest\n"); + return; + } #endif + hsavestd[0] = GetStdHandle(STD_INPUT_HANDLE); + hsavestd[1] = GetStdHandle(STD_OUTPUT_HANDLE); + hsavestd[2] = GetStdHandle(STD_ERROR_HANDLE); + + winetest_get_mainargs(&argv); + + GetTempPathA(ARRAY_SIZE(guiexec), guiexec); + strcat(guiexec, "process_gui.exe"); + copy_change_subsystem(argv[0], guiexec, IMAGE_SUBSYSTEM_WINDOWS_GUI); + GetTempPathA(ARRAY_SIZE(cuiexec), cuiexec); + strcat(cuiexec, "process_cui.exe"); + copy_change_subsystem(argv[0], cuiexec, IMAGE_SUBSYSTEM_WINDOWS_CUI); + get_file_name(std_handle_file); + + for (j = 0; j < ARRAY_SIZE(tests); j++) + { + const struct std_handle_test* std_tests = tests[j].tests; + + for (i = 0; i < tests[j].count; i++) + { + STARTUPINFOA startup; +#if defined(__REACTOS__) && defined(_MSC_VER) + HANDLE hstd[2] = {0}; +#else + HANDLE hstd[2] = {}; +#endif + BOOL needs_close; + + winetest_push_context("%s[%u] ", tests[j].descr, i); + needs_close = build_startupinfo( &startup, std_tests[i].args, hstd ); + + ret = check_run_child(tests[j].use_cui ? cuiexec : guiexec, + tests[j].cp_flags, !!(std_tests[i].args & ARG_CP_INHERIT), + &startup); + ok(ret, "Couldn't run child\n"); + reload_child_info(resfile); + + if (std_tests[i].expected & HATTR_DANGLING) + { + /* The value of the handle (in parent) has been copied in STARTUPINFO fields (in child), + * but the object hasn't been inherited from parent to child. + * There's no reliable way to test that the object hasn't been inherited, as the + * entry in the child's handle table is free and could have been reused before + * this test occurs. + * So simply test that the value is passed untouched. + */ + okChildHexInt("StartupInfoA", "hStdInput", (DWORD_PTR)((std_tests[i].args & ARG_STD) ? INVALID_HANDLE_VALUE : hstd[0]), std_tests[i].is_broken); + okChildHexInt("StartupInfoA", "hStdOutput", (DWORD_PTR)((std_tests[i].args & ARG_STD) ? INVALID_HANDLE_VALUE : hstd[1]), std_tests[i].is_broken); + if (!(std_tests[i].args & ARG_STD)) + { + okChildHexInt("StartupInfoW", "hStdInput", (DWORD_PTR)hstd[0], std_tests[i].is_broken); + okChildHexInt("StartupInfoW", "hStdOutput", (DWORD_PTR)hstd[1], std_tests[i].is_broken); + } + + okChildHexInt("TEB", "hStdInput", (DWORD_PTR)hstd[0], std_tests[i].is_broken); + okChildHexInt("TEB", "hStdOutput", (DWORD_PTR)hstd[1], std_tests[i].is_broken); + } + else + { + unsigned startup_expected = (std_tests[i].args & ARG_STD) ? HATTR_INVALID : std_tests[i].expected; + + okChildHexInt("StartupInfoA", "hStdInputEncode", startup_expected, std_tests[i].is_broken); + okChildHexInt("StartupInfoA", "hStdOutputEncode", startup_expected, std_tests[i].is_broken); + + startup_expected = (std_tests[i].args & ARG_STD) ? HATTR_UNTOUCHED : std_tests[i].expected; + + okChildHexInt("StartupInfoW", "hStdInputEncode", startup_expected, std_tests[i].is_broken); + okChildHexInt("StartupInfoW", "hStdOutputEncode", startup_expected, std_tests[i].is_broken); + +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) { +#endif + okChildHexInt("TEB", "hStdInputEncode", std_tests[i].expected, std_tests[i].is_broken); + okChildHexInt("TEB", "hStdOutputEncode", std_tests[i].expected, std_tests[i].is_broken); +#ifdef __REACTOS__ + } +#endif + } + + release_memory(); + DeleteFileA(resfile); + if (needs_close) + { + SetHandleInformation(hstd[0], HANDLE_FLAG_PROTECT_FROM_CLOSE, 0); + CloseHandle(hstd[0]); + SetHandleInformation(hstd[1], HANDLE_FLAG_PROTECT_FROM_CLOSE, 0); + CloseHandle(hstd[1]); + } + winetest_pop_context(); + } + } + + DeleteFileA(guiexec); + DeleteFileA(cuiexec); + DeleteFileA(std_handle_file); + + SetStdHandle(STD_INPUT_HANDLE, hsavestd[0]); + SetStdHandle(STD_OUTPUT_HANDLE, hsavestd[1]); + SetStdHandle(STD_ERROR_HANDLE, hsavestd[2]); } #if defined(__i386__) || defined(__x86_64__) @@ -3159,7 +3702,7 @@ static BOOL are_imports_resolved(HANDLE process_handle, PVOID module_base, IMAGE ret = ReadProcessMemory(process_handle, (char *)module_base + nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, &iid, sizeof(iid), NULL); - ok(ret, "Failed to read remote module IID (%d)\n", GetLastError()); + ok(ret, "Failed to read remote module IID (%ld)\n", GetLastError()); /* Validate the IID is present and not a bound import, and that we have an OriginalFirstThunk to compare with */ @@ -3171,13 +3714,13 @@ static BOOL are_imports_resolved(HANDLE process_handle, PVOID module_base, IMAGE /* Read a single IAT entry from the FirstThunk */ ret = ReadProcessMemory(process_handle, (char *)module_base + iid.FirstThunk, &iat_entry_value, sizeof(iat_entry_value), NULL); - ok(ret, "Failed to read IAT entry from FirstThunk (%d)\n", GetLastError()); + ok(ret, "Failed to read IAT entry from FirstThunk (%ld)\n", GetLastError()); ok(iat_entry_value, "IAT entry in FirstThunk is NULL\n"); /* Read a single IAT entry from the OriginalFirstThunk */ ret = ReadProcessMemory(process_handle, (char *)module_base + iid.OriginalFirstThunk, &orig_iat_entry_value, sizeof(orig_iat_entry_value), NULL); - ok(ret, "Failed to read IAT entry from OriginalFirstThunk (%d)\n", GetLastError()); + ok(ret, "Failed to read IAT entry from OriginalFirstThunk (%ld)\n", GetLastError()); ok(orig_iat_entry_value, "IAT entry in OriginalFirstThunk is NULL\n"); return iat_entry_value != orig_iat_entry_value; @@ -3199,7 +3742,7 @@ static void test_SuspendProcessNewThread(void) si.cb = sizeof(si); ret = CreateProcessA(NULL, selfname, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi); - ok(ret, "Failed to create process (%d)\n", GetLastError()); + ok(ret, "Failed to create process (%ld)\n", GetLastError()); exe_base = get_process_exe(pi.hProcess, &nt_header); ok(exe_base != NULL, "Could not find EXE in remote process\n"); @@ -3210,58 +3753,55 @@ static void test_SuspendProcessNewThread(void) thread_handle = CreateRemoteThread(pi.hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)exit_thread_ptr, (PVOID)(ULONG_PTR)0x1234, CREATE_SUSPENDED, NULL); - ok(thread_handle != NULL, "Could not create remote thread (%d)\n", GetLastError()); + ok(thread_handle != NULL, "Could not create remote thread (%ld)\n", GetLastError()); ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header); ok(!ret, "IAT entry resolved prematurely\n"); ctx.ContextFlags = CONTEXT_ALL; ret = GetThreadContext( thread_handle, &ctx ); - ok( ret, "Failed retrieving remote thread context (%d)\n", GetLastError() ); - ok( ctx.ContextFlags == CONTEXT_ALL, "wrong flags %x\n", ctx.ContextFlags ); + ok( ret, "Failed retrieving remote thread context (%ld)\n", GetLastError() ); + ok( ctx.ContextFlags == CONTEXT_ALL, "wrong flags %lx\n", ctx.ContextFlags ); #ifdef __x86_64__ - ok( !ctx.Rax, "rax is not zero %lx\n", ctx.Rax ); - ok( !ctx.Rbx, "rbx is not zero %lx\n", ctx.Rbx ); - ok( ctx.Rcx == (ULONG_PTR)exit_thread_ptr, "wrong rcx %lx/%p\n", ctx.Rcx, exit_thread_ptr ); - ok( ctx.Rdx == 0x1234, "wrong rdx %lx\n", ctx.Rdx ); - ok( !ctx.Rsi, "rsi is not zero %lx\n", ctx.Rsi ); - ok( !ctx.Rdi, "rdi is not zero %lx\n", ctx.Rdi ); - ok( !ctx.Rbp, "rbp is not zero %lx\n", ctx.Rbp ); - ok( !ctx.R8, "r8 is not zero %lx\n", ctx.R8 ); - ok( !ctx.R9, "r9 is not zero %lx\n", ctx.R9 ); - ok( !ctx.R10, "r10 is not zero %lx\n", ctx.R10 ); - ok( !ctx.R11, "r11 is not zero %lx\n", ctx.R11 ); - ok( !ctx.R12, "r12 is not zero %lx\n", ctx.R12 ); - ok( !ctx.R13, "r13 is not zero %lx\n", ctx.R13 ); - ok( !ctx.R14, "r14 is not zero %lx\n", ctx.R14 ); - ok( !ctx.R15, "r15 is not zero %lx\n", ctx.R15 ); - ok( !((ctx.Rsp + 0x28) & 0xfff), "rsp is not at top of stack page %lx\n", ctx.Rsp ); - ok( ctx.EFlags == 0x200, "wrong flags %08x\n", ctx.EFlags ); - ok( ctx.MxCsr == 0x1f80, "wrong mxcsr %08x\n", ctx.MxCsr ); + ok( !ctx.Rax, "rax is not zero %Ix\n", ctx.Rax ); + ok( !ctx.Rbx, "rbx is not zero %Ix\n", ctx.Rbx ); + ok( ctx.Rcx == (ULONG_PTR)exit_thread_ptr, "wrong rcx %Ix/%p\n", ctx.Rcx, exit_thread_ptr ); + ok( ctx.Rdx == 0x1234, "wrong rdx %Ix\n", ctx.Rdx ); + ok( !ctx.Rsi, "rsi is not zero %Ix\n", ctx.Rsi ); + ok( !ctx.Rdi, "rdi is not zero %Ix\n", ctx.Rdi ); + ok( !ctx.Rbp, "rbp is not zero %Ix\n", ctx.Rbp ); + ok( !ctx.R8, "r8 is not zero %Ix\n", ctx.R8 ); + ok( !ctx.R9, "r9 is not zero %Ix\n", ctx.R9 ); + ok( !ctx.R10, "r10 is not zero %Ix\n", ctx.R10 ); + ok( !ctx.R11, "r11 is not zero %Ix\n", ctx.R11 ); + ok( !ctx.R12, "r12 is not zero %Ix\n", ctx.R12 ); + ok( !ctx.R13, "r13 is not zero %Ix\n", ctx.R13 ); + ok( !ctx.R14, "r14 is not zero %Ix\n", ctx.R14 ); + ok( !ctx.R15, "r15 is not zero %Ix\n", ctx.R15 ); + ok( ctx.EFlags == 0x200, "wrong flags %08lx\n", ctx.EFlags ); + ok( ctx.MxCsr == 0x1f80, "wrong mxcsr %08lx\n", ctx.MxCsr ); ok( ctx.FltSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FltSave.ControlWord ); #else - ok( !ctx.Ebp || broken(ctx.Ebp), /* winxp */ "ebp is not zero %08x\n", ctx.Ebp ); + ok( !ctx.Ebp || broken(ctx.Ebp), /* winxp */ "ebp is not zero %08lx\n", ctx.Ebp ); if (!ctx.Ebp) /* winxp is completely different */ { - ok( !ctx.Ecx, "ecx is not zero %08x\n", ctx.Ecx ); - ok( !ctx.Edx, "edx is not zero %08x\n", ctx.Edx ); - ok( !ctx.Esi, "esi is not zero %08x\n", ctx.Esi ); - ok( !ctx.Edi, "edi is not zero %08x\n", ctx.Edi ); + ok( !ctx.Ecx, "ecx is not zero %08lx\n", ctx.Ecx ); + ok( !ctx.Edx, "edx is not zero %08lx\n", ctx.Edx ); + ok( !ctx.Esi, "esi is not zero %08lx\n", ctx.Esi ); + ok( !ctx.Edi, "edi is not zero %08lx\n", ctx.Edi ); } - ok( ctx.Eax == (ULONG_PTR)exit_thread_ptr, "wrong eax %08x/%p\n", ctx.Eax, exit_thread_ptr ); - ok( ctx.Ebx == 0x1234, "wrong ebx %08x\n", ctx.Ebx ); - ok( !((ctx.Esp + 0x10) & 0xfff) || broken( !((ctx.Esp + 4) & 0xfff) ), /* winxp, w2k3 */ - "esp is not at top of stack page or properly aligned: %08x\n", ctx.Esp ); - ok( (ctx.EFlags & ~2) == 0x200, "wrong flags %08x\n", ctx.EFlags ); - ok( (WORD)ctx.FloatSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FloatSave.ControlWord ); + ok( ctx.Eax == (ULONG_PTR)exit_thread_ptr, "wrong eax %08lx/%p\n", ctx.Eax, exit_thread_ptr ); + ok( ctx.Ebx == 0x1234, "wrong ebx %08lx\n", ctx.Ebx ); + ok( (ctx.EFlags & ~2) == 0x200, "wrong flags %08lx\n", ctx.EFlags ); + ok( (WORD)ctx.FloatSave.ControlWord == 0x27f, "wrong control %08lx\n", ctx.FloatSave.ControlWord ); ok( *(WORD *)ctx.ExtendedRegisters == 0x27f, "wrong control %08x\n", *(WORD *)ctx.ExtendedRegisters ); #endif ResumeThread( thread_handle ); dret = WaitForSingleObject(thread_handle, 60000); - ok(dret == WAIT_OBJECT_0, "Waiting for remote thread failed (%d)\n", GetLastError()); + ok(dret == WAIT_OBJECT_0, "Waiting for remote thread failed (%ld)\n", GetLastError()); ret = GetExitCodeThread(thread_handle, &exit_code); - ok(ret, "Failed to retrieve remote thread exit code (%d)\n", GetLastError()); + ok(ret, "Failed to retrieve remote thread exit code (%ld)\n", GetLastError()); ok(exit_code == 0x1234, "Invalid remote thread exit code\n"); ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header); @@ -3270,10 +3810,11 @@ static void test_SuspendProcessNewThread(void) if (thread_handle) CloseHandle(thread_handle); + /* Note that the child's main thread is still suspended so the exit code + * is set by the TerminateProcess() call. + */ TerminateProcess(pi.hProcess, 0); - WaitForSingleObject(pi.hProcess, 10000); - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); + wait_and_close_child_process(&pi); } static void test_SuspendProcessState(void) @@ -3328,8 +3869,8 @@ static void test_SuspendProcessState(void) BOOL pipe_connected; ULONG pipe_magic, numb; BOOL ret; - void *entry_ptr, *peb_ptr; - PEB child_peb; + void *user_thread_start, *start_ptr, *entry_ptr, *peb_ptr; + PEB child_peb, *peb = NtCurrentTeb()->Peb; exit_process_ptr = GetProcAddress(hkernel32, "ExitProcess"); ok(exit_process_ptr != NULL, "GetProcAddress ExitProcess failed\n"); @@ -3339,7 +3880,7 @@ static void test_SuspendProcessState(void) si.cb = sizeof(si); ret = CreateProcessA(NULL, selfname, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi); - ok(ret, "Failed to create process (%d)\n", GetLastError()); + ok(ret, "Failed to create process (%ld)\n", GetLastError()); exe_base = get_process_exe(pi.hProcess, &nt_header); /* Make sure we found the EXE in the new process */ @@ -3351,16 +3892,16 @@ static void test_SuspendProcessState(void) server_pipe_handle = CreateNamedPipeA(pipe_name, PIPE_ACCESS_DUPLEX | FILE_FLAG_WRITE_THROUGH, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, 0x20000, 0x20000, 0, NULL); - ok(server_pipe_handle != INVALID_HANDLE_VALUE, "Failed to create communication pipe (%d)\n", GetLastError()); + ok(server_pipe_handle != INVALID_HANDLE_VALUE, "Failed to create communication pipe (%ld)\n", GetLastError()); /* Set up the remote process environment */ ctx.ContextFlags = CONTEXT_ALL; ret = GetThreadContext(pi.hThread, &ctx); - ok(ret, "Failed retrieving remote thread context (%d)\n", GetLastError()); - ok( ctx.ContextFlags == CONTEXT_ALL, "wrong flags %x\n", ctx.ContextFlags ); + ok(ret, "Failed retrieving remote thread context (%ld)\n", GetLastError()); + ok( ctx.ContextFlags == CONTEXT_ALL, "wrong flags %lx\n", ctx.ContextFlags ); remote_pipe_params = VirtualAllocEx(pi.hProcess, NULL, sizeof(pipe_params), MEM_COMMIT, PAGE_READWRITE); - ok(remote_pipe_params != NULL, "Failed allocating memory in remote process (%d)\n", GetLastError()); + ok(remote_pipe_params != NULL, "Failed allocating memory in remote process (%ld)\n", GetLastError()); pipe_params.pipe_write_buf = pipe_write_magic; pipe_params.pipe_read_buf = 0; @@ -3369,26 +3910,26 @@ static void test_SuspendProcessState(void) ret = WriteProcessMemory(pi.hProcess, remote_pipe_params, &pipe_params, sizeof(pipe_params), NULL); - ok(ret, "Failed to write to remote process memory (%d)\n", GetLastError()); + ok(ret, "Failed to write to remote process memory (%ld)\n", GetLastError()); #ifdef __x86_64__ - ok( !ctx.Rax, "rax is not zero %lx\n", ctx.Rax ); - ok( !ctx.Rbx, "rbx is not zero %lx\n", ctx.Rbx ); - ok( !ctx.Rsi, "rsi is not zero %lx\n", ctx.Rsi ); - ok( !ctx.Rdi, "rdi is not zero %lx\n", ctx.Rdi ); - ok( !ctx.Rbp, "rbp is not zero %lx\n", ctx.Rbp ); - ok( !ctx.R8, "r8 is not zero %lx\n", ctx.R8 ); - ok( !ctx.R9, "r9 is not zero %lx\n", ctx.R9 ); - ok( !ctx.R10, "r10 is not zero %lx\n", ctx.R10 ); - ok( !ctx.R11, "r11 is not zero %lx\n", ctx.R11 ); - ok( !ctx.R12, "r12 is not zero %lx\n", ctx.R12 ); - ok( !ctx.R13, "r13 is not zero %lx\n", ctx.R13 ); - ok( !ctx.R14, "r14 is not zero %lx\n", ctx.R14 ); - ok( !ctx.R15, "r15 is not zero %lx\n", ctx.R15 ); - ok( !((ctx.Rsp + 0x28) & 0xfff), "rsp is not at top of stack page %lx\n", ctx.Rsp ); - ok( ctx.EFlags == 0x200, "wrong flags %08x\n", ctx.EFlags ); - ok( ctx.MxCsr == 0x1f80, "wrong mxcsr %08x\n", ctx.MxCsr ); + ok( !ctx.Rax, "rax is not zero %Ix\n", ctx.Rax ); + ok( !ctx.Rbx, "rbx is not zero %Ix\n", ctx.Rbx ); + ok( !ctx.Rsi, "rsi is not zero %Ix\n", ctx.Rsi ); + ok( !ctx.Rdi, "rdi is not zero %Ix\n", ctx.Rdi ); + ok( !ctx.Rbp, "rbp is not zero %Ix\n", ctx.Rbp ); + ok( !ctx.R8, "r8 is not zero %Ix\n", ctx.R8 ); + ok( !ctx.R9, "r9 is not zero %Ix\n", ctx.R9 ); + ok( !ctx.R10, "r10 is not zero %Ix\n", ctx.R10 ); + ok( !ctx.R11, "r11 is not zero %Ix\n", ctx.R11 ); + ok( !ctx.R12, "r12 is not zero %Ix\n", ctx.R12 ); + ok( !ctx.R13, "r13 is not zero %Ix\n", ctx.R13 ); + ok( !ctx.R14, "r14 is not zero %Ix\n", ctx.R14 ); + ok( !ctx.R15, "r15 is not zero %Ix\n", ctx.R15 ); + ok( ctx.EFlags == 0x200, "wrong flags %08lx\n", ctx.EFlags ); + ok( ctx.MxCsr == 0x1f80, "wrong mxcsr %08lx\n", ctx.MxCsr ); ok( ctx.FltSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FltSave.ControlWord ); + start_ptr = (void *)ctx.Rip; entry_ptr = (void *)ctx.Rcx; peb_ptr = (void *)ctx.Rdx; @@ -3404,21 +3945,20 @@ static void test_SuspendProcessState(void) ctx.Rip = (ULONG_PTR)call_named_pipe_a; ctx.Rsp -= sizeof(rop_chain); ret = WriteProcessMemory(pi.hProcess, (void *)ctx.Rsp, &rop_chain, sizeof(rop_chain), NULL); - ok(ret, "Failed to write to remote process thread stack (%d)\n", GetLastError()); + ok(ret, "Failed to write to remote process thread stack (%ld)\n", GetLastError()); #else - ok( !ctx.Ebp || broken(ctx.Ebp), /* winxp */ "ebp is not zero %08x\n", ctx.Ebp ); + ok( !ctx.Ebp || broken(ctx.Ebp), /* winxp */ "ebp is not zero %08lx\n", ctx.Ebp ); if (!ctx.Ebp) /* winxp is completely different */ { - ok( !ctx.Ecx, "ecx is not zero %08x\n", ctx.Ecx ); - ok( !ctx.Edx, "edx is not zero %08x\n", ctx.Edx ); - ok( !ctx.Esi, "esi is not zero %08x\n", ctx.Esi ); - ok( !ctx.Edi, "edi is not zero %08x\n", ctx.Edi ); + ok( !ctx.Ecx, "ecx is not zero %08lx\n", ctx.Ecx ); + ok( !ctx.Edx, "edx is not zero %08lx\n", ctx.Edx ); + ok( !ctx.Esi, "esi is not zero %08lx\n", ctx.Esi ); + ok( !ctx.Edi, "edi is not zero %08lx\n", ctx.Edi ); } - ok( !((ctx.Esp + 0x10) & 0xfff) || broken( !((ctx.Esp + 4) & 0xfff) ), /* winxp, w2k3 */ - "esp is not at top of stack page or properly aligned: %08x\n", ctx.Esp ); - ok( (ctx.EFlags & ~2) == 0x200, "wrong flags %08x\n", ctx.EFlags ); - ok( (WORD)ctx.FloatSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FloatSave.ControlWord ); + ok( (ctx.EFlags & ~2) == 0x200, "wrong flags %08lx\n", ctx.EFlags ); + ok( (WORD)ctx.FloatSave.ControlWord == 0x27f, "wrong control %08lx\n", ctx.FloatSave.ControlWord ); ok( *(WORD *)ctx.ExtendedRegisters == 0x27f, "wrong control %08x\n", *(WORD *)ctx.ExtendedRegisters ); + start_ptr = (void *)ctx.Eip; entry_ptr = (void *)ctx.Eax; peb_ptr = (void *)ctx.Ebx; @@ -3435,19 +3975,76 @@ static void test_SuspendProcessState(void) ctx.Eip = (ULONG_PTR)call_named_pipe_a; ctx.Esp -= sizeof(rop_chain); ret = WriteProcessMemory(pi.hProcess, (void *)ctx.Esp, &rop_chain, sizeof(rop_chain), NULL); - ok(ret, "Failed to write to remote process thread stack (%d)\n", GetLastError()); + ok(ret, "Failed to write to remote process thread stack (%ld)\n", GetLastError()); #endif ret = ReadProcessMemory( pi.hProcess, peb_ptr, &child_peb, sizeof(child_peb), NULL ); - ok( ret, "Failed to read PEB (%u)\n", GetLastError() ); + ok( ret, "Failed to read PEB (%lu)\n", GetLastError() ); ok( child_peb.ImageBaseAddress == exe_base, "wrong base %p/%p\n", child_peb.ImageBaseAddress, exe_base ); + user_thread_start = GetProcAddress( GetModuleHandleA("ntdll.dll"), "RtlUserThreadStart" ); + if (user_thread_start) + ok( start_ptr == user_thread_start, + "wrong start addr %p / %p\n", start_ptr, user_thread_start ); ok( entry_ptr == (char *)exe_base + nt_header.OptionalHeader.AddressOfEntryPoint, "wrong entry point %p/%p\n", entry_ptr, (char *)exe_base + nt_header.OptionalHeader.AddressOfEntryPoint ); + ok( !child_peb.LdrData, "LdrData set %p\n", child_peb.LdrData ); + ok( !child_peb.FastPebLock, "FastPebLock set %p\n", child_peb.FastPebLock ); + ok( !child_peb.TlsBitmap, "TlsBitmap set %p\n", child_peb.TlsBitmap ); + ok( !child_peb.TlsExpansionBitmap, "TlsExpansionBitmap set %p\n", child_peb.TlsExpansionBitmap ); + ok( !child_peb.LoaderLock, "LoaderLock set %p\n", child_peb.LoaderLock ); + ok( !child_peb.ProcessHeap, "ProcessHeap set %p\n", child_peb.ProcessHeap ); + ok( !child_peb.CSDVersion.Buffer, "CSDVersion set %s\n", debugstr_w(child_peb.CSDVersion.Buffer) ); + + ok( child_peb.OSMajorVersion == peb->OSMajorVersion, "OSMajorVersion not set %lu\n", child_peb.OSMajorVersion ); + ok( child_peb.OSPlatformId == peb->OSPlatformId, "OSPlatformId not set %lu\n", child_peb.OSPlatformId ); + ok( child_peb.SessionId == peb->SessionId, "SessionId not set %lu\n", child_peb.SessionId ); + ok( child_peb.CriticalSectionTimeout.QuadPart, "CriticalSectionTimeout not set %s\n", + wine_dbgstr_longlong(child_peb.CriticalSectionTimeout.QuadPart) ); + ok( child_peb.HeapSegmentReserve == peb->HeapSegmentReserve, + "HeapSegmentReserve not set %Iu\n", child_peb.HeapSegmentReserve ); + ok( child_peb.HeapSegmentCommit == peb->HeapSegmentCommit, + "HeapSegmentCommit not set %Iu\n", child_peb.HeapSegmentCommit ); + ok( child_peb.HeapDeCommitTotalFreeThreshold == peb->HeapDeCommitTotalFreeThreshold, + "HeapDeCommitTotalFreeThreshold not set %Iu\n", child_peb.HeapDeCommitTotalFreeThreshold ); + ok( child_peb.HeapDeCommitFreeBlockThreshold == peb->HeapDeCommitFreeBlockThreshold, + "HeapDeCommitFreeBlockThreshold not set %Iu\n", child_peb.HeapDeCommitFreeBlockThreshold ); + + if (pNtQueryInformationThread) + { + TEB child_teb; + THREAD_BASIC_INFORMATION info; + NTSTATUS status = pNtQueryInformationThread( pi.hThread, ThreadBasicInformation, + &info, sizeof(info), NULL ); + ok( !status, "NtQueryInformationProcess failed %lx\n", status ); + ret = ReadProcessMemory( pi.hProcess, info.TebBaseAddress, &child_teb, sizeof(child_teb), NULL ); + ok( ret, "Failed to read TEB (%lu)\n", GetLastError() ); + + ok( child_teb.Peb == peb_ptr, "wrong Peb %p / %p\n", child_teb.Peb, peb_ptr ); + ok( PtrToUlong(child_teb.ClientId.UniqueProcess) == pi.dwProcessId, "wrong pid %lx / %lx\n", + PtrToUlong(child_teb.ClientId.UniqueProcess), pi.dwProcessId ); + ok( PtrToUlong(child_teb.ClientId.UniqueThread) == pi.dwThreadId, "wrong tid %lx / %lx\n", + PtrToUlong(child_teb.ClientId.UniqueThread), pi.dwThreadId ); + ok( PtrToUlong(child_teb.RealClientId.UniqueProcess) == pi.dwProcessId, "wrong real pid %lx / %lx\n", + PtrToUlong(child_teb.RealClientId.UniqueProcess), pi.dwProcessId ); + ok( PtrToUlong(child_teb.RealClientId.UniqueThread) == pi.dwThreadId, "wrong real tid %lx / %lx\n", + PtrToUlong(child_teb.RealClientId.UniqueThread), pi.dwThreadId ); + ok( child_teb.StaticUnicodeString.MaximumLength == sizeof(child_teb.StaticUnicodeBuffer), + "StaticUnicodeString.MaximumLength wrong %x\n", child_teb.StaticUnicodeString.MaximumLength ); + ok( (char *)child_teb.StaticUnicodeString.Buffer == (char *)info.TebBaseAddress + offsetof(TEB, StaticUnicodeBuffer), + "StaticUnicodeString.Buffer wrong %p\n", child_teb.StaticUnicodeString.Buffer ); + + ok( !child_teb.CurrentLocale, "CurrentLocale set %lx\n", child_teb.CurrentLocale ); + ok( !child_teb.TlsLinks.Flink, "TlsLinks.Flink set %p\n", child_teb.TlsLinks.Flink ); + ok( !child_teb.TlsLinks.Blink, "TlsLinks.Blink set %p\n", child_teb.TlsLinks.Blink ); + ok( !child_teb.TlsExpansionSlots, "TlsExpansionSlots set %p\n", child_teb.TlsExpansionSlots ); + ok( !child_teb.FlsSlots, "FlsSlots set %p\n", child_teb.FlsSlots ); + } + ret = SetThreadContext(pi.hThread, &ctx); - ok(ret, "Failed to set remote thread context (%d)\n", GetLastError()); + ok(ret, "Failed to set remote thread context (%ld)\n", GetLastError()); ResumeThread(pi.hThread); @@ -3455,20 +4052,25 @@ static void test_SuspendProcessState(void) ok(pipe_connected, "Pipe did not connect\n"); ret = ReadFile(server_pipe_handle, &pipe_magic, sizeof(pipe_magic), &numb, NULL); - ok(ret, "Failed to read buffer from pipe (%d)\n", GetLastError()); + ok(ret, "Failed to read buffer from pipe (%ld)\n", GetLastError()); ok(pipe_magic == pipe_write_magic, "Did not get the correct magic from the remote process\n"); - /* Validate the Imports, at this point the thread in the new process should have - initialized the EXE module imports and call each dll DllMain notifying it on - the new thread in the process. */ + /* Validate the imports: at this point the thread in the new process + * should have initialized the EXE module imports and called each dll's + * DllMain(), notifying it of the new thread in the process. + */ ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header); ok(ret, "EXE IAT is not resolved\n"); ret = WriteFile(server_pipe_handle, &pipe_magic, sizeof(pipe_magic), &numb, NULL); - ok(ret, "Failed to write the magic back to the pipe (%d)\n", GetLastError()); - + ok(ret, "Failed to write the magic back to the pipe (%ld)\n", GetLastError()); CloseHandle(server_pipe_handle); + + /* Avoid wait_child_process() because the exit code results from a race + * between the TerminateProcess() call and the child's ExitProcess() call + * which uses a random value in the 64 bit case. + */ TerminateProcess(pi.hProcess, 0); WaitForSingleObject(pi.hProcess, 10000); CloseHandle(pi.hProcess); @@ -3483,58 +4085,6 @@ static void test_SuspendProcessState(void) } #endif -static void test_DetachStdHandles(void) -{ -#ifndef _WIN64 - char buffer[MAX_PATH], tempfile[MAX_PATH]; - STARTUPINFOA startup; - PROCESS_INFORMATION info; - HANDLE hstdin, hstdout, hstderr, htemp; - BOOL res; - - hstdin = GetStdHandle(STD_INPUT_HANDLE); - hstdout = GetStdHandle(STD_OUTPUT_HANDLE); - hstderr = GetStdHandle(STD_ERROR_HANDLE); - - get_file_name(tempfile); - htemp = CreateFileA(tempfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); - ok(htemp != INVALID_HANDLE_VALUE, "failed opening temporary file\n"); - - memset(&startup, 0, sizeof(startup)); - startup.cb = sizeof(startup); - startup.dwFlags = STARTF_USESHOWWINDOW; - startup.wShowWindow = SW_SHOWNORMAL; - get_file_name(resfile); - sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); - - SetStdHandle(STD_INPUT_HANDLE, htemp); - SetStdHandle(STD_OUTPUT_HANDLE, htemp); - SetStdHandle(STD_ERROR_HANDLE, htemp); - - res = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, - &info); - - SetStdHandle(STD_INPUT_HANDLE, hstdin); - SetStdHandle(STD_OUTPUT_HANDLE, hstdout); - SetStdHandle(STD_ERROR_HANDLE, hstderr); - - ok(res, "CreateProcess failed\n"); - ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); - WritePrivateProfileStringA(NULL, NULL, NULL, resfile); - okChildInt("StartupInfoA", "hStdInput", (UINT)INVALID_HANDLE_VALUE); - okChildInt("StartupInfoA", "hStdOutput", (UINT)INVALID_HANDLE_VALUE); - okChildInt("StartupInfoA", "hStdError", (UINT)INVALID_HANDLE_VALUE); - okChildInt("TEB", "hStdInput", 0); - okChildInt("TEB", "hStdOutput", 0); - okChildInt("TEB", "hStdError", 0); - release_memory(); - DeleteFileA(resfile); - - CloseHandle(htemp); - DeleteFileA(tempfile); -#endif -} - static void test_GetNumaProcessorNode(void) { SYSTEM_INFO si; @@ -3563,7 +4113,7 @@ static void test_GetNumaProcessorNode(void) { ok(!ret, "GetNumaProcessorNode returned TRUE for processor %d\n", i); ok(node == 0xFF || broken(node == 0xAA) /* WinXP */, "expected node 0xFF, got %x\n", node); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); } } } @@ -3573,21 +4123,15 @@ static void test_session_info(void) DWORD session_id, active_session; BOOL r; - if (!pProcessIdToSessionId) - { - win_skip("ProcessIdToSessionId is missing\n"); - return; - } - - r = pProcessIdToSessionId(GetCurrentProcessId(), &session_id); - ok(r, "ProcessIdToSessionId failed: %u\n", GetLastError()); - trace("session_id = %x\n", session_id); + r = ProcessIdToSessionId(GetCurrentProcessId(), &session_id); + ok(r, "ProcessIdToSessionId failed: %lu\n", GetLastError()); + trace("session_id = %lx\n", session_id); active_session = pWTSGetActiveConsoleSessionId(); - trace("active_session = %x\n", active_session); + trace("active_session = %lx\n", active_session); } -static void test_process_info(void) +static void test_process_info(HANDLE hproc) { char buf[4096]; static const ULONG info_size[] = @@ -3628,22 +4172,22 @@ static void test_process_info(void) sizeof(ULONG) /* ProcessIoPriority */, sizeof(ULONG) /* ProcessExecuteFlags */, 0 /* FIXME: sizeof(?) ProcessTlsInformation */, - 0 /* FIXME: sizeof(?) ProcessCookie */, + sizeof(ULONG) /* ProcessCookie */, sizeof(SECTION_IMAGE_INFORMATION) /* ProcessImageInformation */, - 0 /* FIXME: sizeof(PROCESS_CYCLE_TIME_INFORMATION) ProcessCycleTime */, + sizeof(PROCESS_CYCLE_TIME_INFORMATION) /* ProcessCycleTime */, sizeof(ULONG) /* ProcessPagePriority */, 40 /* ProcessInstrumentationCallback */, 0 /* FIXME: sizeof(PROCESS_STACK_ALLOCATION_INFORMATION) ProcessThreadStackAllocation */, 0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION_EX[]) ProcessWorkingSetWatchEx */, sizeof(buf) /* ProcessImageFileNameWin32 */, +#if 0 /* FIXME: Add remaining classes */ sizeof(HANDLE) /* ProcessImageFileMapping */, - 0 /* FIXME: sizeof(PROCESS_AFFINITY_UPDATE_MODE) ProcessAffinityUpdateMode */, - 0 /* FIXME: sizeof(PROCESS_MEMORY_ALLOCATION_MODE) ProcessMemoryAllocationMode */, - sizeof(USHORT) /* ProcessGroupInformation */, + sizeof(PROCESS_AFFINITY_UPDATE_MODE) /* ProcessAffinityUpdateMode */, + sizeof(PROCESS_MEMORY_ALLOCATION_MODE) /* ProcessMemoryAllocationMode */, + sizeof(USHORT[]) /* ProcessGroupInformation */, sizeof(ULONG) /* ProcessTokenVirtualizationEnabled */, sizeof(ULONG_PTR) /* ProcessConsoleHostProcess */, - 0 /* FIXME: sizeof(PROCESS_WINDOW_INFORMATION) ProcessWindowInformation */, -#if 0 /* FIXME: Add remaining classes */ + sizeof(PROCESS_WINDOW_INFORMATION) /* ProcessWindowInformation */, sizeof(PROCESS_HANDLE_SNAPSHOT_INFORMATION) /* ProcessHandleInformation */, sizeof(PROCESS_MITIGATION_POLICY_INFORMATION) /* ProcessMitigationPolicy */, sizeof(ProcessDynamicFunctionTableInformation) /* ProcessDynamicFunctionTableInformation */, @@ -3667,8 +4211,8 @@ static void test_process_info(void) sizeof(PROCESS_JOB_MEMORY_INFO) /* ProcessJobMemoryInformation */, #endif }; - HANDLE hproc; - ULONG i, status, ret_len, size; + ULONG i, status, ret_len; + BOOL is_current = hproc == GetCurrentProcess(); if (!pNtQueryInformationProcess) { @@ -3676,17 +4220,8 @@ static void test_process_info(void) return; } - hproc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId()); - if (!hproc) + for (i = 0; i < ARRAY_SIZE(info_size); i++) { - win_skip("PROCESS_QUERY_LIMITED_INFORMATION is not supported on this platform\n"); - return; - } - - for (i = 0; i < MaxProcessInfoClass; i++) - { - size = info_size[i]; - if (!size) size = sizeof(buf); ret_len = 0; status = pNtQueryInformationProcess(hproc, i, buf, info_size[i], &ret_len); if (status == STATUS_NOT_IMPLEMENTED) continue; @@ -3701,7 +4236,7 @@ static void test_process_info(void) case ProcessPriorityClass: case ProcessPriorityBoost: case ProcessLUIDDeviceMapsEnabled: - case 33 /* ProcessIoPriority */: + case ProcessIoPriority: case ProcessIoCounters: case ProcessVmCounters: case ProcessWow64Information: @@ -3709,39 +4244,60 @@ static void test_process_info(void) case ProcessHandleCount: case ProcessImageFileName: case ProcessImageInformation: + case ProcessCycleTime: case ProcessPagePriority: case ProcessImageFileNameWin32: - ok(status == STATUS_SUCCESS, "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len); +#ifdef __REACTOS__ + ok(status == STATUS_SUCCESS || broken(status == STATUS_ACCESS_DENIED || status == STATUS_INVALID_PARAMETER) /* WS03 */, "for info %lu expected STATUS_SUCCESS, got %08lx (ret_len %lu)\n", i, status, ret_len); +#else + ok(status == STATUS_SUCCESS, "for info %lu expected STATUS_SUCCESS, got %08lx (ret_len %lu)\n", i, status, ret_len); +#endif break; case ProcessAffinityMask: case ProcessBreakOnTermination: - case ProcessGroupInformation: - case ProcessConsoleHostProcess: ok(status == STATUS_ACCESS_DENIED /* before win8 */ || status == STATUS_SUCCESS /* win8 is less strict */, - "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len); + "for info %lu expected STATUS_SUCCESS, got %08lx (ret_len %lu)\n", i, status, ret_len); break; case ProcessDebugObjectHandle: ok(status == STATUS_ACCESS_DENIED || status == STATUS_PORT_NOT_SET, - "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len); + "for info %lu expected STATUS_ACCESS_DENIED, got %08lx (ret_len %lu)\n", i, status, ret_len); + break; + case ProcessCookie: + if (is_current) + ok(status == STATUS_SUCCESS || status == STATUS_INVALID_PARAMETER /* before win8 */, + "for info %lu got %08lx (ret_len %lu)\n", i, status, ret_len); + else + ok(status == STATUS_INVALID_PARAMETER /* before win8 */ || status == STATUS_ACCESS_DENIED, + "for info %lu got %08lx (ret_len %lu)\n", i, status, ret_len); break; - case ProcessExecuteFlags: case ProcessDebugPort: case ProcessDebugFlags: - case ProcessCookie: -todo_wine - ok(status == STATUS_ACCESS_DENIED, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len); + if (is_current) + ok(status == STATUS_SUCCESS || status == STATUS_INVALID_PARAMETER, + "for info %lu, got %08lx (ret_len %lu)\n", i, status, ret_len); + else + todo_wine +#ifdef __REACTOS__ + ok(status == STATUS_ACCESS_DENIED || broken(status == STATUS_INVALID_PARAMETER) /* WS03 */, +#else + ok(status == STATUS_ACCESS_DENIED, +#endif + "for info %lu expected STATUS_ACCESS_DENIED, got %08lx (ret_len %lu)\n", i, status, ret_len); break; default: - ok(status == STATUS_ACCESS_DENIED, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len); + if (is_current) + ok(status == STATUS_SUCCESS || status == STATUS_UNSUCCESSFUL || status == STATUS_INVALID_PARAMETER, + "for info %lu, got %08lx (ret_len %lu)\n", i, status, ret_len); + else + ok(status == STATUS_ACCESS_DENIED, + "for info %lu expected STATUS_ACCESS_DENIED, got %08lx (ret_len %lu)\n", i, status, ret_len); break; } } - - CloseHandle(hproc); } static void test_GetLogicalProcessorInformationEx(void) @@ -3757,36 +4313,101 @@ static void test_GetLogicalProcessorInformationEx(void) } ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, NULL); - ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError()); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %ld\n", ret, GetLastError()); len = 0; ret = pGetLogicalProcessorInformationEx(RelationProcessorCore, NULL, &len); - ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %d\n", ret, GetLastError()); - ok(len > 0, "got %u\n", len); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %ld\n", ret, GetLastError()); + ok(len > 0, "got %lu\n", len); len = 0; ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, &len); - ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %d\n", ret, GetLastError()); - ok(len > 0, "got %u\n", len); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %ld\n", ret, GetLastError()); + ok(len > 0, "got %lu\n", len); info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len); ret = pGetLogicalProcessorInformationEx(RelationAll, info, &len); - ok(ret, "got %d, error %d\n", ret, GetLastError()); - ok(info->Size > 0, "got %u\n", info->Size); + ok(ret, "got %d, error %ld\n", ret, GetLastError()); + ok(info->Size > 0, "got %lu\n", info->Size); HeapFree(GetProcessHeap(), 0, info); } +static void test_GetSystemCpuSetInformation(void) +{ +#ifdef __REACTOS__ + skip("Cannot build test_GetSystemCpuSetInformation() until kernelbase is synced.\n"); +#else + SYSTEM_CPU_SET_INFORMATION *info, *info_nt; + HANDLE process = GetCurrentProcess(); + ULONG size, expected_size; + NTSTATUS status; + SYSTEM_INFO si; + BOOL ret; + + if (!pGetSystemCpuSetInformation) + { + win_skip("GetSystemCpuSetInformation() is not supported.\n"); + return; + } + + GetSystemInfo(&si); + + expected_size = sizeof(*info) * si.dwNumberOfProcessors; + + if (0) + { + /* Crashes on Windows with NULL return length. */ + pGetSystemCpuSetInformation(NULL, 0, NULL, process, 0); + } + + size = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pGetSystemCpuSetInformation(NULL, size, &size, process, 0); + ok(!ret && GetLastError() == ERROR_NOACCESS, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + ok(!size, "Got unexpected size %lu.\n", size); + + size = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pGetSystemCpuSetInformation(NULL, 0, &size, (HANDLE)0xdeadbeef, 0); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + ok(!size, "Got unexpected size %lu.\n", size); + + size = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pGetSystemCpuSetInformation(NULL, 0, &size, process, 0); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + ok(size == expected_size, "Got unexpected size %lu.\n", size); + + info = heap_alloc(size); + info_nt = heap_alloc(size); + + status = pNtQuerySystemInformationEx(SystemCpuSetInformation, &process, sizeof(process), info_nt, expected_size, NULL); + ok(!status, "Got unexpected status %#lx.\n", status); + + size = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pGetSystemCpuSetInformation(info, expected_size, &size, process, 0); + ok(ret && GetLastError() == 0xdeadbeef, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + ok(size == expected_size, "Got unexpected size %lu.\n", size); + + ok(!memcmp(info, info_nt, expected_size), "Info does not match NtQuerySystemInformationEx().\n"); + + heap_free(info_nt); + heap_free(info); +#endif +} + static void test_largepages(void) { SIZE_T size; if (!pGetLargePageMinimum) { - skip("No GetLargePageMinimum support.\n"); + win_skip("No GetLargePageMinimum support.\n"); return; } size = pGetLargePageMinimum(); - ok((size == 0) || (size == 2*1024*1024) || (size == 4*1024*1024), "GetLargePageMinimum reports %ld size\n", size); + ok((size == 0) || (size == 2*1024*1024) || (size == 4*1024*1024), "GetLargePageMinimum reports %Id size\n", size); } struct proc_thread_attr @@ -3827,16 +4448,16 @@ static void test_ProcThreadAttributeList(void) ok(!ret, "got %d\n", ret); if(i >= 4 && GetLastError() == ERROR_INVALID_PARAMETER) /* Vista only allows a maximium of 3 slots */ break; - ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d\n", GetLastError()); - ok(size == needed, "%d: got %ld expect %ld\n", i, size, needed); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %ld\n", GetLastError()); + ok(size == needed, "%d: got %Id expect %Id\n", i, size, needed); memset(&list, 0xcc, sizeof(list)); ret = pInitializeProcThreadAttributeList(&list, i, 0, &size); ok(ret, "got %d\n", ret); - ok(list.mask == 0, "%d: got %08x\n", i, list.mask); - ok(list.size == i, "%d: got %08x\n", i, list.size); - ok(list.count == 0, "%d: got %08x\n", i, list.count); - ok(list.unk == 0, "%d: got %08lx\n", i, list.unk); + ok(list.mask == 0, "%d: got %08lx\n", i, list.mask); + ok(list.size == i, "%d: got %08lx\n", i, list.size); + ok(list.count == 0, "%d: got %08lx\n", i, list.count); + ok(list.unk == 0, "%d: got %08Ix\n", i, list.unk); } memset(handles, 0, sizeof(handles)); @@ -3848,15 +4469,15 @@ static void test_ProcThreadAttributeList(void) ret = pUpdateProcThreadAttribute(&list, 0, 0xcafe, handles, sizeof(PROCESSOR_NUMBER), NULL, NULL); ok(!ret, "got %d\n", ret); - ok(GetLastError() == ERROR_NOT_SUPPORTED, "got %d\n", GetLastError()); + ok(GetLastError() == ERROR_NOT_SUPPORTED, "got %ld\n", GetLastError()); ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]) / 2, NULL, NULL); ok(!ret, "got %d\n", ret); - ok(GetLastError() == ERROR_BAD_LENGTH, "got %d\n", GetLastError()); + ok(GetLastError() == ERROR_BAD_LENGTH, "got %ld\n", GetLastError()); ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]) * 2, NULL, NULL); ok(!ret, "got %d\n", ret); - ok(GetLastError() == ERROR_BAD_LENGTH, "got %d\n", GetLastError()); + ok(GetLastError() == ERROR_BAD_LENGTH, "got %ld\n", GetLastError()); ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]), NULL, NULL); ok(ret, "got %d\n", ret); @@ -3869,11 +4490,11 @@ static void test_ProcThreadAttributeList(void) ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]), NULL, NULL); ok(!ret, "got %d\n", ret); - ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS, "got %d\n", GetLastError()); + ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS, "got %ld\n", GetLastError()); ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles) - 1, NULL, NULL); ok(!ret, "got %d\n", ret); - ok(GetLastError() == ERROR_BAD_LENGTH, "got %d\n", GetLastError()); + ok(GetLastError() == ERROR_BAD_LENGTH, "got %ld\n", GetLastError()); ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles), NULL, NULL); ok(ret, "got %d\n", ret); @@ -3886,10 +4507,10 @@ static void test_ProcThreadAttributeList(void) ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles), NULL, NULL); ok(!ret, "got %d\n", ret); - ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS, "got %d\n", GetLastError()); + ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS, "got %ld\n", GetLastError()); ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR, handles, sizeof(PROCESSOR_NUMBER), NULL, NULL); - ok(ret || GetLastError() == ERROR_NOT_SUPPORTED, "got %d gle %d\n", ret, GetLastError()); + ok(ret || GetLastError() == ERROR_NOT_SUPPORTED, "got %d gle %ld\n", ret, GetLastError()); if (ret) { @@ -3900,34 +4521,1116 @@ static void test_ProcThreadAttributeList(void) expect_list.count++; } + ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, handles, sizeof(handles[0]), NULL, NULL); + ok(ret || broken(GetLastError() == ERROR_NOT_SUPPORTED), "got %d gle %ld\n", ret, GetLastError()); + + if (ret) + { + unsigned int i = expect_list.count++; + expect_list.mask |= 1 << ProcThreadAttributePseudoConsole; + expect_list.attrs[i].attr = PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE; + expect_list.attrs[i].size = sizeof(HPCON); + expect_list.attrs[i].value = handles; + } + ok(!memcmp(&list, &expect_list, size), "mismatch\n"); pDeleteProcThreadAttributeList(&list); } -static void test_GetActiveProcessorCount(void) +/* level 0: Main test process + * level 1: Process created by level 0 process without handle inheritance + * level 2: Process created by level 1 process with handle inheritance and level 0 + * process parent substitute. + * level 255: Process created by level 1 process during invalid parent handles testing. */ +static void test_parent_process_attribute(unsigned int level, HANDLE read_pipe) { - DWORD count; + PROCESS_BASIC_INFORMATION pbi; + char buffer[MAX_PATH + 64]; + HANDLE write_pipe = NULL; + PROCESS_INFORMATION info; + SECURITY_ATTRIBUTES sa; + STARTUPINFOEXA si; + DWORD parent_id; + NTSTATUS status; + ULONG pbi_size; + HANDLE parent; + DWORD size; + BOOL ret; - if (!pGetActiveProcessorCount) + struct { - win_skip("GetActiveProcessorCount not available, skipping test\n"); + HANDLE parent; + DWORD parent_id; + } + parent_data; + + if (level == 255) + return; + + if (!pInitializeProcThreadAttributeList) + { + win_skip("No support for ProcThreadAttributeList.\n"); return; } - count = pGetActiveProcessorCount(0); - ok(count, "GetActiveProcessorCount failed, error %u\n", GetLastError()); + memset(&sa, 0, sizeof(sa)); + sa.nLength = sizeof(sa); + sa.bInheritHandle = TRUE; + + if (!level) + { + ret = CreatePipe(&read_pipe, &write_pipe, &sa, 0); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + + parent_data.parent = OpenProcess(PROCESS_CREATE_PROCESS | PROCESS_QUERY_INFORMATION, TRUE, GetCurrentProcessId()); + parent_data.parent_id = GetCurrentProcessId(); + } + else + { + status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi), &pbi_size); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + parent_id = pbi.InheritedFromUniqueProcessId; + + memset(&parent_data, 0, sizeof(parent_data)); + ret = ReadFile(read_pipe, &parent_data, sizeof(parent_data), &size, NULL); + ok((level == 2 && ret) || (level == 1 && !ret && GetLastError() == ERROR_INVALID_HANDLE), + "Got unexpected ret %#x, level %u, GetLastError() %lu.\n", + ret, level, GetLastError()); + } + + if (level == 2) + { + ok(parent_id == parent_data.parent_id, "Got parent id %lu, parent_data.parent_id %lu.\n", + parent_id, parent_data.parent_id); + return; + } + + memset(&si, 0, sizeof(si)); + si.StartupInfo.cb = sizeof(si); + + if (level) + { + HANDLE handle; + SIZE_T size; + + ret = pInitializeProcThreadAttributeList(NULL, 1, 0, &size); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + + sprintf(buffer, "\"%s\" process parent %u %p", selfname, 255, read_pipe); + +#if 0 + /* Crashes on some Windows installations, otherwise successfully creates process. */ + ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, + NULL, NULL, (STARTUPINFOA *)&si, &info); + ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError()); + wait_and_close_child_process(&info); +#endif + si.lpAttributeList = heap_alloc(size); + ret = pInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + handle = OpenProcess(PROCESS_CREATE_PROCESS, TRUE, GetCurrentProcessId()); + ret = pUpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, + &handle, sizeof(handle), NULL, NULL); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + ret = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT, + NULL, NULL, (STARTUPINFOA *)&si, &info); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + wait_and_close_child_process(&info); + CloseHandle(handle); + pDeleteProcThreadAttributeList(si.lpAttributeList); + heap_free(si.lpAttributeList); + + si.lpAttributeList = heap_alloc(size); + ret = pInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + handle = (HANDLE)0xdeadbeef; + ret = pUpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, + &handle, sizeof(handle), NULL, NULL); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + ret = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT, + NULL, NULL, (STARTUPINFOA *)&si, &info); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Got unexpected ret %#x, GetLastError() %lu.\n", + ret, GetLastError()); + pDeleteProcThreadAttributeList(si.lpAttributeList); + heap_free(si.lpAttributeList); + + si.lpAttributeList = heap_alloc(size); + ret = pInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + handle = NULL; + ret = pUpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, + &handle, sizeof(handle), NULL, NULL); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + ret = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT, + NULL, NULL, (STARTUPINFOA *)&si, &info); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Got unexpected ret %#x, GetLastError() %lu.\n", + ret, GetLastError()); + pDeleteProcThreadAttributeList(si.lpAttributeList); + heap_free(si.lpAttributeList); + + si.lpAttributeList = heap_alloc(size); + ret = pInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + handle = GetCurrentProcess(); + ret = pUpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, + &handle, sizeof(handle), NULL, NULL); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + ret = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT, + NULL, NULL, (STARTUPINFOA *)&si, &info); + /* Broken on Vista / w7 / w10. */ + ok(ret || broken(!ret && GetLastError() == ERROR_INVALID_HANDLE), + "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + if (ret) + wait_and_close_child_process(&info); + pDeleteProcThreadAttributeList(si.lpAttributeList); + heap_free(si.lpAttributeList); + + si.lpAttributeList = heap_alloc(size); + ret = pInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + + parent = OpenProcess(PROCESS_CREATE_PROCESS, FALSE, parent_id); + + ret = pUpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, + &parent, sizeof(parent), NULL, NULL); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + } + + sprintf(buffer, "\"%s\" process parent %u %p", selfname, level + 1, read_pipe); + ret = CreateProcessA(NULL, buffer, NULL, NULL, level == 1, level == 1 ? EXTENDED_STARTUPINFO_PRESENT : 0, + NULL, NULL, (STARTUPINFOA *)&si, &info); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + + if (level) + { + pDeleteProcThreadAttributeList(si.lpAttributeList); + heap_free(si.lpAttributeList); + CloseHandle(parent); + } + else + { + ret = WriteFile(write_pipe, &parent_data, sizeof(parent_data), &size, NULL); + } + + wait_and_close_child_process(&info); + + if (!level) + { + CloseHandle(read_pipe); + CloseHandle(write_pipe); + CloseHandle(parent_data.parent); + } +} + +static void test_handle_list_attribute(BOOL child, HANDLE handle1, HANDLE handle2) +{ + char buffer[MAX_PATH + 64]; + HANDLE pipe[2]; + PROCESS_INFORMATION info; + STARTUPINFOEXA si; + SIZE_T size; + BOOL ret; + SECURITY_ATTRIBUTES sa; + + if (child) + { + char name1[256], name2[256]; + DWORD flags; + + flags = 0; + ret = GetHandleInformation(handle1, &flags); + ok(ret, "Failed to get handle info, error %ld.\n", GetLastError()); + ok(flags == HANDLE_FLAG_INHERIT, "Unexpected flags %#lx.\n", flags); +#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600 + ret = GetFileInformationByHandleEx(handle1, FileNameInfo, name1, sizeof(name1)); + ok(ret, "Failed to get pipe name, error %ld\n", GetLastError()); +#endif + CloseHandle(handle1); + flags = 0; + ret = GetHandleInformation(handle2, &flags); + if (ret) + { + ok(!(flags & HANDLE_FLAG_INHERIT), "Parent's handle shouldn't have been inherited\n"); +#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600 + ret = GetFileInformationByHandleEx(handle2, FileNameInfo, name2, sizeof(name2)); + ok(!ret || strcmp(name1, name2), "Parent's handle shouldn't have been inherited\n"); +#endif + } + else + ok(GetLastError() == ERROR_INVALID_HANDLE, "Unexpected return value, error %ld.\n", GetLastError()); + + return; + } + +#ifdef __REACTOS__ + if (GetNTVersion() < _WIN32_WINNT_VISTA) { + skip("test_handle_list_attribute() crashes on WS03.\n"); + return; + } +#endif + ret = pInitializeProcThreadAttributeList(NULL, 1, 0, &size); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + + memset(&si, 0, sizeof(si)); + si.StartupInfo.cb = sizeof(si); + si.lpAttributeList = heap_alloc(size); + ret = pInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + + memset(&sa, 0, sizeof(sa)); + sa.nLength = sizeof(sa); + sa.bInheritHandle = TRUE; + + ret = CreatePipe(&pipe[0], &pipe[1], &sa, 1024); + ok(ret, "Failed to create a pipe.\n"); + + ret = pUpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, &pipe[0], + sizeof(pipe[0]), NULL, NULL); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + + sprintf(buffer, "\"%s\" process handlelist %p %p", selfname, pipe[0], pipe[1]); + ret = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, + (STARTUPINFOA *)&si, &info); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + + wait_and_close_child_process(&info); + + CloseHandle(pipe[0]); + CloseHandle(pipe[1]); +} + +static void test_dead_process(void) +{ + DWORD_PTR data[256]; + PROCESS_BASIC_INFORMATION basic; + SYSTEM_PROCESS_INFORMATION *spi; + SECTION_IMAGE_INFORMATION image; + PROCESS_INFORMATION pi; + PROCESS_PRIORITY_CLASS *prio = (PROCESS_PRIORITY_CLASS *)data; + BYTE *buffer = NULL; + BOOL found; + ULONG size = 0; + DWORD offset = 0; + NTSTATUS status; + +#ifdef __REACTOS__ + if (GetNTVersion() < _WIN32_WINNT_VISTA) { + skip("test_dead_process() crashes on WS03.\n"); + return; + } +#endif + create_process("exit", &pi); + wait_child_process(pi.hProcess); + Sleep(100); + + memset( data, 0, sizeof(data) ); + status = NtQueryInformationProcess( pi.hProcess, ProcessImageFileName, data, sizeof(data), NULL); + ok( !status, "ProcessImageFileName failed %lx\n", status ); + ok( ((UNICODE_STRING *)data)->Length, "ProcessImageFileName not set\n" ); + ok( ((UNICODE_STRING *)data)->Buffer[0] == '\\', "ProcessImageFileName not set\n" ); + + memset( prio, 0xcc, sizeof(*prio) ); + status = NtQueryInformationProcess( pi.hProcess, ProcessPriorityClass, prio, sizeof(*prio), NULL); + ok( !status, "ProcessPriorityClass failed %lx\n", status ); + ok( prio->PriorityClass != 0xcc, "ProcessPriorityClass not set\n" ); + + memset( &basic, 0xcc, sizeof(basic) ); + status = NtQueryInformationProcess( pi.hProcess, ProcessBasicInformation, &basic, sizeof(basic), NULL); + ok( !status, "ProcessBasicInformation failed %lx\n", status ); + ok( basic.ExitStatus == 0, "ProcessBasicInformation info modified\n" ); + + memset( &image, 0xcc, sizeof(image) ); + status = NtQueryInformationProcess( pi.hProcess, ProcessImageInformation, &image, sizeof(image), NULL); + ok( status == STATUS_PROCESS_IS_TERMINATING, "ProcessImageInformation wrong error %lx\n", status ); + ok( image.Machine == 0xcccc, "ProcessImageInformation info modified\n" ); + + while ((status = NtQuerySystemInformation(SystemProcessInformation, buffer, size, &size)) == STATUS_INFO_LENGTH_MISMATCH) + { + free(buffer); + buffer = malloc(size); + } + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + found = FALSE; + do + { + spi = (SYSTEM_PROCESS_INFORMATION *)(buffer + offset); + if (spi->UniqueProcessId == ULongToHandle(pi.dwProcessId)) + { + found = TRUE; + break; + } + offset += spi->NextEntryOffset; + } while (spi->NextEntryOffset); + ok( !found, "process still enumerated\n" ); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); +} + +static void test_nested_jobs_child(unsigned int index) +{ + JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info; + HANDLE job, job_parent, job_other, port; + PROCESS_INFORMATION pi; + OVERLAPPED *overlapped; + char job_name[32]; + ULONG_PTR value; + DWORD dead_pid; + BOOL ret, out; + DWORD key; + + sprintf(job_name, "test_nested_jobs_%u", index); + job = pOpenJobObjectA(JOB_OBJECT_ASSIGN_PROCESS | JOB_OBJECT_SET_ATTRIBUTES | JOB_OBJECT_QUERY + | JOB_OBJECT_TERMINATE, FALSE, job_name); + ok(!!job, "OpenJobObjectA error %lu\n", GetLastError()); + + sprintf(job_name, "test_nested_jobs_%u", !index); + job_other = pOpenJobObjectA(JOB_OBJECT_ASSIGN_PROCESS | JOB_OBJECT_SET_ATTRIBUTES | JOB_OBJECT_QUERY + | JOB_OBJECT_TERMINATE, FALSE, job_name); + ok(!!job_other, "OpenJobObjectA error %lu\n", GetLastError()); + + job_parent = pCreateJobObjectW(NULL, NULL); + ok(!!job_parent, "CreateJobObjectA error %lu\n", GetLastError()); + + ret = pAssignProcessToJobObject(job_parent, GetCurrentProcess()); + ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError()); + + create_process("wait", &pi); + + ret = pAssignProcessToJobObject(job_parent, pi.hProcess); + ok(ret || broken(!ret && GetLastError() == ERROR_ACCESS_DENIED) /* Supported since Windows 8. */, + "AssignProcessToJobObject error %lu\n", GetLastError()); + if (!ret) + { + win_skip("Nested jobs are not supported.\n"); + goto done; + } + ret = pAssignProcessToJobObject(job, pi.hProcess); + ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError()); + + out = FALSE; + ret = pIsProcessInJob(pi.hProcess, NULL, &out); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); + ok(out, "IsProcessInJob returned out=%u\n", out); + + out = FALSE; + ret = pIsProcessInJob(pi.hProcess, job, &out); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); + ok(out, "IsProcessInJob returned out=%u\n", out); + + out = TRUE; + ret = pIsProcessInJob(GetCurrentProcess(), job, &out); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); + ok(!out, "IsProcessInJob returned out=%u\n", out); + + out = FALSE; + ret = pIsProcessInJob(pi.hProcess, job, &out); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); + ok(out, "IsProcessInJob returned out=%u\n", out); + + ret = pAssignProcessToJobObject(job, GetCurrentProcess()); + ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError()); + + TerminateProcess(pi.hProcess, 0); + wait_child_process(pi.hProcess); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + + dead_pid = pi.dwProcessId; + + port = pCreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); + ok(!!port, "CreateIoCompletionPort error %lu\n", GetLastError()); + + port_info.CompletionPort = port; + port_info.CompletionKey = job; + ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info)); + ok(ret, "SetInformationJobObject error %lu\n", GetLastError()); + port_info.CompletionKey = job_parent; + ret = pSetInformationJobObject(job_parent, JobObjectAssociateCompletionPortInformation, + &port_info, sizeof(port_info)); + ok(ret, "SetInformationJobObject error %lu\n", GetLastError()); + + create_process("wait", &pi); + out = FALSE; + ret = pIsProcessInJob(pi.hProcess, job, &out); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); + ok(out, "IsProcessInJob returned out=%u\n", out); + + out = FALSE; + ret = pIsProcessInJob(pi.hProcess, job_parent, &out); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); + ok(out, "IsProcessInJob returned out=%u\n", out); + + /* The first already dead child process still shows up randomly. */ + do + { + ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 0); + } while (ret && (ULONG_PTR)overlapped == dead_pid); + + ok(ret, "GetQueuedCompletionStatus: %lx\n", GetLastError()); + ok(key == JOB_OBJECT_MSG_NEW_PROCESS, "unexpected key %lx\n", key); + ok((HANDLE)value == job, "unexpected value %p\n", (void *)value); + ok((ULONG_PTR)overlapped == GetCurrentProcessId(), "unexpected pid %#lx\n", (DWORD)(DWORD_PTR)overlapped); + + do + { + ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 0); + } while (ret && (ULONG_PTR)overlapped == dead_pid); + + ok(ret, "GetQueuedCompletionStatus: %lx\n", GetLastError()); + ok(key == JOB_OBJECT_MSG_NEW_PROCESS, "unexpected key %lx\n", key); + ok((HANDLE)value == job_parent, "unexpected value %p\n", (void *)value); + ok((ULONG_PTR)overlapped == GetCurrentProcessId(), "unexpected pid %#lx\n", (DWORD)(DWORD_PTR)overlapped); + + test_completion(port, JOB_OBJECT_MSG_NEW_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0); + test_completion(port, JOB_OBJECT_MSG_NEW_PROCESS, (DWORD_PTR)job_parent, pi.dwProcessId, 0); + + ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 0); + ok(!ret, "GetQueuedCompletionStatus succeeded.\n"); + + if (index) + { + ret = pAssignProcessToJobObject(job_other, GetCurrentProcess()); + ok(!ret, "AssignProcessToJobObject succeeded\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED, "Got unexpected error %lu.\n", GetLastError()); + } + + CloseHandle(port); + +done: + TerminateProcess(pi.hProcess, 0); + wait_child_process(pi.hProcess); + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + CloseHandle(job_parent); + CloseHandle(job); + CloseHandle(job_other); +} + +static void test_nested_jobs(void) +{ + BOOL ret, already_in_job = TRUE, create_succeeded = FALSE; + PROCESS_INFORMATION info[2]; + char buffer[MAX_PATH + 26]; + STARTUPINFOA si = {0}; + HANDLE job1, job2; + unsigned int i; + + if (!pIsProcessInJob) + { + win_skip("IsProcessInJob not available.\n"); + return; + } + + job1 = pCreateJobObjectW(NULL, NULL); + ok(!!job1, "CreateJobObjectW failed, error %lu.\n", GetLastError()); + job2 = pCreateJobObjectW(NULL, NULL); + ok(!!job2, "CreateJobObjectW failed, error %lu.\n", GetLastError()); + + create_succeeded = TRUE; + sprintf(buffer, "\"%s\" process wait", selfname); + for (i = 0; i < 2; ++i) + { + ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &info[i]); + if (!ret && GetLastError() == ERROR_ACCESS_DENIED) + { + create_succeeded = FALSE; + break; + } + ok(ret, "CreateProcessA error %lu\n", GetLastError()); + } + + if (create_succeeded) + { + ret = pIsProcessInJob(info[0].hProcess, NULL, &already_in_job); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); + + if (!already_in_job) + { + ret = pAssignProcessToJobObject(job2, info[1].hProcess); + ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError()); + + ret = pAssignProcessToJobObject(job1, info[0].hProcess); + ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError()); + + ret = pAssignProcessToJobObject(job2, info[0].hProcess); + ok(!ret, "AssignProcessToJobObject succeeded\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED, "Got unexpected error %lu.\n", GetLastError()); + + TerminateProcess(info[1].hProcess, 0); + wait_child_process(info[1].hProcess); + CloseHandle(info[1].hProcess); + CloseHandle(info[1].hThread); + + ret = pAssignProcessToJobObject(job2, info[0].hProcess); + ok(!ret, "AssignProcessToJobObject succeeded\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED, "Got unexpected error %lu.\n", GetLastError()); + } + + TerminateProcess(info[0].hProcess, 0); + wait_child_process(info[0].hProcess); + CloseHandle(info[0].hProcess); + CloseHandle(info[0].hThread); + } + + if (already_in_job) + { + win_skip("Test process is already in job, can't test parenting non-empty job.\n"); + } + + CloseHandle(job1); + CloseHandle(job2); + + job1 = pCreateJobObjectW(NULL, L"test_nested_jobs_0"); + ok(!!job1, "CreateJobObjectW failed, error %lu.\n", GetLastError()); + job2 = pCreateJobObjectW(NULL, L"test_nested_jobs_1"); + ok(!!job2, "CreateJobObjectW failed, error %lu.\n", GetLastError()); + + sprintf(buffer, "\"%s\" process nested_jobs 0", selfname); + ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &info[0]), + "CreateProcess failed\n"); + wait_child_process(info[0].hProcess); + sprintf(buffer, "\"%s\" process nested_jobs 1", selfname); + ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &info[1]), + "CreateProcess failed\n"); + wait_child_process(info[1].hProcess); + for (i = 0; i < 2; ++i) + { + CloseHandle(info[i].hProcess); + CloseHandle(info[i].hThread); + } + + CloseHandle(job1); + CloseHandle(job2); +} + +static void test_job_list_attribute(HANDLE parent_job) +{ + JOBOBJECT_BASIC_ACCOUNTING_INFORMATION job_info; + JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info; + JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info; + PPROC_THREAD_ATTRIBUTE_LIST attrs; + char buffer[MAX_PATH + 19]; + PROCESS_INFORMATION pi; + OVERLAPPED *overlapped; + HANDLE jobs[2], port; + STARTUPINFOEXA si; + ULONG_PTR value; + BOOL ret, out; + HANDLE tmp; + SIZE_T size; + DWORD key; + + if (!pInitializeProcThreadAttributeList) + { + win_skip("No support for ProcThreadAttributeList\n"); + return; + } + + ret = pInitializeProcThreadAttributeList(NULL, 1, 0, &size); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + attrs = heap_alloc(size); + + + jobs[0] = (HANDLE)0xdeadbeef; + jobs[1] = NULL; + + ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs, + sizeof(*jobs), NULL, NULL); + if (!ret && GetLastError() == ERROR_NOT_SUPPORTED) + { + /* Supported since Win10. */ + win_skip("PROC_THREAD_ATTRIBUTE_JOB_LIST is not supported.\n"); + pDeleteProcThreadAttributeList(attrs); + heap_free(attrs); + return; + } + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + + ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs, + 3, NULL, NULL); + ok(!ret && GetLastError() == ERROR_BAD_LENGTH, "Got unexpected ret %#x, GetLastError() %lu.\n", + ret, GetLastError()); + + ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs, + sizeof(*jobs) * 2, NULL, NULL); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + + ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs, + sizeof(*jobs), NULL, NULL); + + memset(&si, 0, sizeof(si)); + si.StartupInfo.cb = sizeof(si); + si.lpAttributeList = attrs; + sprintf(buffer, "\"%s\" process wait", selfname); + + ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, + (STARTUPINFOA *)&si, &pi); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Got unexpected ret %#x, GetLastError() %lu.\n", + ret, GetLastError()); + + ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs + 1, + sizeof(*jobs), NULL, NULL); + ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, + (STARTUPINFOA *)&si, &pi); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Got unexpected ret %#x, GetLastError() %lu.\n", + ret, GetLastError()); + + ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, &parent_job, + sizeof(parent_job), NULL, NULL); + ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, + (STARTUPINFOA *)&si, &pi); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + + ret = pIsProcessInJob(pi.hProcess, parent_job, &out); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); + ok(out, "IsProcessInJob returned out=%u\n", out); + + TerminateProcess(pi.hProcess, 0); + wait_and_close_child_process(&pi); + + jobs[0] = pCreateJobObjectW(NULL, NULL); + ok(!!jobs[0], "CreateJobObjectA error %lu\n", GetLastError()); + jobs[1] = pCreateJobObjectW(NULL, NULL); + ok(!!jobs[1], "CreateJobObjectA error %lu\n", GetLastError()); + + /* Breakaway works for the inherited job only. */ + limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK; + ret = pSetInformationJobObject(parent_job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info)); + ok(ret, "SetInformationJobObject error %lu\n", GetLastError()); + limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK + | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK; + ret = pSetInformationJobObject(jobs[1], JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info)); + ok(ret, "SetInformationJobObject error %lu\n", GetLastError()); + + ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs + 1, + sizeof(*jobs), NULL, NULL); + ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT + | CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, (STARTUPINFOA *)&si, &pi); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + + ret = pIsProcessInJob(pi.hProcess, parent_job, &out); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); + ok(!out, "IsProcessInJob returned out=%u\n", out); + + ret = pIsProcessInJob(pi.hProcess, jobs[1], &out); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); + ok(out, "IsProcessInJob returned out=%u\n", out); + + ret = pIsProcessInJob(pi.hProcess, jobs[0], &out); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); + ok(!out, "IsProcessInJob returned out=%u\n", out); + + TerminateProcess(pi.hProcess, 0); + wait_and_close_child_process(&pi); + + CloseHandle(jobs[1]); + jobs[1] = pCreateJobObjectW(NULL, NULL); + ok(!!jobs[1], "CreateJobObjectA error %lu\n", GetLastError()); + + ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs + 1, + sizeof(*jobs), NULL, NULL); + ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, + NULL, NULL, (STARTUPINFOA *)&si, &pi); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + + ret = pIsProcessInJob(pi.hProcess, parent_job, &out); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); + ok(out, "IsProcessInJob returned out=%u\n", out); + + ret = pIsProcessInJob(pi.hProcess, jobs[1], &out); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); + ok(out, "IsProcessInJob returned out=%u\n", out); + + ret = pIsProcessInJob(pi.hProcess, jobs[0], &out); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); + ok(!out, "IsProcessInJob returned out=%u\n", out); + + TerminateProcess(pi.hProcess, 0); + wait_and_close_child_process(&pi); + + ret = pQueryInformationJobObject(jobs[0], JobObjectBasicAccountingInformation, &job_info, + sizeof(job_info), NULL); + ok(ret, "QueryInformationJobObject error %lu\n", GetLastError()); + ok(!job_info.TotalProcesses, "Got unexpected TotalProcesses %lu.\n", job_info.TotalProcesses); + ok(!job_info.ActiveProcesses, "Got unexpected ActiveProcesses %lu.\n", job_info.ActiveProcesses); + + ret = pQueryInformationJobObject(jobs[1], JobObjectBasicAccountingInformation, &job_info, + sizeof(job_info), NULL); + ok(ret, "QueryInformationJobObject error %lu\n", GetLastError()); + ok(job_info.TotalProcesses == 1, "Got unexpected TotalProcesses %lu.\n", job_info.TotalProcesses); + ok(!job_info.ActiveProcesses || job_info.ActiveProcesses == 1, "Got unexpected ActiveProcesses %lu.\n", + job_info.ActiveProcesses); + + /* Fails due to the second job already has the parent other than the first job in the list. */ + ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs, + 2 * sizeof(*jobs), NULL, NULL); + + port = pCreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); + ok(!!port, "CreateIoCompletionPort error %lu\n", GetLastError()); + + port_info.CompletionPort = port; + port_info.CompletionKey = jobs[0]; + ret = pSetInformationJobObject(jobs[0], JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info)); + ok(ret, "SetInformationJobObject error %lu\n", GetLastError()); + + ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 0); + ok(!ret, "GetQueuedCompletionStatus succeeded.\n"); + + ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, + (STARTUPINFOA *)&si, &pi); + ok(!ret && GetLastError() == ERROR_ACCESS_DENIED, "Got unexpected ret %#x, GetLastError() %lu.\n", + ret, GetLastError()); + + ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 100); + ok(ret, "GetQueuedCompletionStatus: %lx\n", GetLastError()); + ok(key == JOB_OBJECT_MSG_NEW_PROCESS, "unexpected key %lx\n", key); + ok((HANDLE)value == jobs[0], "unexpected value %p\n", (void *)value); + ok(!!overlapped, "Got zero pid.\n"); + + ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 100); + ok(ret, "GetQueuedCompletionStatus: %lx\n", GetLastError()); + ok(key == JOB_OBJECT_MSG_EXIT_PROCESS, "unexpected key %lx\n", key); + ok((HANDLE)value == jobs[0], "unexpected value %p\n", (void *)value); + ok(!!overlapped, "Got zero pid.\n"); + + ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 100); + ok(ret, "GetQueuedCompletionStatus: %lx\n", GetLastError()); + ok(key == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO, "unexpected key %lx\n", key); + ok((HANDLE)value == jobs[0], "unexpected value %p\n", (void *)value); + ok(!overlapped, "Got unexpected overlapped %p.\n", overlapped); + + ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 0); + ok(!ret, "GetQueuedCompletionStatus succeeded.\n"); + + CloseHandle(port); + + /* The first job got updated even though the process creation failed. */ + ret = pQueryInformationJobObject(jobs[0], JobObjectBasicAccountingInformation, &job_info, + sizeof(job_info), NULL); + ok(ret, "QueryInformationJobObject error %lu\n", GetLastError()); + ok(job_info.TotalProcesses == 1, "Got unexpected TotalProcesses %lu.\n", job_info.TotalProcesses); + ok(!job_info.ActiveProcesses, "Got unexpected ActiveProcesses %lu.\n", job_info.ActiveProcesses); + + ret = pQueryInformationJobObject(jobs[1], JobObjectBasicAccountingInformation, &job_info, + sizeof(job_info), NULL); + ok(ret, "QueryInformationJobObject error %lu\n", GetLastError()); + ok(job_info.TotalProcesses == 1, "Got unexpected TotalProcesses %lu.\n", job_info.TotalProcesses); + ok(!job_info.ActiveProcesses, "Got unexpected ActiveProcesses %lu.\n", job_info.ActiveProcesses); + + /* Check that the first job actually got the job_parent as parent. */ + ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs, + sizeof(*jobs), NULL, NULL); + ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT + | CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, (STARTUPINFOA *)&si, &pi); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + + ret = pIsProcessInJob(pi.hProcess, parent_job, &out); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); + ok(out, "IsProcessInJob returned out=%u\n", out); + + ret = pIsProcessInJob(pi.hProcess, jobs[0], &out); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); + ok(out, "IsProcessInJob returned out=%u\n", out); + + TerminateProcess(pi.hProcess, 0); + wait_and_close_child_process(&pi); + + tmp = jobs[0]; + jobs[0] = jobs[1]; + jobs[1] = tmp; + + ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs, + 2 * sizeof(*jobs), NULL, NULL); + ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, + (STARTUPINFOA *)&si, &pi); + ok(!ret && GetLastError() == ERROR_ACCESS_DENIED, "Got unexpected ret %#x, GetLastError() %lu.\n", + ret, GetLastError()); + + CloseHandle(jobs[0]); + CloseHandle(jobs[1]); + + jobs[0] = pCreateJobObjectW(NULL, NULL); + ok(!!jobs[0], "CreateJobObjectA error %lu\n", GetLastError()); + jobs[1] = pCreateJobObjectW(NULL, NULL); + ok(!!jobs[1], "CreateJobObjectA error %lu\n", GetLastError()); + + /* Create the job chain successfully and check the job chain. */ + ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs, + 2 * sizeof(*jobs), NULL, NULL); + ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, + NULL, NULL, (STARTUPINFOA *)&si, &pi); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + + ret = pIsProcessInJob(pi.hProcess, parent_job, &out); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); + ok(out, "IsProcessInJob returned out=%u\n", out); + + ret = pIsProcessInJob(pi.hProcess, jobs[0], &out); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); + ok(out, "IsProcessInJob returned out=%u\n", out); + + ret = pIsProcessInJob(pi.hProcess, jobs[1], &out); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); + ok(out, "IsProcessInJob returned out=%u\n", out); + + TerminateProcess(pi.hProcess, 0); + wait_and_close_child_process(&pi); + + ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs + 1, + sizeof(*jobs), NULL, NULL); + ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT + | CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, (STARTUPINFOA *)&si, &pi); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + + ret = pIsProcessInJob(pi.hProcess, parent_job, &out); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); + ok(out, "IsProcessInJob returned out=%u\n", out); + + ret = pIsProcessInJob(pi.hProcess, jobs[0], &out); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); + ok(out, "IsProcessInJob returned out=%u\n", out); + + ret = pIsProcessInJob(pi.hProcess, jobs[1], &out); + ok(ret, "IsProcessInJob error %lu\n", GetLastError()); + ok(out, "IsProcessInJob returned out=%u\n", out); + + TerminateProcess(pi.hProcess, 0); + wait_and_close_child_process(&pi); + + CloseHandle(jobs[0]); + CloseHandle(jobs[1]); + + pDeleteProcThreadAttributeList(attrs); + heap_free(attrs); + + limit_info.BasicLimitInformation.LimitFlags = 0; + ret = pSetInformationJobObject(parent_job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info)); + ok(ret, "SetInformationJobObject error %lu\n", GetLastError()); +} + +static void test_services_exe(void) +{ + NTSTATUS status; + ULONG size, offset, try; + char *buf; + SYSTEM_PROCESS_INFORMATION *spi; + ULONG services_pid = 0, services_session_id = ~0; + + /* Check that passing a zero size returns a size suitable for the next call, + * taking into account that in rare cases processes may start between the + * two NtQuerySystemInformation() calls. So this may require a few tries. + */ + for (try = 0; try < 3; try++) + { + status = NtQuerySystemInformation(SystemProcessInformation, NULL, 0, &size); + ok(status == STATUS_INFO_LENGTH_MISMATCH, "got %#lx\n", status); + + buf = malloc(size); + status = NtQuerySystemInformation(SystemProcessInformation, buf, size, &size); + if (status != STATUS_INFO_LENGTH_MISMATCH) break; + free(buf); + } + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + + spi = (SYSTEM_PROCESS_INFORMATION *)buf; + offset = 0; + + do + { + spi = (SYSTEM_PROCESS_INFORMATION *)(buf + offset); + if (!wcsnicmp(spi->ProcessName.Buffer, L"services.exe", spi->ProcessName.Length/sizeof(WCHAR))) + { + services_pid = HandleToUlong(spi->UniqueProcessId); + services_session_id = spi->SessionId; + } + offset += spi->NextEntryOffset; + } while (spi->NextEntryOffset != 0); + + ok(services_pid != 0, "services.exe not found\n"); + todo_wine + ok(services_session_id == 0, "got services.exe SessionId %lu\n", services_session_id); +} + +static void test_startupinfo( void ) +{ + STARTUPINFOA startup_beforeA, startup_afterA; + STARTUPINFOW startup_beforeW, startup_afterW; + RTL_USER_PROCESS_PARAMETERS *params; + + params = RtlGetCurrentPeb()->ProcessParameters; + + startup_beforeA.hStdInput = (HANDLE)0x56780000; + GetStartupInfoA(&startup_beforeA); + + startup_beforeW.hStdInput = (HANDLE)0x12340000; + GetStartupInfoW(&startup_beforeW); + + /* change a couple of fields in PEB */ + params->dwX = ~params->dwX; + params->hStdInput = (HANDLE)~(DWORD_PTR)params->hStdInput; + + startup_afterA.hStdInput = (HANDLE)0x87650000; + GetStartupInfoA(&startup_afterA); + + /* wharf... ansi version is cached... */ + ok(startup_beforeA.dwX == startup_afterA.dwX, "Unexpected field value\n"); + ok(startup_beforeA.dwFlags == startup_afterA.dwFlags, "Unexpected field value\n"); + ok(startup_beforeA.hStdInput == startup_afterA.hStdInput, "Unexpected field value\n"); + + if (startup_beforeW.dwFlags & STARTF_USESTDHANDLES) + { + ok(startup_beforeA.hStdInput != NULL && startup_beforeA.hStdInput != INVALID_HANDLE_VALUE, + "Unexpected field value\n"); + ok(startup_afterA.hStdInput != NULL && startup_afterA.hStdInput != INVALID_HANDLE_VALUE, + "Unexpected field value\n"); + } + else + { + ok(startup_beforeA.hStdInput == INVALID_HANDLE_VALUE, "Unexpected field value %p\n", startup_beforeA.hStdInput); + ok(startup_afterA.hStdInput == INVALID_HANDLE_VALUE, "Unexpected field value %p\n", startup_afterA.hStdInput); + } + + /* ... while unicode is not */ + startup_afterW.hStdInput = (HANDLE)0x43210000; + GetStartupInfoW(&startup_afterW); + + ok(~startup_beforeW.dwX == startup_afterW.dwX, "Unexpected field value\n"); + if (startup_beforeW.dwFlags & STARTF_USESTDHANDLES) + { + ok(params->hStdInput == startup_afterW.hStdInput, "Unexpected field value\n"); + ok((HANDLE)~(DWORD_PTR)startup_beforeW.hStdInput == startup_afterW.hStdInput, "Unexpected field value\n"); + } + else + { + ok(startup_beforeW.hStdInput == (HANDLE)0x12340000, "Unexpected field value\n"); + ok(startup_afterW.hStdInput == (HANDLE)0x43210000, "Unexpected field value\n"); + } + + /* check impact of STARTF_USESTDHANDLES bit */ + params->dwFlags ^= STARTF_USESTDHANDLES; + + startup_afterW.hStdInput = (HANDLE)0x43210000; + GetStartupInfoW(&startup_afterW); + + ok((startup_beforeW.dwFlags ^ STARTF_USESTDHANDLES) == startup_afterW.dwFlags, "Unexpected field value\n"); + if (startup_afterW.dwFlags & STARTF_USESTDHANDLES) + { + ok(params->hStdInput == startup_afterW.hStdInput, "Unexpected field value\n"); + ok(startup_afterW.hStdInput != (HANDLE)0x43210000, "Unexpected field value\n"); + } + else + { + ok(startup_afterW.hStdInput == (HANDLE)0x43210000, "Unexpected field value\n"); + } + + /* FIXME add more tests to check whether the dwFlags controls the returned + * values (as done for STARTF_USESTDHANDLES) in unicode case. + */ + + /* reset the modified fields in PEB */ + params->dwX = ~params->dwX; + params->hStdInput = (HANDLE)~(DWORD_PTR)params->hStdInput; + params->dwFlags ^= STARTF_USESTDHANDLES; +} + +static void test_GetProcessInformation(void) +{ + SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION machines[8]; + PROCESS_MACHINE_INFORMATION mi; + NTSTATUS status; + HANDLE process; + unsigned int i; + BOOL ret; + + if (!pGetProcessInformation) + { + win_skip("GetProcessInformation() is not available.\n"); + return; + } - /* Test would fail on systems with more than 6400 processors */ SetLastError(0xdeadbeef); - count = pGetActiveProcessorCount(101); - ok(count == 0, "Expeced GetActiveProcessorCount to fail\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + ret = pGetProcessInformation(GetCurrentProcess(), ProcessMachineTypeInfo, NULL, 0); + if (!ret && GetLastError() == ERROR_INVALID_PARAMETER) + { + win_skip("GetProcessInformation(ProcessMachineTypeInfo) is not supported.\n"); /* < win11 */ + return; + } + ok(!ret, "Unexpected return value %d.\n", ret); + ok(GetLastError() == ERROR_BAD_LENGTH, "Unexpected error %ld.\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pGetProcessInformation(GetCurrentProcess(), ProcessMachineTypeInfo, &mi, 0); + ok(!ret, "Unexpected return value %d.\n", ret); + ok(GetLastError() == ERROR_BAD_LENGTH, "Unexpected error %ld.\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pGetProcessInformation(GetCurrentProcess(), ProcessMachineTypeInfo, &mi, sizeof(mi) - 1); + ok(!ret, "Unexpected return value %d.\n", ret); + ok(GetLastError() == ERROR_BAD_LENGTH, "Unexpected error %ld.\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pGetProcessInformation(GetCurrentProcess(), ProcessMachineTypeInfo, &mi, sizeof(mi) + 1); + ok(!ret, "Unexpected return value %d.\n", ret); + ok(GetLastError() == ERROR_BAD_LENGTH, "Unexpected error %ld.\n", GetLastError()); + + ret = pGetProcessInformation(GetCurrentProcess(), ProcessMachineTypeInfo, &mi, sizeof(mi)); + ok(ret, "Unexpected return value %d.\n", ret); + +#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x601 + process = GetCurrentProcess(); + status = NtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, &process, sizeof(process), + machines, sizeof(machines), NULL ); + ok(!status, "Failed to get architectures information.\n"); + for (i = 0; machines[i].Machine; i++) + { + if (machines[i].Process) + { + ok(mi.ProcessMachine == machines[i].Machine, "Unexpected process machine %#x.\n", mi.ProcessMachine); + ok(!!(mi.MachineAttributes & UserEnabled) == machines[i].UserMode, "Unexpected attributes %#x.\n", + mi.MachineAttributes); + ok(!!(mi.MachineAttributes & KernelEnabled) == machines[i].KernelMode, "Unexpected attributes %#x.\n", + mi.MachineAttributes); + ok(!!(mi.MachineAttributes & Wow64Container) == machines[i].WoW64Container, "Unexpected attributes %#x.\n", + mi.MachineAttributes); + ok(!(mi.MachineAttributes & ~(UserEnabled | KernelEnabled | Wow64Container)), "Unexpected attributes %#x.\n", + mi.MachineAttributes); + break; + } + } +#endif } START_TEST(process) { - HANDLE job; + HANDLE job, hproc, h, h2; BOOL b = init(); ok(b, "Basic init of CreateProcess test\n"); if (!b) return; @@ -3945,39 +5648,84 @@ START_TEST(process) ok(0, "Child process not killed\n"); return; } + else if (!strcmp(myARGV[2], "sync") && myARGC >= 4) + { + HANDLE sem = OpenSemaphoreA(SYNCHRONIZE, FALSE, myARGV[3]); + ok(sem != 0, "OpenSemaphoreA(%s) failed le=%lu\n", myARGV[3], GetLastError()); + if (sem) + { + DWORD ret = WaitForSingleObject(sem, 30000); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject(%s) returned %lu\n", myARGV[3], ret); + CloseHandle(sem); + } + return; + } else if (!strcmp(myARGV[2], "exit")) { - Sleep(100); return; } else if (!strcmp(myARGV[2], "nested") && myARGC >= 4) { - char buffer[MAX_PATH]; + char buffer[MAX_PATH + 26]; STARTUPINFOA startup; PROCESS_INFORMATION info; + HANDLE hFile; memset(&startup, 0, sizeof(startup)); startup.cb = sizeof(startup); startup.dwFlags = STARTF_USESHOWWINDOW; startup.wShowWindow = SW_SHOWNORMAL; - sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, myARGV[3]); + sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, myARGV[3]); ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &info), "CreateProcess failed\n"); CloseHandle(info.hProcess); CloseHandle(info.hThread); + + /* The nested process is suspended so we can use the same resource + * file and it's up to the parent to read it before resuming the + * nested process. + */ + hFile = CreateFileA(myARGV[3], GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + childPrintf(hFile, "[Nested]\nPid=%08lu\n", info.dwProcessId); + CloseHandle(hFile); + return; + } + else if (!strcmp(myARGV[2], "parent") && myARGC >= 5) + { + sscanf(myARGV[4], "%p", &h); + test_parent_process_attribute(atoi(myARGV[3]), h); + return; + } + else if (!strcmp(myARGV[2], "handlelist") && myARGC >= 5) + { + sscanf(myARGV[3], "%p", &h); + sscanf(myARGV[4], "%p", &h2); + test_handle_list_attribute(TRUE, h, h2); + return; + } + else if (!strcmp(myARGV[2], "nested_jobs") && myARGC >= 4) + { + test_nested_jobs_child(atoi(myARGV[3])); return; } ok(0, "Unexpected command %s\n", myARGV[2]); return; } - - test_process_info(); + hproc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId()); + if (hproc) + { + test_process_info(hproc); + CloseHandle(hproc); + } + else + win_skip("PROCESS_QUERY_LIMITED_INFORMATION is not supported on this platform\n"); + test_process_info(GetCurrentProcess()); test_TerminateProcess(); test_Startup(); test_CommandLine(); test_Directory(); - test_Toolhelp(); // + test_Toolhelp(); test_Environment(); test_SuspendFlag(); test_DebuggingFlag(); @@ -3990,20 +5738,26 @@ START_TEST(process) test_QueryFullProcessImageNameW(); test_Handles(); test_IsWow64Process(); + test_IsWow64Process2(); test_SystemInfo(); + test_ProcessorCount(); test_RegistryQuota(); test_DuplicateHandle(); - test_StartupNoConsole(); - test_DetachConsoleHandles(); - test_DetachStdHandles(); + test_StdHandleInheritance(); test_GetNumaProcessorNode(); test_session_info(); test_GetLogicalProcessorInformationEx(); - test_GetActiveProcessorCount(); + test_GetSystemCpuSetInformation(); test_largepages(); test_ProcThreadAttributeList(); test_SuspendProcessState(); test_SuspendProcessNewThread(); + test_parent_process_attribute(0, NULL); + test_handle_list_attribute(FALSE, NULL, NULL); + test_dead_process(); + test_services_exe(); + test_startupinfo(); + test_GetProcessInformation(); /* things that can be tested: * lookup: check the way program to be executed is searched @@ -4011,6 +5765,12 @@ START_TEST(process) * console: check if console creation parameters work */ +#ifdef __REACTOS__ + if (is_reactos()) { + ok(FALSE, "FIXME: ReactOS's job support is too basic for these tests.\n"); + return; + } +#endif if (!pCreateJobObjectW) { win_skip("No job object support\n"); @@ -4023,8 +5783,10 @@ START_TEST(process) test_CompletionPort(); test_KillOnJobClose(); test_WaitForJobObject(); + test_nested_jobs(); job = test_AddSelfToJob(); test_jobInheritance(job); + test_job_list_attribute(job); test_BreakawayOk(job); CloseHandle(job); } diff --git a/modules/rostests/winetests/kernel32/profile.c b/modules/rostests/winetests/kernel32/profile.c index f3f1cf25df3..710e74804c0 100644 --- a/modules/rostests/winetests/kernel32/profile.c +++ b/modules/rostests/winetests/kernel32/profile.c @@ -32,6 +32,15 @@ #define TESTFILE ".\\testwine.ini" #define TESTFILE2 ".\\testwine2.ini" +static void check_profile_string_(int line, const char *section, const char *name, const char *file, const char *expect) +{ + char value[200] = {0}; + DWORD ret = GetPrivateProfileStringA(section, name, "default", value, sizeof(value), file); + ok_(__FILE__, line)(ret == strlen(expect), "expected len %Iu, got %lu\n", strlen(expect), ret); + ok_(__FILE__, line)(!strcmp(value, expect), "expected %s, got %s\n", debugstr_a(expect), debugstr_a(value)); +} +#define check_profile_string(a, b, c, d) check_profile_string_(__LINE__, a, b, c, d); + struct _profileInt { LPCSTR section; LPCSTR key; @@ -39,39 +48,39 @@ struct _profileInt { LPCSTR iniFile; INT defaultVal; UINT result; - UINT result9x; }; static void test_profile_int(void) { struct _profileInt profileInt[]={ - { NULL, NULL, NULL, NULL, 70, 0 , 0}, /* 0 */ - { NULL, NULL, NULL, TESTFILE, -1, 4294967295U, 0}, - { NULL, NULL, NULL, TESTFILE, 1, 1 , 0}, - { SECTION, NULL, NULL, TESTFILE, -1, 4294967295U, 0}, - { SECTION, NULL, NULL, TESTFILE, 1, 1 , 0}, - { NULL, KEY, NULL, TESTFILE, -1, 4294967295U, 0}, /* 5 */ - { NULL, KEY, NULL, TESTFILE, 1, 1 , 0}, - { SECTION, KEY, NULL, TESTFILE, -1, 4294967295U, 4294967295U}, - { SECTION, KEY, NULL, TESTFILE, 1, 1 , 1}, - { SECTION, KEY, "-1", TESTFILE, -1, 4294967295U, 4294967295U}, - { SECTION, KEY, "-1", TESTFILE, 1, 4294967295U, 4294967295U}, /* 10 */ - { SECTION, KEY, "1", TESTFILE, -1, 1 , 1}, - { SECTION, KEY, "1", TESTFILE, 1, 1 , 1}, - { SECTION, KEY, "+1", TESTFILE, -1, 1 , 0}, - { SECTION, KEY, "+1", TESTFILE, 1, 1 , 0}, - { SECTION, KEY, "4294967296", TESTFILE, -1, 0 , 0}, /* 15 */ - { SECTION, KEY, "4294967296", TESTFILE, 1, 0 , 0}, - { SECTION, KEY, "4294967297", TESTFILE, -1, 1 , 1}, - { SECTION, KEY, "4294967297", TESTFILE, 1, 1 , 1}, - { SECTION, KEY, "-4294967297", TESTFILE, -1, 4294967295U, 4294967295U}, - { SECTION, KEY, "-4294967297", TESTFILE, 1, 4294967295U, 4294967295U}, /* 20 */ - { SECTION, KEY, "42A94967297", TESTFILE, -1, 42 , 42}, - { SECTION, KEY, "42A94967297", TESTFILE, 1, 42 , 42}, - { SECTION, KEY, "B4294967297", TESTFILE, -1, 0 , 0}, - { SECTION, KEY, "B4294967297", TESTFILE, 1, 0 , 0}, + { NULL, NULL, NULL, NULL, 70, 0}, /* 0 */ + { NULL, NULL, NULL, TESTFILE, -1, 4294967295U}, + { NULL, NULL, NULL, TESTFILE, 1, 1}, + { SECTION, NULL, NULL, TESTFILE, -1, 4294967295U}, + { SECTION, NULL, NULL, TESTFILE, 1, 1}, + { NULL, KEY, NULL, TESTFILE, -1, 4294967295U}, /* 5 */ + { NULL, KEY, NULL, TESTFILE, 1, 1}, + { SECTION, KEY, NULL, TESTFILE, -1, 4294967295U}, + { SECTION, KEY, NULL, TESTFILE, 1, 1}, + { SECTION, KEY, "-1", TESTFILE, -1, 4294967295U}, + { SECTION, KEY, "-1", TESTFILE, 1, 4294967295U}, /* 10 */ + { SECTION, KEY, "1", TESTFILE, -1, 1}, + { SECTION, KEY, "1", TESTFILE, 1, 1}, + { SECTION, KEY, "+1", TESTFILE, -1, 1}, + { SECTION, KEY, "+1", TESTFILE, 1, 1}, + { SECTION, KEY, "4294967296", TESTFILE, -1, 0}, /* 15 */ + { SECTION, KEY, "4294967296", TESTFILE, 1, 0}, + { SECTION, KEY, "4294967297", TESTFILE, -1, 1}, + { SECTION, KEY, "4294967297", TESTFILE, 1, 1}, + { SECTION, KEY, "-4294967297", TESTFILE, -1, 4294967295U}, + { SECTION, KEY, "-4294967297", TESTFILE, 1, 4294967295U}, /* 20 */ + { SECTION, KEY, "42A94967297", TESTFILE, -1, 42}, + { SECTION, KEY, "42A94967297", TESTFILE, 1, 42}, + { SECTION, KEY, "B4294967297", TESTFILE, -1, 0}, + { SECTION, KEY, "B4294967297", TESTFILE, 1, 0}, }; - int i, num_test = (sizeof(profileInt)/sizeof(struct _profileInt)); + int i, num_test = ARRAY_SIZE(profileInt); + char section[64]; UINT res; DeleteFileA( TESTFILE); @@ -83,9 +92,14 @@ static void test_profile_int(void) res = GetPrivateProfileIntA(profileInt[i].section, profileInt[i].key, profileInt[i].defaultVal, profileInt[i].iniFile); - ok((res == profileInt[i].result) || (res == profileInt[i].result9x), - "test<%02d>: ret<%010u> exp<%010u><%010u>\n", - i, res, profileInt[i].result, profileInt[i].result9x); + ok((res == profileInt[i].result), "test<%02d>: ret<%010u> exp<%010u>\n", + i, res, profileInt[i].result); + + sprintf(section, " %s ", profileInt[i].section); + res = GetPrivateProfileIntA(profileInt[i].section, profileInt[i].key, + profileInt[i].defaultVal, profileInt[i].iniFile); + ok((res == profileInt[i].result), "test<%02d>: ret<%010u> exp<%010u>\n", + i, res, profileInt[i].result); } DeleteFileA( TESTFILE); @@ -143,18 +157,16 @@ static void test_profile_string(void) WriteFile( h, content2, sizeof(content2), &count, NULL); CloseHandle( h); - /* works only in unicode, ascii crashes */ - ret=GetPrivateProfileStringW(emptyW, keyW, emptyW, bufW, - sizeof(bufW)/sizeof(bufW[0]), TESTFILE2W); + /* works only in unicode, ansi crashes */ + ret=GetPrivateProfileStringW(emptyW, keyW, emptyW, bufW, ARRAY_SIZE(bufW), TESTFILE2W); todo_wine ok(ret == 13, "expected 13, got %u\n", ret); todo_wine ok(!lstrcmpW(valsectionW,bufW), "expected %s, got %s\n", wine_dbgstr_w(valsectionW), wine_dbgstr_w(bufW) ); - /* works only in unicode, ascii crashes */ - ret=GetPrivateProfileStringW(sW, emptyW, emptyW, bufW, - sizeof(bufW)/sizeof(bufW[0]), TESTFILE2W); + /* works only in unicode, ansi crashes */ + ret=GetPrivateProfileStringW(sW, emptyW, emptyW, bufW, ARRAY_SIZE(bufW), TESTFILE2W); ok(ret == 10, "expected 10, got %u\n", ret); ok(!lstrcmpW(valnokeyW,bufW), "expected %s, got %s\n", wine_dbgstr_w(valnokeyW), wine_dbgstr_w(bufW) ); @@ -169,7 +181,7 @@ static void test_profile_sections(void) DWORD count; char buf[100]; char *p; - static const char content[]="[section1]\r\nname1=val1\r\nname2=\r\nname3\r\nname4=val4\r\n[section2]\r\n"; + static const char content[]="[section1]\r\nname1=val1\r\nname2=\r\nname3\r\nname4=val4\r\n[section2]\r\n[section3]\r\n=val5\r\n"; static const char testfile4[]=".\\testwine4.ini"; BOOL on_win98 = FALSE; @@ -186,7 +198,7 @@ static void test_profile_sections(void) ok( ret == 0, "expected return size 0, got %d\n", ret ); ok( GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == 0xdeadbeef /* Win98 */, - "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); if (GetLastError() == 0xdeadbeef) on_win98 = TRUE; SetLastError(0xdeadbeef); @@ -194,38 +206,35 @@ static void test_profile_sections(void) ok( ret == 0, "expected return size 0, got %d\n", ret ); ok( GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == 0xdeadbeef /* Win98 */, - "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); if (!on_win98) { SetLastError(0xdeadbeef); ret = GetPrivateProfileSectionA( "section1", NULL, 0, testfile4 ); ok( ret == 0, "expected return size 0, got %d\n", ret ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); } SetLastError(0xdeadbeef); ret = GetPrivateProfileSectionA( NULL, buf, sizeof(buf), testfile4 ); ok( ret == 0, "expected return size 0, got %d\n", ret ); - ok( GetLastError() == ERROR_INVALID_PARAMETER || - broken(GetLastError() == 0xdeadbeef), /* Win9x, WinME */ - "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + ok( GetLastError() == ERROR_INVALID_PARAMETER, + "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = GetPrivateProfileSectionA( "section1", buf, sizeof(buf), NULL ); ok( ret == 0, "expected return size 0, got %d\n", ret ); todo_wine - ok( GetLastError() == ERROR_FILE_NOT_FOUND || - broken(GetLastError() == 0xdeadbeef), /* Win9x, WinME */ - "expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + ok( GetLastError() == ERROR_FILE_NOT_FOUND, + "expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError()); /* Existing empty section with no keys */ SetLastError(0xdeadbeef); ret=GetPrivateProfileSectionA("section2", buf, sizeof(buf), testfile4); ok( ret == 0, "expected return size 0, got %d\n", ret ); - ok( GetLastError() == ERROR_SUCCESS || - broken(GetLastError() == 0xdeadbeef), /* Win9x, WinME */ - "expected ERROR_SUCCESS, got %d\n", GetLastError()); + ok( GetLastError() == ERROR_SUCCESS, + "expected ERROR_SUCCESS, got %ld\n", GetLastError()); /* Existing section with keys and values*/ SetLastError(0xdeadbeef); @@ -235,9 +244,20 @@ static void test_profile_sections(void) 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() == ERROR_SUCCESS || - broken(GetLastError() == 0xdeadbeef), /* Win9x, WinME */ - "expected ERROR_SUCCESS, got %d\n", GetLastError()); + ok( GetLastError() == ERROR_SUCCESS, + "expected ERROR_SUCCESS, got %ld\n", GetLastError()); + + /* Existing section with no keys but has values */ + SetLastError(0xdeadbeef); + ret=GetPrivateProfileSectionA("section3", buf, sizeof(buf), testfile4); + trace("section3 return: %s\n", buf); + for( p = buf + strlen(buf) + 1; *p;p += strlen(p)+1) + p[-1] = ','; + ok( ret == 6 && !strcmp( buf, "=val5"), "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() == ERROR_SUCCESS, + "expected ERROR_SUCCESS, got %ld\n", GetLastError()); /* Overflow*/ ret=GetPrivateProfileSectionA("section1", buf, 24, testfile4); @@ -257,7 +277,7 @@ static void test_profile_sections_names(void) DWORD count; char buf[100]; WCHAR bufW[100]; - static const char content[]="[section1]\r\n[section2]\r\n[section3]\r\n"; + static const char content[]="[ section1 ]\r\n[section2]\r\n[section3]\r\n"; static const char testfile3[]=".\\testwine3.ini"; static const WCHAR testfile3W[]={ '.','\\','t','e','s','t','w','i','n','e','3','.','i','n','i',0 }; static const WCHAR not_here[] = {'.','\\','n','o','t','_','h','e','r','e','.','i','n','i',0}; @@ -272,42 +292,33 @@ static void test_profile_sections_names(void) /* Test with sufficiently large buffer */ memset(buf, 0xc, sizeof(buf)); ret = GetPrivateProfileSectionNamesA( buf, 29, testfile3 ); - ok( ret == 27 || - broken(ret == 28), /* Win9x, WinME */ - "expected return size 27, got %d\n", ret ); - ok( (buf[ret-1] == 0 && buf[ret] == 0) || - broken(buf[ret-1] == 0 && buf[ret-2] == 0), /* Win9x, WinME */ + ok( ret == 27, "expected return size 27, got %d\n", ret ); + ok( (buf[ret-1] == 0 && buf[ret] == 0), "returned buffer not terminated with double-null\n" ); + ok( !strcmp(buf, "section1"), "Unexpected content %s.\n", debugstr_a(buf)); /* Test with exactly fitting buffer */ memset(buf, 0xc, sizeof(buf)); ret = GetPrivateProfileSectionNamesA( buf, 28, testfile3 ); - ok( ret == 26 || - broken(ret == 28), /* Win9x, WinME */ - "expected return size 26, got %d\n", ret ); + ok( ret == 26, "expected return size 26, got %d\n", ret ); todo_wine ok( (buf[ret+1] == 0 && buf[ret] == 0) || /* W2K3 and higher */ - broken(buf[ret+1] == 0xc && buf[ret] == 0) || /* NT4, W2K, WinXP */ - broken(buf[ret-1] == 0 && buf[ret-2] == 0), /* Win9x, WinME */ + broken(buf[ret+1] == 0xc && buf[ret] == 0), /* NT4, W2K, WinXP */ "returned buffer not terminated with double-null\n" ); /* Test with a buffer too small */ memset(buf, 0xc, sizeof(buf)); ret = GetPrivateProfileSectionNamesA( buf, 27, testfile3 ); ok( ret == 25, "expected return size 25, got %d\n", ret ); - /* Win9x and WinME only fills the buffer with complete section names (double-null terminated) */ count = strlen("section1") + sizeof(CHAR) + strlen("section2"); todo_wine - ok( (buf[ret+1] == 0 && buf[ret] == 0) || - broken(buf[count] == 0 && buf[count+1] == 0), /* Win9x, WinME */ + ok( buf[ret+1] == 0 && buf[ret] == 0, "returned buffer not terminated with double-null\n" ); /* Tests on nonexistent file */ memset(buf, 0xc, sizeof(buf)); ret = GetPrivateProfileSectionNamesA( buf, 10, ".\\not_here.ini" ); - ok( ret == 0 || - broken(ret == 1), /* Win9x, WinME */ - "expected return size 0, got %d\n", ret ); + ok( ret == 0, "expected return size 0, got %d\n", ret ); ok( buf[0] == 0, "returned buffer not terminated with null\n" ); ok( buf[1] != 0, "returned buffer terminated with double-null\n" ); @@ -379,7 +390,7 @@ static void test_profile_existing(void) HANDLE h = 0; char buffer[MAX_PATH]; - for (i=0; i < sizeof(pe)/sizeof(pe[0]); i++) + for (i=0; i < ARRAY_SIZE(pe); i++) { h = CreateFileA(testfile1, pe[i].dwDesiredAccess, pe[i].dwShareMode, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); @@ -391,24 +402,24 @@ static void test_profile_existing(void) { if (!ret) ok( broken(GetLastError() == pe[i].broken_error), - "%d: WritePrivateProfileString failed with error %u\n", i, GetLastError() ); + "%d: WritePrivateProfileString failed with error %lu\n", i, GetLastError() ); CloseHandle(h); size = GetPrivateProfileStringA(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 ); + ok( size == 5, "%d: test failed, number of characters copied: %ld instead of 5\n", i, size ); else - ok( !size, "%d: test failed, number of characters copied: %d instead of 0\n", i, size ); + ok( !size, "%d: test failed, number of characters copied: %ld 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", + ok( err == pe[i].write_error, "%d: WritePrivateProfileString failed with error %lu/%lu\n", i, err, pe[i].write_error ); CloseHandle(h); size = GetPrivateProfileStringA(SECTION, KEY, 0, buffer, MAX_PATH, testfile1); - ok( !size, "%d: test failed, number of characters copied: %d instead of 0\n", i, size ); + ok( !size, "%d: test failed, number of characters copied: %ld instead of 0\n", i, size ); } ok( DeleteFileA(testfile1), "delete failed\n" ); @@ -419,18 +430,15 @@ static void test_profile_existing(void) ok( WriteFile( h, buffer, strlen(buffer), &size, NULL ), "failed to write\n" ); CloseHandle( h ); - for (i=0; i < sizeof(pe)/sizeof(pe[0]); i++) + for (i=0; i < ARRAY_SIZE(pe); i++) { h = CreateFileA(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); - /* Win9x and WinME returns 0 for all cases except the first one */ if (!pe[i].read_error) - ok( ret || - broken(!ret && GetLastError() == 0xdeadbeef), /* Win9x, WinME */ - "%d: GetPrivateProfileString failed with error %u\n", i, GetLastError() ); + ok( ret, "%d: GetPrivateProfileString failed with error %lu\n", i, GetLastError() ); else ok( !ret, "%d: GetPrivateProfileString succeeded\n", i ); CloseHandle(h); @@ -448,14 +456,12 @@ static void test_profile_delete_on_close(void) h = CreateFileA(testfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL); res = WriteFile( h, contents, sizeof contents - 1, &size, NULL ); - ok( res, "Cannot write test file: %x\n", GetLastError() ); + ok( res, "Cannot write test file: %lx\n", GetLastError() ); ok( size == sizeof contents - 1, "Test file: partial write\n"); SetLastError(0xdeadbeef); res = GetPrivateProfileIntA(SECTION, KEY, 0, testfile); - ok( res == 123 || - broken(res == 0 && GetLastError() == ERROR_SHARING_VIOLATION), /* Win9x, WinME */ - "Got %d instead of 123\n", res); + ok( res == 123, "Got %ld instead of 123\n", res); /* This also deletes the file */ CloseHandle(h); @@ -472,14 +478,12 @@ static void test_profile_refresh(void) h = CreateFileA(testfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL); res = WriteFile( h, contents1, sizeof contents1 - 1, &size, NULL ); - ok( res, "Cannot write test file: %x\n", GetLastError() ); + ok( res, "Cannot write test file: %lx\n", GetLastError() ); ok( size == sizeof contents1 - 1, "Test file: partial write\n"); SetLastError(0xdeadbeef); res = GetPrivateProfileIntA(SECTION, KEY, 0, testfile); - ok( res == 123 || - broken(res == 0 && GetLastError() == ERROR_SHARING_VIOLATION), /* Win9x, WinME */ - "Got %d instead of 123\n", res); + ok( res == 123, "Got %ld instead of 123\n", res); CloseHandle(h); @@ -488,14 +492,12 @@ static void test_profile_refresh(void) h = CreateFileA(testfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL); res = WriteFile( h, contents2, sizeof contents2 - 1, &size, NULL ); - ok( res, "Cannot write test file: %x\n", GetLastError() ); + ok( res, "Cannot write test file: %lx\n", GetLastError() ); ok( size == sizeof contents2 - 1, "Test file: partial write\n"); SetLastError(0xdeadbeef); res = GetPrivateProfileIntA(SECTION, KEY, 0, testfile); - ok( res == 124 || - broken(res == 0 && GetLastError() == 0xdeadbeef), /* Win9x, WinME */ - "Got %d instead of 124\n", res); + ok( res == 124, "Got %ld instead of 124\n", res); /* This also deletes the file */ CloseHandle(h); @@ -503,9 +505,7 @@ static void test_profile_refresh(void) /* Cache must be invalidated if file no longer exists and default must be returned */ SetLastError(0xdeadbeef); res = GetPrivateProfileIntA(SECTION, KEY, 421, testfile); - ok( res == 421 || - broken(res == 0 && GetLastError() == 0xdeadbeef), /* Win9x, WinME */ - "Got %d instead of 421\n", res); + ok( res == 421, "Got %ld instead of 421\n", res); } static void create_test_file(LPCSTR name, LPCSTR data, DWORD size) @@ -544,7 +544,7 @@ static void test_profile_directory_readonly(void) attributes.nLength = sizeof(attributes); ret = ConvertStringSecurityDescriptorToSecurityDescriptorA(sddl_string_everyone_readonly, SDDL_REVISION_1, &attributes.lpSecurityDescriptor, NULL); - ok(ret == TRUE, "ConvertStringSecurityDescriptorToSecurityDescriptor failed: %d\n", GetLastError()); + ok(ret == TRUE, "ConvertStringSecurityDescriptorToSecurityDescriptor failed: %ld\n", GetLastError()); GetTempPathA(MAX_PATH, path_folder); lstrcatA(path_folder, "wine-test"); @@ -553,7 +553,7 @@ static void test_profile_directory_readonly(void) lstrcatA(path_file, "\\tmp.ini"); ret = CreateDirectoryA(path_folder, &attributes); - ok(ret == TRUE, "CreateDirectoryA failed: %d\n", GetLastError()); + ok(ret == TRUE, "CreateDirectoryA failed: %ld\n", GetLastError()); ret = WritePrivateProfileStringA("App", "key", "string", path_file); ok(ret == FALSE, "Expected FALSE, got %d\n", ret); @@ -565,7 +565,9 @@ static void test_profile_directory_readonly(void) ok(ret == FALSE, "Expected FALSE, got %d\n", ret); ret = RemoveDirectoryA(path_folder); - ok(ret == TRUE, "RemoveDirectoryA failed: %d\n", GetLastError()); + ok(ret == TRUE, "RemoveDirectoryA failed: %ld\n", GetLastError()); + + LocalFree(attributes.lpSecurityDescriptor); } static void test_GetPrivateProfileString(const char *content, const char *descript) @@ -584,18 +586,6 @@ static void test_GetPrivateProfileString(const char *content, const char *descri trace("test_GetPrivateProfileStringA: %s\n", descript); - if(!lstrcmpA(descript, "CR only")) - { - SetLastError(0xdeadbeef); - ret = GetPrivateProfileStringW(NULL, NULL, NULL, - NULL, 0, NULL); - if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) - { - win_skip("Win9x and WinME don't handle 'CR only' correctly\n"); - return; - } - } - create_test_file(filename, content, lstrlenA(content)); /* Run this test series with caching. Wine won't cache profile @@ -607,19 +597,19 @@ static void test_GetPrivateProfileString(const char *content, const char *descri lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA(NULL, "name1", "default", buf, MAX_PATH, filename); - ok(ret == 18 || - broken(ret == 19), /* Win9x and WinME */ - "Expected 18, got %d\n", ret); + ok(ret == 18, "Expected 18, got %ld\n", ret); len = lstrlenA("section1") + sizeof(CHAR) + lstrlenA("section2") + 2 * sizeof(CHAR); - ok(!memcmp(buf, "section1\0section2\0\0", len), - "Expected \"section1\\0section2\\0\\0\", got \"%s\"\n", buf); + + ok(!memcmp(buf, "section1\0section2\0", len), + "Expected \"section1\\x00section2\\x00\\x00\", got %s\n", + debugstr_an(buf, (ret + 2 >= MAX_PATH ? MAX_PATH : ret + 1))); /* lpAppName is empty */ memset(buf, 0xc, sizeof(buf)); lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA(emptystr, "name1", "default", buf, MAX_PATH, filename); - ok(ret == 7, "Expected 7, got %d\n", ret); + ok(ret == 7, "Expected 7, got %ld\n", ret); ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); ok(emptystr_ok(emptystr), "AppName modified\n"); @@ -628,7 +618,7 @@ static void test_GetPrivateProfileString(const char *content, const char *descri lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA("notasection", "name1", "default", buf, MAX_PATH, filename); - ok(ret == 7, "Expected 7, got %d\n", ret); + ok(ret == 7, "Expected 7, got %ld\n", ret); ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); /* lpAppName is empty, lpDefault is NULL */ @@ -636,10 +626,8 @@ static void test_GetPrivateProfileString(const char *content, const char *descri lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA(emptystr, "name1", NULL, buf, MAX_PATH, filename); - ok(ret == 0, "Expected 0, got %d\n", ret); - ok(!lstrcmpA(buf, "") || - broken(!lstrcmpA(buf, "kumquat")), /* Win9x, WinME */ - "Expected \"\", got \"%s\"\n", buf); + ok(ret == 0, "Expected 0, got %ld\n", ret); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); ok(emptystr_ok(emptystr), "AppName modified\n"); /* lpAppName is empty, lpDefault is empty */ @@ -647,7 +635,7 @@ static void test_GetPrivateProfileString(const char *content, const char *descri lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA(emptystr, "name1", "", buf, MAX_PATH, filename); - ok(ret == 0, "Expected 0, got %d\n", ret); + ok(ret == 0, "Expected 0, got %ld\n", ret); ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); ok(emptystr_ok(emptystr), "AppName modified\n"); @@ -658,7 +646,7 @@ static void test_GetPrivateProfileString(const char *content, const char *descri lstrcpyA(def_val, "default "); ret = GetPrivateProfileStringA(emptystr, "name1", def_val, buf, MAX_PATH, filename); - ok(ret == 7, "Expected 7, got %d\n", ret); + ok(ret == 7, "Expected 7, got %ld\n", ret); ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); ok(emptystr_ok(emptystr), "AppName modified\n"); @@ -669,7 +657,7 @@ static void test_GetPrivateProfileString(const char *content, const char *descri 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(ret == 7, "Expected 7, got %ld\n", ret); ok(!lstrcmpA(buf, "one two"), "Expected \"one two\", got \"%s\"\n", buf); ok(emptystr_ok(emptystr), "AppName modified\n"); @@ -678,7 +666,7 @@ static void test_GetPrivateProfileString(const char *content, const char *descri lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA(emptystr, "name1", "one two", buf, MAX_PATH, filename); - ok(ret == 7, "Expected 7, got %d\n", ret); + ok(ret == 7, "Expected 7, got %ld\n", ret); ok(!lstrcmpA(buf, "one two"), "Expected \"one two\", got \"%s\"\n", buf); ok(emptystr_ok(emptystr), "AppName modified\n"); @@ -687,16 +675,17 @@ static void test_GetPrivateProfileString(const char *content, const char *descri lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA("section1", NULL, "default", buf, MAX_PATH, filename); - ok(ret == 18, "Expected 18, got %d\n", ret); + ok(ret == 18, "Expected 18, got %ld\n", ret); ok(!memcmp(buf, "name1\0name2\0name4\0", ret + 1), - "Expected \"name1\\0name2\\0name4\\0\", got \"%s\"\n", buf); + "Expected \"name1\\x00name2\\x00name4\\x00\\x00\", got %s\n", + debugstr_an(buf, (ret + 2 >= MAX_PATH ? MAX_PATH : ret + 1))); /* lpKeyName is empty */ memset(buf, 0xc,sizeof(buf)); lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA("section1", emptystr, "default", buf, MAX_PATH, filename); - ok(ret == 7, "Expected 7, got %d\n", ret); + ok(ret == 7, "Expected 7, got %ld\n", ret); ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); ok(emptystr_ok(emptystr), "KeyName modified\n"); @@ -705,7 +694,7 @@ static void test_GetPrivateProfileString(const char *content, const char *descri lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA("section1", "notakey", "default", buf, MAX_PATH, filename); - ok(ret == 7, "Expected 7, got %d\n", ret); + ok(ret == 7, "Expected 7, got %ld\n", ret); ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); /* lpKeyName is empty, lpDefault is NULL */ @@ -713,10 +702,8 @@ static void test_GetPrivateProfileString(const char *content, const char *descri lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA("section1", emptystr, NULL, buf, MAX_PATH, filename); - ok(ret == 0, "Expected 0, got %d\n", ret); - ok(!lstrcmpA(buf, "") || - broken(!lstrcmpA(buf, "kumquat")), /* Win9x, WinME */ - "Expected \"\", got \"%s\"\n", buf); + ok(ret == 0, "Expected 0, got %ld\n", ret); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); ok(emptystr_ok(emptystr), "KeyName modified\n"); /* lpKeyName is empty, lpDefault is empty */ @@ -724,7 +711,7 @@ static void test_GetPrivateProfileString(const char *content, const char *descri lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA("section1", emptystr, "", buf, MAX_PATH, filename); - ok(ret == 0, "Expected 0, got %d\n", ret); + ok(ret == 0, "Expected 0, got %ld\n", ret); ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); ok(emptystr_ok(emptystr), "KeyName modified\n"); @@ -735,7 +722,7 @@ static void test_GetPrivateProfileString(const char *content, const char *descri lstrcpyA(def_val, "default "); ret = GetPrivateProfileStringA("section1", emptystr, def_val, buf, MAX_PATH, filename); - ok(ret == 7, "Expected 7, got %d\n", ret); + ok(ret == 7, "Expected 7, got %ld\n", ret); ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); ok(emptystr_ok(emptystr), "KeyName modified\n"); @@ -751,19 +738,15 @@ static void test_GetPrivateProfileString(const char *content, const char *descri lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA("section1", "name1", "default", buf, MAX_PATH, NULL); - ok(ret == 7 || - broken(ret == 0), /* Win9x, WinME */ - "Expected 7, got %d\n", ret); - ok(!lstrcmpA(buf, "default") || - broken(!lstrcmpA(buf, "kumquat")), /* Win9x, WinME */ - "Expected \"default\", got \"%s\"\n", buf); + ok(ret == 7, "Expected 7, got %ld\n", ret); + ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); /* lpFileName is empty */ memset(buf, 0xc,sizeof(buf)); lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA("section1", "name1", "default", buf, MAX_PATH, ""); - ok(ret == 7, "Expected 7, got %d\n", ret); + ok(ret == 7, "Expected 7, got %ld\n", ret); ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); /* lpFileName is nonexistent */ @@ -771,7 +754,7 @@ static void test_GetPrivateProfileString(const char *content, const char *descri lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA("section1", "name1", "default", buf, MAX_PATH, "nonexistent"); - ok(ret == 7, "Expected 7, got %d\n", ret); + ok(ret == 7, "Expected 7, got %ld\n", ret); ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); /* nSize is 0 */ @@ -779,7 +762,7 @@ static void test_GetPrivateProfileString(const char *content, const char *descri lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA("section1", "name1", "default", buf, 0, filename); - ok(ret == 0, "Expected 0, got %d\n", ret); + ok(ret == 0, "Expected 0, got %ld\n", ret); ok(!lstrcmpA(buf, "kumquat"), "Expected buf to be unchanged, got \"%s\"\n", buf); /* nSize is exact size of output */ @@ -787,7 +770,7 @@ static void test_GetPrivateProfileString(const char *content, const char *descri lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA("section1", "name1", "default", buf, 4, filename); - ok(ret == 3, "Expected 3, got %d\n", ret); + ok(ret == 3, "Expected 3, got %ld\n", ret); ok(!lstrcmpA(buf, "val"), "Expected \"val\", got \"%s\"\n", buf); /* nSize has room for NULL terminator */ @@ -795,7 +778,7 @@ static void test_GetPrivateProfileString(const char *content, const char *descri lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA("section1", "name1", "default", buf, 5, filename); - ok(ret == 4, "Expected 4, got %d\n", ret); + ok(ret == 4, "Expected 4, got %ld\n", ret); ok(!lstrcmpA(buf, "val1"), "Expected \"val1\", got \"%s\"\n", buf); /* output is 1 character */ @@ -803,7 +786,7 @@ static void test_GetPrivateProfileString(const char *content, const char *descri lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA("section1", "name4", "default", buf, MAX_PATH, filename); - ok(ret == 1, "Expected 1, got %d\n", ret); + ok(ret == 1, "Expected 1, got %ld\n", ret); ok(!lstrcmpA(buf, "a"), "Expected \"a\", got \"%s\"\n", buf); /* output is 1 character, no room for NULL terminator */ @@ -811,7 +794,7 @@ static void test_GetPrivateProfileString(const char *content, const char *descri lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA("section1", "name4", "default", buf, 1, filename); - ok(ret == 0, "Expected 0, got %d\n", ret); + ok(ret == 0, "Expected 0, got %ld\n", ret); ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); /* lpAppName is NULL, not enough room for final section name */ @@ -819,30 +802,30 @@ static void test_GetPrivateProfileString(const char *content, const char *descri lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA(NULL, "name1", "default", buf, 16, filename); - ok(ret == 14, "Expected 14, got %d\n", ret); + ok(ret == 14, "Expected 14, got %ld\n", ret); len = lstrlenA("section1") + 2 * sizeof(CHAR); todo_wine - ok(!memcmp(buf, "section1\0secti\0\0", ret + 2) || - broken(!memcmp(buf, "section1\0\0", len)), /* Win9x, WinME */ - "Expected \"section1\\0secti\\0\\0\", got \"%s\"\n", buf); + ok(!memcmp(buf, "section1\0secti\0", ret + 2), + "Expected \"section1\\x00secti\\x00\\x00\", got %s\n", + debugstr_an(buf, (ret + 2 >= 16 ? 16 : ret + 1))); /* lpKeyName is NULL, not enough room for final key name */ memset(buf, 0xc,sizeof(buf)); lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA("section1", NULL, "default", buf, 16, filename); - ok(ret == 14, "Expected 14, got %d\n", ret); + ok(ret == 14, "Expected 14, got %ld\n", ret); todo_wine - ok(!memcmp(buf, "name1\0name2\0na\0\0", ret + 2) || - broken(!memcmp(buf, "name1\0name2\0n\0\0", ret + 1)), /* Win9x, WinME */ - "Expected \"name1\\0name2\\0na\\0\\0\", got \"%s\"\n", buf); + ok(!memcmp(buf, "name1\0name2\0na\0", ret + 2), + "Expected \"name1\\x00name2\\x00na\\x00\\x00\", got %s\n", + debugstr_an(buf, (ret + 2 >= 16 ? 16 : ret + 1))); /* key value has quotation marks which are stripped */ memset(buf, 0xc,sizeof(buf)); lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA("section1", "name2", "default", buf, MAX_PATH, filename); - ok(ret == 4, "Expected 4, got %d\n", ret); + ok(ret == 4, "Expected 4, got %ld\n", ret); ok(!lstrcmpA(buf, "val2"), "Expected \"val2\", got \"%s\"\n", buf); /* case does not match */ @@ -850,7 +833,7 @@ static void test_GetPrivateProfileString(const char *content, const char *descri lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA("section1", "NaMe1", "default", buf, MAX_PATH, filename); - ok(ret == 4, "Expected 4, got %d\n", ret); + ok(ret == 4, "Expected 4, got %ld\n", ret); ok(!lstrcmpA(buf, "val1"), "Expected \"val1\", got \"%s\"\n", buf); /* only filename is used */ @@ -858,7 +841,7 @@ static void test_GetPrivateProfileString(const char *content, const char *descri lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA("section1", "NaMe1", "default", buf, MAX_PATH, "winetest.ini"); - ok(ret == 7, "Expected 7, got %d\n", ret); + ok(ret == 7, "Expected 7, got %ld\n", ret); ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); GetWindowsDirectoryA(windir, MAX_PATH); @@ -878,7 +861,7 @@ static void test_GetPrivateProfileString(const char *content, const char *descri lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA("section1", "NaMe1", "default", buf, MAX_PATH, tempfile); - ok(ret == 4, "Expected 4, got %d\n", ret); + ok(ret == 4, "Expected 4, got %ld\n", ret); ok(!lstrcmpA(buf, "val1"), "Expected \"val1\", got \"%s\"\n", buf); /* successful case */ @@ -886,7 +869,7 @@ static void test_GetPrivateProfileString(const char *content, const char *descri lstrcpyA(buf, "kumquat"); ret = GetPrivateProfileStringA("section1", "name1", "default", buf, MAX_PATH, filename); - ok(ret == 4, "Expected 4, got %d\n", ret); + ok(ret == 4, "Expected 4, got %ld\n", ret); ok(!lstrcmpA(buf, "val1"), "Expected \"val1\", got \"%s\"\n", buf); /* Existing section with no keys in an existing file */ @@ -894,12 +877,12 @@ static void test_GetPrivateProfileString(const char *content, const char *descri SetLastError(0xdeadbeef); ret=GetPrivateProfileStringA("section2", "DoesntExist", "", buf, MAX_PATH, filename); - ok( ret == 0, "expected return size 0, got %d\n", ret ); + ok( ret == 0, "expected return size 0, got %ld\n", ret ); ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); todo_wine ok( GetLastError() == 0xdeadbeef || GetLastError() == ERROR_FILE_NOT_FOUND /* Win 7 */, - "expected 0xdeadbeef or ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + "expected 0xdeadbeef or ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError()); DeleteFileA(path); @@ -941,19 +924,7 @@ static void test_WritePrivateProfileString(void) LPCSTR data; CHAR path[MAX_PATH]; CHAR temp[MAX_PATH]; - - SetLastError(0xdeadbeef); - ret = WritePrivateProfileStringW(NULL, NULL, NULL, NULL); - if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) - { - /* Win9x/WinME needs (variable) timeouts between tests and even long timeouts don't - * guarantee a correct result. - * Win9x/WinMe also produces different ini files where there is always a newline before - * a section start (except for the first one). - */ - win_skip("WritePrivateProfileString on Win9x/WinME is hard to test reliably\n"); - return; - } + HANDLE file; GetTempPathA(MAX_PATH, temp); GetTempFileNameA(temp, "wine", 0, path); @@ -965,10 +936,8 @@ static void test_WritePrivateProfileString(void) SetLastError(0xdeadbeef); ret = WritePrivateProfileStringA(NULL, "key", "string", path); ok(ret == FALSE, "Expected FALSE, got %d\n", ret); - ok(GetLastError() == ERROR_FILE_NOT_FOUND || - broken(GetLastError() == ERROR_INVALID_PARAMETER) || /* NT4 */ - broken(GetLastError() == 0xdeadbeef), /* Win9x and WinME */ - "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError()); ok(GetFileAttributesA(path) == INVALID_FILE_ATTRIBUTES, "Expected path to not exist\n"); @@ -979,10 +948,8 @@ static void test_WritePrivateProfileString(void) SetLastError(0xdeadbeef); ret = WritePrivateProfileStringA(NULL, "key", "string", path); ok(ret == FALSE, "Expected FALSE, got %d\n", ret); - ok(GetLastError() == ERROR_FILE_NOT_FOUND || - broken(GetLastError() == ERROR_INVALID_PARAMETER) || /* NT4 */ - broken(GetLastError() == 0xdeadbeef), /* Win9x and WinME */ - "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError()); ok(check_file_data(path, data), "File doesn't match\n"); DeleteFileA(path); @@ -1027,9 +994,7 @@ static void test_WritePrivateProfileString(void) ok(ret == TRUE, "Expected TRUE, got %d\n", ret); todo_wine { - ok(check_file_data(path, data) || - (broken(GetFileAttributesA(path) == INVALID_FILE_ATTRIBUTES)), /* Win9x and WinME */ - "File doesn't match\n"); + ok(check_file_data(path, data), "File doesn't match\n"); } DeleteFileA(path); @@ -1037,35 +1002,32 @@ static void test_WritePrivateProfileString(void) data = "[App]\r\n" "key=\r\n"; ret = WritePrivateProfileStringA("App", "key", "", path); - ok(ret == TRUE || - broken(!ret), /* Win9x and WinME */ - "Expected TRUE, got %d\n", ret); - ok(check_file_data(path, data) || - (broken(GetFileAttributesA(path) == INVALID_FILE_ATTRIBUTES)), /* Win9x and WinME */ - "File doesn't match\n"); + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); + ok(check_file_data(path, data), "File doesn't match\n"); DeleteFileA(path); /* empty lpFileName */ SetLastError(0xdeadbeef); ret = WritePrivateProfileStringA("App", "key", "string", ""); ok(ret == FALSE, "Expected FALSE, got %d\n", ret); - ok(GetLastError() == ERROR_ACCESS_DENIED || - broken(GetLastError() == ERROR_PATH_NOT_FOUND), /* Win9x and WinME */ - "Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_ACCESS_DENIED, + "Expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError()); /* Relative paths are relative to X:\\%WINDIR% */ - GetWindowsDirectoryA(temp, MAX_PATH); - GetTempFileNameA(temp, "win", 1, path); - if (GetFileAttributesA(path) == INVALID_FILE_ATTRIBUTES) + GetWindowsDirectoryA(path, MAX_PATH); + strcat(path, "\\win1.tmp"); + file = CreateFileA(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (!ret && GetLastError() == ERROR_ACCESS_DENIED) skip("Not allowed to create a file in the Windows directory\n"); else { + CloseHandle(file); DeleteFileA(path); data = "[App]\r\n" "key=string\r\n"; ret = WritePrivateProfileStringA("App", "key", "string", "win1.tmp"); - ok(ret == TRUE, "Expected TRUE, got %d, le=%u\n", ret, GetLastError()); + ok(ret == TRUE, "Expected TRUE, got %d, le=%lu\n", ret, GetLastError()); ok(check_file_data(path, data), "File doesn't match\n"); DeleteFileA(path); } @@ -1148,15 +1110,506 @@ static void test_WritePrivateProfileString(void) ret = WritePrivateProfileStringA("section1", "key1", "string1", path); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); todo_wine - ok( check_binary_file_data(path, data, 59) || - broken( check_binary_file_data(path, /* Windows 9x */ - "Data \0 before \0 first \0 section" /* 31 bytes */ - "\r\n\r\n[section1]\r\n" /* 14 bytes */ - "key1=string1" /* 14 bytes */ - , 59)), "File doesn't match\n"); + ok( check_binary_file_data(path, data, 59), "File doesn't match\n"); DeleteFileA(path); } +static void test_profile_struct(void) +{ + static const char expect_data[] = "[s]\r\nkey=616261637573006F\r\n"; + static const char expect_data_empty[] = "[s]\r\n"; + char buffer[20]; + BOOL ret; + + SetLastError(0xdeadbeef); + ret = GetPrivateProfileStructA("s", "key", buffer, sizeof(buffer), "./winetest.ini"); + ok(!ret, "expected failure\n"); + todo_wine ok(GetLastError() == ERROR_BAD_LENGTH, "got error %lu\n", GetLastError()); + + ret = WritePrivateProfileStructA("s", "key", (void *)"abacus", sizeof("abacus"), "./winetest.ini"); + ok(ret, "got error %lu\n", GetLastError()); + ok(check_file_data("./winetest.ini", expect_data), "file doesn't match\n"); + + SetLastError(0xdeadbeef); + ret = GetPrivateProfileStructA("s", "key", buffer, 6, "./winetest.ini"); + ok(!ret, "expected failure\n"); + todo_wine ok(GetLastError() == ERROR_BAD_LENGTH, "got error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = GetPrivateProfileStructA("s", "key", buffer, 8, "./winetest.ini"); + ok(!ret, "expected failure\n"); + todo_wine ok(GetLastError() == ERROR_BAD_LENGTH, "got error %lu\n", GetLastError()); + + memset(buffer, 0xcc, sizeof(buffer)); + ret = GetPrivateProfileStructA("s", "key", buffer, 7, "./winetest.ini"); + ok(ret, "got error %lu\n", GetLastError()); + ok(!strcmp(buffer, "abacus"), "data didn't match\n"); + + memset(buffer, 0xcc, sizeof(buffer)); + ret = GetPrivateProfileStringA("s", "key", "default", buffer, sizeof(buffer), "./winetest.ini"); + ok(ret == 16, "got size %u\n", ret); + ok(!strcmp(buffer, "616261637573006F"), "got %s\n", debugstr_a(buffer)); + + ret = WritePrivateProfileStringA("s", "key", "636163747573006F", "./winetest.ini"); + ok(ret, "got error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = GetPrivateProfileStructA("s", "key", buffer, 7, "./winetest.ini"); + ok(!ret, "expected failure\n"); + todo_wine ok(GetLastError() == ERROR_INVALID_DATA, "got error %lu\n", GetLastError()); + + ret = WritePrivateProfileStringA("s", "key", "6361637475730083", "./winetest.ini"); + ok(ret, "got error %lu\n", GetLastError()); + + memset(buffer, 0xcc, sizeof(buffer)); + ret = GetPrivateProfileStructA("s", "key", buffer, 7, "./winetest.ini"); + ok(ret, "got error %lu\n", GetLastError()); + ok(!strcmp(buffer, "cactus"), "data didn't match\n"); + + ret = WritePrivateProfileStringA("s", "key", "636163747573008Q", "./winetest.ini"); + ok(ret, "got error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = GetPrivateProfileStructA("s", "key", buffer, 7, "./winetest.ini"); + ok(!ret, "expected failure\n"); + todo_wine ok(GetLastError() == ERROR_INVALID_DATA, "got error %lu\n", GetLastError()); + + ret = WritePrivateProfileStringA("s", "key", "16361637475730083", "./winetest.ini"); + ok(ret, "got error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = GetPrivateProfileStructA("s", "key", buffer, 7, "./winetest.ini"); + ok(!ret, "expected failure\n"); + todo_wine ok(GetLastError() == ERROR_BAD_LENGTH, "got error %lu\n", GetLastError()); + + /* Test deleting struct */ +#ifdef __REACTOS__ + if (is_reactos()) { + ok(FALSE, "FIXME: Deleting private profile struct crashes on ReactOS!\n"); + } else { +#endif + ret = WritePrivateProfileStructA("s", "key", NULL, sizeof("abacus"), "./winetest.ini"); + ok(ret, "got error %lu\n", GetLastError()); + ok(check_file_data("./winetest.ini", expect_data_empty), "file doesn't match\n"); +#ifdef __REACTOS__ + } +#endif + + ret = DeleteFileA("./winetest.ini"); + ok(ret, "got error %lu\n", GetLastError()); +} + +static void check_registry_value_(int line, HKEY key, const char *value, const char *expect) +{ + char buffer[30]; + DWORD type, size = sizeof(buffer); + LSTATUS ret; + + memset(buffer, 0xcc, sizeof(buffer)); + ret = RegQueryValueExA(key, value, 0, &type, (BYTE *)buffer, &size); + ok_(__FILE__, line)(!ret, "got error %lu\n", ret); + ok_(__FILE__, line)(!strcmp(buffer, expect), "expected %s, got %s\n", debugstr_a(expect), debugstr_a(buffer)); + ok_(__FILE__, line)(type == REG_SZ, "got type %lu\n", type); +} +#define check_registry_value(a, b, c) check_registry_value_(__LINE__, a, b, c) + +static void test_registry_mapping(void) +{ + static const DWORD ivalue = 0xabacab; + HKEY mapping_key, mapped_key, mapping_subkey; + char buffer[30]; + LSTATUS ret; + + /* impersonate ourselves to prevent registry virtualization */ + ret = ImpersonateSelf(SecurityImpersonation); + ok(ret, "got error %lu\n", GetLastError()); + + ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, + "Software\\Microsoft\\Windows NT\\CurrentVersion\\IniFileMapping\\winetest_map.ini", + 0, NULL, 0, KEY_READ | KEY_WRITE | KEY_WOW64_64KEY, NULL, &mapping_key, NULL); + if (ret == ERROR_ACCESS_DENIED) + { + skip("Not enough permissions to write to the IniFileMapping key.\n"); + return; + } + ok(!ret, "got error %lu\n", ret); + + ret = RegSetValueExA(mapping_key, "section1", 0, REG_SZ, (BYTE *)"USR:winetest_map", sizeof("USR:winetest_map")); + ok(!ret, "got error %lu\n", ret); + ret = WritePrivateProfileStringA(NULL, NULL, NULL, "winetest_map.ini"); + todo_wine ok(ret, "got error %lu\n", GetLastError()); + + check_profile_string("section1", "name1", "winetest_map.ini", "default"); + + ret = WritePrivateProfileStringA("section1", "name1", "value1", "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + + check_profile_string("section1", "name1", "winetest_map.ini", "value1"); + check_profile_string("section1", "name1", "C:/fake/path/winetest_map.ini", "value1"); + + ret = RegOpenKeyExA(HKEY_CURRENT_USER, "winetest_map", 0, KEY_READ | KEY_WRITE, &mapped_key); + ok(!ret, "got error %lu\n", ret); + check_registry_value(mapped_key, "name1", "value1"); + + ret = RegSetValueExA(mapped_key, "name2", 0, REG_SZ, (BYTE *)"value2", sizeof("value2")); + ok(!ret, "got error %lu\n", ret); + + check_profile_string("section1", "name2", "winetest_map.ini", "value2"); + + ret = GetFileAttributesA("C:/windows/winetest_map.ini"); + ok(ret == INVALID_FILE_ATTRIBUTES, "winetest_map.ini should not exist.\n"); + + ret = WritePrivateProfileStringA("section1", "name2", NULL, "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + ret = RegQueryValueExA(mapped_key, "name2", 0, NULL, NULL, NULL); + ok(ret == ERROR_FILE_NOT_FOUND, "got error %lu\n", ret); + + /* Test non-string types. */ + + ret = RegSetValueExA(mapped_key, "name3", 0, REG_DWORD, (BYTE *)&ivalue, sizeof(ivalue)); + ok(!ret, "got error %lu\n", ret); + check_profile_string("section1", "name3", "winetest_map.ini", "default"); + + ret = GetPrivateProfileIntA("section1", "name3", 0, "winetest_map.ini"); + ok(ret == 0, "got %#lx\n", ret); + + ret = RegSetValueExA(mapped_key, "name3", 0, REG_BINARY, (BYTE *)"value3", sizeof("value3")); + ok(!ret, "got error %lu\n", ret); + check_profile_string("section1", "name3", "winetest_map.ini", "default"); + + ret = RegSetValueExA(mapped_key, "name3", 0, REG_MULTI_SZ, (BYTE *)"one\0two\0", sizeof("one\0two\0")); + ok(!ret, "got error %lu\n", ret); + check_profile_string("section1", "name3", "winetest_map.ini", "default"); + + ret = RegSetValueExA(mapped_key, "name3", 0, REG_EXPAND_SZ, (BYTE *)"x%SystemRoot%", sizeof("x%SystemRoot%")); + ok(!ret, "got error %lu\n", ret); + check_profile_string("section1", "name3", "winetest_map.ini", "default"); + + /* Test WritePrivateProfileSection(). Unlike with .ini files, it doesn't + * remove existing entries. */ + + ret = WritePrivateProfileStringA("section1", "name4", "value4", "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + ret = WritePrivateProfileStringA("section1", "name5", "value5", "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + ret = WritePrivateProfileSectionA("section1", "name4=four\0name6=six\0", "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + check_profile_string("section1", "name4", "winetest_map.ini", "four"); + check_profile_string("section1", "name5", "winetest_map.ini", "value5"); + check_profile_string("section1", "name6", "winetest_map.ini", "six"); + + /* Test deleting the section. */ + + RegCloseKey(mapped_key); + + ret = RegCreateKeyExA(HKEY_CURRENT_USER, "winetest_map\\subkey", 0, NULL, 0, 0, NULL, &mapped_key, NULL); + ok(!ret, "got error %lu\n", ret); + RegCloseKey(mapped_key); + + ret = WritePrivateProfileStringA("section1", "name1", "value1", "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + ret = WritePrivateProfileStringA("section1", NULL, NULL, "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + check_profile_string("section1", "name1", "winetest_map.ini", "default"); + + ret = WritePrivateProfileStringA("section1", "name1", "value1", "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + ret = WritePrivateProfileSectionA("section1", NULL, "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + check_profile_string("section1", "name1", "winetest_map.ini", "default"); + + ret = RegDeleteKeyA(HKEY_CURRENT_USER, "winetest_map\\subkey"); + ok(!ret, "got error %lu\n", ret); + ret = RegDeleteKeyA(HKEY_CURRENT_USER, "winetest_map"); + ok(!ret, "got error %lu\n", ret); + + /* Test GetPrivateProfileSectionNames(). */ + + memset(buffer, 0xcc, sizeof(buffer)); + ret = GetPrivateProfileSectionNamesA(buffer, 5, "winetest_map.ini"); + ok(ret == 3, "got %lu\n", ret); + ok(!memcmp(buffer, "sec\0", 5), "got %s\n", debugstr_an(buffer, ret)); + + memset(buffer, 0xcc, sizeof(buffer)); + ret = GetPrivateProfileSectionNamesA(buffer, sizeof(buffer), "winetest_map.ini"); + ok(ret == 9, "got %lu\n", ret); + ok(!memcmp(buffer, "section1\0", 10), "got %s\n", debugstr_an(buffer, ret)); + + ret = WritePrivateProfileStringA("file_section", "name1", "value1", "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + + memset(buffer, 0xcc, sizeof(buffer)); + ret = GetPrivateProfileSectionNamesA(buffer, 5, "winetest_map.ini"); + ok(ret == 3, "got %lu\n", ret); + ok(!memcmp(buffer, "sec\0", 5), "got %s\n", debugstr_an(buffer, ret)); + + memset(buffer, 0xcc, sizeof(buffer)); + ret = GetPrivateProfileSectionNamesA(buffer, sizeof(buffer), "winetest_map.ini"); + ok(ret == 22, "got %lu\n", ret); + ok(!memcmp(buffer, "section1\0file_section\0", 23), "got %s\n", debugstr_an(buffer, ret)); + + ret = DeleteFileA("C:/windows/winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + + /* Test the SYS: prefix. */ + + ret = RegSetValueExA(mapping_key, "section2", 0, REG_SZ, (BYTE *)"SYS:winetest_map", sizeof("SYS:winetest_map")); + ok(!ret, "got error %lu\n", ret); + ret = WritePrivateProfileStringA(NULL, NULL, NULL, "winetest_map.ini"); + todo_wine ok(ret, "got error %lu\n", GetLastError()); + + check_profile_string("section2", "name1", "winetest_map.ini", "default"); + + ret = WritePrivateProfileStringA("section2", "name1", "value1", "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + + check_profile_string("section2", "name1", "winetest_map.ini", "value1"); + + ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\winetest_map", 0, KEY_READ | KEY_WRITE, &mapped_key); + ok(!ret, "got error %lu\n", ret); + check_registry_value(mapped_key, "name1", "value1"); + + ret = RegSetValueExA(mapped_key, "name2", 0, REG_SZ, (BYTE *)"value2", sizeof("value2")); + ok(!ret, "got error %lu\n", ret); + + check_profile_string("section2", "name2", "winetest_map.ini", "value2"); + + ret = GetFileAttributesA("C:/windows/winetest_map.ini"); + ok(ret == INVALID_FILE_ATTRIBUTES, "winetest_map.ini should not exist.\n"); + + ret = RegDeleteKeyA(mapped_key, ""); + ok(!ret, "got error %lu\n", ret); + RegCloseKey(mapped_key); + + /* Try writing directly to the .ini file on disk instead. */ + + ret = WritePrivateProfileStringA("section3", "name1", "value1", "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + check_profile_string("section3", "name1", "winetest_map.ini", "value1"); + + ret = RegSetValueExA(mapping_key, "section3", 0, REG_SZ, (BYTE *)"USR:winetest_map", sizeof("USR:winetest_map")); + ok(!ret, "got error %lu\n", ret); + ret = WritePrivateProfileStringA(NULL, NULL, NULL, "winetest_map.ini"); + todo_wine ok(ret, "got error %lu\n", GetLastError()); + + check_profile_string("section3", "name1", "winetest_map.ini", "default"); + + ret = RegOpenKeyExA(HKEY_CURRENT_USER, "winetest_section3", 0, KEY_READ | KEY_WRITE, &mapped_key); + ok(ret == ERROR_FILE_NOT_FOUND, "got error %lu\n", ret); + + ret = WritePrivateProfileStringA("section3", "name1", "value2", "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + + check_profile_string("section3", "name1", "winetest_map.ini", "value2"); + + ret = RegOpenKeyExA(HKEY_CURRENT_USER, "winetest_map", 0, KEY_READ | KEY_WRITE, &mapped_key); + ok(!ret, "got error %lu\n", ret); + + ret = RegDeleteKeyA(mapped_key, ""); + ok(!ret, "got error %lu\n", ret); + RegCloseKey(mapped_key); + + ret = RegDeleteValueA(mapping_key, "section3"); + ok(!ret, "got error %lu\n", ret); + ret = WritePrivateProfileStringA(NULL, NULL, NULL, "winetest_map.ini"); + todo_wine ok(ret, "got error %lu\n", GetLastError()); + + check_profile_string("section3", "name1", "winetest_map.ini", "value1"); + + ret = DeleteFileA("C:/windows/winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + + /* Test default keys. */ + + ret = WritePrivateProfileStringA("section4", "name1", "value1", "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + + check_profile_string("section4", "name1", "winetest_map.ini", "value1"); + + ret = DeleteFileA("C:/windows/winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + + ret = RegSetValueExA(mapping_key, NULL, 0, REG_SZ, (BYTE *)"SYS:winetest_default", sizeof("SYS:winetest_default")); + ok(!ret, "got error %lu\n", ret); + ret = WritePrivateProfileStringA(NULL, NULL, NULL, "winetest_map.ini"); + todo_wine ok(ret, "got error %lu\n", GetLastError()); + + ret = WritePrivateProfileStringA("section4", "name1", "value1", "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + + ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\winetest_default\\section4", 0, KEY_READ, &mapped_key); + ok(!ret, "got error %lu\n", ret); + check_registry_value(mapped_key, "name1", "value1"); + RegCloseKey(mapped_key); + + ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\winetest_default\\section5", + 0, NULL, 0, KEY_WRITE, NULL, &mapped_key, NULL); + ok(!ret, "got error %lu\n", ret); + ret = RegSetValueExA(mapped_key, "name2", 0, REG_SZ, (BYTE *)"value2", sizeof("value2")); + ok(!ret, "got error %lu\n", ret); + RegCloseKey(mapped_key); + + check_profile_string("section5", "name2", "winetest_map.ini", "value2"); + + ret = GetFileAttributesA("C:/windows/winetest_map.ini"); + ok(ret == INVALID_FILE_ATTRIBUTES, "winetest_map.ini should not exist.\n"); + + ret = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "Software\\winetest_default\\Section4"); + ret = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "Software\\winetest_default\\Section5"); + ret = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "Software\\winetest_default"); + ok(!ret, "got error %lu\n", ret); + ret = RegDeleteValueA(mapping_key, NULL); + ok(!ret, "got error %lu\n", ret); + + /* Test name-specific mapping. */ + + ret = RegCreateKeyExA(mapping_key, "section6", 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &mapping_subkey, NULL); + ok(!ret, "got error %lu\n", ret); + ret = RegSetValueExA(mapping_subkey, "name1", 0, REG_SZ, (BYTE *)"USR:winetest_name1", sizeof("USR:winetest_name1")); + ok(!ret, "got error %lu\n", ret); + ret = RegSetValueExA(mapping_subkey, "name2", 0, REG_SZ, (BYTE *)"SYS:winetest_name2", sizeof("SYS:winetest_name2")); + ok(!ret, "got error %lu\n", ret); + ret = WritePrivateProfileStringA(NULL, NULL, NULL, "winetest_map.ini"); + todo_wine ok(ret, "got error %lu\n", GetLastError()); + + ret = WritePrivateProfileStringA("section6", "name1", "value1", "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + check_profile_string("section6", "name1", "winetest_map.ini", "value1"); + + ret = RegOpenKeyExA(HKEY_CURRENT_USER, "winetest_name1", 0, KEY_READ | KEY_WRITE, &mapped_key); + ok(!ret, "got error %lu\n", ret); + check_registry_value(mapped_key, "name1", "value1"); + + ret = RegSetValueExA(mapped_key, "name1", 0, REG_SZ, (BYTE *)"one", sizeof("one")); + ok(!ret, "got error %lu\n", ret); + check_profile_string("section6", "name1", "winetest_map.ini", "one"); + + ret = RegDeleteKeyA(mapped_key, ""); + ok(!ret, "got error %lu\n", ret); + RegCloseKey(mapped_key); + + ret = WritePrivateProfileStringA("section6", "name2", "value2", "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + + ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\winetest_name2", 0, KEY_READ | KEY_WRITE, &mapped_key); + ok(!ret, "got error %lu\n", ret); + check_registry_value(mapped_key, "name2", "value2"); + + ret = RegSetValueExA(mapped_key, "name2", 0, REG_SZ, (BYTE *)"two", sizeof("two")); + ok(!ret, "got error %lu\n", ret); + check_profile_string("section6", "name2", "winetest_map.ini", "two"); + + ret = RegDeleteKeyA(mapped_key, ""); + ok(!ret, "got error %lu\n", ret); + RegCloseKey(mapped_key); + + ret = WritePrivateProfileStringA("section6", "name3", "value3", "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + check_profile_string("section6", "name3", "winetest_map.ini", "value3"); + ret = DeleteFileA("C:/windows/winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + + /* Test name-specific mapping with Get/WritePrivateProfileSection(). */ + + ret = WritePrivateProfileStringA("section6", "name2", "value2", "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + + ret = WritePrivateProfileStringA("section6", "name3", "value3", "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + + ret = WritePrivateProfileSectionA("section6", "name1=one\0name3=three\0", "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + check_profile_string("section6", "name1", "winetest_map.ini", "one"); + check_profile_string("section6", "name2", "winetest_map.ini", "value2"); + check_profile_string("section6", "name3", "winetest_map.ini", "value3"); + + ret = RegOpenKeyExA(HKEY_CURRENT_USER, "winetest_name1", 0, KEY_READ | KEY_WRITE, &mapped_key); + ok(!ret, "got error %lu\n", ret); + ret = RegDeleteValueA(mapped_key, "name1"); + ok(!ret, "got error %lu\n", ret); + RegCloseKey(mapped_key); + + memset(buffer, 0xcc, sizeof(buffer)); + ret = GetPrivateProfileSectionA("section6", buffer, 5, "winetest_map.ini"); + ok(ret == 3, "got %lu\n", ret); + ok(!memcmp(buffer, "nam\0", 5), "got %s\n", debugstr_an(buffer, ret)); + + memset(buffer, 0xcc, sizeof(buffer)); + ret = GetPrivateProfileSectionA("section6", buffer, sizeof(buffer), "winetest_map.ini"); + ok(ret == 26, "got %lu\n", ret); + ok(!memcmp(buffer, "name2=value2\0name3=value3\0", 27), "got %s\n", debugstr_an(buffer, ret)); + + ret = WritePrivateProfileStringA("section6", NULL, NULL, "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + check_profile_string("section6", "name1", "winetest_map.ini", "default"); + check_profile_string("section6", "name2", "winetest_map.ini", "default"); + check_profile_string("section6", "name3", "winetest_map.ini", "default"); + + ret = RegDeleteKeyA(HKEY_CURRENT_USER, "winetest_name1"); + ok(!ret, "got error %lu\n", ret); + ret = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "Software\\winetest_name2"); + ok(!ret, "got error %lu\n", ret); + ret = DeleteFileA("C:/windows/winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + + /* Test name-specific mapping with a default value. */ + + ret = RegSetValueExA(mapping_subkey, NULL, 0, REG_SZ, (BYTE *)"USR:winetest_default", sizeof("USR:winetest_default")); + ok(!ret, "got error %lu\n", ret); + ret = WritePrivateProfileStringA(NULL, NULL, NULL, "winetest_map.ini"); + todo_wine ok(ret, "got error %lu\n", GetLastError()); + + ret = WritePrivateProfileStringA("section6", "name2", "value2", "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + ret = WritePrivateProfileStringA("section6", "name3", "value3", "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + + ret = RegOpenKeyExA(HKEY_CURRENT_USER, "winetest_default", 0, KEY_READ | KEY_WRITE, &mapped_key); + ok(!ret, "got error %lu\n", ret); + check_registry_value(mapped_key, "name3", "value3"); + + ret = RegSetValueExA(mapped_key, "name3", 0, REG_SZ, (BYTE *)"three", sizeof("three")); + ok(!ret, "got error %lu\n", ret); + check_profile_string("section6", "name3", "winetest_map.ini", "three"); + + memset(buffer, 0xcc, sizeof(buffer)); + ret = GetPrivateProfileSectionA("section6", buffer, sizeof(buffer), "winetest_map.ini"); + ok(ret == 25, "got %lu\n", ret); + todo_wine ok(!memcmp(buffer, "name2=value2\0name3=three\0", 26), "got %s\n", debugstr_an(buffer, ret)); + + ret = WritePrivateProfileSectionA("section6", "name2=duo\0name3=treis\0", "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + check_profile_string("section6", "name2", "winetest_map.ini", "duo"); + check_profile_string("section6", "name3", "winetest_map.ini", "treis"); + + ret = WritePrivateProfileStringA("section6", NULL, NULL, "winetest_map.ini"); + ok(ret, "got error %lu\n", GetLastError()); + check_profile_string("section6", "name2", "winetest_map.ini", "default"); + check_profile_string("section6", "name3", "winetest_map.ini", "default"); + + ret = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "Software\\winetest_name2"); + ok(!ret, "got error %lu\n", ret); + ret = RegDeleteKeyA(HKEY_CURRENT_USER, "winetest_name1"); + ok(!ret, "got error %lu\n", ret); + ret = RegDeleteKeyA(mapped_key, ""); + ok(!ret, "got error %lu\n", ret); + RegCloseKey(mapped_key); + + ret = RegDeleteKeyA(mapping_subkey, ""); + ok(!ret, "got error %lu\n", ret); + RegCloseKey(mapping_subkey); + + ret = RegDeleteKeyA(mapping_key, ""); + ok(!ret, "got error %lu\n", ret); + RegCloseKey(mapping_key); + + ret = DeleteFileA("C:/windows/winetest_map.ini"); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "got error %lu\n", GetLastError()); + ret = RevertToSelf(); + ok(ret, "got error %lu\n", GetLastError()); +} + START_TEST(profile) { test_profile_int(); @@ -1184,4 +1637,6 @@ START_TEST(profile) "[section2]\r", "CR only"); test_WritePrivateProfileString(); + test_profile_struct(); + test_registry_mapping(); } diff --git a/modules/rostests/winetests/kernel32/resource.c b/modules/rostests/winetests/kernel32/resource.c index 74066cfba3c..f1c6a21eccd 100644 --- a/modules/rostests/winetests/kernel32/resource.c +++ b/modules/rostests/winetests/kernel32/resource.c @@ -24,6 +24,7 @@ #include "wine/test.h" static const char filename[] = "test_.exe"; +static const WCHAR filenameW[] = {'t','e','s','t','_','.','e','x','e',0}; static DWORD GLE; enum constants { @@ -200,6 +201,7 @@ static int build_exe( const sec_build* sec_descr ) opt->SectionAlignment = page_size; opt->FileAlignment = page_size; + opt->NumberOfRvaAndSizes = IMAGE_FILE_RESOURCE_DIRECTORY + 1; opt->DataDirectory[IMAGE_FILE_RESOURCE_DIRECTORY].VirtualAddress = rva_rsrc_start; opt->DataDirectory[IMAGE_FILE_RESOURCE_DIRECTORY].Size = page_size; @@ -330,10 +332,10 @@ static void update_resources_version( void ) MAKEINTRESOURCEA(0x4567), 0xabcd, foo, sizeof foo ); - ok( r == TRUE, "UpdateResource failed: %d\n", GetLastError()); + ok( r == TRUE, "UpdateResource failed: %ld\n", GetLastError()); r = EndUpdateResourceA( res, FALSE ); - ok( r, "EndUpdateResource failed: %d\n", GetLastError()); + ok( r, "EndUpdateResource failed: %ld\n", GetLastError()); } static void update_resources_bigdata( void ) @@ -350,12 +352,44 @@ static void update_resources_bigdata( void ) MAKEINTRESOURCEA(0x5647), 0xcdba, foo, sizeof foo ); - ok( r == TRUE, "UpdateResource failed: %d\n", GetLastError()); + ok( r == TRUE, "UpdateResource failed: %ld\n", GetLastError()); r = EndUpdateResourceA( res, FALSE ); ok( r, "EndUpdateResource failed\n"); } +static void update_resources_name( void ) +{ + char foo[] = "resource data", res_name[] = "name", res_type[] = "type"; + HANDLE res = NULL; + HMODULE module; + HRSRC rsrc; + BOOL ret; + + res = BeginUpdateResourceA( filename, TRUE ); + ok( res != NULL, "BeginUpdateResource failed: %lu\n", GetLastError() ); + if ( !res ) return; + + ret = UpdateResourceA( res, res_type, res_name, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), foo, sizeof(foo) ); + ok( ret == TRUE, "UpdateResource failed: %lu\n", GetLastError() ); + + ret = EndUpdateResourceA( res, FALSE ); + ok( ret, "EndUpdateResource failed: %lu\n", GetLastError() ); + if ( !ret ) return; + + module = LoadLibraryExA( filename, NULL, LOAD_LIBRARY_AS_DATAFILE ); + ok( module != NULL, "LoadLibraryEx failed: %lu\n", GetLastError() ); + if ( !module ) return; + + rsrc = FindResourceA( module, res_name, res_type ); + ok( rsrc != NULL || + broken( GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND ) /* win2008 */, + "FindResource failed: %lu\n", GetLastError() ); + + ret = FreeLibrary(module); + ok( ret, "FreeLibrary failed: %lu\n", GetLastError() ); +} + static void check_exe( const sec_verify *verify ) { int i; @@ -368,7 +402,7 @@ static void check_exe( const sec_verify *verify ) DWORD length, sec_count = 0; file = CreateFileA(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); - ok (file != INVALID_HANDLE_VALUE, "failed to create file (%d)\n", GetLastError()); + ok (file != INVALID_HANDLE_VALUE, "failed to create file (%ld)\n", GetLastError()); length = GetFileSize( file, NULL ); ok( length >= verify->length, "file size wrong\n"); @@ -389,11 +423,11 @@ static void check_exe( const sec_verify *verify ) for(i = 0; i < max_sections; i++) if (verify->sect_out[i]) { - ok( !memcmp(&verify->sect_out[i]->Name, &sec[sec_count].Name, 8), "section %d name wrong\n", sec_count); - ok( verify->sect_out[i]->VirtualAddress == sec[sec_count].VirtualAddress, "section %d vaddr wrong\n", sec_count); - ok( verify->sect_out[i]->SizeOfRawData <= sec[sec_count].SizeOfRawData, "section %d SizeOfRawData wrong (%d vs %d)\n", sec_count, verify->sect_out[i]->SizeOfRawData ,sec[sec_count].SizeOfRawData); - ok( verify->sect_out[i]->PointerToRawData == sec[sec_count].PointerToRawData, "section %d PointerToRawData wrong\n", sec_count); - ok( verify->sect_out[i]->Characteristics == sec[sec_count].Characteristics , "section %d characteristics wrong\n", sec_count); + ok( !memcmp(&verify->sect_out[i]->Name, &sec[sec_count].Name, 8), "section %ld name wrong\n", sec_count); + ok( verify->sect_out[i]->VirtualAddress == sec[sec_count].VirtualAddress, "section %ld vaddr wrong\n", sec_count); + ok( verify->sect_out[i]->SizeOfRawData <= sec[sec_count].SizeOfRawData, "section %ld SizeOfRawData wrong (%ld vs %ld)\n", sec_count, verify->sect_out[i]->SizeOfRawData ,sec[sec_count].SizeOfRawData); + ok( verify->sect_out[i]->PointerToRawData == sec[sec_count].PointerToRawData, "section %ld PointerToRawData wrong\n", sec_count); + ok( verify->sect_out[i]->Characteristics == sec[sec_count].Characteristics , "section %ld characteristics wrong\n", sec_count); sec_count++; } @@ -404,18 +438,17 @@ static void check_exe( const sec_verify *verify ) dir = (void*) ((BYTE*) dos + sec[verify->rsrc_section].VirtualAddress); ok( dir->Characteristics == 0, "Characteristics wrong\n"); - ok( dir->TimeDateStamp == 0 || abs( dir->TimeDateStamp - GetTickCount() ) < 1000 /* nt4 */, - "TimeDateStamp wrong %u\n", dir->TimeDateStamp); + ok( dir->TimeDateStamp == 0, "TimeDateStamp wrong %lu\n", dir->TimeDateStamp); ok( dir->MajorVersion == 4, "MajorVersion wrong\n"); ok( dir->MinorVersion == 0, "MinorVersion wrong\n"); - ok( dir->NumberOfNamedEntries == verify->NumberOfNamedEntries, "NumberOfNamedEntries should be %d instead of %d\n", + ok( dir->NumberOfNamedEntries == verify->NumberOfNamedEntries, "NumberOfNamedEntries should be %ld instead of %d\n", verify->NumberOfNamedEntries, dir->NumberOfNamedEntries); - ok( dir->NumberOfIdEntries == verify->NumberOfIdEntries, "NumberOfIdEntries should be %d instead of %d\n", + ok( dir->NumberOfIdEntries == verify->NumberOfIdEntries, "NumberOfIdEntries should be %ld instead of %d\n", verify->NumberOfIdEntries, dir->NumberOfIdEntries); ok(opt->DataDirectory[IMAGE_FILE_RESOURCE_DIRECTORY].VirtualAddress == sec[verify->rsrc_section].VirtualAddress, - "VirtualAddress in optional header should be %d instead of %d\n", + "VirtualAddress in optional header should be %ld instead of %ld\n", sec[verify->rsrc_section].VirtualAddress, opt->DataDirectory[IMAGE_FILE_RESOURCE_DIRECTORY].VirtualAddress); } @@ -443,24 +476,367 @@ static void test_find_resource(void) SetLastError( 0xdeadbeef ); rsrc = FindResourceW( GetModuleHandleW(NULL), MAKEINTRESOURCEW(1), (LPCWSTR)RT_DIALOG ); ok( !rsrc, "resource found\n" ); - ok( GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); rsrc = FindResourceW( GetModuleHandleW(NULL), MAKEINTRESOURCEW(2), (LPCWSTR)RT_MENU ); ok( !rsrc, "resource found\n" ); - ok( GetLastError() == ERROR_RESOURCE_NAME_NOT_FOUND, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_RESOURCE_NAME_NOT_FOUND, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); rsrc = FindResourceExW( GetModuleHandleW(NULL), (LPCWSTR)RT_MENU, MAKEINTRESOURCEW(1), MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT ) ); ok( !rsrc, "resource found\n" ); - ok( GetLastError() == ERROR_RESOURCE_LANG_NOT_FOUND, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_RESOURCE_LANG_NOT_FOUND, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); rsrc = FindResourceExW( GetModuleHandleW(NULL), (LPCWSTR)RT_MENU, MAKEINTRESOURCEW(1), MAKELANGID( LANG_FRENCH, SUBLANG_DEFAULT ) ); ok( !rsrc, "resource found\n" ); - ok( GetLastError() == ERROR_RESOURCE_LANG_NOT_FOUND, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_RESOURCE_LANG_NOT_FOUND, "wrong error %lu\n", GetLastError() ); +} + +typedef struct +{ + void *unknown[6]; + HGLOBAL pFileName; +} QUEUEDUPDATES; + +static void test_internal_structure(void) +{ + HANDLE res; + QUEUEDUPDATES *res_data; + WCHAR *res_filenameW; + + res = BeginUpdateResourceW( filenameW, FALSE ); + ok( res != NULL, "BeginUpdateResourceW failed\n" ); + res_data = GlobalLock(res); + ok( res_data != NULL, "GlobalLock failed\n" ); + res_filenameW = GlobalLock( res_data->pFileName ); + ok( res_filenameW != NULL, "GlobalLock for res_filenameW failed\n" ); + ok( !lstrcmpW( res_filenameW, filenameW ), "Filename fields do not match\n" ); + ok( GlobalUnlock( res_filenameW ), "GlobalUnlock res_filenamed failed\n" ); + ok( GlobalUnlock( res_data ), "GlobalUnlock res_data failed\n" ); + ok( EndUpdateResourceW( res, TRUE ), "EndUpdateResourceW failed\n"); +} + +static const struct +{ + IMAGE_DOS_HEADER dos; + IMAGE_NT_HEADERS nt; + IMAGE_SECTION_HEADER section; +} dll_image = +{ + { IMAGE_DOS_SIGNATURE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, { 0 }, 0, 0, { 0 }, + sizeof(IMAGE_DOS_HEADER) }, + { + IMAGE_NT_SIGNATURE, /* Signature */ + { +#if defined __i386__ + IMAGE_FILE_MACHINE_I386, /* Machine */ +#elif defined __x86_64__ + IMAGE_FILE_MACHINE_AMD64, /* Machine */ +#elif defined __arm__ + IMAGE_FILE_MACHINE_ARMNT, /* Machine */ +#elif defined __aarch64__ + IMAGE_FILE_MACHINE_ARM64, /* Machine */ +#else +# error You must specify the machine type +#endif + 1, /* NumberOfSections */ + 0, /* TimeDateStamp */ + 0, /* PointerToSymbolTable */ + 0, /* NumberOfSymbols */ + sizeof(IMAGE_OPTIONAL_HEADER), /* SizeOfOptionalHeader */ + IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL /* Characteristics */ + }, + { IMAGE_NT_OPTIONAL_HDR_MAGIC, /* Magic */ + 1, /* MajorLinkerVersion */ + 0, /* MinorLinkerVersion */ + 0, /* SizeOfCode */ + 0, /* SizeOfInitializedData */ + 0, /* SizeOfUninitializedData */ + 0, /* AddressOfEntryPoint */ + 0x1000, /* BaseOfCode */ +#ifndef _WIN64 + 0, /* BaseOfData */ +#endif + 0x10000000, /* ImageBase */ + 0x1000, /* SectionAlignment */ + 0x1000, /* FileAlignment */ + 4, /* MajorOperatingSystemVersion */ + 0, /* MinorOperatingSystemVersion */ + 1, /* MajorImageVersion */ + 0, /* MinorImageVersion */ + 4, /* MajorSubsystemVersion */ + 0, /* MinorSubsystemVersion */ + 0, /* Win32VersionValue */ + 0x3000, /* SizeOfImage */ + sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS), + 0, /* CheckSum */ + IMAGE_SUBSYSTEM_WINDOWS_CUI, /* Subsystem */ + IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLLCHARACTERISTICS_NX_COMPAT, /* DllCharacteristics */ + 0, /* SizeOfStackReserve */ + 0, /* SizeOfStackCommit */ + 0, /* SizeOfHeapReserve */ + 0, /* SizeOfHeapCommit */ + 0, /* LoaderFlags */ + IMAGE_FILE_RESOURCE_DIRECTORY + 1, /* NumberOfRvaAndSizes */ + { { 0 }, { 0 }, { 0x1000, 0x1000 } } /* DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] */ + } + }, + { ".rsrc\0\0", { 0 }, 0x1000, 0x1000, 0, 0, 0, 0, 0, + IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ } +}; + +static void create_test_dll( const WCHAR *name ) +{ + DWORD dummy; + HANDLE handle = CreateFileW( name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0 ); + + ok( handle != INVALID_HANDLE_VALUE, "failed to create file err %lu\n", GetLastError() ); + WriteFile( handle, &dll_image, sizeof(dll_image), &dummy, NULL ); + SetFilePointer( handle, dll_image.nt.OptionalHeader.SizeOfImage, NULL, FILE_BEGIN ); + SetEndOfFile( handle ); + CloseHandle( handle ); +} + +static struct mui_res +{ + DWORD signature; + DWORD size; + DWORD version; + DWORD path_type; + DWORD file_type; + DWORD system_attributes; + DWORD fallback_location; + BYTE service_checksum[16]; + BYTE checksum[16]; + DWORD unk1[2]; + DWORD mui_path_off; + DWORD mui_path_size; + DWORD unk2[2]; + DWORD ln_type_name_off; + DWORD ln_type_name_size; + DWORD ln_type_id_off; + DWORD ln_type_id_size; + DWORD mui_type_name_off; + DWORD mui_type_name_size; + DWORD mui_type_id_off; + DWORD mui_type_id_size; + DWORD lang_off; + DWORD lang_size; + DWORD fallback_lang_off; + DWORD fallback_lang_size; + WCHAR ln_type_names[8]; + DWORD ln_type_ids[1]; + WCHAR mui_type_names[8]; + DWORD mui_type_ids[1]; + WCHAR lang[8]; + WCHAR fallback_lang[8]; +} ln_mui_res = { + 0xfecdfecd, sizeof(ln_mui_res), 0x10000, 0, + MUI_FILETYPE_LANGUAGE_NEUTRAL_MAIN >> 1, + 0, 0, {'s','c'}, {'c'}, {0}, 0, 0, {0}, + offsetof(struct mui_res, ln_type_names), sizeof(L"MUI\0"), + offsetof(struct mui_res, ln_type_ids), sizeof(ln_mui_res.ln_type_ids), + offsetof(struct mui_res, mui_type_names), sizeof(L"MUI\0"), + offsetof(struct mui_res, mui_type_ids), sizeof(ln_mui_res.mui_type_ids), 0, 0, + offsetof(struct mui_res, fallback_lang), sizeof(L"en-US"), + {'M','U','I',0,0}, {RT_CURSOR}, {'M','U','I',0,0}, {RT_STRING}, {0}, {'e','n','-','U','S',0}, +}, en_mui_res = { + 0xfecdfecd, sizeof(ln_mui_res), 0x10000, 0, + MUI_FILETYPE_LANGUAGE_NEUTRAL_MUI >> 1, + 0, 0, {'s','c'}, {'c'}, {0}, 0, 0, {0}, + offsetof(struct mui_res, ln_type_names), sizeof(L"MUI\0"), + offsetof(struct mui_res, ln_type_ids), sizeof(ln_mui_res.ln_type_ids), + 0, 0, 0, 0, offsetof(struct mui_res, lang), sizeof(L"en-US"), 0, 0, + {'M','U','I',0,0}, {RT_STRING}, {0}, {0}, {'e','n','-','U','S',0} +}; + +static void test_mui(void) +{ +#if defined(__REACTOS__) && DLL_EXPORT_VERSION < 0x600 + skip("Cannot build test_mui() unless DLL_EXPORT_VERSION >= 0x600.\n"); +#else + static const WCHAR ln_dll[] = L"test_mui.dll"; + static const WCHAR en_dll[] = L"en-US\\test_mui.dll.mui"; + static const BYTE zeros[16] = { 0 }; + BYTE buf[1024]; + FILEMUIINFO *info = (FILEMUIINFO *)buf; + const WCHAR *str; + DWORD size, *id; + HANDLE res; + BOOL r; + + size = 0; + r = GetFileMUIInfo( 0, ln_dll, NULL, &size); + ok( !r, "GetFileMUIInfo succeeded\n" ); + ok( GetLastError() == ERROR_FILE_NOT_FOUND, "GetLastError() = %ld\n", GetLastError() ); + + create_test_dll( ln_dll ); + CreateDirectoryW( L"en-US", NULL ); + create_test_dll( en_dll ); + + size = 0; + r = GetFileMUIInfo( 0, ln_dll, NULL, &size ); + ok( r, "GetFileMUIInfo failed: %ld\n", GetLastError() ); + ok( size == sizeof(*info), "unexpected size: %ld\n", size ); + + memset( buf, 0xfe, sizeof(buf) ); + size = sizeof(buf); + info->dwSize = sizeof(buf); + info->dwVersion = 0; + r = GetFileMUIInfo( 0, ln_dll, info, &size ); + ok( !r, "GetFileMUIInfo succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError() = %ld\n", GetLastError() ); + ok( !size, "size = %ld\n", size ); + + size = sizeof(buf); + info->dwVersion = MUI_FILEINFO_VERSION; + r = GetFileMUIInfo( 0, ln_dll, info, &size ); + ok( r, "GetFileMUIInfo failed: %ld\n", GetLastError() ); + ok( info->dwSize == sizeof(buf), "dwSize = %ld\n", info->dwSize ); + ok( info->dwVersion == MUI_FILEINFO_VERSION, "dwVersion = %ld\n", info->dwVersion ); + ok( info->dwFileType == MUI_FILETYPE_NOT_LANGUAGE_NEUTRAL, "dwFileType = %ld\n", info->dwFileType ); + ok( !memcmp(info->pChecksum, zeros, sizeof(info->pChecksum)), "pChecksum = %s\n", + wine_dbgstr_an((char *)info->pChecksum, sizeof(info->pChecksum)) ); + ok( !memcmp(info->pServiceChecksum, zeros, sizeof(info->pServiceChecksum)), "pServiceChecksum = %s\n", + wine_dbgstr_an((char *)info->pServiceChecksum, sizeof(info->pServiceChecksum)) ); + ok( !info->dwLanguageNameOffset, "dwLanguageNameOffset = %ld\n", info->dwLanguageNameOffset ); + ok( !info->dwTypeIDMainSize, "dwTypeIDMainSize = %ld\n", info->dwTypeIDMainSize ); + ok( !info->dwTypeIDMainOffset, "dwTypeIDMainOffset = %ld\n", info->dwTypeIDMainOffset ); + ok( !info->dwTypeNameMainOffset, "dwTypeNameMainOffset = %ld\n", info->dwTypeNameMainOffset ); + ok( !info->dwTypeIDMUISize, "dwTypeIDMUISize = %ld\n", info->dwTypeIDMUISize ); + ok( !info->dwTypeIDMUIOffset, "dwTypeIDMUIOffset = %ld\n", info->dwTypeIDMUIOffset ); + ok( !info->dwTypeNameMUIOffset, "dwTypeNameMUIOffset = %ld\n", info->dwTypeNameMUIOffset ); + ok( !memcmp(info->abBuffer, zeros, sizeof(info->abBuffer)), "abBuffer = %s\n", + wine_dbgstr_an((char *)info->abBuffer, sizeof(info->abBuffer)) ); + + res = BeginUpdateResourceW( ln_dll, TRUE ); + ok( res != NULL, "BeginUpdateResourceW failed: %ld\n", GetLastError() ); + r = UpdateResourceW( res, L"MUI", MAKEINTRESOURCEW(1), 0, &ln_mui_res, 4 ); + ok( r, "UpdateResource failed: %ld\n", GetLastError() ); + r = EndUpdateResourceW( res, FALSE ); + ok( r, "EndUpdateResourceW failed: %ld\n", GetLastError() ); + + size = 0; + r = GetFileMUIInfo( MUI_QUERY_TYPE | MUI_QUERY_CHECKSUM | MUI_QUERY_LANGUAGE_NAME + | MUI_QUERY_RESOURCE_TYPES, ln_dll, NULL, &size ); + ok( !r, "GetFileMUIInfo succeeded\n" ); +#if defined(__REACTOS__) && defined(_WIN64) + ok( GetLastError() == ERROR_BAD_EXE_FORMAT || GetLastError() == ERROR_INSUFFICIENT_BUFFER /* Vista x64 */, "GetLastError() = %ld\n", GetLastError() ); +#else + ok( GetLastError() == ERROR_BAD_EXE_FORMAT, "GetLastError() = %ld\n", GetLastError() ); +#endif + + res = BeginUpdateResourceW( ln_dll, TRUE ); + ok( res != NULL, "BeginUpdateResourceW failed: %ld\n", GetLastError() ); + r = UpdateResourceW( res, L"MUI", MAKEINTRESOURCEW(1), 0, &ln_mui_res, sizeof(ln_mui_res) ); + ok( r, "UpdateResource failed: %ld\n", GetLastError() ); + r = EndUpdateResourceW( res, FALSE ); + ok( r, "EndUpdateResourceW failed: %ld\n", GetLastError() ); + + size = 0; + r = GetFileMUIInfo( MUI_QUERY_TYPE | MUI_QUERY_CHECKSUM | MUI_QUERY_LANGUAGE_NAME + | MUI_QUERY_RESOURCE_TYPES, ln_dll, NULL, &size ); + ok( !r, "GetFileMUIInfo succeeded\n" ); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetLastError() = %ld\n", GetLastError() ); + ok( size, "size was not set\n" ); + + memset( buf, 0xfe, sizeof(buf) ); + size = sizeof(buf); + info->dwSize = sizeof(buf); + info->dwVersion = MUI_FILEINFO_VERSION; + r = GetFileMUIInfo( MUI_QUERY_TYPE | MUI_QUERY_CHECKSUM | MUI_QUERY_LANGUAGE_NAME + | MUI_QUERY_RESOURCE_TYPES, ln_dll, info, &size ); + ok( r, "GetFileMUIInfo failed: %ld\n", GetLastError() ); + ok( info->dwSize == sizeof(buf), "dwSize = %ld\n", info->dwSize ); + ok( info->dwVersion == MUI_FILEINFO_VERSION, "dwVersion = %ld\n", info->dwVersion ); + ok( info->dwFileType == MUI_FILETYPE_LANGUAGE_NEUTRAL_MAIN, "dwFileType = %ld\n", info->dwFileType ); + ok( info->pChecksum[0] == 'c', "pChecksum = %s\n", + wine_dbgstr_an((char *)info->pChecksum, sizeof(info->pChecksum)) ); + ok( info->pServiceChecksum[0] == 's', "pServiceChecksum = %s\n", + wine_dbgstr_an((char *)info->pServiceChecksum, sizeof(info->pServiceChecksum)) ); + ok( info->dwLanguageNameOffset == 72, "dwLanguageNameOffset = %ld\n", info->dwLanguageNameOffset ); +#if defined(__REACTOS__) && DLL_EXPORT_VERSION >= 0x600 + if (is_reactos()) { + ok(FALSE, "FIXME: These tests crash on ReactOS!\n"); + } else { +#endif + str = (WCHAR *)(buf + info->dwLanguageNameOffset); + ok( !wcscmp(str, L"en-US"), "language name = %s\n", wine_dbgstr_w(str) ); + ok( info->dwTypeIDMainSize == 1, "dwTypeIDMainSize = %ld\n", info->dwTypeIDMainSize ); + ok( info->dwTypeIDMainOffset == 84, "dwTypeIDMainOffset = %ld\n", info->dwTypeIDMainOffset ); + id = (DWORD *)(buf + info->dwTypeIDMainOffset); + ok( id[0] == RT_CURSOR, "type ID main[0] = %ld\n", id[0] ); + ok( info->dwTypeNameMainOffset == 88, "dwTypeNameMainOffset = %ld\n", info->dwTypeNameMainOffset ); + str = (WCHAR *)(buf + info->dwTypeNameMainOffset); + ok( !wcscmp(str, L"MUI"), "type name main[0] = %s\n", wine_dbgstr_w(str) ); + str += wcslen(str) + 1; + ok( !str[0], "string list is not NULL terminated: %s\n", wine_dbgstr_w(str) ); + ok( info->dwTypeIDMUISize == 1, "dwTypeIDMUISize = %ld\n", info->dwTypeIDMUISize ); + ok( info->dwTypeIDMUIOffset == 98, "dwTypeIDMUIOffset = %ld\n", info->dwTypeIDMUIOffset ); + id = (DWORD *)(buf + info->dwTypeIDMUIOffset); + ok( id[0] == RT_STRING, "type ID MUI[0] = %ld\n", id[0] ); + ok( info->dwTypeNameMUIOffset == 102, "dwTypeNameMUIOffset = %ld\n", info->dwTypeNameMUIOffset ); + str = (WCHAR *)(buf + info->dwTypeNameMUIOffset); + ok( !wcscmp(str, L"MUI"), "type name MUI[0] = %s\n", wine_dbgstr_w(str) ); + str += wcslen(str) + 1; + ok( !str[0], "string list is not NULL terminated: %s\n", wine_dbgstr_w(str) ); +#if defined(__REACTOS__) && DLL_EXPORT_VERSION >= 0x600 + } +#endif + + res = BeginUpdateResourceW( en_dll, TRUE ); + ok( res != NULL, "BeginUpdateResourceW failed: %ld\n", GetLastError() ); + r = UpdateResourceW( res, L"MUI", MAKEINTRESOURCEW(1), 0, &en_mui_res, sizeof(en_mui_res) ); + ok( r, "UpdateResource failed: %ld\n", GetLastError() ); + r = EndUpdateResourceW( res, FALSE ); + ok( r, "EndUpdateResourceW failed: %ld\n", GetLastError() ); + + memset( buf, 0xfe, sizeof(buf) ); + size = sizeof(buf); + info->dwSize = sizeof(buf); + info->dwVersion = MUI_FILEINFO_VERSION; + r = GetFileMUIInfo( MUI_QUERY_TYPE | MUI_QUERY_CHECKSUM | MUI_QUERY_LANGUAGE_NAME + | MUI_QUERY_RESOURCE_TYPES, en_dll, info, &size ); + ok( r, "GetFileMUIInfo failed: %ld\n", GetLastError() ); + ok( info->dwSize == sizeof(buf), "dwSize = %ld\n", info->dwSize ); + ok( info->dwVersion == MUI_FILEINFO_VERSION, "dwVersion = %ld\n", info->dwVersion ); + ok( info->dwFileType == MUI_FILETYPE_LANGUAGE_NEUTRAL_MUI, "dwFileType = %ld\n", info->dwFileType ); + ok( info->pChecksum[0] == 'c', "pChecksum = %s\n", + wine_dbgstr_an((char *)info->pChecksum, sizeof(info->pChecksum)) ); + ok( info->pServiceChecksum[0] == 's', "pServiceChecksum = %s\n", + wine_dbgstr_an((char *)info->pServiceChecksum, sizeof(info->pServiceChecksum)) ); + ok( info->dwLanguageNameOffset == 72, "dwLanguageNameOffset = %ld\n", info->dwLanguageNameOffset ); +#if defined(__REACTOS__) && DLL_EXPORT_VERSION >= 0x600 + if (is_reactos()) { + ok(FALSE, "FIXME: These tests crash on ReactOS!\n"); + } else { +#endif + str = (WCHAR *)(buf + info->dwLanguageNameOffset); + ok( !wcscmp(str, L"en-US"), "language name = %s\n", wine_dbgstr_w(str) ); + ok( !info->dwTypeIDMainSize, "dwTypeIDMainSize = %ld\n", info->dwTypeIDMainSize ); + ok( !info->dwTypeIDMainOffset, "dwTypeIDMainOffset = %ld\n", info->dwTypeIDMainOffset ); + ok( !info->dwTypeNameMainOffset, "dwTypeNameMainOffset = %ld\n", info->dwTypeNameMainOffset ); + ok( info->dwTypeIDMUISize == 1, "dwTypeIDMUISize = %ld\n", info->dwTypeIDMUISize ); + ok( info->dwTypeIDMUIOffset == 84, "dwTypeIDMUIOffset = %ld\n", info->dwTypeIDMUIOffset ); + id = (DWORD *)(buf + info->dwTypeIDMUIOffset); + ok( id[0] == RT_STRING, "type ID MUI[0] = %ld\n", id[0] ); + ok( info->dwTypeNameMUIOffset == 88, "dwTypeNameMUIOffset = %ld\n", info->dwTypeNameMUIOffset ); + str = (WCHAR *)(buf + info->dwTypeNameMUIOffset); + ok( !wcscmp(str, L"MUI"), "type name MUI[0] = %s\n", wine_dbgstr_w(str) ); + str += wcslen(str) + 1; + ok( !str[0], "string list is not NULL terminated: %s\n", wine_dbgstr_w(str) ); +#if defined(__REACTOS__) && DLL_EXPORT_VERSION >= 0x600 + } +#endif + + DeleteFileW( ln_dll ); + DeleteFileW( en_dll ); + RemoveDirectoryW( L"en-US" ); +#endif } START_TEST(resource) @@ -478,10 +854,11 @@ START_TEST(resource) update_empty_exe(); - for(i=0; i < sizeof( sec_variants ) / sizeof( sec_variants[0] ); i++) + for(i=0; i < ARRAY_SIZE(sec_variants); i++) { const struct _sec_variants *sec = &sec_variants[i]; build_exe( &sec->build ); + test_internal_structure(); update_resources_none(); check_exe( &sec->chk_none ); update_resources_delete(); @@ -490,7 +867,9 @@ START_TEST(resource) check_exe( &sec->chk_version ); update_resources_bigdata(); check_exe( &sec->chk_bigdata ); + update_resources_name(); DeleteFileA( filename ); } test_find_resource(); + test_mui(); } diff --git a/modules/rostests/winetests/kernel32/resource.rc b/modules/rostests/winetests/kernel32/resource.rc index f40a87819ea..40dd40d1f3e 100644 --- a/modules/rostests/winetests/kernel32/resource.rc +++ b/modules/rostests/winetests/kernel32/resource.rc @@ -24,3 +24,9 @@ { MENUITEM "foo", 1 } + +/* @makedep: wine_test.manifest */ +124 24 wine_test.manifest +#ifdef __REACTOS__ +DUMMY.DLL TESTDLL "dummy.dll" +#endif diff --git a/modules/rostests/winetests/kernel32/sync.c b/modules/rostests/winetests/kernel32/sync.c index e03ebae1f9f..93069448b7b 100644 --- a/modules/rostests/winetests/kernel32/sync.c +++ b/modules/rostests/winetests/kernel32/sync.c @@ -21,19 +21,16 @@ #include #include #include + +#include "ntstatus.h" +#define WIN32_NO_STATUS #include #include #include +#include #include "wine/test.h" -#ifdef __REACTOS__ -#define QueryDepthSList(x) RtlQueryDepthSList(x) -#define InterlockedPushEntrySList(x,y) RtlInterlockedPushEntrySList(x,y) -#define InterlockedPopEntrySList(x) RtlInterlockedPopEntrySList(x) -#define InterlockedFlushSList(x) RtlInterlockedFlushSList(x) -#endif - #undef __fastcall #define __fastcall __stdcall @@ -44,6 +41,7 @@ static BOOL (WINAPI *pInitOnceExecuteOnce)(PINIT_ONCE,PINIT_ONCE_FN,PVOID,LPVO static BOOL (WINAPI *pInitOnceBeginInitialize)(PINIT_ONCE,DWORD,BOOL*,LPVOID*); static BOOL (WINAPI *pInitOnceComplete)(PINIT_ONCE,DWORD,LPVOID); +static BOOL (WINAPI *pInitializeCriticalSectionEx)(CRITICAL_SECTION*,DWORD,DWORD); static VOID (WINAPI *pInitializeConditionVariable)(PCONDITION_VARIABLE); static BOOL (WINAPI *pSleepConditionVariableCS)(PCONDITION_VARIABLE,PCRITICAL_SECTION,DWORD); static BOOL (WINAPI *pSleepConditionVariableSRW)(PCONDITION_VARIABLE,PSRWLOCK,DWORD,ULONG); @@ -58,7 +56,7 @@ static VOID (WINAPI *pReleaseSRWLockShared)(PSRWLOCK); static BOOLEAN (WINAPI *pTryAcquireSRWLockExclusive)(PSRWLOCK); static BOOLEAN (WINAPI *pTryAcquireSRWLockShared)(PSRWLOCK); -static NTSTATUS (WINAPI *pNtAllocateVirtualMemory)(HANDLE, PVOID *, ULONG, SIZE_T *, ULONG, ULONG); +static NTSTATUS (WINAPI *pNtAllocateVirtualMemory)(HANDLE, PVOID *, ULONG_PTR, SIZE_T *, ULONG, ULONG); static NTSTATUS (WINAPI *pNtFreeVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG); static NTSTATUS (WINAPI *pNtWaitForSingleObject)(HANDLE, BOOLEAN, const LARGE_INTEGER *); static NTSTATUS (WINAPI *pNtWaitForMultipleObjects)(ULONG,const HANDLE*,BOOLEAN,BOOLEAN,const LARGE_INTEGER*); @@ -66,6 +64,8 @@ static PSLIST_ENTRY (__fastcall *pRtlInterlockedPushListSList)(PSLIST_HEADER lis PSLIST_ENTRY last, ULONG count); static PSLIST_ENTRY (WINAPI *pRtlInterlockedPushListSListEx)(PSLIST_HEADER list, PSLIST_ENTRY first, PSLIST_ENTRY last, ULONG count); +static NTSTATUS (WINAPI *pNtQueueApcThread)(HANDLE,PNTAPCFUNC,ULONG_PTR,ULONG_PTR,ULONG_PTR); +static NTSTATUS (WINAPI *pNtTestAlert)(void); #ifdef __i386__ @@ -183,6 +183,51 @@ static void test_signalandwait(void) CloseHandle(file); } +static void test_temporary_objects(void) +{ + HANDLE handle; + + SetLastError(0xdeadbeef); + handle = CreateMutexA(NULL, FALSE, "WineTestMutex2"); + ok(handle != NULL, "CreateMutex failed with error %ld\n", GetLastError()); + CloseHandle(handle); + + SetLastError(0xdeadbeef); + handle = OpenMutexA(READ_CONTROL, FALSE, "WineTestMutex2"); + ok(!handle, "OpenMutex succeeded\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + handle = CreateSemaphoreA(NULL, 0, 1, "WineTestSemaphore2"); + ok(handle != NULL, "CreateSemaphore failed with error %ld\n", GetLastError()); + CloseHandle(handle); + + SetLastError(0xdeadbeef); + handle = OpenSemaphoreA(READ_CONTROL, FALSE, "WineTestSemaphore2"); + ok(!handle, "OpenSemaphore succeeded\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + handle = CreateEventA(NULL, FALSE, FALSE, "WineTestEvent2"); + ok(handle != NULL, "CreateEvent failed with error %ld\n", GetLastError()); + CloseHandle(handle); + + SetLastError(0xdeadbeef); + handle = OpenEventA(READ_CONTROL, FALSE, "WineTestEvent2"); + ok(!handle, "OpenEvent succeeded\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + handle = CreateWaitableTimerA(NULL, FALSE, "WineTestWaitableTimer2"); + ok(handle != NULL, "CreateWaitableTimer failed with error %ld\n", GetLastError()); + CloseHandle(handle); + + SetLastError(0xdeadbeef); + handle = OpenWaitableTimerA(READ_CONTROL, FALSE, "WineTestWaitableTimer2"); + ok(!handle, "OpenWaitableTimer succeeded\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError()); +} + static void test_mutex(void) { DWORD wait_ret; @@ -195,35 +240,35 @@ static void test_mutex(void) SetLastError(0xdeadbeef); hOpened = OpenMutexA(0, FALSE, "WineTestMutex"); ok(hOpened == NULL, "OpenMutex succeeded\n"); - ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError()); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError()); SetLastError(0xdeadbeef); hCreated = CreateMutexA(NULL, FALSE, "WineTestMutex"); - ok(hCreated != NULL, "CreateMutex failed with error %d\n", GetLastError()); + ok(hCreated != NULL, "CreateMutex failed with error %ld\n", GetLastError()); SetLastError(0xdeadbeef); hOpened = OpenMutexA(0, FALSE, "WineTestMutex"); -todo_wine + todo_wine ok(hOpened == NULL, "OpenMutex succeeded\n"); -todo_wine - ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %u\n", GetLastError()); + todo_wine + ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %lu\n", GetLastError()); SetLastError(0xdeadbeef); hOpened = OpenMutexA(GENERIC_EXECUTE, FALSE, "WineTestMutex"); - ok(hOpened != NULL, "OpenMutex failed with error %d\n", GetLastError()); + ok(hOpened != NULL, "OpenMutex failed with error %ld\n", GetLastError()); wait_ret = WaitForSingleObject(hOpened, INFINITE); - ok(wait_ret == WAIT_OBJECT_0, "WaitForSingleObject failed with error %d\n", GetLastError()); + ok(wait_ret == WAIT_OBJECT_0, "WaitForSingleObject failed with error %ld\n", GetLastError()); CloseHandle(hOpened); for(i=0; i < 31; i++) { wait_ret = WaitForSingleObject(hCreated, INFINITE); - ok(wait_ret == WAIT_OBJECT_0, "WaitForSingleObject failed with error 0x%08x\n", wait_ret); + ok(wait_ret == WAIT_OBJECT_0, "WaitForSingleObject failed with error 0x%08lx\n", wait_ret); } SetLastError(0xdeadbeef); hOpened = OpenMutexA(GENERIC_READ | GENERIC_WRITE, FALSE, "WineTestMutex"); - ok(hOpened != NULL, "OpenMutex failed with error %d\n", GetLastError()); + ok(hOpened != NULL, "OpenMutex failed with error %ld\n", GetLastError()); wait_ret = WaitForSingleObject(hOpened, INFINITE); ok(wait_ret == WAIT_FAILED, "WaitForSingleObject succeeded\n"); CloseHandle(hOpened); @@ -236,60 +281,60 @@ todo_wine { SetLastError(0xdeadbeef); ret = ReleaseMutex(hOpened); - ok(ret, "ReleaseMutex failed with error %d, access %x\n", GetLastError(), 1 << i); + ok(ret, "ReleaseMutex failed with error %ld, access %x\n", GetLastError(), 1 << i); CloseHandle(hOpened); } else { if ((1 << i) == ACCESS_SYSTEM_SECURITY) - todo_wine ok(GetLastError() == ERROR_PRIVILEGE_NOT_HELD, "wrong error %u, access %x\n", GetLastError(), 1 << i); + todo_wine ok(GetLastError() == ERROR_PRIVILEGE_NOT_HELD, "wrong error %lu, access %x\n", GetLastError(), 1 << i); else - todo_wine ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %u, , access %x\n", GetLastError(), 1 << i); + todo_wine ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %lu, , access %x\n", GetLastError(), 1 << i); ReleaseMutex(hCreated); failed |=0x1 << i; } } -todo_wine - ok( failed == 0x0de0fffe, "open succeeded when it shouldn't: %x\n", failed); + todo_wine + ok( failed == 0x0de0fffe, "open succeeded when it shouldn't: %lx\n", failed); SetLastError(0xdeadbeef); ret = ReleaseMutex(hCreated); ok(!ret && (GetLastError() == ERROR_NOT_OWNER), - "ReleaseMutex should have failed with ERROR_NOT_OWNER instead of %d\n", GetLastError()); + "ReleaseMutex should have failed with ERROR_NOT_OWNER instead of %ld\n", GetLastError()); /* test case sensitivity */ SetLastError(0xdeadbeef); hOpened = OpenMutexA(READ_CONTROL, FALSE, "WINETESTMUTEX"); ok(!hOpened, "OpenMutex succeeded\n"); - ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError()); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError()); SetLastError(0xdeadbeef); hOpened = OpenMutexA(READ_CONTROL, FALSE, "winetestmutex"); ok(!hOpened, "OpenMutex succeeded\n"); - ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError()); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError()); SetLastError(0xdeadbeef); hOpened = OpenMutexA(READ_CONTROL, FALSE, NULL); ok(!hOpened, "OpenMutex succeeded\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError()); SetLastError(0xdeadbeef); hOpened = OpenMutexW(READ_CONTROL, FALSE, NULL); ok(!hOpened, "OpenMutex succeeded\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError()); SetLastError(0xdeadbeef); hOpened = CreateMutexA(NULL, FALSE, "WineTestMutex"); - ok(hOpened != NULL, "CreateMutex failed with error %d\n", GetLastError()); - ok(GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError()); + ok(hOpened != NULL, "CreateMutex failed with error %ld\n", GetLastError()); + ok(GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %lu\n", GetLastError()); CloseHandle(hOpened); SetLastError(0xdeadbeef); hOpened = CreateMutexA(NULL, FALSE, "WINETESTMUTEX"); - ok(hOpened != NULL, "CreateMutex failed with error %d\n", GetLastError()); - ok(GetLastError() == 0, "wrong error %u\n", GetLastError()); + ok(hOpened != NULL, "CreateMutex failed with error %ld\n", GetLastError()); + ok(GetLastError() == 0, "wrong error %lu\n", GetLastError()); CloseHandle(hOpened); CloseHandle(hCreated); @@ -476,8 +521,12 @@ static void test_event(void) BOOL val; /* no sd */ +#if defined(__REACTOS__) && defined(_MSC_VER) + handle = CreateEventA(NULL, FALSE, FALSE, __FILE_FW_SLASH__ ": Test Event"); +#else handle = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": Test Event"); - ok(handle != NULL, "CreateEventW with blank sd failed with error %d\n", GetLastError()); +#endif + ok(handle != NULL, "CreateEventW with blank sd failed with error %ld\n", GetLastError()); CloseHandle(handle); sa.nLength = sizeof(sa); @@ -487,61 +536,93 @@ static void test_event(void) InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); /* blank sd */ +#if defined(__REACTOS__) && defined(_MSC_VER) + handle = CreateEventA(&sa, FALSE, FALSE, __FILE_FW_SLASH__ ": Test Event"); +#else handle = CreateEventA(&sa, FALSE, FALSE, __FILE__ ": Test Event"); - ok(handle != NULL, "CreateEventW with blank sd failed with error %d\n", GetLastError()); +#endif + ok(handle != NULL, "CreateEventW with blank sd failed with error %ld\n", GetLastError()); CloseHandle(handle); /* sd with NULL dacl */ SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); +#if defined(__REACTOS__) && defined(_MSC_VER) + handle = CreateEventA(&sa, FALSE, FALSE, __FILE_FW_SLASH__ ": Test Event"); +#else handle = CreateEventA(&sa, FALSE, FALSE, __FILE__ ": Test Event"); - ok(handle != NULL, "CreateEventW with blank sd failed with error %d\n", GetLastError()); +#endif + ok(handle != NULL, "CreateEventW with blank sd failed with error %ld\n", GetLastError()); CloseHandle(handle); /* sd with empty dacl */ InitializeAcl(&acl, sizeof(acl), ACL_REVISION); SetSecurityDescriptorDacl(&sd, TRUE, &acl, FALSE); +#if defined(__REACTOS__) && defined(_MSC_VER) + handle = CreateEventA(&sa, FALSE, FALSE, __FILE_FW_SLASH__ ": Test Event"); +#else handle = CreateEventA(&sa, FALSE, FALSE, __FILE__ ": Test Event"); - ok(handle != NULL, "CreateEventW with blank sd failed with error %d\n", GetLastError()); +#endif + ok(handle != NULL, "CreateEventW with blank sd failed with error %ld\n", GetLastError()); CloseHandle(handle); /* test case sensitivity */ SetLastError(0xdeadbeef); +#if defined(__REACTOS__) && defined(_MSC_VER) + handle = CreateEventA(NULL, FALSE, FALSE, __FILE_FW_SLASH__ ": Test Event"); +#else 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()); +#endif + ok( handle != NULL, "CreateEvent failed with error %lu\n", GetLastError()); + ok( GetLastError() == 0, "wrong error %lu\n", GetLastError()); SetLastError(0xdeadbeef); +#if defined(__REACTOS__) && defined(_MSC_VER) + handle2 = CreateEventA(NULL, FALSE, FALSE, __FILE_FW_SLASH__ ": Test Event"); +#else 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()); +#endif + ok( handle2 != NULL, "CreateEvent failed with error %ld\n", GetLastError()); + ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %lu\n", GetLastError()); CloseHandle( handle2 ); SetLastError(0xdeadbeef); +#if defined(__REACTOS__) && defined(_MSC_VER) + handle2 = CreateEventA(NULL, FALSE, FALSE, __FILE_FW_SLASH__ ": TEST EVENT"); +#else 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()); +#endif + ok( handle2 != NULL, "CreateEvent failed with error %ld\n", GetLastError()); + ok( GetLastError() == 0, "wrong error %lu\n", GetLastError()); CloseHandle( handle2 ); SetLastError(0xdeadbeef); +#if defined(__REACTOS__) && defined(_MSC_VER) + handle2 = OpenEventA( EVENT_ALL_ACCESS, FALSE, __FILE_FW_SLASH__ ": Test Event"); +#else handle2 = OpenEventA( EVENT_ALL_ACCESS, FALSE, __FILE__ ": Test Event"); - ok( handle2 != NULL, "OpenEvent failed with error %d\n", GetLastError()); +#endif + ok( handle2 != NULL, "OpenEvent failed with error %ld\n", GetLastError()); CloseHandle( handle2 ); SetLastError(0xdeadbeef); +#if defined(__REACTOS__) && defined(_MSC_VER) + handle2 = OpenEventA( EVENT_ALL_ACCESS, FALSE, __FILE_FW_SLASH__ ": TEST EVENT"); +#else handle2 = OpenEventA( EVENT_ALL_ACCESS, FALSE, __FILE__ ": TEST EVENT"); +#endif ok( !handle2, "OpenEvent succeeded\n"); - ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError()); + ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError()); SetLastError(0xdeadbeef); handle2 = OpenEventA( EVENT_ALL_ACCESS, FALSE, NULL ); ok( !handle2, "OpenEvent succeeded\n"); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError()); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError()); SetLastError(0xdeadbeef); handle2 = OpenEventW( EVENT_ALL_ACCESS, FALSE, NULL ); ok( !handle2, "OpenEvent succeeded\n"); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError()); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError()); CloseHandle( handle ); @@ -554,27 +635,31 @@ static void test_event(void) } handle = pCreateMemoryResourceNotification( HighMemoryResourceNotification + 1 ); ok( !handle, "CreateMemoryResourceNotification succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); ret = pQueryMemoryResourceNotification( handle, &val ); ok( !ret, "QueryMemoryResourceNotification succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); handle = pCreateMemoryResourceNotification( LowMemoryResourceNotification ); - ok( handle != 0, "CreateMemoryResourceNotification failed err %u\n", GetLastError() ); + ok( handle != 0, "CreateMemoryResourceNotification failed err %lu\n", GetLastError() ); ret = WaitForSingleObject( handle, 10 ); - ok( ret == WAIT_OBJECT_0 || ret == WAIT_TIMEOUT, "WaitForSingleObject wrong ret %u\n", ret ); + ok( ret == WAIT_OBJECT_0 || ret == WAIT_TIMEOUT, "WaitForSingleObject wrong ret %lu\n", ret ); val = ~0; ret = pQueryMemoryResourceNotification( handle, &val ); - ok( ret, "QueryMemoryResourceNotification failed err %u\n", GetLastError() ); + ok( ret, "QueryMemoryResourceNotification failed err %lu\n", GetLastError() ); ok( val == FALSE || val == TRUE, "wrong value %u\n", val ); ret = CloseHandle( handle ); - ok( ret, "CloseHandle failed err %u\n", GetLastError() ); + ok( ret, "CloseHandle failed err %lu\n", GetLastError() ); +#if defined(__REACTOS__) && defined(_MSC_VER) + handle = CreateEventA(NULL, FALSE, FALSE, __FILE_FW_SLASH__ ": Test Event"); +#else handle = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": Test Event"); +#endif val = ~0; ret = pQueryMemoryResourceNotification( handle, &val ); - ok( ret, "QueryMemoryResourceNotification failed err %u\n", GetLastError() ); + ok( ret, "QueryMemoryResourceNotification failed err %lu\n", GetLastError() ); ok( val == FALSE || val == TRUE, "wrong value %u\n", val ); CloseHandle( handle ); } @@ -586,41 +671,61 @@ static void test_semaphore(void) /* test case sensitivity */ SetLastError(0xdeadbeef); +#if defined(__REACTOS__) && defined(_MSC_VER) + handle = CreateSemaphoreA(NULL, 0, 1, __FILE_FW_SLASH__ ": Test Semaphore"); +#else 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()); +#endif + ok(handle != NULL, "CreateSemaphore failed with error %lu\n", GetLastError()); + ok(GetLastError() == 0, "wrong error %lu\n", GetLastError()); SetLastError(0xdeadbeef); +#if defined(__REACTOS__) && defined(_MSC_VER) + handle2 = CreateSemaphoreA(NULL, 0, 1, __FILE_FW_SLASH__ ": Test Semaphore"); +#else 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()); +#endif + ok( handle2 != NULL, "CreateSemaphore failed with error %ld\n", GetLastError()); + ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %lu\n", GetLastError()); CloseHandle( handle2 ); SetLastError(0xdeadbeef); +#if defined(__REACTOS__) && defined(_MSC_VER) + handle2 = CreateSemaphoreA(NULL, 0, 1, __FILE_FW_SLASH__ ": TEST SEMAPHORE"); +#else 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()); +#endif + ok( handle2 != NULL, "CreateSemaphore failed with error %ld\n", GetLastError()); + ok( GetLastError() == 0, "wrong error %lu\n", GetLastError()); CloseHandle( handle2 ); SetLastError(0xdeadbeef); +#if defined(__REACTOS__) && defined(_MSC_VER) + handle2 = OpenSemaphoreA( SEMAPHORE_ALL_ACCESS, FALSE, __FILE_FW_SLASH__ ": Test Semaphore"); +#else handle2 = OpenSemaphoreA( SEMAPHORE_ALL_ACCESS, FALSE, __FILE__ ": Test Semaphore"); - ok( handle2 != NULL, "OpenSemaphore failed with error %d\n", GetLastError()); +#endif + ok( handle2 != NULL, "OpenSemaphore failed with error %ld\n", GetLastError()); CloseHandle( handle2 ); SetLastError(0xdeadbeef); +#if defined(__REACTOS__) && defined(_MSC_VER) + handle2 = OpenSemaphoreA( SEMAPHORE_ALL_ACCESS, FALSE, __FILE_FW_SLASH__ ": TEST SEMAPHORE"); +#else handle2 = OpenSemaphoreA( SEMAPHORE_ALL_ACCESS, FALSE, __FILE__ ": TEST SEMAPHORE"); +#endif ok( !handle2, "OpenSemaphore succeeded\n"); - ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError()); + ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError()); SetLastError(0xdeadbeef); handle2 = OpenSemaphoreA( SEMAPHORE_ALL_ACCESS, FALSE, NULL ); ok( !handle2, "OpenSemaphore succeeded\n"); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError()); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError()); SetLastError(0xdeadbeef); handle2 = OpenSemaphoreW( SEMAPHORE_ALL_ACCESS, FALSE, NULL ); ok( !handle2, "OpenSemaphore succeeded\n"); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError()); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError()); CloseHandle( handle ); } @@ -632,41 +737,61 @@ static void test_waitable_timer(void) /* test case sensitivity */ SetLastError(0xdeadbeef); +#if defined(__REACTOS__) && defined(_MSC_VER) + handle = CreateWaitableTimerA(NULL, FALSE, __FILE_FW_SLASH__ ": Test WaitableTimer"); +#else handle = CreateWaitableTimerA(NULL, FALSE, __FILE__ ": Test WaitableTimer"); - ok(handle != NULL, "CreateWaitableTimer failed with error %u\n", GetLastError()); - ok(GetLastError() == 0, "wrong error %u\n", GetLastError()); +#endif + ok(handle != NULL, "CreateWaitableTimer failed with error %lu\n", GetLastError()); + ok(GetLastError() == 0, "wrong error %lu\n", GetLastError()); SetLastError(0xdeadbeef); +#if defined(__REACTOS__) && defined(_MSC_VER) + handle2 = CreateWaitableTimerA(NULL, FALSE, __FILE_FW_SLASH__ ": Test WaitableTimer"); +#else handle2 = CreateWaitableTimerA(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()); +#endif + ok( handle2 != NULL, "CreateWaitableTimer failed with error %ld\n", GetLastError()); + ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %lu\n", GetLastError()); CloseHandle( handle2 ); SetLastError(0xdeadbeef); +#if defined(__REACTOS__) && defined(_MSC_VER) + handle2 = CreateWaitableTimerA(NULL, FALSE, __FILE_FW_SLASH__ ": TEST WAITABLETIMER"); +#else handle2 = CreateWaitableTimerA(NULL, FALSE, __FILE__ ": TEST WAITABLETIMER"); - ok( handle2 != NULL, "CreateWaitableTimer failed with error %d\n", GetLastError()); - ok( GetLastError() == 0, "wrong error %u\n", GetLastError()); +#endif + ok( handle2 != NULL, "CreateWaitableTimer failed with error %ld\n", GetLastError()); + ok( GetLastError() == 0, "wrong error %lu\n", GetLastError()); CloseHandle( handle2 ); SetLastError(0xdeadbeef); +#if defined(__REACTOS__) && defined(_MSC_VER) + handle2 = OpenWaitableTimerA( TIMER_ALL_ACCESS, FALSE, __FILE_FW_SLASH__ ": Test WaitableTimer"); +#else handle2 = OpenWaitableTimerA( TIMER_ALL_ACCESS, FALSE, __FILE__ ": Test WaitableTimer"); - ok( handle2 != NULL, "OpenWaitableTimer failed with error %d\n", GetLastError()); +#endif + ok( handle2 != NULL, "OpenWaitableTimer failed with error %ld\n", GetLastError()); CloseHandle( handle2 ); SetLastError(0xdeadbeef); +#if defined(__REACTOS__) && defined(_MSC_VER) + handle2 = OpenWaitableTimerA( TIMER_ALL_ACCESS, FALSE, __FILE_FW_SLASH__ ": TEST WAITABLETIMER"); +#else handle2 = OpenWaitableTimerA( TIMER_ALL_ACCESS, FALSE, __FILE__ ": TEST WAITABLETIMER"); +#endif ok( !handle2, "OpenWaitableTimer succeeded\n"); - ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError()); + ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError()); SetLastError(0xdeadbeef); handle2 = OpenWaitableTimerA( TIMER_ALL_ACCESS, FALSE, NULL ); - ok( !handle2, "OpenWaitableTimer failed with error %d\n", GetLastError()); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError()); + ok( !handle2, "OpenWaitableTimer failed with error %ld\n", GetLastError()); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError()); SetLastError(0xdeadbeef); handle2 = OpenWaitableTimerW( TIMER_ALL_ACCESS, FALSE, NULL ); - ok( !handle2, "OpenWaitableTimer failed with error %d\n", GetLastError()); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError()); + ok( !handle2, "OpenWaitableTimer failed with error %ld\n", GetLastError()); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError()); CloseHandle( handle ); } @@ -703,35 +828,35 @@ static void test_iocp_callback(void) ok(sem != INVALID_HANDLE_VALUE, "Creating a semaphore failed\n"); ret = GetTempPathA(MAX_PATH, temp_path); - ok(ret != 0, "GetTempPathA error %d\n", GetLastError()); + ok(ret != 0, "GetTempPathA error %ld\n", GetLastError()); ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n"); ret = GetTempFileNameA(temp_path, prefix, 0, filename); - ok(ret != 0, "GetTempFileNameA error %d\n", GetLastError()); + ok(ret != 0, "GetTempFileNameA error %ld\n", GetLastError()); hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_RANDOM_ACCESS, 0); - ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA: error %d\n", GetLastError()); + ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA: error %ld\n", GetLastError()); retb = p_BindIoCompletionCallback(hFile, iocp_callback, 0); ok(retb == FALSE, "BindIoCompletionCallback succeeded on a file that wasn't created with FILE_FLAG_OVERLAPPED\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error is %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error is %ld\n", GetLastError()); ret = CloseHandle(hFile); - ok( ret, "CloseHandle: error %d\n", GetLastError()); + ok( ret, "CloseHandle: error %ld\n", GetLastError()); ret = DeleteFileA(filename); - ok( ret, "DeleteFileA: error %d\n", GetLastError()); + ok( ret, "DeleteFileA: error %ld\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()); + ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA: error %ld\n", GetLastError()); retb = p_BindIoCompletionCallback(hFile, iocp_callback, 0); ok(retb == TRUE, "BindIoCompletionCallback failed\n"); memset(&overlapped, 0, sizeof(overlapped)); retb = WriteFile(hFile, buffer, 4, &bytesWritten, &overlapped); - ok(retb == TRUE || GetLastError() == ERROR_IO_PENDING, "WriteFile failed, lastError = %d\n", GetLastError()); + ok(retb == TRUE || GetLastError() == ERROR_IO_PENDING, "WriteFile failed, lastError = %ld\n", GetLastError()); ret = WaitForSingleObject(sem, 5000); ok(ret == WAIT_OBJECT_0, "Wait for the IO completion callback failed\n"); @@ -739,43 +864,42 @@ static void test_iocp_callback(void) retb = p_BindIoCompletionCallback(hFile, iocp_callback, 0); ok(retb == FALSE, "BindIoCompletionCallback succeeded when setting the same callback on the file again\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error is %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error is %ld\n", GetLastError()); retb = p_BindIoCompletionCallback(hFile, NULL, 0); ok(retb == FALSE, "BindIoCompletionCallback succeeded when setting the callback to NULL\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error is %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error is %ld\n", GetLastError()); ret = CloseHandle(hFile); - ok( ret, "CloseHandle: error %d\n", GetLastError()); + ok( ret, "CloseHandle: error %ld\n", GetLastError()); ret = DeleteFileA(filename); - ok( ret, "DeleteFileA: error %d\n", GetLastError()); + ok( ret, "DeleteFileA: error %ld\n", GetLastError()); /* win2k3 requires the Flags parameter to be zero */ SetLastError(0xdeadbeef); 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()); + ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA: error %ld\n", GetLastError()); retb = p_BindIoCompletionCallback(hFile, iocp_callback, 12345); if (!retb) ok(GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); else ok(retb == TRUE, "BindIoCompletionCallback failed with Flags != 0\n"); ret = CloseHandle(hFile); - ok( ret, "CloseHandle: error %d\n", GetLastError()); + ok( ret, "CloseHandle: error %ld\n", GetLastError()); ret = DeleteFileA(filename); - ok( ret, "DeleteFileA: error %d\n", GetLastError()); + ok( ret, "DeleteFileA: error %ld\n", GetLastError()); retb = p_BindIoCompletionCallback(NULL, iocp_callback, 0); ok(retb == FALSE, "BindIoCompletionCallback succeeded on a NULL file\n"); ok(GetLastError() == ERROR_INVALID_HANDLE || GetLastError() == ERROR_INVALID_PARAMETER, /* vista */ - "Last error is %d\n", GetLastError()); + "Last error is %ld\n", GetLastError()); } static void CALLBACK timer_queue_cb1(PVOID p, BOOLEAN timedOut) { int *pn = p; - disable_success_count ok(timedOut, "Timer callbacks should always time out\n"); ++*pn; } @@ -890,7 +1014,7 @@ static void test_timer_queue(void) SetLastError(0xdeadbeef); ret = DeleteTimerQueueEx(q, NULL); ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING, - "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %d\n", + "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %ld\n", GetLastError()); /* Test synchronous deletion of the queue and running timers. */ @@ -906,7 +1030,7 @@ static void test_timer_queue(void) ret0 = DeleteTimerQueueTimer(q, t0, NULL); ok((!ret0 && GetLastError() == ERROR_IO_PENDING) || broken(ret0), /* Win 2000 & XP & 2003 */ - "DeleteTimerQueueTimer ret=%d le=%u\n", ret0, GetLastError()); + "DeleteTimerQueueTimer ret=%d le=%lu\n", ret0, GetLastError()); /* Called once. */ t1 = NULL; @@ -1008,21 +1132,21 @@ static void test_timer_queue(void) SetLastError(0xdeadbeef); ret = DeleteTimerQueueTimer(q, t1, NULL); ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING, - "DeleteTimerQueueTimer, GetLastError: expected ERROR_IO_PENDING, got %d\n", + "DeleteTimerQueueTimer, GetLastError: expected ERROR_IO_PENDING, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = DeleteTimerQueueTimer(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", + "DeleteTimerQueueTimer, GetLastError: expected ERROR_IO_PENDING, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = DeleteTimerQueueTimer(q, t3, et1); ok(ret, "DeleteTimerQueueTimer call was expected to fail\n"); ok(GetLastError() == 0xdeadbeef, - "DeleteTimerQueueTimer, GetLastError: expected 0xdeadbeef, got %d\n", + "DeleteTimerQueueTimer, GetLastError: expected 0xdeadbeef, got %ld\n", GetLastError()); ok(WaitForSingleObject(et1, 250) == WAIT_OBJECT_0, "Timer destruction event not triggered\n"); @@ -1031,7 +1155,7 @@ static void test_timer_queue(void) ret = DeleteTimerQueueTimer(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", + "DeleteTimerQueueTimer, GetLastError: expected ERROR_IO_PENDING, got %ld\n", GetLastError()); ok(WaitForSingleObject(et2, 1000) == WAIT_OBJECT_0, "Timer destruction event not triggered\n"); @@ -1039,7 +1163,7 @@ static void test_timer_queue(void) SetLastError(0xdeadbeef); ret = DeleteTimerQueueEx(q, e); ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING, - "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %d\n", + "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %ld\n", GetLastError()); ok(WaitForSingleObject(e, 250) == WAIT_OBJECT_0, "Queue destruction event not triggered\n"); @@ -1111,7 +1235,7 @@ static void test_timer_queue(void) SetLastError(0xdeadbeef); ret = DeleteTimerQueueEx(q, NULL); ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING, - "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %d\n", + "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %ld\n", GetLastError()); ok(d1.num_calls == 1, "DeleteTimerQueueTimer\n"); @@ -1161,13 +1285,13 @@ static void test_timer_queue(void) ret = DeleteTimerQueueEx(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", + "DeleteTimerQueueEx, GetLastError: expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = DeleteTimerQueueEx(q, NULL); ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING, - "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %d\n", + "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %ld\n", GetLastError()); } @@ -1192,80 +1316,80 @@ static void test_WaitForSingleObject(void) /* invalid handle with different values for lower 2 bits */ SetLastError(0xdeadbeef); ret = WaitForSingleObject(invalid, 0); - ok(ret == WAIT_FAILED, "expected WAIT_FAILED, got %d\n", ret); - ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + ok(ret == WAIT_FAILED, "expected WAIT_FAILED, got %ld\n", ret); + ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = WaitForSingleObject(modify_handle(invalid, 1), 0); - ok(ret == WAIT_FAILED, "expected WAIT_FAILED, got %d\n", ret); - ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + ok(ret == WAIT_FAILED, "expected WAIT_FAILED, got %ld\n", ret); + ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = WaitForSingleObject(modify_handle(invalid, 2), 0); - ok(ret == WAIT_FAILED, "expected WAIT_FAILED, got %d\n", ret); - ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + ok(ret == WAIT_FAILED, "expected WAIT_FAILED, got %ld\n", ret); + ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = WaitForSingleObject(modify_handle(invalid, 3), 0); - ok(ret == WAIT_FAILED, "expected WAIT_FAILED, got %d\n", ret); - ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + ok(ret == WAIT_FAILED, "expected WAIT_FAILED, got %ld\n", ret); + ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError()); /* valid handle with different values for lower 2 bits */ SetLastError(0xdeadbeef); ret = WaitForSingleObject(nonsignaled, 0); - ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %d\n", ret); - ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); + ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %ld\n", ret); + ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = WaitForSingleObject(modify_handle(nonsignaled, 1), 0); - ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %d\n", ret); - ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); + ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %ld\n", ret); + ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = WaitForSingleObject(modify_handle(nonsignaled, 2), 0); - ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %d\n", ret); - ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); + ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %ld\n", ret); + ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = WaitForSingleObject(modify_handle(nonsignaled, 3), 0); - ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %d\n", ret); - ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); + ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %ld\n", ret); + ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError()); /* valid handle with different values for lower 2 bits */ SetLastError(0xdeadbeef); ret = WaitForSingleObject(signaled, 0); - ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %d\n", ret); - ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); + ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %ld\n", ret); + ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = WaitForSingleObject(modify_handle(signaled, 1), 0); - ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %d\n", ret); - ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); + ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %ld\n", ret); + ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = WaitForSingleObject(modify_handle(signaled, 2), 0); - ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %d\n", ret); - ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); + ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %ld\n", ret); + ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = WaitForSingleObject(modify_handle(signaled, 3), 0); - ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %d\n", ret); - ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); + ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %ld\n", ret); + ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError()); /* pseudo handles are allowed in WaitForSingleObject and NtWaitForSingleObject */ ret = WaitForSingleObject(GetCurrentProcess(), 100); - ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %u\n", ret); + ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %lu\n", ret); ret = WaitForSingleObject(GetCurrentThread(), 100); - ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %u\n", ret); + ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %lu\n", ret); timeout.QuadPart = -1000000; status = pNtWaitForSingleObject(GetCurrentProcess(), FALSE, &timeout); - ok(status == STATUS_TIMEOUT, "expected STATUS_TIMEOUT, got %08x\n", status); + ok(status == STATUS_TIMEOUT, "expected STATUS_TIMEOUT, got %08lx\n", status); timeout.QuadPart = -1000000; status = pNtWaitForSingleObject(GetCurrentThread(), FALSE, &timeout); - ok(status == STATUS_TIMEOUT, "expected STATUS_TIMEOUT, got %08x\n", status); + ok(status == STATUS_TIMEOUT, "expected STATUS_TIMEOUT, got %08lx\n", status); CloseHandle(signaled); CloseHandle(nonsignaled); @@ -1289,15 +1413,15 @@ static void test_WaitForMultipleObjects(void) /* a manual-reset event remains signaled, an auto-reset event is cleared */ r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, FALSE, 0); - ok( r == WAIT_OBJECT_0, "should signal lowest handle first, got %d\n", r); + ok( r == WAIT_OBJECT_0, "should signal lowest handle first, got %ld\n", r); r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, FALSE, 0); - ok( r == WAIT_OBJECT_0, "should signal handle #0 first, got %d\n", r); + ok( r == WAIT_OBJECT_0, "should signal handle #0 first, got %ld\n", r); ok(ResetEvent(maxevents[0]), "ResetEvent\n"); for (i=1; ihProcess, &base, 0, &size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - disable_success_count - ok(!status, "expected STATUS_SUCCESS, got %08x\n", status); + ok(!status, "expected STATUS_SUCCESS, got %08lx\n", status); ok(base != NULL, "expected base != NULL, got %p\n", base); SetEvent(info->event); size = 0; status = pNtFreeVirtualMemory(pi->hProcess, &base, &size, MEM_RELEASE); - disable_success_count - ok(!status, "expected STATUS_SUCCESS, got %08x\n", status); + ok(!status, "expected STATUS_SUCCESS, got %08lx\n", status); SetEvent(info->event); } @@ -2596,49 +2792,47 @@ static void test_apc_deadlock(void) char **argv; int i; -#if defined(__REACTOS__) && defined(_M_AMD64) - if (!winetest_interactive) - { - skip("ROSTESTS-371: Skipping kernel32_winetest:sync test_apc_deadlock because it fails on Windows Server 2003 x64-Testbot. Set winetest_interactive to run it anyway.\n"); - return; - } -#endif - winetest_get_mainargs(&argv); sprintf(cmdline, "\"%s\" sync apc_deadlock", argv[0]); success = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); - ok(success, "CreateProcess failed with %u\n", GetLastError()); + ok(success, "CreateProcess failed with %lu\n", GetLastError()); event = CreateEventA(NULL, FALSE, FALSE, NULL); - ok(event != NULL, "CreateEvent failed with %u\n", GetLastError()); + ok(event != NULL, "CreateEvent failed with %lu\n", GetLastError()); info.pi = π info.event = event; info.running = TRUE; thread = CreateThread(NULL, 0, apc_deadlock_thread, &info, 0, NULL); - ok(thread != NULL, "CreateThread failed with %u\n", GetLastError()); + ok(thread != NULL, "CreateThread failed with %lu\n", GetLastError()); result = WaitForSingleObject(event, 1000); - ok(result == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", result); + ok(result == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %lu\n", result); - disable_success_count - for (i = 0; i < 1000; i++) + for (i = 0; i < 1000 && info.running; i++) { result = SuspendThread(pi.hThread); - ok(result == 0, "expected 0, got %u\n", result); + ok(result == 0, "expected 0, got %lu\n", result); WaitForSingleObject(event, 0); /* reset event */ result = WaitForSingleObject(event, 1000); - ok(result == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", result); + if (result == WAIT_TIMEOUT) + { + todo_wine + ok(result == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %lu\n", result); + info.running = FALSE; + } + else + ok(result == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %lu\n", result); result = ResumeThread(pi.hThread); - ok(result == 1, "expected 1, got %u\n", result); + ok(result == 1, "expected 1, got %lu\n", result); Sleep(1); } info.running = FALSE; result = WaitForSingleObject(thread, 1000); - ok(result == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", result); + ok(result == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %lu\n", result); CloseHandle(thread); CloseHandle(event); @@ -2647,15 +2841,187 @@ static void test_apc_deadlock(void) CloseHandle(pi.hProcess); } +static jmp_buf bad_cs_jmpbuf; + +static LONG WINAPI bad_cs_handler( EXCEPTION_POINTERS *eptr ) +{ + EXCEPTION_RECORD *rec = eptr->ExceptionRecord; + + ok(!rec->NumberParameters, "got %lu.\n", rec->NumberParameters); + ok(rec->ExceptionFlags == EXCEPTION_NONCONTINUABLE + || rec->ExceptionFlags == (EXCEPTION_NONCONTINUABLE | EXCEPTION_SOFTWARE_ORIGINATE), + "got %#lx.\n", rec->ExceptionFlags); + longjmp(bad_cs_jmpbuf, rec->ExceptionCode); + return EXCEPTION_CONTINUE_SEARCH; +} + +static void test_crit_section(void) +{ + void *vectored_handler; + CRITICAL_SECTION cs; + int exc_code; + HANDLE old; + BOOL ret; + + /* Win8+ does not initialize debug info, one has to use RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO + to override that. */ + memset(&cs, 0, sizeof(cs)); + InitializeCriticalSection(&cs); + ok(cs.DebugInfo == (void *)(ULONG_PTR)-1 || broken(!!cs.DebugInfo) /* before Win8 */, + "Unexpected debug info pointer %p.\n", cs.DebugInfo); + DeleteCriticalSection(&cs); + ok(cs.DebugInfo == NULL, "Unexpected debug info pointer %p.\n", cs.DebugInfo); + + if (!pInitializeCriticalSectionEx) + { + win_skip("InitializeCriticalSectionEx isn't available, skipping tests.\n"); + return; + } + + memset(&cs, 0, sizeof(cs)); + ret = pInitializeCriticalSectionEx(&cs, 0, 0); + ok(ret, "Failed to initialize critical section.\n"); + ok(cs.DebugInfo == (void *)(ULONG_PTR)-1 || broken(!!cs.DebugInfo) /* before Win8 */, + "Unexpected debug info pointer %p.\n", cs.DebugInfo); + DeleteCriticalSection(&cs); + ok(cs.DebugInfo == NULL, "Unexpected debug info pointer %p.\n", cs.DebugInfo); + + memset(&cs, 0, sizeof(cs)); + ret = pInitializeCriticalSectionEx(&cs, 0, CRITICAL_SECTION_NO_DEBUG_INFO); + ok(ret, "Failed to initialize critical section.\n"); + ok(cs.DebugInfo == (void *)(ULONG_PTR)-1, "Unexpected debug info pointer %p.\n", cs.DebugInfo); + DeleteCriticalSection(&cs); + ok(cs.DebugInfo == NULL, "Unexpected debug info pointer %p.\n", cs.DebugInfo); + + memset(&cs, 0, sizeof(cs)); + ret = pInitializeCriticalSectionEx(&cs, 0, 0); + ok(ret, "Failed to initialize critical section.\n"); + ok(cs.DebugInfo == (void *)(ULONG_PTR)-1 || broken(!!cs.DebugInfo) /* before Win8 */, + "Unexpected debug info pointer %p.\n", cs.DebugInfo); + DeleteCriticalSection(&cs); + ok(cs.DebugInfo == NULL, "Unexpected debug info pointer %p.\n", cs.DebugInfo); + + memset(&cs, 0, sizeof(cs)); + ret = pInitializeCriticalSectionEx(&cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); + ok(ret || broken(GetLastError() == ERROR_INVALID_PARAMETER) /* before Win8 */, + "Failed to initialize critical section, error %lu.\n", GetLastError()); + if (!ret) + { + ret = pInitializeCriticalSectionEx(&cs, 0, 0); + ok(ret, "Failed to initialize critical section.\n"); + } + ok(cs.DebugInfo && cs.DebugInfo != (void *)(ULONG_PTR)-1, "Unexpected debug info pointer %p.\n", cs.DebugInfo); + + ret = TryEnterCriticalSection(&cs); + ok(ret, "Failed to enter critical section.\n"); + LeaveCriticalSection(&cs); + + cs.DebugInfo = NULL; + + ret = TryEnterCriticalSection(&cs); + ok(ret, "Failed to enter critical section.\n"); + LeaveCriticalSection(&cs); + + DeleteCriticalSection(&cs); + ok(cs.DebugInfo == NULL, "Unexpected debug info pointer %p.\n", cs.DebugInfo); + + ret = pInitializeCriticalSectionEx(&cs, 0, 0); + ok(ret, "got error %lu.\n", GetLastError()); + old = cs.LockSemaphore; + cs.LockSemaphore = (HANDLE)0xdeadbeef; + + cs.LockCount = 0; + vectored_handler = AddVectoredExceptionHandler(TRUE, bad_cs_handler); + if (!(exc_code = setjmp(bad_cs_jmpbuf))) + EnterCriticalSection(&cs); + ok(cs.LockCount, "got %ld.\n", cs.LockCount); + ok(exc_code == STATUS_INVALID_HANDLE, "got %#x.\n", exc_code); + RemoveVectoredExceptionHandler(vectored_handler); + cs.LockSemaphore = old; + DeleteCriticalSection(&cs); +} + +static DWORD WINAPI thread_proc(LPVOID unused) +{ + Sleep(INFINITE); + return 0; +} + +static int apc_count; + +static void CALLBACK user_apc(ULONG_PTR unused) +{ + apc_count++; +} + +static void CALLBACK call_user_apc(ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3) +{ + PAPCFUNC func = (PAPCFUNC)arg1; + func(arg2); +} + +static void test_QueueUserAPC(void) +{ + HANDLE thread; + DWORD tid, ret; + NTSTATUS status; + + thread = CreateThread(NULL, 0, thread_proc, NULL, CREATE_SUSPENDED, &tid); + ok(thread != NULL, "CreateThread error %lu\n", GetLastError()); + + ret = TerminateThread(thread, 0xdeadbeef); + ok(ret, "TerminateThread error %lu\n", GetLastError()); + + ret = WaitForSingleObject(thread, 1000); + ok(ret == WAIT_OBJECT_0, "got %lu\n", ret); + + ret = pNtQueueApcThread(thread, call_user_apc, (ULONG_PTR)user_apc, 0, 0); + ok(ret == STATUS_UNSUCCESSFUL, "got %#lx\n", ret); + ret = pNtQueueApcThread(thread, NULL, 0, 0, 0); + ok(ret == STATUS_UNSUCCESSFUL, "got %#lx\n", ret); + + SetLastError(0xdeadbeef); + ret = QueueUserAPC(user_apc, thread, 0); + ok(!ret, "QueueUserAPC should fail\n"); +#ifdef __REACTOS__ + ok(GetLastError() == ERROR_GEN_FAILURE || broken(GetLastError() == 0xdeadbeef) /* WS03 */, "got %lu\n", GetLastError()); +#else + ok(GetLastError() == ERROR_GEN_FAILURE, "got %lu\n", GetLastError()); +#endif + + CloseHandle(thread); + + apc_count = 0; + ret = QueueUserAPC(user_apc, GetCurrentThread(), 0); + ok(ret, "QueueUserAPC failed err %lu\n", GetLastError()); + ok(!apc_count, "APC count %u\n", apc_count); + ret = SleepEx( 100, TRUE ); + ok( ret == WAIT_IO_COMPLETION, "SleepEx returned %lu\n", ret); + ok(apc_count == 1, "APC count %u\n", apc_count); + + ret = pNtQueueApcThread( GetCurrentThread(), NULL, 0, 0, 0 ); + ok( !ret, "got %#lx\n", ret); + ret = SleepEx( 100, TRUE ); + ok( ret == WAIT_OBJECT_0, "SleepEx returned %lu\n", ret); + + apc_count = 0; + ret = QueueUserAPC(user_apc, GetCurrentThread(), 0); + ok(ret, "QueueUserAPC failed err %lu\n", GetLastError()); + ok(!apc_count, "APC count %u\n", apc_count); + status = pNtTestAlert(); + ok(!status, "got %lx\n", status); + ok(apc_count == 1, "APC count %u\n", apc_count); + status = pNtTestAlert(); + ok(!status, "got %lx\n", status); + ok(apc_count == 1, "APC count %u\n", apc_count); +} + START_TEST(sync) { char **argv; int argc; HMODULE hdll = GetModuleHandleA("kernel32.dll"); HMODULE hntdll = GetModuleHandleA("ntdll.dll"); -#ifdef __REACTOS__ - HMODULE hdll_vista = GetModuleHandleA("kernel32_vista.dll"); -#endif pInitOnceInitialize = (void *)GetProcAddress(hdll, "InitOnceInitialize"); pInitOnceExecuteOnce = (void *)GetProcAddress(hdll, "InitOnceExecuteOnce"); @@ -2666,6 +3032,7 @@ START_TEST(sync) pSleepConditionVariableSRW = (void *)GetProcAddress(hdll, "SleepConditionVariableSRW"); pWakeAllConditionVariable = (void *)GetProcAddress(hdll, "WakeAllConditionVariable"); pWakeConditionVariable = (void *)GetProcAddress(hdll, "WakeConditionVariable"); + pInitializeCriticalSectionEx = (void *)GetProcAddress(hdll, "InitializeCriticalSectionEx"); pInitializeSRWLock = (void *)GetProcAddress(hdll, "InitializeSRWLock"); pAcquireSRWLockExclusive = (void *)GetProcAddress(hdll, "AcquireSRWLockExclusive"); pAcquireSRWLockShared = (void *)GetProcAddress(hdll, "AcquireSRWLockShared"); @@ -2679,28 +3046,8 @@ START_TEST(sync) pNtWaitForMultipleObjects = (void *)GetProcAddress(hntdll, "NtWaitForMultipleObjects"); pRtlInterlockedPushListSList = (void *)GetProcAddress(hntdll, "RtlInterlockedPushListSList"); pRtlInterlockedPushListSListEx = (void *)GetProcAddress(hntdll, "RtlInterlockedPushListSListEx"); - -#ifdef __REACTOS__ - if (!pInitializeConditionVariable) - { - pInitializeConditionVariable = (void *)GetProcAddress(hdll_vista, "InitializeConditionVariable"); - pSleepConditionVariableCS = (void *)GetProcAddress(hdll_vista, "SleepConditionVariableCS"); - pSleepConditionVariableSRW = (void *)GetProcAddress(hdll_vista, "SleepConditionVariableSRW"); - pWakeAllConditionVariable = (void *)GetProcAddress(hdll_vista, "WakeAllConditionVariable"); - pWakeConditionVariable = (void *)GetProcAddress(hdll_vista, "WakeConditionVariable"); - } - - if (!pInitializeSRWLock) - { - pInitializeSRWLock = (void *)GetProcAddress(hdll_vista, "InitializeSRWLock"); - pAcquireSRWLockExclusive = (void *)GetProcAddress(hdll_vista, "AcquireSRWLockExclusive"); - pAcquireSRWLockShared = (void *)GetProcAddress(hdll_vista, "AcquireSRWLockShared"); - pReleaseSRWLockExclusive = (void *)GetProcAddress(hdll_vista, "ReleaseSRWLockExclusive"); - pReleaseSRWLockShared = (void *)GetProcAddress(hdll_vista, "ReleaseSRWLockShared"); - pTryAcquireSRWLockExclusive = (void *)GetProcAddress(hdll_vista, "TryAcquireSRWLockExclusive"); - pTryAcquireSRWLockShared = (void *)GetProcAddress(hdll_vista, "TryAcquireSRWLockShared"); - } -#endif + pNtQueueApcThread = (void *)GetProcAddress(hntdll, "NtQueueApcThread"); + pNtTestAlert = (void *)GetProcAddress(hntdll, "NtTestAlert"); argc = winetest_get_mainargs( &argv ); if (argc >= 3) @@ -2713,7 +3060,10 @@ START_TEST(sync) } init_fastcall_thunk(); + + test_QueueUserAPC(); test_signalandwait(); + test_temporary_objects(); test_mutex(); test_slist(); test_event(); @@ -2724,10 +3074,17 @@ START_TEST(sync) test_WaitForSingleObject(); test_WaitForMultipleObjects(); test_initonce(); - test_condvars_base(); + test_condvars_base(&aligned_cv); + test_condvars_base(&unaligned_cv.cv); test_condvars_consumer_producer(); - test_srwlock_base(); + test_srwlock_base(&aligned_srwlock); + test_srwlock_quirk(); +#if defined(__i386__) || defined(__x86_64__) + /* unaligned locks only work on x86 platforms */ + test_srwlock_base(&unaligned_srwlock.lock); +#endif test_srwlock_example(); test_alertable_wait(); test_apc_deadlock(); + test_crit_section(); } diff --git a/modules/rostests/winetests/kernel32/testlist.c b/modules/rostests/winetests/kernel32/testlist.c index 769baa6b241..45f42a65d32 100644 --- a/modules/rostests/winetests/kernel32/testlist.c +++ b/modules/rostests/winetests/kernel32/testlist.c @@ -24,6 +24,7 @@ extern void func_mailslot(void); extern void func_module(void); extern void func_path(void); extern void func_pipe(void); +extern void func_power(void); extern void func_process(void); extern void func_profile(void); extern void func_resource(void); @@ -48,7 +49,7 @@ const struct test winetest_testlist[] = { "comm", func_comm }, { "console", func_console }, /* ReactOS */ - //{ "debugger", func_debugger }, + { "debugger", func_debugger }, { "directory", func_directory }, { "drive", func_drive }, { "environ", func_environ }, @@ -56,7 +57,7 @@ const struct test winetest_testlist[] = { "file", func_file }, { "format_msg", func_format_msg }, /* ReactOS */ - //{ "generated", func_generated }, + { "generated", func_generated }, { "heap", func_heap }, { "loader", func_loader }, { "locale", func_locale }, @@ -64,6 +65,7 @@ const struct test winetest_testlist[] = { "module", func_module }, { "path", func_path }, { "pipe", func_pipe }, + { "power", func_power }, { "process", func_process }, { "profile", func_profile }, { "resource", func_resource }, diff --git a/modules/rostests/winetests/kernel32/thread.c b/modules/rostests/winetests/kernel32/thread.c index 85a86581de5..4cdf31329b9 100644 --- a/modules/rostests/winetests/kernel32/thread.c +++ b/modules/rostests/winetests/kernel32/thread.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include /* the tests intentionally pass invalid pointers and need an exception handler */ #define WINE_NO_INLINE_STRING @@ -73,22 +75,18 @@ #define ARCH "none" #endif +static void (WINAPI *pGetCurrentThreadStackLimits)(PULONG_PTR,PULONG_PTR); static BOOL (WINAPI *pGetThreadPriorityBoost)(HANDLE,PBOOL); static HANDLE (WINAPI *pOpenThread)(DWORD,BOOL,DWORD); static BOOL (WINAPI *pQueueUserWorkItem)(LPTHREAD_START_ROUTINE,PVOID,ULONG); -static DWORD (WINAPI *pSetThreadIdealProcessor)(HANDLE,DWORD); static BOOL (WINAPI *pSetThreadPriorityBoost)(HANDLE,BOOL); +static BOOL (WINAPI *pSetThreadStackGuarantee)(ULONG*); static BOOL (WINAPI *pRegisterWaitForSingleObject)(PHANDLE,HANDLE,WAITORTIMERCALLBACK,PVOID,ULONG,ULONG); static BOOL (WINAPI *pUnregisterWait)(HANDLE); static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL); static BOOL (WINAPI *pSetThreadErrorMode)(DWORD,PDWORD); static DWORD (WINAPI *pGetThreadErrorMode)(void); static DWORD (WINAPI *pRtlGetThreadErrorMode)(void); -static BOOL (WINAPI *pActivateActCtx)(HANDLE,ULONG_PTR*); -static HANDLE (WINAPI *pCreateActCtxW)(PCACTCTXW); -static BOOL (WINAPI *pDeactivateActCtx)(DWORD,ULONG_PTR); -static BOOL (WINAPI *pGetCurrentActCtx)(HANDLE *); -static void (WINAPI *pReleaseActCtx)(HANDLE); static PTP_POOL (WINAPI *pCreateThreadpool)(PVOID); static void (WINAPI *pCloseThreadpool)(PTP_POOL); static PTP_WORK (WINAPI *pCreateThreadpoolWork)(PTP_WORK_CALLBACK,PVOID,PTP_CALLBACK_ENVIRON); @@ -99,7 +97,10 @@ static NTSTATUS (WINAPI *pNtQueryInformationThread)(HANDLE,THREADINFOCLASS,PVOID static BOOL (WINAPI *pGetThreadGroupAffinity)(HANDLE,GROUP_AFFINITY*); static BOOL (WINAPI *pSetThreadGroupAffinity)(HANDLE,const GROUP_AFFINITY*,GROUP_AFFINITY*); static NTSTATUS (WINAPI *pNtSetInformationThread)(HANDLE,THREADINFOCLASS,LPCVOID,ULONG); -static NTSTATUS (WINAPI *pNtSetLdtEntries)(ULONG,ULONG,ULONG,ULONG,ULONG,ULONG); +static HRESULT (WINAPI *pSetThreadDescription)(HANDLE,const WCHAR *); +static HRESULT (WINAPI *pGetThreadDescription)(HANDLE,WCHAR **); +static PVOID (WINAPI *pRtlAddVectoredExceptionHandler)(ULONG,PVECTORED_EXCEPTION_HANDLER); +static ULONG (WINAPI *pRtlRemoveVectoredExceptionHandler)(PVOID); static HANDLE create_target_process(const char *arg) { @@ -113,9 +114,9 @@ static HANDLE create_target_process(const char *arg) winetest_get_mainargs( &argv ); sprintf(cmdline, "%s %s %s", argv[0], argv[1], arg); ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); - ok(ret, "error: %u\n", GetLastError()); + ok(ret, "error: %lu\n", GetLastError()); ret = CloseHandle(pi.hThread); - ok(ret, "error %u\n", GetLastError()); + ok(ret, "error %lu\n", GetLastError()); return pi.hProcess; } @@ -156,7 +157,7 @@ static BOOL sync_threads_and_run_one(DWORD sync_id, DWORD my_id) else { DWORD ret = WaitForSingleObject(start_event, 10000); - ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed %x\n",ret); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed %lx\n",ret); } return sync_id == my_id; } @@ -305,8 +306,8 @@ static DWORD WINAPI thread_actctx_func(void *p) BOOL ret; cur = (void*)0xdeadbeef; - ret = pGetCurrentActCtx(&cur); - ok(ret, "thread GetCurrentActCtx failed, %u\n", GetLastError()); + ret = GetCurrentActCtx(&cur); + ok(ret, "thread GetCurrentActCtx failed, %lu\n", GetLastError()); ok(cur == param->handle, "got %p, expected %p\n", cur, param->handle); param->thread_context = cur; @@ -343,13 +344,13 @@ static VOID test_CreateRemoteThread(void) skip("child process wasn't mapped at same address, so can't do CreateRemoteThread tests.\n"); return; } - ok(ret == WAIT_OBJECT_0 || broken(ret == WAIT_OBJECT_0+1 /* nt4,w2k */), "WaitForAllObjects 2 events %d\n", ret); + ok(ret == WAIT_OBJECT_0 || broken(ret == WAIT_OBJECT_0+1 /* nt4,w2k */), "WaitForAllObjects 2 events %ld\n", ret); hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); - ok(hEvent != NULL, "Can't create event, err=%u\n", GetLastError()); + ok(hEvent != NULL, "Can't create event, err=%lu\n", GetLastError()); ret = DuplicateHandle(GetCurrentProcess(), hEvent, hProcess, &hRemoteEvent, 0, FALSE, DUPLICATE_SAME_ACCESS); - ok(ret != 0, "DuplicateHandle failed, err=%u\n", GetLastError()); + ok(ret != 0, "DuplicateHandle failed, err=%lu\n", GetLastError()); /* create suspended remote thread with entry point SetEvent() */ SetLastError(0xdeadbeef); @@ -360,51 +361,51 @@ static VOID test_CreateRemoteThread(void) win_skip("CreateRemoteThread is not implemented\n"); goto cleanup; } - ok(hThread != NULL, "CreateRemoteThread failed, err=%u\n", GetLastError()); + ok(hThread != NULL, "CreateRemoteThread failed, err=%lu\n", GetLastError()); ok(tid != 0, "null tid\n"); ret = SuspendThread(hThread); - ok(ret == 1, "ret=%u, err=%u\n", ret, GetLastError()); + ok(ret == 1, "ret=%lu, err=%lu\n", ret, GetLastError()); ret = ResumeThread(hThread); - ok(ret == 2, "ret=%u, err=%u\n", ret, GetLastError()); + ok(ret == 2, "ret=%lu, err=%lu\n", ret, GetLastError()); /* thread still suspended, so wait times out */ ret = WaitForSingleObject(hEvent, 1000); - ok(ret == WAIT_TIMEOUT, "wait did not time out, ret=%u\n", ret); + ok(ret == WAIT_TIMEOUT, "wait did not time out, ret=%lu\n", ret); ret = ResumeThread(hThread); - ok(ret == 1, "ret=%u, err=%u\n", ret, GetLastError()); + ok(ret == 1, "ret=%lu, err=%lu\n", ret, GetLastError()); /* wait that doesn't time out */ ret = WaitForSingleObject(hEvent, 1000); - ok(ret == WAIT_OBJECT_0, "object not signaled, ret=%u\n", ret); + ok(ret == WAIT_OBJECT_0, "object not signaled, ret=%lu\n", ret); /* wait for thread end */ ret = WaitForSingleObject(hThread, 1000); - ok(ret == WAIT_OBJECT_0, "waiting for thread failed, ret=%u\n", ret); + ok(ret == WAIT_OBJECT_0, "waiting for thread failed, ret=%lu\n", ret); CloseHandle(hThread); /* create and wait for remote thread with entry point CloseHandle() */ hThread = CreateRemoteThread(hProcess, NULL, 0, threadFunc_CloseHandle, hRemoteEvent, 0, &tid); - ok(hThread != NULL, "CreateRemoteThread failed, err=%u\n", GetLastError()); + ok(hThread != NULL, "CreateRemoteThread failed, err=%lu\n", GetLastError()); ret = WaitForSingleObject(hThread, 1000); - ok(ret == WAIT_OBJECT_0, "waiting for thread failed, ret=%u\n", ret); + ok(ret == WAIT_OBJECT_0, "waiting for thread failed, ret=%lu\n", ret); CloseHandle(hThread); /* create remote thread with entry point SetEvent() */ hThread = CreateRemoteThread(hProcess, NULL, 0, threadFunc_SetEvent, hRemoteEvent, 0, &tid); - ok(hThread != NULL, "CreateRemoteThread failed, err=%u\n", GetLastError()); + ok(hThread != NULL, "CreateRemoteThread failed, err=%lu\n", GetLastError()); /* closed handle, so wait times out */ ret = WaitForSingleObject(hEvent, 1000); - ok(ret == WAIT_TIMEOUT, "wait did not time out, ret=%u\n", ret); + ok(ret == WAIT_TIMEOUT, "wait did not time out, ret=%lu\n", ret); /* check that remote SetEvent() failed */ ret = GetExitCodeThread(hThread, &exitcode); - ok(ret != 0, "GetExitCodeThread failed, err=%u\n", GetLastError()); + ok(ret != 0, "GetExitCodeThread failed, err=%lu\n", GetLastError()); if (ret) ok(exitcode == 0, "SetEvent succeeded, expected to fail\n"); CloseHandle(hThread); @@ -483,31 +484,31 @@ static VOID test_CreateThread_basic(void) SetLastError(0xCAFEF00D); bRet = TlsFree(tlsIndex); - ok(bRet, "TlsFree failed: %08x\n", GetLastError()); + ok(bRet, "TlsFree failed: %08lx\n", GetLastError()); ok(GetLastError()==0xCAFEF00D, - "GetLastError: expected 0xCAFEF00D, got %08x\n", GetLastError()); + "GetLastError: expected 0xCAFEF00D, got %08lx\n", GetLastError()); /* Test freeing an already freed TLS index */ SetLastError(0xCAFEF00D); ok(TlsFree(tlsIndex)==0,"TlsFree succeeded\n"); ok(GetLastError()==ERROR_INVALID_PARAMETER, - "GetLastError: expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + "GetLastError: expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError()); /* Test how passing NULL as a pointer to threadid works */ SetLastError(0xFACEaBAD); 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); + ok(GLE==0xFACEaBAD, "CreateThread set last error to %ld, expected 4207848365\n", GLE); ret = WaitForSingleObject(thread[0],100); ok(ret==WAIT_OBJECT_0, "threadFunc2 did not exit during 100 ms\n"); ret = GetExitCodeThread(thread[0],&exitCode); - ok(ret!=0, "GetExitCodeThread returned %d (expected nonzero)\n", ret); - ok(exitCode==99, "threadFunc2 exited with code: %d (expected 99)\n", exitCode); + ok(ret!=0, "GetExitCodeThread returned %ld (expected nonzero)\n", ret); + ok(exitCode==99, "threadFunc2 exited with code: %ld (expected 99)\n", exitCode); ok(CloseHandle(thread[0])!=0,"Error closing thread handle\n"); } else { /* 9x */ - ok(GLE==ERROR_INVALID_PARAMETER, "CreateThread set last error to %d, expected 87\n", GLE); + ok(GLE==ERROR_INVALID_PARAMETER, "CreateThread set last error to %ld, expected 87\n", GLE); } } @@ -540,12 +541,12 @@ static VOID test_CreateThread_suspended(void) } suspend_count = SuspendThread(thread); - ok(suspend_count == -1, "SuspendThread returned %d, expected -1\n", suspend_count); + ok(suspend_count == -1, "SuspendThread returned %ld, 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); + "ResumeThread returned %ld, expected 0\n", suspend_count); ok(CloseHandle(thread)!=0,"CloseHandle failed\n"); } @@ -598,8 +599,8 @@ static VOID test_SuspendThread(void) } /* Trying to suspend a terminated thread should fail */ error=SuspendThread(thread); - ok(error==~0U, "wrong return code: %d\n", error); - ok(GetLastError()==ERROR_ACCESS_DENIED || GetLastError()==ERROR_NO_MORE_ITEMS, "unexpected error code: %d\n", GetLastError()); + ok(error==~0U, "wrong return code: %ld\n", error); + ok(GetLastError()==ERROR_ACCESS_DENIED || GetLastError()==ERROR_NO_MORE_ITEMS, "unexpected error code: %ld\n", GetLastError()); ok(CloseHandle(thread)!=0,"CloseHandle Failed\n"); } @@ -730,7 +731,7 @@ static VOID test_thread_priority(void) ok(rc == FALSE, "SetThreadPriority passed with a bad argument\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_INVALID_PRIORITY /* Win9x */, - "SetThreadPriority error %d, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n", + "SetThreadPriority error %ld, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n", GetLastError()); ok(GetThreadPriority(curthread)==min_priority, "GetThreadPriority didn't return min_priority\n"); @@ -742,7 +743,7 @@ static VOID test_thread_priority(void) ok(rc == FALSE, "SetThreadPriority passed with a bad argument\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_INVALID_PRIORITY /* Win9x */, - "SetThreadPriority error %d, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n", + "SetThreadPriority error %ld, expected ERROR_INVALID_PARAMETER or ERROR_INVALID_PRIORITY\n", GetLastError()); ok(GetThreadPriority(curthread)==max_priority, "GetThreadPriority didn't return max_priority\n"); @@ -759,7 +760,7 @@ static VOID test_thread_priority(void) return; } - ok(rc!=0,"error=%d\n",GetLastError()); + ok(rc!=0,"error=%ld\n",GetLastError()); if (pOpenThread) { /* check that access control is obeyed */ @@ -775,18 +776,18 @@ static VOID test_thread_priority(void) } rc = pSetThreadPriorityBoost(curthread,1); - ok( rc != 0, "error=%d\n",GetLastError()); + ok( rc != 0, "error=%ld\n",GetLastError()); todo_wine { rc=pGetThreadPriorityBoost(curthread,&disabled); ok(rc!=0 && disabled==1, - "rc=%d error=%d disabled=%d\n",rc,GetLastError(),disabled); + "rc=%d error=%ld disabled=%d\n",rc,GetLastError(),disabled); } rc = pSetThreadPriorityBoost(curthread,0); - ok( rc != 0, "error=%d\n",GetLastError()); + ok( rc != 0, "error=%ld\n",GetLastError()); rc=pGetThreadPriorityBoost(curthread,&disabled); ok(rc!=0 && disabled==0, - "rc=%d error=%d disabled=%d\n",rc,GetLastError(),disabled); + "rc=%d error=%ld disabled=%d\n",rc,GetLastError(),disabled); } /* check the GetThreadTimes function */ @@ -852,11 +853,21 @@ static VOID test_thread_processor(void) HANDLE curthread,curproc; DWORD_PTR processMask,systemMask,retMask; SYSTEM_INFO sysInfo; - int error=0; - BOOL is_wow64; + BOOL is_wow64, old_wow64 = FALSE; + DWORD ret; if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE; + if (is_wow64) + { + TEB64 *teb64 = ULongToPtr(NtCurrentTeb()->GdiBatchCount); + if (teb64) + { + PEB64 *peb64 = ULongToPtr(teb64->Peb); + old_wow64 = !peb64->LdrData; + } + } + sysInfo.dwNumberOfProcessors=0; GetSystemInfo(&sysInfo); ok(sysInfo.dwNumberOfProcessors>0, @@ -883,7 +894,7 @@ static VOID test_thread_processor(void) /* Show that the "all processors" flag is handled in ntdll */ DWORD_PTR mask = ~0u; NTSTATUS status = pNtSetInformationThread(curthread, ThreadAffinityMask, &mask, sizeof(mask)); - ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS in NtSetInformationThread, got %x\n", status); + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS in NtSetInformationThread, got %lx\n", status); } if (retMask == processMask && sizeof(ULONG_PTR) > sizeof(ULONG)) @@ -894,43 +905,38 @@ static VOID test_thread_processor(void) retMask = SetThreadAffinityMask(curthread,~(ULONG_PTR)0 >> 3); ok(retMask == processMask, "SetThreadAffinityMask failed\n"); } -/* NOTE: This only works on WinNT/2000/XP) */ - if (pSetThreadIdealProcessor) + + SetLastError(0xdeadbeef); + ret = SetThreadIdealProcessor(GetCurrentThread(), 0); + ok(ret != ~0u, "Unexpected return value %lu.\n", ret); + + if (is_wow64) { SetLastError(0xdeadbeef); - error=pSetThreadIdealProcessor(curthread,0); - if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) - { - ok(error!=-1, "SetThreadIdealProcessor failed\n"); + ret = SetThreadIdealProcessor(GetCurrentThread(), MAXIMUM_PROCESSORS + 1); + todo_wine_if(old_wow64) + ok(ret != ~0u, "Unexpected return value %lu.\n", ret); - if (is_wow64) - { - SetLastError(0xdeadbeef); - error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1); - todo_wine - ok(error!=-1, "SetThreadIdealProcessor failed for %u on Wow64\n", MAXIMUM_PROCESSORS+1); - - SetLastError(0xdeadbeef); - error=pSetThreadIdealProcessor(curthread,65); - ok(error==-1, "SetThreadIdealProcessor succeeded with an illegal processor #\n"); - ok(GetLastError()==ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); - } - else - { - SetLastError(0xdeadbeef); - error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1); - ok(error==-1, "SetThreadIdealProcessor succeeded with an illegal processor #\n"); - ok(GetLastError()==ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); - } - - error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS); - ok(error!=-1, "SetThreadIdealProcessor failed\n"); - } - else - win_skip("SetThreadIdealProcessor is not implemented\n"); + SetLastError(0xdeadbeef); + ret = SetThreadIdealProcessor(GetCurrentThread(), 65); + ok(ret == ~0u, "Unexpected return value %lu.\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Unexpected error %ld.\n", GetLastError()); } + else + { + SetLastError(0xdeadbeef); + ret = SetThreadIdealProcessor(GetCurrentThread(), MAXIMUM_PROCESSORS+1); +#if defined(__REACTOS__) && defined(_WIN64) + ok(ret == ~0u || broken(ret == 0) /* x86_64 */, "Unexpected return value %lu.\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef) /* x86_64 */, "Unexpected error %ld.\n", GetLastError()); +#else + ok(ret == ~0u, "Unexpected return value %lu.\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Unexpected error %ld.\n", GetLastError()); +#endif + } + + ret = SetThreadIdealProcessor(GetCurrentThread(), MAXIMUM_PROCESSORS); + ok(ret != ~0u, "Unexpected return value %lu.\n", ret); if (pGetThreadGroupAffinity && pSetThreadGroupAffinity) { @@ -943,53 +949,134 @@ static VOID test_thread_processor(void) SetLastError(0xdeadbeef); ok(!pGetThreadGroupAffinity(curthread, NULL), "GetThreadGroupAffinity succeeded\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == ERROR_NOACCESS), /* Win 7 and 8 */ - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); ok(affinity.Group == 0, "Expected group 0 got %u\n", affinity.Group); memset(&affinity_new, 0, sizeof(affinity_new)); affinity_new.Group = 0; affinity_new.Mask = affinity.Mask; ok(pSetThreadGroupAffinity(curthread, &affinity_new, &affinity), "SetThreadGroupAffinity failed\n"); - ok(affinity_new.Mask == affinity.Mask, "Expected old affinity mask %lx, got %lx\n", + ok(affinity_new.Mask == affinity.Mask, "Expected old affinity mask %Ix, got %Ix\n", affinity_new.Mask, affinity.Mask); /* show that the "all processors" flag is not supported for SetThreadGroupAffinity */ - affinity_new.Group = 0; - affinity_new.Mask = ~0u; - SetLastError(0xdeadbeef); - ok(!pSetThreadGroupAffinity(curthread, &affinity_new, NULL), "SetThreadGroupAffinity succeeded\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + if (sysInfo.dwNumberOfProcessors < 8 * sizeof(DWORD_PTR)) + { + affinity_new.Group = 0; + affinity_new.Mask = ~(DWORD_PTR)0; + SetLastError(0xdeadbeef); + ok(!pSetThreadGroupAffinity(curthread, &affinity_new, NULL), "SetThreadGroupAffinity succeeded\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); + } affinity_new.Group = 1; /* assumes that you have less than 64 logical processors */ affinity_new.Mask = 0x1; SetLastError(0xdeadbeef); ok(!pSetThreadGroupAffinity(curthread, &affinity_new, NULL), "SetThreadGroupAffinity succeeded\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ok(!pSetThreadGroupAffinity(curthread, NULL, NULL), "SetThreadGroupAffinity succeeded\n"); ok(GetLastError() == ERROR_NOACCESS, - "Expected ERROR_NOACCESS, got %d\n", GetLastError()); + "Expected ERROR_NOACCESS, got %ld\n", GetLastError()); /* show that the access violation was detected in ntdll */ status = pNtSetInformationThread(curthread, ThreadGroupInformation, NULL, sizeof(affinity_new)); ok(status == STATUS_ACCESS_VIOLATION, - "Expected STATUS_ACCESS_VIOLATION, got %08x\n", status); + "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", status); /* restore original mask */ affinity_new.Group = 0; affinity_new.Mask = affinity.Mask; SetLastError(0xdeadbeef); ok(pSetThreadGroupAffinity(curthread, &affinity_new, &affinity), "SetThreadGroupAffinity failed\n"); - ok(affinity_new.Mask == affinity.Mask, "Expected old affinity mask %lx, got %lx\n", + ok(affinity_new.Mask == affinity.Mask, "Expected old affinity mask %Ix, got %Ix\n", affinity_new.Mask, affinity.Mask); } else win_skip("Get/SetThreadGroupAffinity not available\n"); } +static VOID test_GetCurrentThreadStackLimits(void) +{ + ULONG_PTR low = 0, high = 0; + + if (!pGetCurrentThreadStackLimits) + { + win_skip("GetCurrentThreadStackLimits not available.\n"); + return; + } + + if (0) + { + /* crashes on native */ + pGetCurrentThreadStackLimits(NULL, NULL); + pGetCurrentThreadStackLimits(NULL, &high); + pGetCurrentThreadStackLimits(&low, NULL); + } + + pGetCurrentThreadStackLimits(&low, &high); + ok(low == (ULONG_PTR)NtCurrentTeb()->DeallocationStack, "expected %p, got %Ix\n", NtCurrentTeb()->DeallocationStack, low); + ok(high == (ULONG_PTR)NtCurrentTeb()->Tib.StackBase, "expected %p, got %Ix\n", NtCurrentTeb()->Tib.StackBase, high); +} + +static void test_SetThreadStackGuarantee(void) +{ + ULONG size; + BOOL ret; + + if (!pSetThreadStackGuarantee) + { + win_skip("SetThreadStackGuarantee not available.\n"); + return; + } + size = 0; + ret = pSetThreadStackGuarantee( &size ); + ok( ret, "failed err %lu\n", GetLastError() ); + ok( size == 0, "wrong size %lu\n", size ); + ok( NtCurrentTeb()->GuaranteedStackBytes == 0, "wrong teb %lu\n", + NtCurrentTeb()->GuaranteedStackBytes ); + size = 0xdeadbef; + ret = pSetThreadStackGuarantee( &size ); + ok( !ret, "succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_INVALID_ADDRESS, + "wrong error %lu\n", GetLastError()); + ok( size == 0, "wrong size %lu\n", size ); + ok( NtCurrentTeb()->GuaranteedStackBytes == 0, "wrong teb %lu\n", + NtCurrentTeb()->GuaranteedStackBytes ); + size = 200; + ret = pSetThreadStackGuarantee( &size ); + ok( ret, "failed err %lu\n", GetLastError() ); + ok( size == 0, "wrong size %lu\n", size ); + ok( NtCurrentTeb()->GuaranteedStackBytes == 4096 * sizeof(void *) / 4, "wrong teb %lu\n", + NtCurrentTeb()->GuaranteedStackBytes ); + size = 5000; + ret = pSetThreadStackGuarantee( &size ); + ok( ret, "failed err %lu\n", GetLastError() ); + ok( size == 4096 * sizeof(void *) / 4, "wrong size %lu\n", size ); + ok( NtCurrentTeb()->GuaranteedStackBytes == 8192, "wrong teb %lu\n", + NtCurrentTeb()->GuaranteedStackBytes ); + size = 2000; + ret = pSetThreadStackGuarantee( &size ); + ok( ret, "failed err %lu\n", GetLastError() ); + ok( size == 8192, "wrong size %lu\n", size ); + ok( NtCurrentTeb()->GuaranteedStackBytes == 8192, "wrong teb %lu\n", + NtCurrentTeb()->GuaranteedStackBytes ); + size = 10000; + ret = pSetThreadStackGuarantee( &size ); + ok( ret, "failed err %lu\n", GetLastError() ); + ok( size == 8192, "wrong size %lu\n", size ); + ok( NtCurrentTeb()->GuaranteedStackBytes == 12288, "wrong teb %lu\n", + NtCurrentTeb()->GuaranteedStackBytes ); + ret = pSetThreadStackGuarantee( &size ); + ok( ret, "failed err %lu\n", GetLastError() ); + ok( size == 12288, "wrong size %lu\n", size ); + ok( NtCurrentTeb()->GuaranteedStackBytes == 12288, "wrong teb %lu\n", + NtCurrentTeb()->GuaranteedStackBytes ); +} + static VOID test_GetThreadExitCode(void) { DWORD exitCode, threadid; @@ -997,17 +1084,17 @@ static VOID test_GetThreadExitCode(void) HANDLE thread; ret = GetExitCodeThread((HANDLE)0x2bad2bad,&exitCode); - ok(ret==0, "GetExitCodeThread returned non zero value: %d\n", ret); + ok(ret==0, "GetExitCodeThread returned non zero value: %ld\n", ret); GLE = GetLastError(); - ok(GLE==ERROR_INVALID_HANDLE, "GetLastError returned %d (expected 6)\n", GLE); + ok(GLE==ERROR_INVALID_HANDLE, "GetLastError returned %ld (expected 6)\n", GLE); thread = CreateThread(NULL,0,threadFunc2,NULL,0,&threadid); ret = WaitForSingleObject(thread,100); ok(ret==WAIT_OBJECT_0, "threadFunc2 did not exit during 100 ms\n"); ret = GetExitCodeThread(thread,&exitCode); ok(ret==exitCode || ret==1, - "GetExitCodeThread returned %d (expected 1 or %d)\n", ret, exitCode); - ok(exitCode==99, "threadFunc2 exited with code %d (expected 99)\n", exitCode); + "GetExitCodeThread returned %ld (expected 1 or %ld)\n", ret, exitCode); + ok(exitCode==99, "threadFunc2 exited with code %ld (expected 99)\n", exitCode); ok(CloseHandle(thread)!=0,"Error closing thread handle\n"); } @@ -1042,7 +1129,7 @@ static void test_SetThreadContext(void) SetLastError(0xdeadbeef); event = CreateEventW( NULL, TRUE, FALSE, NULL ); thread = CreateThread( NULL, 0, threadFunc6, (void *)2, 0, &threadid ); - ok( thread != NULL, "CreateThread failed : (%d)\n", GetLastError() ); + ok( thread != NULL, "CreateThread failed : (%ld)\n", GetLastError() ); if (!thread) { trace("Thread creation failed, skipping rest of test\n"); @@ -1055,7 +1142,7 @@ static void test_SetThreadContext(void) ctx.ContextFlags = CONTEXT_FULL; SetLastError(0xdeadbeef); ret = GetThreadContext( thread, &ctx ); - ok( ret, "GetThreadContext failed : (%u)\n", GetLastError() ); + ok( ret, "GetThreadContext failed : (%lu)\n", GetLastError() ); if (ret) { @@ -1067,12 +1154,12 @@ static void test_SetThreadContext(void) ctx.Eip = (DWORD)set_test_val; SetLastError(0xdeadbeef); ret = SetThreadContext( thread, &ctx ); - ok( ret, "SetThreadContext failed : (%d)\n", GetLastError() ); + ok( ret, "SetThreadContext failed : (%ld)\n", GetLastError() ); } SetLastError(0xdeadbeef); prevcount = ResumeThread( thread ); - ok ( prevcount == 1, "Previous suspend count (%d) instead of 1, last error : (%d)\n", + ok ( prevcount == 1, "Previous suspend count (%ld) instead of 1, last error : (%ld)\n", prevcount, GetLastError() ); WaitForSingleObject( thread, INFINITE ); @@ -1084,7 +1171,7 @@ static void test_SetThreadContext(void) ok( (!ret && ((GetLastError() == ERROR_GEN_FAILURE) || (GetLastError() == ERROR_ACCESS_DENIED))) || (!ret && broken(GetLastError() == ERROR_INVALID_HANDLE)) || /* win2k */ broken(ret), /* 32bit application on NT 5.x 64bit */ - "got %d with %u (expected FALSE with ERROR_GEN_FAILURE or ERROR_ACCESS_DENIED)\n", + "got %d with %lu (expected FALSE with ERROR_GEN_FAILURE or ERROR_ACCESS_DENIED)\n", ret, GetLastError() ); SetLastError(0xdeadbeef); @@ -1092,12 +1179,41 @@ static void test_SetThreadContext(void) ok( (!ret && ((GetLastError() == ERROR_GEN_FAILURE) || (GetLastError() == ERROR_ACCESS_DENIED))) || (!ret && broken(GetLastError() == ERROR_INVALID_HANDLE)) || /* win2k */ broken(ret), /* 32bit application on NT 5.x 64bit */ - "got %d with %u (expected FALSE with ERROR_GEN_FAILURE or ERROR_ACCESS_DENIED)\n", + "got %d with %lu (expected FALSE with ERROR_GEN_FAILURE or ERROR_ACCESS_DENIED)\n", ret, GetLastError() ); CloseHandle( thread ); } +static DWORD WINAPI test_stack( void *arg ) +{ + DWORD *stack = (DWORD *)(((DWORD)&arg & ~0xfff) + 0x1000); + + ok( stack == NtCurrentTeb()->Tib.StackBase, "wrong stack %p/%p\n", + stack, NtCurrentTeb()->Tib.StackBase ); + ok( !stack[-1], "wrong data %p = %08lx\n", stack - 1, stack[-1] ); + return 0; +} + +static void test_GetThreadContext(void) +{ + CONTEXT ctx; + BOOL ret; + HANDLE thread; + + memset(&ctx, 0xcc, sizeof(ctx)); + ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; + ret = GetThreadContext(GetCurrentThread(), &ctx); + ok(ret, "GetThreadContext failed: %lu\n", GetLastError()); + ok(ctx.ContextFlags == CONTEXT_DEBUG_REGISTERS, "ContextFlags = %lx\n", ctx.ContextFlags); + ok(!ctx.Dr0, "Dr0 = %lx\n", ctx.Dr0); + ok(!ctx.Dr1, "Dr0 = %lx\n", ctx.Dr0); + + thread = CreateThread( NULL, 0, test_stack, (void *)0x1234, 0, NULL ); + WaitForSingleObject( thread, 1000 ); + CloseHandle( thread ); +} + static void test_GetThreadSelectorEntry(void) { LDT_ENTRY entry; @@ -1109,26 +1225,41 @@ static void test_GetThreadSelectorEntry(void) memset(&ctx, 0x11, sizeof(ctx)); ctx.ContextFlags = CONTEXT_SEGMENTS | CONTEXT_CONTROL; ret = GetThreadContext(GetCurrentThread(), &ctx); - ok(ret, "GetThreadContext error %u\n", GetLastError()); - ok(!HIWORD(ctx.SegCs), "expected HIWORD(SegCs) == 0, got %u\n", ctx.SegCs); - ok(!HIWORD(ctx.SegDs), "expected HIWORD(SegDs) == 0, got %u\n", ctx.SegDs); - ok(!HIWORD(ctx.SegFs), "expected HIWORD(SegFs) == 0, got %u\n", ctx.SegFs); + ok(ret, "GetThreadContext error %lu\n", GetLastError()); + ok(!HIWORD(ctx.SegCs), "expected HIWORD(SegCs) == 0, got %lu\n", ctx.SegCs); + ok(!HIWORD(ctx.SegDs), "expected HIWORD(SegDs) == 0, got %lu\n", ctx.SegDs); + ok(!HIWORD(ctx.SegFs), "expected HIWORD(SegFs) == 0, got %lu\n", ctx.SegFs); ret = GetThreadSelectorEntry(GetCurrentThread(), ctx.SegCs, &entry); - ok(ret, "GetThreadSelectorEntry(SegCs) error %u\n", GetLastError()); + ok(ret, "GetThreadSelectorEntry(SegCs) error %lu\n", GetLastError()); ret = GetThreadSelectorEntry(GetCurrentThread(), ctx.SegDs, &entry); - ok(ret, "GetThreadSelectorEntry(SegDs) error %u\n", GetLastError()); + ok(ret, "GetThreadSelectorEntry(SegDs) error %lu\n", GetLastError()); + ret = GetThreadSelectorEntry(GetCurrentThread(), ctx.SegDs & ~3, &entry); + ok(ret, "GetThreadSelectorEntry(SegDs) error %lu\n", GetLastError()); + ret = GetThreadSelectorEntry(GetCurrentThread(), 0, &entry); + ok(ret, "GetThreadSelectorEntry(SegDs) error %lu\n", GetLastError()); + ret = GetThreadSelectorEntry(GetCurrentThread(), 3, &entry); + ok(ret, "GetThreadSelectorEntry(SegDs) error %lu\n", GetLastError()); + SetLastError( 0xdeadbeef ); + ret = GetThreadSelectorEntry(GetCurrentThread(), 0xdeadbeef, &entry); + ok(!ret, "GetThreadSelectorEntry(invalid) succeeded\n"); + ok( GetLastError() == ERROR_GEN_FAILURE + || GetLastError() == ERROR_INVALID_THREAD_ID /* 32-bit */, "wrong error %lu\n", GetLastError() ); + ret = GetThreadSelectorEntry(GetCurrentThread(), ctx.SegDs + 0x100, &entry); + ok(!ret, "GetThreadSelectorEntry(invalid) succeeded\n"); + ok( GetLastError() == ERROR_GEN_FAILURE + || GetLastError() == ERROR_NOACCESS /* 32-bit */, "wrong error %lu\n", GetLastError() ); memset(&entry, 0x11, sizeof(entry)); ret = GetThreadSelectorEntry(GetCurrentThread(), ctx.SegFs, &entry); - ok(ret, "GetThreadSelectorEntry(SegFs) error %u\n", GetLastError()); + ok(ret, "GetThreadSelectorEntry(SegFs) error %lu\n", GetLastError()); entry.HighWord.Bits.Type &= ~1; /* ignore accessed bit */ base = (void *)((entry.HighWord.Bits.BaseHi << 24) | (entry.HighWord.Bits.BaseMid << 16) | entry.BaseLow); limit = (entry.HighWord.Bits.LimitHi << 16) | entry.LimitLow; ok(base == NtCurrentTeb(), "expected %p, got %p\n", NtCurrentTeb(), base); - ok(limit == 0x0fff || limit == 0x4000, "expected 0x0fff or 0x4000, got %#x\n", limit); + ok(limit == 0x0fff || limit == 0x4000, "expected 0x0fff or 0x4000, got %#lx\n", limit); ok(entry.HighWord.Bits.Type == 0x12, "expected 0x12, got %#x\n", entry.HighWord.Bits.Type); ok(entry.HighWord.Bits.Dpl == 3, "expected 3, got %u\n", entry.HighWord.Bits.Dpl); ok(entry.HighWord.Bits.Pres == 1, "expected 1, got %u\n", entry.HighWord.Bits.Pres); @@ -1136,78 +1267,40 @@ static void test_GetThreadSelectorEntry(void) ok(entry.HighWord.Bits.Reserved_0 == 0, "expected 0, got %u\n", entry.HighWord.Bits.Reserved_0); ok(entry.HighWord.Bits.Default_Big == 1, "expected 1, got %u\n", entry.HighWord.Bits.Default_Big); ok(entry.HighWord.Bits.Granularity == 0, "expected 0, got %u\n", entry.HighWord.Bits.Granularity); -} -static void test_NtSetLdtEntries(void) -{ - THREAD_DESCRIPTOR_INFORMATION tdi; - LDT_ENTRY ds_entry; - CONTEXT ctx; - DWORD ret; - union - { - LDT_ENTRY entry; - DWORD dw[2]; - } sel; + memset(&entry, 0x11, sizeof(entry)); + ret = GetThreadSelectorEntry(GetCurrentThread(), ctx.SegCs, &entry); + ok(ret, "GetThreadSelectorEntry(SegDs) error %lu\n", GetLastError()); + entry.HighWord.Bits.Type &= ~1; /* ignore accessed bit */ + base = (void *)((entry.HighWord.Bits.BaseHi << 24) | (entry.HighWord.Bits.BaseMid << 16) | entry.BaseLow); + limit = (entry.HighWord.Bits.LimitHi << 16) | entry.LimitLow; - if (!pNtSetLdtEntries) - { - win_skip("NtSetLdtEntries is not available on this platform\n"); - return; - } + ok(base == 0, "got base %p\n", base); + ok(limit == ~0u >> 12, "got limit %#lx\n", limit); + ok(entry.HighWord.Bits.Type == 0x1a, "expected 0x12, got %#x\n", entry.HighWord.Bits.Type); + ok(entry.HighWord.Bits.Dpl == 3, "expected 3, got %u\n", entry.HighWord.Bits.Dpl); + ok(entry.HighWord.Bits.Pres == 1, "expected 1, got %u\n", entry.HighWord.Bits.Pres); + ok(entry.HighWord.Bits.Sys == 0, "expected 0, got %u\n", entry.HighWord.Bits.Sys); + ok(entry.HighWord.Bits.Reserved_0 == 0, "expected 0, got %u\n", entry.HighWord.Bits.Reserved_0); + ok(entry.HighWord.Bits.Default_Big == 1, "expected 1, got %u\n", entry.HighWord.Bits.Default_Big); + ok(entry.HighWord.Bits.Granularity == 1, "expected 1, got %u\n", entry.HighWord.Bits.Granularity); - if (pNtSetLdtEntries(0, 0, 0, 0, 0, 0) == STATUS_NOT_IMPLEMENTED) /* WoW64 */ - { - win_skip("NtSetLdtEntries is not implemented on this platform\n"); - return; - } + memset(&entry, 0x11, sizeof(entry)); + ret = GetThreadSelectorEntry(GetCurrentThread(), ctx.SegDs, &entry); + ok(ret, "GetThreadSelectorEntry(SegDs) error %lu\n", GetLastError()); + entry.HighWord.Bits.Type &= ~1; /* ignore accessed bit */ + base = (void *)((entry.HighWord.Bits.BaseHi << 24) | (entry.HighWord.Bits.BaseMid << 16) | entry.BaseLow); + limit = (entry.HighWord.Bits.LimitHi << 16) | entry.LimitLow; - ret = pNtSetLdtEntries(0, 0, 0, 0, 0, 0); - ok(!ret, "NtSetLdtEntries failed: %08x\n", ret); - - ctx.ContextFlags = CONTEXT_SEGMENTS; - ret = GetThreadContext(GetCurrentThread(), &ctx); - ok(ret, "GetThreadContext failed\n"); - - tdi.Selector = ctx.SegDs; - ret = pNtQueryInformationThread(GetCurrentThread(), ThreadDescriptorTableEntry, &tdi, sizeof(tdi), &ret); - ok(!ret, "NtQueryInformationThread failed: %08x\n", ret); - ds_entry = tdi.Entry; - - tdi.Selector = 0x000f; - ret = pNtQueryInformationThread(GetCurrentThread(), ThreadDescriptorTableEntry, &tdi, sizeof(tdi), &ret); - ok(ret == STATUS_ACCESS_VIOLATION, "got %08x\n", ret); - - tdi.Selector = 0x001f; - ret = pNtQueryInformationThread(GetCurrentThread(), ThreadDescriptorTableEntry, &tdi, sizeof(tdi), &ret); - ok(ret == STATUS_ACCESS_VIOLATION, "NtQueryInformationThread returned %08x\n", ret); - - ret = GetThreadSelectorEntry(GetCurrentThread(), 0x000f, &sel.entry); - ok(!ret, "GetThreadSelectorEntry should fail\n"); - - ret = GetThreadSelectorEntry(GetCurrentThread(), 0x001f, &sel.entry); - ok(!ret, "GetThreadSelectorEntry should fail\n"); - - memset(&sel.entry, 0x9a, sizeof(sel.entry)); - ret = GetThreadSelectorEntry(GetCurrentThread(), ctx.SegDs, &sel.entry); - ok(ret, "GetThreadSelectorEntry failed\n"); - ok(!memcmp(&ds_entry, &sel.entry, sizeof(ds_entry)), "entries do not match\n"); - - ret = pNtSetLdtEntries(0x000f, sel.dw[0], sel.dw[1], 0x001f, sel.dw[0], sel.dw[1]); - ok(!ret || broken(ret == STATUS_INVALID_LDT_DESCRIPTOR) /*XP*/, "NtSetLdtEntries failed: %08x\n", ret); - - if (!ret) - { - memset(&sel.entry, 0x9a, sizeof(sel.entry)); - ret = GetThreadSelectorEntry(GetCurrentThread(), 0x000f, &sel.entry); - ok(ret, "GetThreadSelectorEntry failed\n"); - ok(!memcmp(&ds_entry, &sel.entry, sizeof(ds_entry)), "entries do not match\n"); - - memset(&sel.entry, 0x9a, sizeof(sel.entry)); - ret = GetThreadSelectorEntry(GetCurrentThread(), 0x001f, &sel.entry); - ok(ret, "GetThreadSelectorEntry failed\n"); - ok(!memcmp(&ds_entry, &sel.entry, sizeof(ds_entry)), "entries do not match\n"); - } + ok(base == 0, "got base %p\n", base); + ok(limit == ~0u >> 12, "got limit %#lx\n", limit); + ok(entry.HighWord.Bits.Type == 0x12, "expected 0x12, got %#x\n", entry.HighWord.Bits.Type); + ok(entry.HighWord.Bits.Dpl == 3, "expected 3, got %u\n", entry.HighWord.Bits.Dpl); + ok(entry.HighWord.Bits.Pres == 1, "expected 1, got %u\n", entry.HighWord.Bits.Pres); + ok(entry.HighWord.Bits.Sys == 0, "expected 0, got %u\n", entry.HighWord.Bits.Sys); + ok(entry.HighWord.Bits.Reserved_0 == 0, "expected 0, got %u\n", entry.HighWord.Bits.Reserved_0); + ok(entry.HighWord.Bits.Default_Big == 1, "expected 1, got %u\n", entry.HighWord.Bits.Default_Big); + ok(entry.HighWord.Bits.Granularity == 1, "expected 1, got %u\n", entry.HighWord.Bits.Granularity); } #endif /* __i386__ */ @@ -1240,14 +1333,14 @@ static void test_QueueUserWorkItem(void) for (i = 0; i < 100; i++) { BOOL ret = pQueueUserWorkItem(work_function, (void *)i, WT_EXECUTEDEFAULT); - ok(ret, "QueueUserWorkItem failed with error %d\n", GetLastError()); + ok(ret, "QueueUserWorkItem failed with error %ld\n", GetLastError()); } wait_result = WaitForSingleObject(finish_event, 10000); after = GetTickCount(); - trace("100 QueueUserWorkItem calls took %dms\n", after - before); - ok(wait_result == WAIT_OBJECT_0, "wait failed with error 0x%x\n", wait_result); + trace("100 QueueUserWorkItem calls took %ldms\n", after - before); + ok(wait_result == WAIT_OBJECT_0, "wait failed with error 0x%lx\n", wait_result); ok(times_executed == 100, "didn't execute all of the work items\n"); } @@ -1259,6 +1352,15 @@ static void CALLBACK signaled_function(PVOID p, BOOLEAN TimerOrWaitFired) ok(!TimerOrWaitFired, "wait shouldn't have timed out\n"); } +static void CALLBACK wait_complete_function(PVOID p, BOOLEAN TimerOrWaitFired) +{ + HANDLE event = p; + DWORD res; + ok(!TimerOrWaitFired, "wait shouldn't have timed out\n"); + res = WaitForSingleObject(event, INFINITE); + ok(res == WAIT_OBJECT_0, "WaitForSingleObject returned %lx\n", res); +} + static void CALLBACK timeout_function(PVOID p, BOOLEAN TimerOrWaitFired) { HANDLE event = p; @@ -1266,12 +1368,51 @@ static void CALLBACK timeout_function(PVOID p, BOOLEAN TimerOrWaitFired) ok(TimerOrWaitFired, "wait should have timed out\n"); } +struct waitthread_test_param +{ + HANDLE trigger_event; + HANDLE wait_event; + HANDLE complete_event; +}; + +static void CALLBACK waitthread_test_function(PVOID p, BOOLEAN TimerOrWaitFired) +{ + struct waitthread_test_param *param = p; + DWORD ret; + + SetEvent(param->trigger_event); + ret = WaitForSingleObject(param->wait_event, 100); + ok(ret == WAIT_TIMEOUT, "wait should have timed out\n"); + SetEvent(param->complete_event); +} + +struct unregister_params +{ + HANDLE wait_handle; + HANDLE complete_event; +}; + +static void CALLBACK unregister_function(PVOID p, BOOLEAN TimerOrWaitFired) +{ + struct unregister_params *param = p; + HANDLE wait_handle = param->wait_handle; + BOOL ret; + ok(wait_handle != INVALID_HANDLE_VALUE, "invalid wait handle\n"); + ret = pUnregisterWait(param->wait_handle); + todo_wine ok(ret, "UnregisterWait failed with error %ld\n", GetLastError()); + SetEvent(param->complete_event); +} + static void test_RegisterWaitForSingleObject(void) { BOOL ret; - HANDLE wait_handle; + HANDLE wait_handle, wait_handle2; HANDLE handle; HANDLE complete_event; + HANDLE waitthread_trigger_event, waitthread_wait_event; + struct waitthread_test_param param; + struct unregister_params unregister_param; + DWORD i; if (!pRegisterWaitForSingleObject || !pUnregisterWait) { @@ -1285,42 +1426,122 @@ static void test_RegisterWaitForSingleObject(void) complete_event = CreateEventW(NULL, FALSE, FALSE, NULL); ret = pRegisterWaitForSingleObject(&wait_handle, handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE); - ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError()); + ok(ret, "RegisterWaitForSingleObject failed with error %ld\n", GetLastError()); WaitForSingleObject(complete_event, INFINITE); /* give worker thread chance to complete */ Sleep(100); ret = pUnregisterWait(wait_handle); - ok(ret, "UnregisterWait failed with error %d\n", GetLastError()); + ok(ret, "UnregisterWait failed with error %ld\n", GetLastError()); /* test cancel case */ ResetEvent(handle); ret = pRegisterWaitForSingleObject(&wait_handle, handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE); - ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError()); + ok(ret, "RegisterWaitForSingleObject failed with error %ld\n", GetLastError()); ret = pUnregisterWait(wait_handle); - ok(ret, "UnregisterWait failed with error %d\n", GetLastError()); + ok(ret, "UnregisterWait failed with error %ld\n", GetLastError()); + + /* test unregister while running */ + + SetEvent(handle); + ret = pRegisterWaitForSingleObject(&wait_handle, handle, wait_complete_function, complete_event, INFINITE, WT_EXECUTEONLYONCE); + ok(ret, "RegisterWaitForSingleObject failed with error %ld\n", GetLastError()); + + /* give worker thread chance to start */ + Sleep(50); + ret = pUnregisterWait(wait_handle); + ok(!ret, "UnregisterWait succeeded\n"); + ok(GetLastError() == ERROR_IO_PENDING, "UnregisterWait failed with error %ld\n", GetLastError()); + + /* give worker thread chance to complete */ + SetEvent(complete_event); + Sleep(50); /* test timeout case */ + ResetEvent(handle); + ret = pRegisterWaitForSingleObject(&wait_handle, handle, timeout_function, complete_event, 0, WT_EXECUTEONLYONCE); - ok(ret, "RegisterWaitForSingleObject failed with error %d\n", GetLastError()); + ok(ret, "RegisterWaitForSingleObject failed with error %ld\n", GetLastError()); WaitForSingleObject(complete_event, INFINITE); /* give worker thread chance to complete */ Sleep(100); ret = pUnregisterWait(wait_handle); - ok(ret, "UnregisterWait failed with error %d\n", GetLastError()); + ok(ret, "UnregisterWait failed with error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = pUnregisterWait(NULL); ok(!ret, "Expected UnregisterWait to fail\n"); ok(GetLastError() == ERROR_INVALID_HANDLE, - "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + "Expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError()); + + /* test WT_EXECUTEINWAITTHREAD */ + + SetEvent(handle); + ret = pRegisterWaitForSingleObject(&wait_handle, handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE | WT_EXECUTEINWAITTHREAD); + ok(ret, "RegisterWaitForSingleObject failed with error %ld\n", GetLastError()); + + WaitForSingleObject(complete_event, INFINITE); + /* give worker thread chance to complete */ + Sleep(100); + + ret = pUnregisterWait(wait_handle); + ok(ret, "UnregisterWait failed with error %ld\n", GetLastError()); + + /* the callback execution should be sequentially consistent with the wait handle return, + even if the event is already set */ + + for (i = 0; i < 100; ++i) + { + SetEvent(handle); + unregister_param.complete_event = complete_event; + unregister_param.wait_handle = INVALID_HANDLE_VALUE; + + ret = pRegisterWaitForSingleObject(&unregister_param.wait_handle, handle, unregister_function, &unregister_param, INFINITE, WT_EXECUTEONLYONCE | WT_EXECUTEINWAITTHREAD); + ok(ret, "RegisterWaitForSingleObject failed with error %ld\n", GetLastError()); + + WaitForSingleObject(complete_event, INFINITE); + } + + /* test multiple waits with WT_EXECUTEINWAITTHREAD. + * Windows puts multiple waits on the same wait thread, and using WT_EXECUTEINWAITTHREAD causes the callbacks to run serially. + */ + + SetEvent(handle); + waitthread_trigger_event = CreateEventW(NULL, FALSE, FALSE, NULL); + waitthread_wait_event = CreateEventW(NULL, FALSE, FALSE, NULL); + + param.trigger_event = waitthread_trigger_event; + param.wait_event = waitthread_wait_event; + param.complete_event = complete_event; + + ret = pRegisterWaitForSingleObject(&wait_handle2, waitthread_trigger_event, signaled_function, waitthread_wait_event, + INFINITE, WT_EXECUTEONLYONCE | WT_EXECUTEINWAITTHREAD); + ok(ret, "RegisterWaitForSingleObject failed with error %ld\n", GetLastError()); + + ret = pRegisterWaitForSingleObject(&wait_handle, handle, waitthread_test_function, ¶m, INFINITE, WT_EXECUTEONLYONCE | WT_EXECUTEINWAITTHREAD); + ok(ret, "RegisterWaitForSingleObject failed with error %ld\n", GetLastError()); + + WaitForSingleObject(complete_event, INFINITE); + /* give worker thread chance to complete */ + Sleep(100); + + ret = pUnregisterWait(wait_handle); + ok(ret, "UnregisterWait failed with error %ld\n", GetLastError()); + + ret = pUnregisterWait(wait_handle2); + ok(ret, "UnregisterWait failed with error %ld\n", GetLastError()); + + CloseHandle(waitthread_wait_event); + CloseHandle(waitthread_trigger_event); + CloseHandle(complete_event); + CloseHandle(handle); } static DWORD LS_main; @@ -1521,7 +1742,7 @@ static void run_LS_tests(void) } ret = WaitForMultipleObjects(2, threads, TRUE, 60000); - ok(ret == WAIT_OBJECT_0 || broken(ret == WAIT_OBJECT_0+1 /* nt4,w2k */), "WaitForAllObjects 2 threads %d\n",ret); + ok(ret == WAIT_OBJECT_0 || broken(ret == WAIT_OBJECT_0+1 /* nt4,w2k */), "WaitForAllObjects 2 threads %ld\n",ret); for (i = 0; i < 2; ++i) CloseHandle(threads[i]); @@ -1594,48 +1815,48 @@ static void test_ThreadErrorMode(void) ret = pSetThreadErrorMode(0, &mode); ok(ret, "SetThreadErrorMode failed\n"); ok(mode == oldmode, - "SetThreadErrorMode returned old mode 0x%x, expected 0x%x\n", + "SetThreadErrorMode returned old mode 0x%lx, expected 0x%lx\n", mode, oldmode); mode = pGetThreadErrorMode(); - ok(mode == 0, "GetThreadErrorMode returned mode 0x%x, expected 0\n", mode); + ok(mode == 0, "GetThreadErrorMode returned mode 0x%lx, expected 0\n", mode); rtlmode = pRtlGetThreadErrorMode(); ok(rtlmode == 0, - "RtlGetThreadErrorMode returned mode 0x%x, expected 0\n", mode); + "RtlGetThreadErrorMode returned mode 0x%lx, expected 0\n", mode); ret = pSetThreadErrorMode(SEM_FAILCRITICALERRORS, &mode); ok(ret, "SetThreadErrorMode failed\n"); ok(mode == 0, - "SetThreadErrorMode returned old mode 0x%x, expected 0\n", mode); + "SetThreadErrorMode returned old mode 0x%lx, expected 0\n", mode); mode = pGetThreadErrorMode(); ok(mode == SEM_FAILCRITICALERRORS, - "GetThreadErrorMode returned mode 0x%x, expected SEM_FAILCRITICALERRORS\n", + "GetThreadErrorMode returned mode 0x%lx, expected SEM_FAILCRITICALERRORS\n", mode); rtlmode = pRtlGetThreadErrorMode(); ok(rtlmode == 0x10, - "RtlGetThreadErrorMode returned mode 0x%x, expected 0x10\n", mode); + "RtlGetThreadErrorMode returned mode 0x%lx, expected 0x10\n", mode); ret = pSetThreadErrorMode(SEM_NOGPFAULTERRORBOX, &mode); ok(ret, "SetThreadErrorMode failed\n"); ok(mode == SEM_FAILCRITICALERRORS, - "SetThreadErrorMode returned old mode 0x%x, expected SEM_FAILCRITICALERRORS\n", + "SetThreadErrorMode returned old mode 0x%lx, expected SEM_FAILCRITICALERRORS\n", mode); mode = pGetThreadErrorMode(); ok(mode == SEM_NOGPFAULTERRORBOX, - "GetThreadErrorMode returned mode 0x%x, expected SEM_NOGPFAULTERRORBOX\n", + "GetThreadErrorMode returned mode 0x%lx, expected SEM_NOGPFAULTERRORBOX\n", mode); rtlmode = pRtlGetThreadErrorMode(); ok(rtlmode == 0x20, - "RtlGetThreadErrorMode returned mode 0x%x, expected 0x20\n", mode); + "RtlGetThreadErrorMode returned mode 0x%lx, expected 0x20\n", mode); ret = pSetThreadErrorMode(SEM_NOOPENFILEERRORBOX, NULL); ok(ret, "SetThreadErrorMode failed\n"); mode = pGetThreadErrorMode(); ok(mode == SEM_NOOPENFILEERRORBOX, - "GetThreadErrorMode returned mode 0x%x, expected SEM_NOOPENFILEERRORBOX\n", + "GetThreadErrorMode returned mode 0x%lx, expected SEM_NOOPENFILEERRORBOX\n", mode); rtlmode = pRtlGetThreadErrorMode(); ok(rtlmode == 0x40, - "RtlGetThreadErrorMode returned mode 0x%x, expected 0x40\n", rtlmode); + "RtlGetThreadErrorMode returned mode 0x%lx, expected 0x40\n", rtlmode); for (mode = 1; mode; mode <<= 1) { @@ -1645,17 +1866,17 @@ static void test_ThreadErrorMode(void) SEM_NOOPENFILEERRORBOX)) { ok(ret, - "SetThreadErrorMode(0x%x,NULL) failed with error %d\n", + "SetThreadErrorMode(0x%lx,NULL) failed with error %ld\n", mode, GetLastError()); } else { DWORD GLE = GetLastError(); ok(!ret, - "SetThreadErrorMode(0x%x,NULL) succeeded, expected failure\n", + "SetThreadErrorMode(0x%lx,NULL) succeeded, expected failure\n", mode); ok(GLE == ERROR_INVALID_PARAMETER, - "SetThreadErrorMode(0x%x,NULL) failed with %d, " + "SetThreadErrorMode(0x%lx,NULL) failed with %ld, " "expected ERROR_INVALID_PARAMETER\n", mode, GLE); } @@ -1664,94 +1885,191 @@ static void test_ThreadErrorMode(void) pSetThreadErrorMode(oldmode, NULL); } -#if (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) || (defined(_MSC_VER) && defined(__i386__)) -static inline void set_fpu_cw(WORD cw) -{ -#ifdef _MSC_VER - __asm { fnclex } - __asm { fldcw [cw] } -#else - __asm__ volatile ("fnclex; fldcw %0" : : "m" (cw)); -#endif -} - -static inline WORD get_fpu_cw(void) -{ - WORD cw = 0; -#ifdef _MSC_VER - __asm { fnstcw [cw] } -#else - __asm__ volatile ("fnstcw %0" : "=m" (cw)); -#endif - return cw; -} - struct fpu_thread_ctx { - WORD cw; + unsigned int cw; + unsigned long fpu_cw; HANDLE finished; }; +static inline unsigned long get_fpu_cw(void) +{ +#ifdef __arm64ec__ + extern NTSTATUS (*__os_arm64x_get_x64_information)(ULONG,void*,void*); + unsigned int cw, sse; + __os_arm64x_get_x64_information( 0, &sse, NULL ); + __os_arm64x_get_x64_information( 2, &cw, NULL ); + return MAKELONG( cw, sse ); +#elif defined(__i386__) || defined(__x86_64__) + WORD cw = 0; + unsigned int sse = 0; +#ifdef _MSC_VER +#if defined(__REACTOS__) && defined (__x86_64__) + extern void get_fpu_cw_raw(WORD *cw, unsigned int *sse); + get_fpu_cw_raw(&cw, &sse); +#else + __asm { fnstcw [cw] } + __asm { stmxcsr [sse] } +#endif +#else + __asm__ volatile ("fnstcw %0" : "=m" (cw)); + __asm__ volatile ("stmxcsr %0" : "=m" (sse)); +#endif + return MAKELONG( cw, sse ); +#elif defined(__aarch64__) + ULONG_PTR cw; + __asm__ __volatile__( "mrs %0, fpcr" : "=r" (cw) ); + return cw; +#else + return 0; +#endif +} + +static inline void fpu_invalid_operation(void) +{ + double d; + +#if defined(__i386__) + unsigned int sse; +#ifdef _MSC_VER + __asm { stmxcsr [sse] } + sse |= 1; /* invalid operation flag */ + __asm { ldmxcsr [sse] } +#else + __asm__ volatile ("stmxcsr %0" : "=m" (sse)); + sse |= 1; + __asm__ volatile ("ldmxcsr %0" : : "m" (sse)); +#endif +#endif + + d = acos(2.0); + ok(_isnan(d), "d = %lf\n", d); + ok(_statusfp() & _SW_INVALID, "_statusfp() = %x\n", _statusfp()); +} + static DWORD WINAPI fpu_thread(void *param) { struct fpu_thread_ctx *ctx = param; BOOL ret; - ctx->cw = get_fpu_cw(); + ctx->cw = _control87( 0, 0 ); + ctx->fpu_cw = get_fpu_cw(); ret = SetEvent(ctx->finished); - ok(ret, "SetEvent failed, last error %#x.\n", GetLastError()); + ok(ret, "SetEvent failed, last error %#lx.\n", GetLastError()); return 0; } -static WORD get_thread_fpu_cw(void) +static unsigned int get_thread_fpu_cw( unsigned long *fpu_cw ) { struct fpu_thread_ctx ctx; DWORD tid, res; HANDLE thread; ctx.finished = CreateEventW(NULL, FALSE, FALSE, NULL); - ok(!!ctx.finished, "Failed to create event, last error %#x.\n", GetLastError()); + ok(!!ctx.finished, "Failed to create event, last error %#lx.\n", GetLastError()); thread = CreateThread(NULL, 0, fpu_thread, &ctx, 0, &tid); - ok(!!thread, "Failed to create thread, last error %#x.\n", GetLastError()); + ok(!!thread, "Failed to create thread, last error %#lx.\n", GetLastError()); res = WaitForSingleObject(ctx.finished, INFINITE); - ok(res == WAIT_OBJECT_0, "Wait failed (%#x), last error %#x.\n", res, GetLastError()); + ok(res == WAIT_OBJECT_0, "Wait failed (%#lx), last error %#lx.\n", res, GetLastError()); res = CloseHandle(ctx.finished); - ok(!!res, "Failed to close event handle, last error %#x.\n", GetLastError()); + ok(!!res, "Failed to close event handle, last error %#lx.\n", GetLastError()); CloseHandle(thread); + *fpu_cw = ctx.fpu_cw; return ctx.cw; } static void test_thread_fpu_cw(void) { - WORD initial_cw, cw; - - initial_cw = get_fpu_cw(); - ok(initial_cw == 0x27f, "Expected FPU control word 0x27f, got %#x.\n", initial_cw); - - cw = get_thread_fpu_cw(); - ok(cw == 0x27f, "Expected FPU control word 0x27f, got %#x.\n", cw); - - set_fpu_cw(0xf60); - cw = get_fpu_cw(); - ok(cw == 0xf60, "Expected FPU control word 0xf60, got %#x.\n", cw); - - cw = get_thread_fpu_cw(); - ok(cw == 0x27f, "Expected FPU control word 0x27f, got %#x.\n", cw); - - cw = get_fpu_cw(); - ok(cw == 0xf60, "Expected FPU control word 0xf60, got %#x.\n", cw); - - set_fpu_cw(initial_cw); - cw = get_fpu_cw(); - ok(cw == initial_cw, "Expected FPU control word %#x, got %#x.\n", initial_cw, cw); -} + static const struct { + unsigned int cw; unsigned long fpu_cw; unsigned long fpu_cw_broken; + } expected_cw[8] = + { +#ifdef __i386__ + { _MCW_EM | _PC_53, MAKELONG( 0x27f, 0x1f80 ) }, + { _MCW_EM | _PC_53, MAKELONG( 0x27f, 0x1f80 ) }, + { _EM_INEXACT | _RC_CHOP | _PC_24, MAKELONG( 0xc60, 0x7000 ), MAKELONG( 0xc60, 0x1f80 ) }, + { _MCW_EM | _PC_53, MAKELONG( 0x27f, 0x1f80 ) }, + { _EM_INEXACT | _RC_CHOP | _PC_24, MAKELONG( 0xc60, 0x7000 ), MAKELONG( 0xc60, 0x1f80 ) }, + { _MCW_EM | _PC_53, MAKELONG( 0x27f, 0x1f80 ) }, + { _MCW_EM | _PC_53, MAKELONG( 0x27f, 0x1f81 ) }, + { _MCW_EM | _PC_53, MAKELONG( 0x27f, 0x1f81 ) } +#elif defined(__x86_64__) + { _MCW_EM | _PC_64, MAKELONG( 0x27f, 0x1f80 ) }, + { _MCW_EM | _PC_64, MAKELONG( 0x27f, 0x1f80 ) }, + { _EM_INEXACT | _RC_CHOP | _PC_64, MAKELONG( 0x27f, 0x7000 ) }, + { _MCW_EM | _PC_64, MAKELONG( 0x27f, 0x1f80 ) }, + { _EM_INEXACT | _RC_CHOP | _PC_64, MAKELONG( 0x27f, 0x7000 ) }, + { _MCW_EM | _PC_64, MAKELONG( 0x27f, 0x1f80 ) }, + { _MCW_EM | _PC_64, MAKELONG( 0x27f, 0x1f81 ) }, + { _MCW_EM | _PC_64, MAKELONG( 0x27f, 0x1f81 ) } +#elif defined(__aarch64__) + { _MCW_EM | _PC_64, 0 }, + { _MCW_EM | _PC_64, 0 }, + { _EM_INEXACT | _RC_CHOP | _PC_64, 0xc08f00 }, + { _MCW_EM | _PC_64, 0 }, + { _EM_INEXACT | _RC_CHOP | _PC_64, 0xc08f00 }, + { _MCW_EM | _PC_64, 0 }, + { _MCW_EM | _PC_64, 0 }, + { _MCW_EM | _PC_64, 0 } +#else + { 0xdeadbeef, 0xdeadbeef } #endif + }; + unsigned int initial_cw, cw; + unsigned long fpu_cw; + + fpu_cw = get_fpu_cw(); + initial_cw = _control87( 0, 0 ); + ok(initial_cw == expected_cw[0].cw, "expected %#x got %#x\n", expected_cw[0].cw, initial_cw); + ok(fpu_cw == expected_cw[0].fpu_cw, "expected %#lx got %#lx\n", expected_cw[0].fpu_cw, fpu_cw); + + cw = get_thread_fpu_cw( &fpu_cw ); + ok(cw == expected_cw[1].cw, "expected %#x got %#x\n", expected_cw[1].cw, cw); + ok(fpu_cw == expected_cw[1].fpu_cw, "expected %#lx got %#lx\n", expected_cw[1].fpu_cw, fpu_cw); + + _control87( _EM_INEXACT | _RC_CHOP | _PC_24, _MCW_EM | _MCW_RC | _MCW_PC ); + cw = _control87( 0, 0 ); + fpu_cw = get_fpu_cw(); + ok(cw == expected_cw[2].cw, "expected %#x got %#x\n", expected_cw[2].cw, cw); + ok(fpu_cw == expected_cw[2].fpu_cw || + broken(expected_cw[2].fpu_cw_broken && fpu_cw == expected_cw[2].fpu_cw_broken), + "expected %#lx got %#lx\n", expected_cw[2].fpu_cw, fpu_cw); + + cw = get_thread_fpu_cw( &fpu_cw ); + ok(cw == expected_cw[3].cw, "expected %#x got %#x\n", expected_cw[3].cw, cw); + ok(fpu_cw == expected_cw[3].fpu_cw, "expected %#lx got %#lx\n", expected_cw[3].fpu_cw, fpu_cw); + + cw = _control87( 0, 0 ); + fpu_cw = get_fpu_cw(); + ok(cw == expected_cw[4].cw, "expected %#x got %#x\n", expected_cw[4].cw, cw); + ok(fpu_cw == expected_cw[4].fpu_cw || + broken(expected_cw[4].fpu_cw_broken && fpu_cw == expected_cw[4].fpu_cw_broken), + "expected %#lx got %#lx\n", expected_cw[4].fpu_cw, fpu_cw); + + _control87( initial_cw, _MCW_EM | _MCW_RC | _MCW_PC ); + cw = _control87( 0, 0 ); + fpu_cw = get_fpu_cw(); + ok(cw == expected_cw[5].cw, "expected %#x got %#x\n", expected_cw[5].cw, cw); + ok(fpu_cw == expected_cw[5].fpu_cw, "expected %#lx got %#lx\n", expected_cw[5].fpu_cw, fpu_cw); + + fpu_invalid_operation(); + cw = _control87( 0, 0 ); + fpu_cw = get_fpu_cw(); + ok(cw == expected_cw[6].cw, "expected %#x got %#x\n", expected_cw[6].cw, cw); + ok(fpu_cw == expected_cw[6].fpu_cw, "expected %#lx got %#lx\n", expected_cw[6].fpu_cw, fpu_cw); + + cw = _control87( initial_cw, _MCW_EM | _MCW_RC | _MCW_PC ); + fpu_cw = get_fpu_cw(); + ok(cw == expected_cw[7].cw, "expected %#x got %#x\n", expected_cw[6].cw, cw); + ok(fpu_cw == expected_cw[7].fpu_cw, "expected %#lx got %#lx\n", expected_cw[6].fpu_cw, fpu_cw); + _clearfp(); +} static const char manifest_dep[] = "" @@ -1777,7 +2095,7 @@ static void create_manifest_file(const char *filename, const char *manifest) MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH ); file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError()); + ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %lu\n", GetLastError()); WriteFile(file, manifest, strlen(manifest), &size, NULL); CloseHandle(file); } @@ -1793,11 +2111,11 @@ static HANDLE test_create(const char *file) actctx.cbSize = sizeof(ACTCTXW); actctx.lpSource = path; - handle = pCreateActCtxW(&actctx); - ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %u\n", GetLastError()); + handle = CreateActCtxW(&actctx); + ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %lu\n", GetLastError()); - ok(actctx.cbSize == sizeof(actctx), "cbSize=%d\n", actctx.cbSize); - ok(actctx.dwFlags == 0, "dwFlags=%d\n", actctx.dwFlags); + ok(actctx.cbSize == sizeof(actctx), "cbSize=%ld\n", actctx.cbSize); + ok(actctx.dwFlags == 0, "dwFlags=%ld\n", actctx.dwFlags); ok(actctx.lpSource == path, "lpSource=%p\n", actctx.lpSource); ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture); ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId); @@ -1817,12 +2135,6 @@ static void test_thread_actctx(void) DWORD tid, ret; BOOL b; - if (!pActivateActCtx) - { - win_skip("skipping activation context tests\n"); - return; - } - create_manifest_file("testdep1.manifest", manifest_dep); create_manifest_file("main.manifest", manifest_main); @@ -1831,63 +2143,62 @@ static void test_thread_actctx(void) DeleteFileA("main.manifest"); handle = (void*)0xdeadbeef; - b = pGetCurrentActCtx(&handle); - ok(b, "GetCurrentActCtx failed: %u\n", GetLastError()); + b = GetCurrentActCtx(&handle); + ok(b, "GetCurrentActCtx failed: %lu\n", GetLastError()); ok(handle == 0, "active context %p\n", handle); /* without active context */ param.thread_context = (void*)0xdeadbeef; param.handle = NULL; thread = CreateThread(NULL, 0, thread_actctx_func, ¶m, 0, &tid); - ok(thread != NULL, "failed, got %u\n", GetLastError()); + ok(thread != NULL, "failed, got %lu\n", GetLastError()); ret = WaitForSingleObject(thread, 1000); ok(ret == WAIT_OBJECT_0, "wait timeout\n"); ok(param.thread_context == NULL, "got wrong thread context %p\n", param.thread_context); CloseHandle(thread); - b = pActivateActCtx(context, &cookie); - ok(b, "activation failed: %u\n", GetLastError()); + b = ActivateActCtx(context, &cookie); + ok(b, "activation failed: %lu\n", GetLastError()); handle = 0; - b = pGetCurrentActCtx(&handle); - ok(b, "GetCurrentActCtx failed: %u\n", GetLastError()); + b = GetCurrentActCtx(&handle); + ok(b, "GetCurrentActCtx failed: %lu\n", GetLastError()); ok(handle != 0, "no active context\n"); - pReleaseActCtx(handle); + ReleaseActCtx(handle); param.handle = NULL; - b = pGetCurrentActCtx(¶m.handle); - ok(b && param.handle != NULL, "failed to get context, %u\n", GetLastError()); + b = GetCurrentActCtx(¶m.handle); + ok(b && param.handle != NULL, "failed to get context, %lu\n", GetLastError()); param.thread_context = (void*)0xdeadbeef; thread = CreateThread(NULL, 0, thread_actctx_func, ¶m, 0, &tid); - ok(thread != NULL, "failed, got %u\n", GetLastError()); + ok(thread != NULL, "failed, got %lu\n", GetLastError()); ret = WaitForSingleObject(thread, 1000); ok(ret == WAIT_OBJECT_0, "wait timeout\n"); ok(param.thread_context == context, "got wrong thread context %p, %p\n", param.thread_context, context); - pReleaseActCtx(param.thread_context); + ReleaseActCtx(param.thread_context); CloseHandle(thread); /* similar test for CreateRemoteThread() */ param.thread_context = (void*)0xdeadbeef; thread = CreateRemoteThread(GetCurrentProcess(), NULL, 0, thread_actctx_func, ¶m, 0, &tid); - ok(thread != NULL, "failed, got %u\n", GetLastError()); + ok(thread != NULL, "failed, got %lu\n", GetLastError()); ret = WaitForSingleObject(thread, 1000); ok(ret == WAIT_OBJECT_0, "wait timeout\n"); ok(param.thread_context == context, "got wrong thread context %p, %p\n", param.thread_context, context); - pReleaseActCtx(param.thread_context); + ReleaseActCtx(param.thread_context); CloseHandle(thread); - pReleaseActCtx(param.handle); + ReleaseActCtx(param.handle); - b = pDeactivateActCtx(0, cookie); - ok(b, "DeactivateActCtx failed: %u\n", GetLastError()); - pReleaseActCtx(context); + b = DeactivateActCtx(0, cookie); + ok(b, "DeactivateActCtx failed: %lu\n", GetLastError()); + ReleaseActCtx(context); } - static void WINAPI threadpool_workcallback(PTP_CALLBACK_INSTANCE instance, void *context, PTP_WORK work) { int *foo = (int*)context; @@ -1907,7 +2218,7 @@ static void test_threadpool(void) } work = pCreateThreadpoolWork(threadpool_workcallback, &workcalled, NULL); - ok (work != NULL, "Error %d in CreateThreadpoolWork\n", GetLastError()); + ok (work != NULL, "Error %ld in CreateThreadpoolWork\n", GetLastError()); pSubmitThreadpoolWork(work); pWaitForThreadpoolWorkCallbacks(work, FALSE); pCloseThreadpoolWork(work); @@ -1936,7 +2247,7 @@ static void test_reserved_tls(void) /* Also make sure that there is a TLS allocated. */ tls = TlsAlloc(); - ok(tls && tls != TLS_OUT_OF_INDEXES, "tls = %x\n", tls); + ok(tls && tls != TLS_OUT_OF_INDEXES, "tls = %lx\n", tls); TlsSetValue(tls, (void*)1); val = TlsGetValue(0); @@ -1949,7 +2260,7 @@ static void test_reserved_tls(void) /* Set TLS index 0 value and see that this works and doesn't cause problems * for remaining tests. */ ret = TlsSetValue(0, (void*)1); - ok(ret, "TlsSetValue(0, 1) failed: %u\n", GetLastError()); + ok(ret, "TlsSetValue(0, 1) failed: %lu\n", GetLastError()); val = TlsGetValue(0); ok(val == (void*)1, "TlsGetValue(0) = %p\n", val); @@ -2003,7 +2314,7 @@ static void test_thread_info(void) return; } - for (i = 0; i < sizeof(info_size)/sizeof(info_size[0]); i++) + for (i = 0; i < ARRAY_SIZE(info_size); i++) { memset(buf, 0, sizeof(buf)); @@ -2029,30 +2340,35 @@ static void test_thread_info(void) case ThreadBasicInformation: case ThreadAmILastThread: case ThreadPriorityBoost: - ok(status == STATUS_SUCCESS, "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len); +#ifdef __REACTOS__ + ok(status == STATUS_SUCCESS || broken(status == STATUS_ACCESS_DENIED && (i == 0 || i == 14)) /* WS03 */, "for info %lu expected STATUS_SUCCESS, got %08lx (ret_len %lu)\n", i, status, ret_len); +#else + ok(status == STATUS_SUCCESS, "for info %lu expected STATUS_SUCCESS, got %08lx (ret_len %lu)\n", i, status, ret_len); +#endif break; #ifdef __i386__ case ThreadDescriptorTableEntry: ok(status == STATUS_SUCCESS || broken(status == STATUS_ACCESS_DENIED) /* testbot VM is broken */, - "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len); + "for info %lu expected STATUS_SUCCESS, got %08lx (ret_len %lu)\n", i, status, ret_len); break; #endif case ThreadTimes: -todo_wine - ok(status == STATUS_SUCCESS, "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len); +#ifdef __REACTOS__ + ok(status == STATUS_SUCCESS || broken(status == STATUS_ACCESS_DENIED) /* WS03 */, "for info %lu expected STATUS_SUCCESS, got %08lx (ret_len %lu)\n", i, status, ret_len); +#else + ok(status == STATUS_SUCCESS, "for info %lu expected STATUS_SUCCESS, got %08lx (ret_len %lu)\n", i, status, ret_len); +#endif break; - case ThreadAffinityMask: - case ThreadQuerySetWin32StartAddress: case ThreadIsIoPending: -todo_wine - ok(status == STATUS_ACCESS_DENIED, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len); + todo_wine + ok(status == STATUS_ACCESS_DENIED, "for info %lu expected STATUS_ACCESS_DENIED, got %08lx (ret_len %lu)\n", i, status, ret_len); break; default: - ok(status == STATUS_ACCESS_DENIED, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len); + ok(status == STATUS_ACCESS_DENIED, "for info %lu expected STATUS_ACCESS_DENIED, got %08lx (ret_len %lu)\n", i, status, ret_len); break; } } @@ -2060,6 +2376,220 @@ todo_wine CloseHandle(thread); } +typedef struct tagTHREADNAME_INFO +{ + DWORD dwType; /* Must be 0x1000. */ + LPCSTR szName; /* Pointer to name (in user addr space). */ + DWORD dwThreadID; /* Thread ID (-1 = caller thread). */ + DWORD dwFlags; /* Reserved for future use, must be zero. */ +} THREADNAME_INFO; + +static LONG CALLBACK msvc_threadname_vec_handler(EXCEPTION_POINTERS *ExceptionInfo) +{ + if (ExceptionInfo->ExceptionRecord != NULL && + ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_WINE_NAME_THREAD) + return EXCEPTION_CONTINUE_EXECUTION; + + return EXCEPTION_CONTINUE_SEARCH; +} + +static void test_thread_description(void) +{ + THREAD_NAME_INFORMATION *thread_desc; + static const WCHAR *desc = L"thread_desc"; + ULONG len, len2, desc_len; + NTSTATUS status; + char buff[128]; + WCHAR *ptr; + HRESULT hr; + HANDLE thread; + PVOID vectored_handler; + THREADNAME_INFO info; + + if (!pGetThreadDescription) + { + win_skip("Thread description API is not supported.\n"); + return; + } + + desc_len = lstrlenW(desc) * sizeof(*desc); + thread_desc = (THREAD_NAME_INFORMATION *)buff; + + /* Initial description. */ + ptr = NULL; + hr = pGetThreadDescription(GetCurrentThread(), &ptr); + ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to get thread description, hr %#lx.\n", hr); + ok(!lstrcmpW(ptr, L""), "Unexpected description %s.\n", wine_dbgstr_w(ptr)); + LocalFree(ptr); + + len = 0; + status = pNtQueryInformationThread(GetCurrentThread(), ThreadNameInformation, NULL, 0, &len); + ok(status == STATUS_BUFFER_TOO_SMALL, "Unexpected status %#lx.\n", status); + ok(len == sizeof(*thread_desc), "Unexpected structure length %lu.\n", len); + + len2 = 0; + thread_desc->ThreadName.Length = 1; + thread_desc->ThreadName.MaximumLength = 0; + thread_desc->ThreadName.Buffer = (WCHAR *)thread_desc; + status = pNtQueryInformationThread(GetCurrentThread(), ThreadNameInformation, thread_desc, len, &len2); + ok(!status, "Failed to get thread info, status %#lx.\n", status); + ok(len2 == sizeof(*thread_desc), "Unexpected structure length %lu.\n", len); + ok(!thread_desc->ThreadName.Length, "Unexpected description length %#x.\n", thread_desc->ThreadName.Length); + ok(thread_desc->ThreadName.Buffer == (WCHAR *)(thread_desc + 1), + "Unexpected description string pointer %p, %p.\n", thread_desc->ThreadName.Buffer, thread_desc); + + hr = pSetThreadDescription(GetCurrentThread(), NULL); + ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to set thread description, hr %#lx.\n", hr); + + hr = pSetThreadDescription(GetCurrentThread(), desc); + ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to set thread description, hr %#lx.\n", hr); + + ptr = NULL; + hr = pGetThreadDescription(GetCurrentThread(), &ptr); + ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to get thread description, hr %#lx.\n", hr); + ok(!lstrcmpW(ptr, desc), "Unexpected description %s.\n", wine_dbgstr_w(ptr)); + LocalFree(ptr); + + len = 0; + status = pNtQueryInformationThread(GetCurrentThread(), ThreadNameInformation, NULL, 0, &len); + ok(status == STATUS_BUFFER_TOO_SMALL, "Failed to get thread info, status %#lx.\n", status); + ok(len == sizeof(*thread_desc) + desc_len, "Unexpected structure length %lu.\n", len); + + len = 0; + status = pNtQueryInformationThread(GetCurrentThread(), ThreadNameInformation, buff, sizeof(buff), &len); + ok(!status, "Failed to get thread info.\n"); + ok(len == sizeof(*thread_desc) + desc_len, "Unexpected structure length %lu.\n", len); + + ok(thread_desc->ThreadName.Length == desc_len && thread_desc->ThreadName.MaximumLength == desc_len, + "Unexpected description length %u.\n", thread_desc->ThreadName.Length); + ok(thread_desc->ThreadName.Buffer == (WCHAR *)(thread_desc + 1), + "Unexpected description string pointer %p, %p.\n", thread_desc->ThreadName.Buffer, thread_desc); + ok(!memcmp(thread_desc->ThreadName.Buffer, desc, desc_len), "Unexpected description string.\n"); + + /* Partial results. */ + len = 0; + status = pNtQueryInformationThread(GetCurrentThread(), ThreadNameInformation, NULL, 0, &len); + ok(status == STATUS_BUFFER_TOO_SMALL, "Unexpected status %#lx.\n", status); + ok(len == sizeof(*thread_desc) + desc_len, "Unexpected structure length %lu.\n", len); + + status = pNtQueryInformationThread(GetCurrentThread(), ThreadNameInformation, buff, len - sizeof(WCHAR), &len); + ok(status == STATUS_BUFFER_TOO_SMALL, "Unexpected status %#lx.\n", status); + ok(len == sizeof(*thread_desc) + desc_len, "Unexpected structure length %lu.\n", len); + + /* Change description. */ + thread_desc->ThreadName.Length = thread_desc->ThreadName.MaximumLength = 8; + lstrcpyW((WCHAR *)(thread_desc + 1), L"desc"); + + status = pNtSetInformationThread(GetCurrentThread(), ThreadNameInformation, thread_desc, sizeof(*thread_desc)); + ok(status == STATUS_SUCCESS, "Failed to set thread description, status %#lx.\n", status); + + ptr = NULL; + hr = pGetThreadDescription(GetCurrentThread(), &ptr); + ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to get thread description, hr %#lx.\n", hr); + ok(!lstrcmpW(ptr, L"desc"), "Unexpected description %s.\n", wine_dbgstr_w(ptr)); + LocalFree(ptr); + + status = pNtSetInformationThread(GetCurrentThread(), ThreadNameInformation, thread_desc, sizeof(*thread_desc) - 1); + ok(status == STATUS_INFO_LENGTH_MISMATCH, "Unexpected status %#lx.\n", status); + + status = NtSetInformationThread(GetCurrentThread(), ThreadNameInformation, NULL, sizeof(*thread_desc)); + ok(status == STATUS_ACCESS_VIOLATION, "Unexpected status %#lx.\n", status); + + thread_desc->ThreadName.Buffer = NULL; + status = pNtSetInformationThread(GetCurrentThread(), ThreadNameInformation, thread_desc, sizeof(*thread_desc)); + ok(status == STATUS_ACCESS_VIOLATION, "Unexpected status %#lx.\n", status); + + hr = pSetThreadDescription(GetCurrentThread(), NULL); + ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to set thread description, hr %#lx.\n", hr); + + ptr = NULL; + hr = pGetThreadDescription(GetCurrentThread(), &ptr); + ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to get thread description, hr %#lx.\n", hr); + ok(!lstrcmpW(ptr, L""), "Unexpected description %s.\n", wine_dbgstr_w(ptr)); + LocalFree(ptr); + + /* Set with a string from RtlInitUnicodeString. */ + hr = pSetThreadDescription(GetCurrentThread(), L"123"); + ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to set thread description, hr %#lx.\n", hr); + + lstrcpyW((WCHAR *)(thread_desc + 1), L"desc"); + RtlInitUnicodeString(&thread_desc->ThreadName, (WCHAR *)(thread_desc + 1)); + + status = pNtSetInformationThread(GetCurrentThread(), ThreadNameInformation, thread_desc, sizeof(*thread_desc)); + ok(status == STATUS_SUCCESS, "Failed to set thread description, status %#lx.\n", status); + + ptr = NULL; + hr = pGetThreadDescription(GetCurrentThread(), &ptr); + ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to get thread description, hr %#lx.\n", hr); + ok(!lstrcmpW(ptr, L"desc"), "Unexpected description %s.\n", wine_dbgstr_w(ptr)); + LocalFree(ptr); + + /* Set with 0 length/NULL pointer. */ + hr = pSetThreadDescription(GetCurrentThread(), L"123"); + ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to set thread description, hr %#lx.\n", hr); + + memset(thread_desc, 0, sizeof(*thread_desc)); + status = pNtSetInformationThread(GetCurrentThread(), ThreadNameInformation, thread_desc, sizeof(*thread_desc)); + ok(!status, "Failed to set thread description, status %#lx.\n", status); + + ptr = NULL; + hr = pGetThreadDescription(GetCurrentThread(), &ptr); + ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to get thread description, hr %#lx.\n", hr); + ok(!lstrcmpW(ptr, L""), "Unexpected description %s.\n", wine_dbgstr_w(ptr)); + LocalFree(ptr); + + /* Get with only THREAD_QUERY_LIMITED_INFORMATION access. */ + thread = OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentThreadId()); + + ptr = NULL; + hr = pGetThreadDescription(thread, &ptr); + ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to get thread description, hr %#lx.\n", hr); + ok(!lstrcmpW(ptr, L""), "Unexpected description %s.\n", wine_dbgstr_w(ptr)); + LocalFree(ptr); + + len = 0; + status = pNtQueryInformationThread(thread, ThreadNameInformation, NULL, 0, &len); + ok(status == STATUS_BUFFER_TOO_SMALL, "Unexpected status %#lx.\n", status); + ok(len == sizeof(*thread_desc), "Unexpected structure length %lu.\n", len); + + CloseHandle(thread); + + /* Set with only THREAD_SET_LIMITED_INFORMATION access. */ + thread = OpenThread(THREAD_SET_LIMITED_INFORMATION, FALSE, GetCurrentThreadId()); + + hr = pSetThreadDescription(thread, desc); + ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to set thread description, hr %#lx.\n", hr); + + ptr = NULL; + hr = pGetThreadDescription(GetCurrentThread(), &ptr); + ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to get thread description, hr %#lx.\n", hr); + ok(!lstrcmpW(ptr, desc), "Unexpected description %s.\n", wine_dbgstr_w(ptr)); + LocalFree(ptr); + + CloseHandle(thread); + + /* The old exception-based thread name method should not affect GetThreadDescription. */ + hr = pSetThreadDescription(GetCurrentThread(), desc); + ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to set thread description, hr %#lx.\n", hr); + + vectored_handler = pRtlAddVectoredExceptionHandler(FALSE, &msvc_threadname_vec_handler); + ok(vectored_handler != 0, "RtlAddVectoredExceptionHandler failed\n"); + + info.dwType = 0x1000; + info.szName = "123"; + info.dwThreadID = -1; + info.dwFlags = 0; + RaiseException(EXCEPTION_WINE_NAME_THREAD, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info); + + pRtlRemoveVectoredExceptionHandler(vectored_handler); + + ptr = NULL; + hr = pGetThreadDescription(GetCurrentThread(), &ptr); + ok(hr == HRESULT_FROM_NT(STATUS_SUCCESS), "Failed to get thread description, hr %#lx.\n", hr); + ok(!lstrcmpW(ptr, desc), "Unexpected description %s.\n", wine_dbgstr_w(ptr)); + LocalFree(ptr); +} + static void init_funcs(void) { HMODULE hKernel32 = GetModuleHandleA("kernel32.dll"); @@ -2069,21 +2599,17 @@ static void init_funcs(void) so that the compile passes */ #define X(f) p##f = (void*)GetProcAddress(hKernel32, #f) + X(GetCurrentThreadStackLimits); X(GetThreadPriorityBoost); X(OpenThread); X(QueueUserWorkItem); - X(SetThreadIdealProcessor); X(SetThreadPriorityBoost); + X(SetThreadStackGuarantee); X(RegisterWaitForSingleObject); X(UnregisterWait); X(IsWow64Process); X(SetThreadErrorMode); X(GetThreadErrorMode); - X(ActivateActCtx); - X(CreateActCtxW); - X(DeactivateActCtx); - X(GetCurrentActCtx); - X(ReleaseActCtx); X(CreateThreadpool); X(CloseThreadpool); @@ -2094,6 +2620,8 @@ static void init_funcs(void) X(GetThreadGroupAffinity); X(SetThreadGroupAffinity); + X(SetThreadDescription); + X(GetThreadDescription); X(FlsAlloc); X(FlsFree); @@ -2107,7 +2635,8 @@ static void init_funcs(void) X(NtQueryInformationThread); X(RtlGetThreadErrorMode); X(NtSetInformationThread); - X(NtSetLdtEntries); + X(RtlAddVectoredExceptionHandler); + X(RtlRemoveVectoredExceptionHandler); } #undef X } @@ -2136,7 +2665,7 @@ START_TEST(thread) HANDLE hThread; DWORD tid; hThread = CreateThread(NULL, 0, threadFunc2, NULL, 0, &tid); - ok(hThread != NULL, "CreateThread failed, error %u\n", + ok(hThread != NULL, "CreateThread failed, error %lu\n", GetLastError()); ok(WaitForSingleObject(hThread, 200) == WAIT_OBJECT_0, "Thread did not exit in time\n"); @@ -2155,23 +2684,24 @@ START_TEST(thread) test_TerminateThread(); test_CreateThread_stack(); test_thread_priority(); + test_GetCurrentThreadStackLimits(); + test_SetThreadStackGuarantee(); test_GetThreadTimes(); test_thread_processor(); test_GetThreadExitCode(); #ifdef __i386__ test_SetThreadContext(); test_GetThreadSelectorEntry(); - test_NtSetLdtEntries(); + test_GetThreadContext(); #endif test_QueueUserWorkItem(); test_RegisterWaitForSingleObject(); test_TLS(); test_FLS(); test_ThreadErrorMode(); -#if (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) || (defined(_MSC_VER) && defined(__i386__)) test_thread_fpu_cw(); -#endif test_thread_actctx(); + test_thread_description(); test_threadpool(); } diff --git a/modules/rostests/winetests/kernel32/time.c b/modules/rostests/winetests/kernel32/time.c index e6e779c703c..c044432c958 100644 --- a/modules/rostests/winetests/kernel32/time.c +++ b/modules/rostests/winetests/kernel32/time.c @@ -32,6 +32,7 @@ static int (WINAPI *pGetCalendarInfoW)(LCID,CALID,CALTYPE,LPWSTR,int,LPDWORD); static DWORD (WINAPI *pGetDynamicTimeZoneInformation)(DYNAMIC_TIME_ZONE_INFORMATION*); static void (WINAPI *pGetSystemTimePreciseAsFileTime)(LPFILETIME); static BOOL (WINAPI *pGetTimeZoneInformationForYear)(USHORT, PDYNAMIC_TIME_ZONE_INFORMATION, LPTIME_ZONE_INFORMATION); +static ULONG (WINAPI *pNtGetTickCount)(void); #define SECSPERMIN 60 #define SECSPERDAY 86400 @@ -121,14 +122,14 @@ static void test_conversions(void) SETUP_ZEROTIME(st) ok (SystemTimeToFileTime(&st, &ft), "Conversion failed ZERO_TIME\n"); ok( (!((ft.dwHighDateTime != 0) || (ft.dwLowDateTime != 0))), - "Wrong time for ATIME: %08x %08x (correct %08x %08x)\n", + "Wrong time for ATIME: %08lx %08lx (correct %08x %08x)\n", ft.dwLowDateTime, ft.dwHighDateTime, 0, 0); SETUP_ATIME(st) ok (SystemTimeToFileTime(&st,&ft), "Conversion Failed ATIME\n"); ok( (!((ft.dwHighDateTime != ATIME_HI) || (ft.dwLowDateTime!=ATIME_LOW))), - "Wrong time for ATIME: %08x %08x (correct %08x %08x)\n", + "Wrong time for ATIME: %08lx %08lx (correct %08x %08x)\n", ft.dwLowDateTime, ft.dwHighDateTime, ATIME_LOW, ATIME_HI); @@ -137,7 +138,7 @@ static void test_conversions(void) ok( (!((ft.dwHighDateTime != MAYDAY_2002_HI) || (ft.dwLowDateTime!=MAYDAY_2002_LO))), - "Wrong time for 2002 %08x %08x (correct %08x %08x)\n", ft.dwLowDateTime, + "Wrong time for 2002 %08lx %08lx (correct %08x %08x)\n", ft.dwLowDateTime, ft.dwHighDateTime, MAYDAY_2002_LO, MAYDAY_2002_HI); @@ -146,7 +147,7 @@ static void test_conversions(void) ok( (!((ft.dwHighDateTime!=NEWYEAR_1980_HI) || (ft.dwLowDateTime!=NEWYEAR_1980_LO))) , - "Wrong time for 1980 %08x %08x (correct %08x %08x)\n", ft.dwLowDateTime, + "Wrong time for 1980 %08lx %08lx (correct %08x %08x)\n", ft.dwLowDateTime, ft.dwHighDateTime, NEWYEAR_1980_LO,NEWYEAR_1980_HI ); ok(DosDateTimeToFileTime(DOS_DATE(1980,1,1),DOS_TIME(0,0,0),&ft), @@ -154,7 +155,7 @@ static void test_conversions(void) ok( (!((ft.dwHighDateTime!=NEWYEAR_1980_HI) || (ft.dwLowDateTime!=NEWYEAR_1980_LO))), - "Wrong time DosDateTimeToFileTime %08x %08x (correct %08x %08x)\n", + "Wrong time DosDateTimeToFileTime %08lx %08lx (correct %08x %08x)\n", ft.dwHighDateTime, ft.dwLowDateTime, NEWYEAR_1980_HI, NEWYEAR_1980_LO); } @@ -172,7 +173,7 @@ static void test_invalid_arg(void) "DosDateTimeToFileTime() failed\n"); ok( (ft.dwHighDateTime==NEWYEAR_1980_HI) && (ft.dwLowDateTime==NEWYEAR_1980_LO), - "filetime for 1/1/80 00:00:00 was %08x %08x\n", ft.dwHighDateTime, ft.dwLowDateTime); + "filetime for 1/1/80 00:00:00 was %08lx %08lx\n", ft.dwHighDateTime, ft.dwLowDateTime); /* now check SystemTimeToFileTime */ memset(&ft,0,sizeof ft); @@ -205,7 +206,7 @@ static LONGLONG system_time_to_minutes(const SYSTEMTIME *st) SetLastError(0xdeadbeef); ret = SystemTimeToFileTime(st, &ft); - ok(ret, "SystemTimeToFileTime error %u\n", GetLastError()); + ok(ret, "SystemTimeToFileTime error %lu\n", GetLastError()); minutes = ((LONGLONG)ft.dwHighDateTime << 32) + ft.dwLowDateTime; minutes /= (LONGLONG)600000000; /* convert to minutes */ @@ -225,7 +226,7 @@ static LONG get_tz_bias(const TIME_ZONE_INFORMATION *tzinfo, DWORD tz_id) return tzinfo->StandardBias; default: - trace("unknown time zone id %d\n", tz_id); + trace("unknown time zone id %ld\n", tz_id); /* fall through */ case TIME_ZONE_ID_UNKNOWN: return 0; @@ -248,19 +249,19 @@ static void test_GetTimeZoneInformation(void) SetLastError(0xdeadbeef); res = SystemTimeToFileTime(&st, &s_ft); - ok(res, "SystemTimeToFileTime error %u\n", GetLastError()); + ok(res, "SystemTimeToFileTime error %lu\n", GetLastError()); SetLastError(0xdeadbeef); res = FileTimeToLocalFileTime(&s_ft, &l_ft); - ok(res, "FileTimeToLocalFileTime error %u\n", GetLastError()); + ok(res, "FileTimeToLocalFileTime error %lu\n", GetLastError()); SetLastError(0xdeadbeef); res = FileTimeToSystemTime(&l_ft, &local); - ok(res, "FileTimeToSystemTime error %u\n", GetLastError()); + ok(res, "FileTimeToSystemTime error %lu\n", GetLastError()); l_time = system_time_to_minutes(&local); tz_id = GetTimeZoneInformation(&tzinfo); ok(tz_id != TIME_ZONE_ID_INVALID, "GetTimeZoneInformation failed\n"); - trace("tz_id %u (%s)\n", tz_id, + trace("tz_id %lu (%s)\n", tz_id, tz_id == TIME_ZONE_ID_DAYLIGHT ? "TIME_ZONE_ID_DAYLIGHT" : (tz_id == TIME_ZONE_ID_STANDARD ? "TIME_ZONE_ID_STANDARD" : (tz_id == TIME_ZONE_ID_UNKNOWN ? "TIME_ZONE_ID_UNKNOWN" : @@ -268,14 +269,14 @@ static void test_GetTimeZoneInformation(void) WideCharToMultiByte(CP_ACP, 0, tzinfo.StandardName, -1, std_name, sizeof(std_name), NULL, NULL); WideCharToMultiByte(CP_ACP, 0, tzinfo.DaylightName, -1, dlt_name, sizeof(dlt_name), NULL, NULL); - trace("bias %d, %s - %s\n", tzinfo.Bias, std_name, dlt_name); - trace("standard (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n", + trace("bias %ld, %s - %s\n", tzinfo.Bias, std_name, dlt_name); + trace("standard (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %ld\n", tzinfo.StandardDate.wDay, tzinfo.StandardDate.wMonth, tzinfo.StandardDate.wYear, tzinfo.StandardDate.wDayOfWeek, tzinfo.StandardDate.wHour, tzinfo.StandardDate.wMinute, tzinfo.StandardDate.wSecond, tzinfo.StandardDate.wMilliseconds, tzinfo.StandardBias); - trace("daylight (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n", + trace("daylight (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %ld\n", tzinfo.DaylightDate.wDay, tzinfo.DaylightDate.wMonth, tzinfo.DaylightDate.wYear, tzinfo.DaylightDate.wDayOfWeek, tzinfo.DaylightDate.wHour, tzinfo.DaylightDate.wMinute, @@ -284,7 +285,7 @@ static void test_GetTimeZoneInformation(void) diff = (LONG)(s_time - l_time); ok(diff == tzinfo.Bias + get_tz_bias(&tzinfo, tz_id), - "system/local diff %d != tz bias %d\n", + "system/local diff %ld != tz bias %ld\n", diff, tzinfo.Bias + get_tz_bias(&tzinfo, tz_id)); ok(SetEnvironmentVariableA("TZ","GMT0") != 0, @@ -316,16 +317,16 @@ static void test_GetTimeZoneInformation(void) return; } - ok(res, "SystemTimeToTzSpecificLocalTime error %u\n", GetLastError()); + ok(res, "SystemTimeToTzSpecificLocalTime error %lu\n", GetLastError()); s_time = system_time_to_minutes(¤t); tzinfo.StandardBias -= 123; tzinfo.DaylightBias += 456; res = pSystemTimeToTzSpecificLocalTime(&tzinfo, &utc, &local); - ok(res, "SystemTimeToTzSpecificLocalTime error %u\n", GetLastError()); + ok(res, "SystemTimeToTzSpecificLocalTime error %lu\n", GetLastError()); l_time = system_time_to_minutes(&local); - ok(l_time - s_time == diff - get_tz_bias(&tzinfo, tz_id), "got %d, expected %d\n", + ok(l_time - s_time == diff - get_tz_bias(&tzinfo, tz_id), "got %ld, expected %ld\n", (LONG)(l_time - s_time), diff - get_tz_bias(&tzinfo, tz_id)); /* pretend that there is no transition dates */ @@ -337,9 +338,9 @@ static void test_GetTimeZoneInformation(void) tzinfo.StandardDate.wYear = 0; res = pSystemTimeToTzSpecificLocalTime(&tzinfo, &utc, &local); - ok(res, "SystemTimeToTzSpecificLocalTime error %u\n", GetLastError()); + ok(res, "SystemTimeToTzSpecificLocalTime error %lu\n", GetLastError()); l_time = system_time_to_minutes(&local); - ok(l_time - s_time == diff, "got %d, expected %d\n", + ok(l_time - s_time == diff, "got %ld, expected %ld\n", (LONG)(l_time - s_time), diff); /* test 23:01, 31st of December date */ @@ -360,7 +361,7 @@ static void test_GetTimeZoneInformation(void) utc.wHour = 23; utc.wMinute = 1; res = pSystemTimeToTzSpecificLocalTime(&tzinfo, &utc, &local); - ok(res, "SystemTimeToTzSpecificLocalTime error %u\n", GetLastError()); + ok(res, "SystemTimeToTzSpecificLocalTime error %lu\n", GetLastError()); ok(local.wYear==2012 && local.wMonth==12 && local.wDay==31 && local.wHour==23 && local.wMinute==1, "got (%d-%d-%d %02d:%02d), expected (2012-12-31 23:01)\n", local.wYear, local.wMonth, local.wDay, local.wHour, local.wMinute); @@ -377,7 +378,7 @@ static void test_FileTimeToSystemTime(void) ft.dwLowDateTime = 0; ret = FileTimeToSystemTime(&ft, &st); ok( ret, - "FileTimeToSystemTime() failed with Error %d\n",GetLastError()); + "FileTimeToSystemTime() failed with Error %ld\n",GetLastError()); ok(((st.wYear == 1601) && (st.wMonth == 1) && (st.wDay == 1) && (st.wHour == 0) && (st.wMinute == 0) && (st.wSecond == 0) && (st.wMilliseconds == 0)), @@ -387,13 +388,21 @@ static void test_FileTimeToSystemTime(void) ft.dwLowDateTime = (UINT)time; ret = FileTimeToSystemTime(&ft, &st); ok( ret, - "FileTimeToSystemTime() failed with Error %d\n",GetLastError()); + "FileTimeToSystemTime() failed with Error %ld\n",GetLastError()); ok(((st.wYear == 1970) && (st.wMonth == 1) && (st.wDay == 1) && (st.wHour == 0) && (st.wMinute == 0) && (st.wSecond == 1) && (st.wMilliseconds == 0)), "Got Year %4d Month %2d Day %2d Hour %2d Min %2d Sec %2d mSec %3d\n", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); + + ft.dwHighDateTime = -1; + ft.dwLowDateTime = -1; + SetLastError(0xdeadbeef); + ret = FileTimeToSystemTime(&ft, &st); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); } static void test_FileTimeToLocalFileTime(void) @@ -414,7 +423,7 @@ static void test_FileTimeToLocalFileTime(void) ft.dwLowDateTime = (UINT)time; ret = FileTimeToLocalFileTime(&ft, &lft); ok( ret, - "FileTimeToLocalFileTime() failed with Error %d\n",GetLastError()); + "FileTimeToLocalFileTime() failed with Error %ld\n",GetLastError()); FileTimeToSystemTime(&lft, &st); ok(((st.wYear == 1970) && (st.wMonth == 1) && (st.wDay == 1) && (st.wHour == 0) && (st.wMinute == 0) && (st.wSecond == 1) && @@ -428,7 +437,7 @@ static void test_FileTimeToLocalFileTime(void) ok(res != TIME_ZONE_ID_INVALID, "GetTimeZoneInformation failed\n"); ret = FileTimeToLocalFileTime(&ft, &lft); ok( ret, - "FileTimeToLocalFileTime() failed with Error %d\n",GetLastError()); + "FileTimeToLocalFileTime() failed with Error %ld\n",GetLastError()); FileTimeToSystemTime(&lft, &st); ok(((st.wYear == 1970) && (st.wMonth == 1) && (st.wDay == 1) && (st.wHour == 0) && (st.wMinute == 0) && (st.wSecond == 1) && @@ -646,25 +655,25 @@ static void test_FileTimeToDosDateTime(void) ret = FileTimeToDosDateTime(&ft, NULL, NULL); ok(!ret, "expected failure\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = FileTimeToDosDateTime(&ft, &fatdate, NULL); ok(!ret, "expected failure\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = FileTimeToDosDateTime(&ft, NULL, &fattime); ok(!ret, "expected failure\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = FileTimeToDosDateTime(&ft, &fatdate, &fattime); ok(!ret, "expected failure\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); } static void test_GetCalendarInfo(void) @@ -672,7 +681,7 @@ static void test_GetCalendarInfo(void) char bufferA[20]; WCHAR bufferW[20]; DWORD val1, val2; - int ret, ret2; + int i, j, ret, ret2; if (!pGetCalendarInfoA || !pGetCalendarInfoW) { @@ -682,59 +691,85 @@ static void test_GetCalendarInfo(void) ret = pGetCalendarInfoA( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX | CAL_RETURN_NUMBER, NULL, 0, &val1 ); - ok( ret, "GetCalendarInfoA failed err %u\n", GetLastError() ); + ok( ret, "GetCalendarInfoA failed err %lu\n", GetLastError() ); ok( ret == sizeof(val1), "wrong size %u\n", ret ); - ok( val1 >= 2000 && val1 < 2100, "wrong value %u\n", val1 ); + ok( val1 >= 2000 && val1 < 2100, "wrong value %lu\n", val1 ); ret = pGetCalendarInfoW( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX | CAL_RETURN_NUMBER, NULL, 0, &val2 ); - ok( ret, "GetCalendarInfoW failed err %u\n", GetLastError() ); + ok( ret, "GetCalendarInfoW failed err %lu\n", GetLastError() ); ok( ret == sizeof(val2)/sizeof(WCHAR), "wrong size %u\n", ret ); - ok( val1 == val2, "A/W mismatch %u/%u\n", val1, val2 ); + ok( val1 == val2, "A/W mismatch %lu/%lu\n", val1, val2 ); ret = pGetCalendarInfoA( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX, bufferA, sizeof(bufferA), NULL ); - ok( ret, "GetCalendarInfoA failed err %u\n", GetLastError() ); + ok( ret, "GetCalendarInfoA failed err %lu\n", GetLastError() ); ok( ret == 5, "wrong size %u\n", ret ); - ok( atoi( bufferA ) == val1, "wrong value %s/%u\n", bufferA, val1 ); + ok( atoi( bufferA ) == val1, "wrong value %s/%lu\n", bufferA, val1 ); - ret = pGetCalendarInfoW( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX, bufferW, sizeof(bufferW), NULL ); - ok( ret, "GetCalendarInfoW failed err %u\n", GetLastError() ); + ret = pGetCalendarInfoW( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX, bufferW, ARRAY_SIZE(bufferW), NULL ); + ok( ret, "GetCalendarInfoW failed err %lu\n", GetLastError() ); ok( ret == 5, "wrong size %u\n", ret ); memset( bufferA, 0x55, sizeof(bufferA) ); WideCharToMultiByte( CP_ACP, 0, bufferW, -1, bufferA, sizeof(bufferA), NULL, NULL ); - ok( atoi( bufferA ) == val1, "wrong value %s/%u\n", bufferA, val1 ); + ok( atoi( bufferA ) == val1, "wrong value %s/%lu\n", bufferA, val1 ); ret = pGetCalendarInfoA( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX | CAL_RETURN_NUMBER, NULL, 0, NULL ); ok( !ret, "GetCalendarInfoA succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); ret = pGetCalendarInfoA( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX, NULL, 0, NULL ); - ok( ret, "GetCalendarInfoA failed err %u\n", GetLastError() ); + ok( ret, "GetCalendarInfoA failed err %lu\n", GetLastError() ); ok( ret == 5, "wrong size %u\n", ret ); ret = pGetCalendarInfoW( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX | CAL_RETURN_NUMBER, NULL, 0, NULL ); ok( !ret, "GetCalendarInfoW succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); ret = pGetCalendarInfoW( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX, NULL, 0, NULL ); - ok( ret, "GetCalendarInfoW failed err %u\n", GetLastError() ); + ok( ret, "GetCalendarInfoW failed err %lu\n", GetLastError() ); ok( ret == 5, "wrong size %u\n", ret ); ret = pGetCalendarInfoA( LANG_SYSTEM_DEFAULT, CAL_GREGORIAN, CAL_SDAYNAME1, bufferA, sizeof(bufferA), NULL); - ok( ret, "GetCalendarInfoA failed err %u\n", GetLastError() ); + ok( ret, "GetCalendarInfoA failed err %lu\n", GetLastError() ); ret2 = pGetCalendarInfoA( LANG_SYSTEM_DEFAULT, CAL_GREGORIAN, CAL_SDAYNAME1, bufferA, 0, NULL); - ok( ret2, "GetCalendarInfoA failed err %u\n", GetLastError() ); + ok( ret2, "GetCalendarInfoA failed err %lu\n", GetLastError() ); ok( ret == ret2, "got %d, expected %d\n", ret2, ret ); ret2 = pGetCalendarInfoW( LANG_SYSTEM_DEFAULT, CAL_GREGORIAN, CAL_SDAYNAME1, - bufferW, sizeof(bufferW), NULL); - ok( ret2, "GetCalendarInfoW failed err %u\n", GetLastError() ); + bufferW, ARRAY_SIZE(bufferW), NULL); + ok( ret2, "GetCalendarInfoW failed err %lu\n", GetLastError() ); ret2 = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL ); ok( ret == ret2, "got %d, expected %d\n", ret, ret2 ); + +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) { +#endif + for (i = CAL_GREGORIAN; i <= CAL_UMALQURA; i++) + { + WCHAR name[80]; + ret = pGetCalendarInfoW( 0x0409, i, CAL_SCALNAME, name, ARRAY_SIZE(name), NULL); + for (j = CAL_ICALINTVALUE; j <= CAL_SRELATIVELONGDATE; j++) + { + ret2 = pGetCalendarInfoW( 0x0409, i, j, bufferW, ARRAY_SIZE(bufferW), NULL); + if (ret || j == CAL_ITWODIGITYEARMAX) +#ifdef __REACTOS__ + ok( ret2 || broken(j == CAL_SRELATIVELONGDATE) /* Win7 */ || broken(j == CAL_SMONTHDAY || j == CAL_SABBREVERASTRING), /* Vista */ +#else + ok( ret2 || broken(j == CAL_SRELATIVELONGDATE), /* win7 doesn't have this */ +#endif + "calendar %u %s value %02x failed\n", i, wine_dbgstr_w(name), j ); + else + ok( !ret2, "calendar %u %s value %02x succeeded %s\n", + i, wine_dbgstr_w(name), j, wine_dbgstr_w(bufferW) ); + } + } +#ifdef __REACTOS__ + } +#endif } static void test_GetDynamicTimeZoneInformation(void) @@ -743,7 +778,12 @@ static void test_GetDynamicTimeZoneInformation(void) TIME_ZONE_INFORMATION tzinfo; DWORD ret, ret2; +#if defined(__REACTOS__) && DLL_EXPORT_VERSION >= 0x600 + /* FIXME: GetDynamicTimeZoneInformation is a STUB on ReactOS */ + if (is_reactos() || !pGetDynamicTimeZoneInformation) +#else if (!pGetDynamicTimeZoneInformation) +#endif { win_skip("GetDynamicTimeZoneInformation() is not supported.\n"); return; @@ -751,13 +791,13 @@ static void test_GetDynamicTimeZoneInformation(void) ret = pGetDynamicTimeZoneInformation(&dyninfo); ret2 = GetTimeZoneInformation(&tzinfo); - ok(ret == ret2, "got %d, %d\n", ret, ret2); + ok(ret == ret2, "got %ld, %ld\n", ret, ret2); - ok(dyninfo.Bias == tzinfo.Bias, "got %d, %d\n", dyninfo.Bias, tzinfo.Bias); + ok(dyninfo.Bias == tzinfo.Bias, "got %ld, %ld\n", dyninfo.Bias, tzinfo.Bias); ok(!lstrcmpW(dyninfo.StandardName, tzinfo.StandardName), "got std name %s, %s\n", wine_dbgstr_w(dyninfo.StandardName), wine_dbgstr_w(tzinfo.StandardName)); ok(!memcmp(&dyninfo.StandardDate, &tzinfo.StandardDate, sizeof(dyninfo.StandardDate)), "got different StandardDate\n"); - ok(dyninfo.StandardBias == tzinfo.StandardBias, "got %d, %d\n", dyninfo.StandardBias, tzinfo.StandardBias); + ok(dyninfo.StandardBias == tzinfo.StandardBias, "got %ld, %ld\n", dyninfo.StandardBias, tzinfo.StandardBias); ok(!lstrcmpW(dyninfo.DaylightName, tzinfo.DaylightName), "got daylight name %s, %s\n", wine_dbgstr_w(dyninfo.DaylightName), wine_dbgstr_w(tzinfo.DaylightName)); ok(!memcmp(&dyninfo.DaylightDate, &tzinfo.DaylightDate, sizeof(dyninfo.DaylightDate)), "got different DaylightDate\n"); @@ -773,6 +813,20 @@ static ULONGLONG get_longlong_time(FILETIME *time) return uli.QuadPart; } +static void test_GetSystemTimeAsFileTime(void) +{ + LARGE_INTEGER t1, t2, t3; + FILETIME ft; + + NtQuerySystemTime( &t1 ); + GetSystemTimeAsFileTime( &ft ); + NtQuerySystemTime( &t3 ); + t2.QuadPart = get_longlong_time( &ft ); + + ok(t1.QuadPart <= t2.QuadPart, "out of order %s %s\n", wine_dbgstr_longlong(t1.QuadPart), wine_dbgstr_longlong(t2.QuadPart)); + ok(t2.QuadPart <= t3.QuadPart, "out of order %s %s\n", wine_dbgstr_longlong(t2.QuadPart), wine_dbgstr_longlong(t3.QuadPart)); +} + static void test_GetSystemTimePreciseAsFileTime(void) { FILETIME ft; @@ -841,7 +895,7 @@ static void test_GetSystemTimes(void) ok( !NtQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), &ReturnLength), "NtQuerySystemInformation failed\n" ); - ok( sizeof(sbi) == ReturnLength, "Inconsistent length %d\n", ReturnLength ); + ok( sizeof(sbi) == ReturnLength, "Inconsistent length %ld\n", ReturnLength ); /* Check if we have some return values */ trace( "Number of Processors : %d\n", sbi.NumberOfProcessors ); @@ -879,6 +933,9 @@ static WORD day_of_month(const SYSTEMTIME* systemtime, WORD year) if (systemtime->wYear != 0) return systemtime->wDay; + if (systemtime->wMonth == 0) + return 0; + first_of_month.wYear = year; first_of_month.wMonth = systemtime->wMonth; first_of_month.wDay = 1; @@ -911,15 +968,42 @@ static WORD day_of_month(const SYSTEMTIME* systemtime, WORD year) static void test_GetTimeZoneInformationForYear(void) { - BOOL ret; + BOOL ret, broken_test = FALSE; SYSTEMTIME systemtime; TIME_ZONE_INFORMATION local_tzinfo, tzinfo, tzinfo2; DYNAMIC_TIME_ZONE_INFORMATION dyn_tzinfo; - static const WCHAR std_tzname[] = {'G','r','e','e','n','l','a','n','d',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',0}; - static const WCHAR dlt_tzname[] = {'G','r','e','e','n','l','a','n','d',' ','D','a','y','l','i','g','h','t',' ','T','i','m','e',0}; WORD std_day, dlt_day; + unsigned i; + static const struct + { + const WCHAR *tzname; + USHORT year; + LONG bias, std_bias, dlt_bias; + WORD std_month, std_day, dlt_month, dlt_day; + } + test_data[] = + { + { L"Greenland Standard Time", 2015, 180, 0, -60, 10, 24, 3, 28 }, + { L"Greenland Standard Time", 2016, 180, 0, -60, 10, 29, 3, 26 }, + { L"Greenland Standard Time", 2017, 180, 0, -60, 10, 28, 3, 25 }, + { L"Easter Island Standard Time", 2014, 360, 0, -60, 4, 26, 9, 6 }, + { L"Easter Island Standard Time", 2015, 300, 0, -60, 0, 0, 0, 0 }, + { L"Easter Island Standard Time", 2016, 360, 0, -60, 5, 14, 8, 13 }, + { L"Egypt Standard Time", 2013, -120, 0, -60, 0, 0, 0, 0 }, + { L"Egypt Standard Time", 2014, -120, 0, -60, 9, 25, 5, 15 }, + { L"Egypt Standard Time", 2015, -120, 0, -60, 0, 0, 0, 0 }, + { L"Egypt Standard Time", 2016, -120, 0, -60, 0, 0, 0, 0 }, + { L"Altai Standard Time", 2016, -420, 0, 60, 3, 27, 1, 1 }, + { L"Altai Standard Time", 2017, -420, 0, -60, 0, 0, 0, 0 }, + { L"Altai Standard Time", 2018, -420, 0, -60, 0, 0, 0, 0 }, + }; +#if defined(__REACTOS__) && DLL_EXPORT_VERSION >= 0x600 + /* FIXME: GetTimeZoneInformationForYear and GetDynamicTimeZoneInformation are STUBS on ReactOS */ + if (is_reactos() || !pGetTimeZoneInformationForYear || !pGetDynamicTimeZoneInformation) +#else if (!pGetTimeZoneInformationForYear || !pGetDynamicTimeZoneInformation) +#endif { win_skip("GetTimeZoneInformationForYear not available\n"); return; @@ -930,69 +1014,227 @@ static void test_GetTimeZoneInformationForYear(void) GetTimeZoneInformation(&local_tzinfo); ret = pGetTimeZoneInformationForYear(systemtime.wYear, NULL, &tzinfo); - ok(ret == TRUE, "GetTimeZoneInformationForYear failed, err %u\n", GetLastError()); - ok(tzinfo.Bias == local_tzinfo.Bias, "Expected Bias %d, got %d\n", local_tzinfo.Bias, tzinfo.Bias); + ok(ret == TRUE, "GetTimeZoneInformationForYear failed, err %lu\n", GetLastError()); + ok(tzinfo.Bias == local_tzinfo.Bias, "Expected Bias %ld, got %ld\n", local_tzinfo.Bias, tzinfo.Bias); ok(!lstrcmpW(tzinfo.StandardName, local_tzinfo.StandardName), "Expected StandardName %s, got %s\n", wine_dbgstr_w(local_tzinfo.StandardName), wine_dbgstr_w(tzinfo.StandardName)); ok(!memcmp(&tzinfo.StandardDate, &local_tzinfo.StandardDate, sizeof(SYSTEMTIME)), "StandardDate does not match\n"); - ok(tzinfo.StandardBias == local_tzinfo.StandardBias, "Expected StandardBias %d, got %d\n", local_tzinfo.StandardBias, tzinfo.StandardBias); + ok(tzinfo.StandardBias == local_tzinfo.StandardBias, "Expected StandardBias %ld, got %ld\n", local_tzinfo.StandardBias, tzinfo.StandardBias); ok(!lstrcmpW(tzinfo.DaylightName, local_tzinfo.DaylightName), "Expected DaylightName %s, got %s\n", wine_dbgstr_w(local_tzinfo.DaylightName), wine_dbgstr_w(tzinfo.DaylightName)); ok(!memcmp(&tzinfo.DaylightDate, &local_tzinfo.DaylightDate, sizeof(SYSTEMTIME)), "DaylightDate does not match\n"); - ok(tzinfo.DaylightBias == local_tzinfo.DaylightBias, "Expected DaylightBias %d, got %d\n", local_tzinfo.DaylightBias, tzinfo.DaylightBias); + ok(tzinfo.DaylightBias == local_tzinfo.DaylightBias, "Expected DaylightBias %ld, got %ld\n", local_tzinfo.DaylightBias, tzinfo.DaylightBias); pGetDynamicTimeZoneInformation(&dyn_tzinfo); ret = pGetTimeZoneInformationForYear(systemtime.wYear, &dyn_tzinfo, &tzinfo); - ok(ret == TRUE, "GetTimeZoneInformationForYear failed, err %u\n", GetLastError()); - ok(tzinfo.Bias == local_tzinfo.Bias, "Expected Bias %d, got %d\n", local_tzinfo.Bias, tzinfo.Bias); + ok(ret == TRUE, "GetTimeZoneInformationForYear failed, err %lu\n", GetLastError()); + ok(tzinfo.Bias == local_tzinfo.Bias, "Expected Bias %ld, got %ld\n", local_tzinfo.Bias, tzinfo.Bias); ok(!lstrcmpW(tzinfo.StandardName, local_tzinfo.StandardName), "Expected StandardName %s, got %s\n", wine_dbgstr_w(local_tzinfo.StandardName), wine_dbgstr_w(tzinfo.StandardName)); ok(!memcmp(&tzinfo.StandardDate, &local_tzinfo.StandardDate, sizeof(SYSTEMTIME)), "StandardDate does not match\n"); - ok(tzinfo.StandardBias == local_tzinfo.StandardBias, "Expected StandardBias %d, got %d\n", local_tzinfo.StandardBias, tzinfo.StandardBias); + ok(tzinfo.StandardBias == local_tzinfo.StandardBias, "Expected StandardBias %ld, got %ld\n", local_tzinfo.StandardBias, tzinfo.StandardBias); ok(!lstrcmpW(tzinfo.DaylightName, local_tzinfo.DaylightName), "Expected DaylightName %s, got %s\n", wine_dbgstr_w(local_tzinfo.DaylightName), wine_dbgstr_w(tzinfo.DaylightName)); ok(!memcmp(&tzinfo.DaylightDate, &local_tzinfo.DaylightDate, sizeof(SYSTEMTIME)), "DaylightDate does not match\n"); - ok(tzinfo.DaylightBias == local_tzinfo.DaylightBias, "Expected DaylightBias %d, got %d\n", local_tzinfo.DaylightBias, tzinfo.DaylightBias); + ok(tzinfo.DaylightBias == local_tzinfo.DaylightBias, "Expected DaylightBias %ld, got %ld\n", local_tzinfo.DaylightBias, tzinfo.DaylightBias); memset(&dyn_tzinfo, 0xaa, sizeof(dyn_tzinfo)); - lstrcpyW(dyn_tzinfo.TimeZoneKeyName, std_tzname); - dyn_tzinfo.DynamicDaylightTimeDisabled = FALSE; - - ret = pGetTimeZoneInformationForYear(2015, &dyn_tzinfo, &tzinfo); - ok(ret == TRUE, "GetTimeZoneInformationForYear failed, err %u\n", GetLastError()); - ok(tzinfo.Bias == 180, "Expected Bias 180, got %d\n", tzinfo.Bias); - ok(tzinfo.StandardDate.wMonth == 10, "Expected standard month 10, got %d\n", tzinfo.StandardDate.wMonth); - std_day = day_of_month(&tzinfo.StandardDate, 2015); - ok(std_day == 24, "Expected standard day 24, got %d\n", std_day); - ok(tzinfo.StandardBias == 0, "Expected StandardBias 0, got %d\n", tzinfo.StandardBias); - ok(tzinfo.DaylightDate.wMonth == 3, "Expected daylight month 3, got %d\n", tzinfo.DaylightDate.wMonth); - dlt_day = day_of_month(&tzinfo.DaylightDate, 2015); - ok(dlt_day == 28, "Expected daylight day 28, got %d\n", dlt_day); - ok(tzinfo.DaylightBias == -60, "Expected DaylightBias -60, got %d\n", tzinfo.DaylightBias); - - ret = pGetTimeZoneInformationForYear(2016, &dyn_tzinfo, &tzinfo2); - ok(ret == TRUE, "GetTimeZoneInformationForYear failed, err %u\n", GetLastError()); - ok(!lstrcmpW(tzinfo.StandardName, tzinfo2.StandardName), - "Got differing StandardName values %s and %s\n", - wine_dbgstr_w(tzinfo.StandardName), wine_dbgstr_w(tzinfo2.StandardName)); - ok(!lstrcmpW(tzinfo.DaylightName, tzinfo2.DaylightName), - "Got differing DaylightName values %s and %s\n", - wine_dbgstr_w(tzinfo.DaylightName), wine_dbgstr_w(tzinfo2.DaylightName)); - - memset(&dyn_tzinfo, 0xaa, sizeof(dyn_tzinfo)); - lstrcpyW(dyn_tzinfo.TimeZoneKeyName, dlt_tzname); - + lstrcpyW(dyn_tzinfo.TimeZoneKeyName, L"Greenland Daylight Time"); SetLastError(0xdeadbeef); ret = pGetTimeZoneInformationForYear(2015, &dyn_tzinfo, &tzinfo); + if (ret) + broken_test = TRUE; ok((ret == FALSE && GetLastError() == ERROR_FILE_NOT_FOUND) || - broken(ret == TRUE) /* vista,7 */, - "GetTimeZoneInformationForYear err %u\n", GetLastError()); + broken(broken_test) /* vista,7 */, + "GetTimeZoneInformationForYear err %lu\n", GetLastError()); + + memset(&dyn_tzinfo, 0xaa, sizeof(dyn_tzinfo)); + lstrcpyW(dyn_tzinfo.TimeZoneKeyName, L"Altai Standard Time"); + SetLastError(0xdeadbeef); + ret = pGetTimeZoneInformationForYear(2015, &dyn_tzinfo, &tzinfo); + if (!ret && GetLastError() == ERROR_FILE_NOT_FOUND) + broken_test = TRUE; + ok(ret == TRUE || broken(broken_test) /* before 10 1809 */, + "GetTimeZoneInformationForYear err %lu\n", GetLastError()); + + if (broken(broken_test)) + { + win_skip("Old Windows version\n"); + return; + } + + for (i = 0; i < ARRAY_SIZE(test_data); i++) + { + memset(&dyn_tzinfo, 0xaa, sizeof(dyn_tzinfo)); + memset(&tzinfo, 0xbb, sizeof(tzinfo)); + lstrcpyW(dyn_tzinfo.TimeZoneKeyName, test_data[i].tzname); + dyn_tzinfo.DynamicDaylightTimeDisabled = FALSE; + + ret = pGetTimeZoneInformationForYear(test_data[i].year, &dyn_tzinfo, &tzinfo); + ok(ret == TRUE, "GetTimeZoneInformationForYear failed, err %lu, for %s\n", GetLastError(), wine_dbgstr_w(test_data[i].tzname)); + if (!ret) + continue; + ok(tzinfo.Bias == test_data[i].bias, "Expected bias %ld, got %ld, for %s\n", + test_data[i].bias, tzinfo.Bias, wine_dbgstr_w(test_data[i].tzname)); + ok(tzinfo.StandardDate.wMonth == test_data[i].std_month, "Expected standard month %d, got %d, for %s\n", + test_data[i].std_month, tzinfo.StandardDate.wMonth, wine_dbgstr_w(test_data[i].tzname)); + std_day = day_of_month(&tzinfo.StandardDate, test_data[i].year); + ok(std_day == test_data[i].std_day, "Expected standard day %d, got %d, for %s\n", + test_data[i].std_day, std_day, wine_dbgstr_w(test_data[i].tzname)); + ok(tzinfo.StandardBias == test_data[i].std_bias, "Expected standard bias %ld, got %ld, for %s\n", + test_data[i].std_bias, tzinfo.StandardBias, wine_dbgstr_w(test_data[i].tzname)); + ok(tzinfo.DaylightDate.wMonth == test_data[i].dlt_month, "Expected daylight month %d, got %d, for %s\n", + test_data[i].dlt_month, tzinfo.DaylightDate.wMonth, wine_dbgstr_w(test_data[i].tzname)); + dlt_day = day_of_month(&tzinfo.DaylightDate, test_data[i].year); + ok(dlt_day == test_data[i].dlt_day, "Expected daylight day %d, got %d, for %s\n", + test_data[i].dlt_day, dlt_day, wine_dbgstr_w(test_data[i].tzname)); + ok(tzinfo.DaylightBias == test_data[i].dlt_bias, "Expected daylight bias %ld, got %ld, for %s\n", + test_data[i].dlt_bias, tzinfo.DaylightBias, wine_dbgstr_w(test_data[i].tzname)); + + if (i > 0 && test_data[i-1].tzname == test_data[i].tzname) + { + ok(!lstrcmpW(tzinfo.StandardName, tzinfo2.StandardName), + "Got differing StandardName values %s and %s\n", + wine_dbgstr_w(tzinfo.StandardName), wine_dbgstr_w(tzinfo2.StandardName)); + ok(!lstrcmpW(tzinfo.DaylightName, tzinfo2.DaylightName), + "Got differing DaylightName values %s and %s\n", + wine_dbgstr_w(tzinfo.DaylightName), wine_dbgstr_w(tzinfo2.DaylightName)); + } + + memcpy(&tzinfo2, &tzinfo, sizeof(tzinfo2)); + } +} + +static void test_GetTickCount(void) +{ + DWORD t1, t2, t3; + int i = 0; + + if (!pNtGetTickCount) + { + win_skip("NtGetTickCount not implemented\n"); + return; + } + + do + { + t1 = pNtGetTickCount(); + t2 = GetTickCount(); + t3 = pNtGetTickCount(); + } while(t3 < t1 && i++ < 1); /* allow for wrap, but only once */ + + ok(t1 <= t2, "out of order %ld %ld\n", t1, t2); + ok(t2 <= t3, "out of order %ld %ld\n", t2, t3); +} + +BOOL (WINAPI *pQueryUnbiasedInterruptTime)(ULONGLONG *time); +BOOL (WINAPI *pRtlQueryUnbiasedInterruptTime)(ULONGLONG *time); + +static void test_QueryUnbiasedInterruptTime(void) +{ + ULONGLONG time; + BOOL ret; + + if (pQueryUnbiasedInterruptTime) + { + SetLastError( 0xdeadbeef ); + ret = pQueryUnbiasedInterruptTime( &time ); + ok( ret, "QueryUnbiasedInterruptTime failed err %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = pQueryUnbiasedInterruptTime( NULL ); + ok( !ret, "QueryUnbiasedInterruptTime succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); + } + else win_skip( "QueryUnbiasedInterruptTime not supported\n" ); + if (pRtlQueryUnbiasedInterruptTime) + { + SetLastError( 0xdeadbeef ); + ret = pRtlQueryUnbiasedInterruptTime( &time ); + ok( ret, "RtlQueryUnbiasedInterruptTime failed err %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = pRtlQueryUnbiasedInterruptTime( NULL ); + ok( !ret, "RtlQueryUnbiasedInterruptTime succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); + } + else win_skip( "RtlQueryUnbiasedInterruptTime not supported\n" ); +} + +static void test_processor_idle_cycle_time(void) +{ +#ifdef __REACTOS__ + skip("Cannot build test_processor_idle_cycle_time() until kernelbase is synced.\n"); +#else + unsigned int cpu_count = NtCurrentTeb()->Peb->NumberOfProcessors; + ULONG64 buffer[64]; + ULONG size; + DWORD err; + BOOL bret; + + SetLastError( 0xdeadbeef ); + size = 0; + bret = QueryIdleProcessorCycleTime( &size, NULL ); + err = GetLastError(); + ok( bret == TRUE && err == 0xdeadbeef, "got %d, %ld.\n", bret, err ); + ok( size == cpu_count * sizeof(ULONG64), "got %lu.\n", size ); + + size = 4; + memset( buffer, 0xcc, sizeof(buffer) ); + SetLastError( 0xdeadbeef ); + bret = QueryIdleProcessorCycleTime( &size, NULL ); + err = GetLastError(); + ok( bret == TRUE && err == 0xdeadbeef, "got %d, %ld.\n", bret, err ); + ok( size == 4, "got %lu.\n", size ); + ok( buffer[0] == 0xcccccccccccccccc, "got %#I64x.\n", buffer[0] ); + + size = sizeof(buffer); + SetLastError( 0xdeadbeef ); + bret = QueryIdleProcessorCycleTime( &size, NULL ); + err = GetLastError(); + ok( bret == TRUE && err == 0xdeadbeef, "got %d, %ld.\n", bret, err ); + ok( size == sizeof(buffer), "got %lu.\n", size ); + + size = sizeof(buffer); + SetLastError( 0xdeadbeef ); + bret = QueryIdleProcessorCycleTime( &size, buffer ); + err = GetLastError(); + ok( bret == TRUE && err == 0xdeadbeef, "got %d, %ld.\n", bret, err ); + ok( size == cpu_count * sizeof(ULONG64), "got %lu.\n", size ); + + SetLastError( 0xdeadbeef ); + size = 0; + bret = QueryIdleProcessorCycleTimeEx( 0, &size, NULL ); + err = GetLastError(); + ok( bret == TRUE && err == 0xdeadbeef, "got %d, %ld.\n", bret, err ); + ok( size == cpu_count * sizeof(ULONG64), "got %lu.\n", size ); + + size = 4; + SetLastError( 0xdeadbeef ); + bret = QueryIdleProcessorCycleTimeEx( 0, &size, NULL ); + err = GetLastError(); + ok( bret == TRUE && err == 0xdeadbeef, "got %d, %ld.\n", bret, err ); + ok( size == 4, "got %lu.\n", size ); + + size = sizeof(buffer); + SetLastError( 0xdeadbeef ); + bret = QueryIdleProcessorCycleTimeEx( 0, &size, NULL ); + err = GetLastError(); + ok( bret == TRUE && err == 0xdeadbeef, "got %d, %ld.\n", bret, err ); + ok( size == sizeof(buffer), "got %lu.\n", size ); + + size = sizeof(buffer); + SetLastError( 0xdeadbeef ); + bret = QueryIdleProcessorCycleTimeEx( 0, &size, buffer ); + err = GetLastError(); + ok( bret == TRUE && err == 0xdeadbeef, "got %d, %ld.\n", bret, err ); + ok( size == cpu_count * sizeof(ULONG64), "got %lu.\n", size ); +#endif } START_TEST(time) { HMODULE hKernel = GetModuleHandleA("kernel32"); + HMODULE hntdll = GetModuleHandleA("ntdll"); pTzSpecificLocalTimeToSystemTime = (void *)GetProcAddress(hKernel, "TzSpecificLocalTimeToSystemTime"); pSystemTimeToTzSpecificLocalTime = (void *)GetProcAddress( hKernel, "SystemTimeToTzSpecificLocalTime"); pGetSystemTimes = (void *)GetProcAddress( hKernel, "GetSystemTimes"); @@ -1001,6 +1243,9 @@ START_TEST(time) pGetDynamicTimeZoneInformation = (void *)GetProcAddress(hKernel, "GetDynamicTimeZoneInformation"); pGetSystemTimePreciseAsFileTime = (void *)GetProcAddress(hKernel, "GetSystemTimePreciseAsFileTime"); pGetTimeZoneInformationForYear = (void *)GetProcAddress(hKernel, "GetTimeZoneInformationForYear"); + pQueryUnbiasedInterruptTime = (void *)GetProcAddress(hKernel, "QueryUnbiasedInterruptTime"); + pNtGetTickCount = (void *)GetProcAddress(hntdll, "NtGetTickCount"); + pRtlQueryUnbiasedInterruptTime = (void *)GetProcAddress(hntdll, "RtlQueryUnbiasedInterruptTime"); test_conversions(); test_invalid_arg(); @@ -1012,6 +1257,10 @@ START_TEST(time) test_FileTimeToDosDateTime(); test_GetCalendarInfo(); test_GetDynamicTimeZoneInformation(); + test_GetSystemTimeAsFileTime(); test_GetSystemTimePreciseAsFileTime(); test_GetTimeZoneInformationForYear(); + test_GetTickCount(); + test_QueryUnbiasedInterruptTime(); + test_processor_idle_cycle_time(); } diff --git a/modules/rostests/winetests/kernel32/timer.c b/modules/rostests/winetests/kernel32/timer.c index d2a6138c97a..47cfd11062e 100644 --- a/modules/rostests/winetests/kernel32/timer.c +++ b/modules/rostests/winetests/kernel32/timer.c @@ -20,53 +20,224 @@ #include "wine/test.h" #include "winbase.h" +#include "winternl.h" +#include "winuser.h" static void test_timer(void) { - HANDLE (WINAPI *pCreateWaitableTimerA)( SECURITY_ATTRIBUTES*, BOOL, LPSTR ); - BOOL (WINAPI *pSetWaitableTimer)(HANDLE, LARGE_INTEGER*, LONG, PTIMERAPCROUTINE, LPVOID, BOOL); - HMODULE hker = GetModuleHandleA("kernel32.dll"); HANDLE handle; BOOL r; LARGE_INTEGER due; - pCreateWaitableTimerA = (void*)GetProcAddress( hker, "CreateWaitableTimerA"); - if( !pCreateWaitableTimerA ) - { - win_skip("CreateWaitableTimerA is not available\n"); - return; - } - - pSetWaitableTimer = (void*)GetProcAddress( hker, "SetWaitableTimer"); - if( !pSetWaitableTimer ) - { - win_skip("SetWaitableTimer is not available\n"); - return; - } - /* try once with a positive number */ - handle = pCreateWaitableTimerA( NULL, 0, NULL ); + handle = CreateWaitableTimerA( NULL, 0, NULL ); ok( handle != NULL, "failed to create waitable timer with no name\n" ); due.QuadPart = 10000; - r = pSetWaitableTimer( handle, &due, 0x1f4, NULL, NULL, FALSE ); + r = SetWaitableTimer( handle, &due, 0x1f4, NULL, NULL, FALSE ); ok( r, "failed to set timer\n"); CloseHandle( handle ); /* try once with a negative number */ - handle = pCreateWaitableTimerA( NULL, 0, NULL ); + handle = CreateWaitableTimerA( NULL, 0, NULL ); ok( handle != NULL, "failed to create waitable timer with no name\n" ); due.QuadPart = -10000; - r = pSetWaitableTimer( handle, &due, 0x1f4, NULL, NULL, FALSE ); + r = SetWaitableTimer( handle, &due, 0x1f4, NULL, NULL, FALSE ); ok( r, "failed to set timer\n"); CloseHandle( handle ); } +#define TICKSPERSEC 10000000 + +static BOOL adjust_system_time(int sec) +{ + ULARGE_INTEGER uli; + SYSTEMTIME st; + FILETIME ft; + + GetSystemTimeAsFileTime(&ft); + uli.u.LowPart = ft.dwLowDateTime; + uli.u.HighPart = ft.dwHighDateTime; + uli.QuadPart += (LONGLONG)sec * TICKSPERSEC; + ft.dwLowDateTime = uli.u.LowPart; + ft.dwHighDateTime = uli.u.HighPart; + if (!FileTimeToSystemTime(&ft, &st)) + return FALSE; + return SetSystemTime(&st); +} + +static DWORD WINAPI thread_WaitForSingleObject(void *arg) +{ + HANDLE event; + DWORD t, r; + + event = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(event != NULL, "CreateEvent failed\n"); + t = GetTickCount(); + r = WaitForSingleObject(event, 3000); + ok(r == WAIT_TIMEOUT, "WiatForSingleObject returned %lx\n", r); + CloseHandle(event); + t = GetTickCount() - t; + ok(t > 2000, "t = %ld\n", t); + return 0; +} + +static DWORD WINAPI thread_Sleep(void *arg) +{ + DWORD t = GetTickCount(); + + Sleep(3000); + t = GetTickCount() - t; + ok(t > 2000, "t = %ld\n", t); + return 0; +} + +static DWORD WINAPI thread_SleepEx(void *arg) +{ + DWORD t = GetTickCount(); + + SleepEx(3000, TRUE); + t = GetTickCount() - t; + ok(t > 2000, "t = %ld\n", t); + return 0; +} + +static DWORD WINAPI thread_WaitableTimer_rel(void *arg) +{ + LARGE_INTEGER li; + HANDLE timer; + DWORD t, r; + + li.QuadPart = -3 * TICKSPERSEC; + + timer = CreateWaitableTimerA(NULL, TRUE, NULL); + ok(timer != NULL, "CreateWaitableTimer failed\n"); + + t = GetTickCount(); + r = SetWaitableTimer(timer, &li, 0, NULL, NULL, FALSE); + ok(r, "SetWaitableTimer failed\n"); + + r = WaitForSingleObject(timer, INFINITE); + ok(r == WAIT_OBJECT_0, "WaitForSingleObject returned %ld\n", r); + CloseHandle(timer); + t = GetTickCount() - t; + ok(t > 2000, "t = %ld\n", t); + return 0; +} + +static DWORD WINAPI thread_WaitableTimer_abs(void *arg) +{ + LARGE_INTEGER li; + HANDLE timer; + FILETIME ft; + DWORD t, r; + + GetSystemTimeAsFileTime(&ft); + li.u.LowPart = ft.dwLowDateTime; + li.u.HighPart = ft.dwHighDateTime; + li.QuadPart += 3 * TICKSPERSEC; + + timer = CreateWaitableTimerA(NULL, TRUE, NULL); + ok(timer != NULL, "CreateWaitableTimer failed\n"); + + t = GetTickCount(); + r = SetWaitableTimer(timer, &li, 0, NULL, NULL, FALSE); + ok(r, "SetWaitableTimer failed\n"); + + r = WaitForSingleObject(timer, INFINITE); + ok(r == WAIT_OBJECT_0, "WaitForSingleObject returned %ld\n", r); + CloseHandle(timer); + t = GetTickCount() - t; + ok(t < 2000, "t = %ld\n", t); + return 0; +} + +static DWORD WINAPI thread_WaitableTimer_period(void *arg) +{ + LARGE_INTEGER li; + HANDLE timer; + DWORD t, r; + + li.QuadPart = -1; + + timer = CreateWaitableTimerA(NULL, FALSE, NULL); + ok(timer != NULL, "CreateWaitableTimer failed\n"); + + t = GetTickCount(); + r = SetWaitableTimer(timer, &li, 3000, NULL, NULL, FALSE); + ok(r, "SetWaitableTimer failed\n"); + + r = WaitForSingleObject(timer, INFINITE); + ok(r == WAIT_OBJECT_0, "WaitForSingleObject returned %ld\n", r); + + r = WaitForSingleObject(timer, INFINITE); + ok(r == WAIT_OBJECT_0, "WaitForSingleObject returned %ld\n", r); + CloseHandle(timer); + t = GetTickCount() - t; + ok(t > 2000, "t = %ld\n", t); + return 0; +} + +static DWORD WINAPI thread_SetTimer(void *arg) +{ + DWORD t = GetTickCount(); + UINT_PTR timer; + MSG msg; + + timer = SetTimer(NULL, 0, 3000, NULL); + ok(timer, "SetTimer failed (%ld)\n", GetLastError()); + + while (GetMessageW(&msg, NULL, 0, 0)) + { + DispatchMessageW(&msg); + if (msg.message == WM_TIMER) break; + } + + t = GetTickCount() - t; + ok(t > 2000, "t = %ld\n", t); + KillTimer(NULL, timer); + return 0; +} + +static void test_timeouts(void) +{ + HANDLE threads[7]; + DWORD i; + + if (!adjust_system_time(1)) + { + skip("can't adjust system clock (%ld)\n", GetLastError()); + return; + } + + + threads[0] = CreateThread(NULL, 0, thread_WaitForSingleObject, NULL, 0, NULL); + threads[1] = CreateThread(NULL, 0, thread_Sleep, NULL, 0, NULL); + threads[2] = CreateThread(NULL, 0, thread_SleepEx, NULL, 0, NULL); + threads[3] = CreateThread(NULL, 0, thread_WaitableTimer_rel, NULL, 0, NULL); + threads[4] = CreateThread(NULL, 0, thread_WaitableTimer_abs, NULL, 0, NULL); + threads[5] = CreateThread(NULL, 0, thread_WaitableTimer_period, NULL, 0, NULL); + threads[6] = CreateThread(NULL, 0, thread_SetTimer, NULL, 0, NULL); + for(i=0; i #include +#include "ntstatus.h" +#define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" #include "tlhelp32.h" #include "wine/test.h" #include "winuser.h" +#include "winternl.h" static char selfname[MAX_PATH]; @@ -38,9 +41,12 @@ static BOOL (WINAPI *pProcess32First)(HANDLE, LPPROCESSENTRY32); static BOOL (WINAPI *pProcess32Next)(HANDLE, LPPROCESSENTRY32); static BOOL (WINAPI *pThread32First)(HANDLE, LPTHREADENTRY32); static BOOL (WINAPI *pThread32Next)(HANDLE, LPTHREADENTRY32); +static NTSTATUS (WINAPI * pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, void *, ULONG, ULONG *); /* 1 minute should be more than enough */ #define WAIT_TIME (60 * 1000) +/* Specify the number of simultaneous threads to test */ +#define NUM_THREADS 4 static DWORD WINAPI sub_thread(void* pmt) { @@ -118,11 +124,15 @@ static void test_process(DWORD curr_pid, DWORD sub_pcs_pid) { if (pe.th32ProcessID == curr_pid) found++; if (pe.th32ProcessID == sub_pcs_pid) { childpos = num; found++; } - trace("PID=%x %s\n", pe.th32ProcessID, pe.szExeFile); + trace("PID=%lx %s\n", pe.th32ProcessID, pe.szExeFile); num++; } while (pProcess32Next( hSnapshot, &pe )); } +#if defined(__REACTOS__) && defined(_WIN64) + ok(found == 2 || broken(found == 0) /* x86_64 */, "couldn't find self and/or sub-process in process list\n"); +#else ok(found == 2, "couldn't find self and/or sub-process in process list\n"); +#endif /* check that first really resets the enumeration */ found = 0; @@ -132,11 +142,15 @@ static void test_process(DWORD curr_pid, DWORD sub_pcs_pid) { if (pe.th32ProcessID == curr_pid) found++; if (pe.th32ProcessID == sub_pcs_pid) found++; - trace("PID=%x %s\n", pe.th32ProcessID, pe.szExeFile); + trace("PID=%lx %s\n", pe.th32ProcessID, pe.szExeFile); num--; } while (pProcess32Next( hSnapshot, &pe )); } +#if defined(__REACTOS__) && defined(_WIN64) + ok(found == 2 || broken(found == 0) /* x86_64 */, "couldn't find self and/or sub-process in process list\n"); +#else ok(found == 2, "couldn't find self and/or sub-process in process list\n"); +#endif ok(!num, "mismatch in counting\n"); /* one broken program does Process32First() and does not expect anything @@ -150,15 +164,169 @@ static void test_process(DWORD curr_pid, DWORD sub_pcs_pid) ok(!pProcess32First( hSnapshot, &pe ), "shouldn't return a process\n"); } +static DWORD WINAPI get_id_thread(void* curr_pid) +{ + HANDLE hSnapshot; + THREADENTRY32 te; + HANDLE ev, threads[NUM_THREADS]; + DWORD thread_ids[NUM_THREADS]; + DWORD thread_traversed[NUM_THREADS]; + DWORD tid, first_tid = 0; + BOOL found = FALSE; + int i, matched_idx = -1; + ULONG buf_size = 0; + NTSTATUS status; + BYTE* pcs_buffer = NULL; + DWORD pcs_offset = 0; + SYSTEM_PROCESS_INFORMATION* spi = NULL; + + ev = CreateEventW(NULL, TRUE, FALSE, NULL); + ok(ev != NULL, "Cannot create event\n"); + + for (i = 0; i < NUM_THREADS; i++) + { + threads[i] = CreateThread(NULL, 0, sub_thread, ev, 0, &tid); + ok(threads[i] != NULL, "Cannot create thread\n"); + thread_ids[i] = tid; + } + + hSnapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + ok(hSnapshot != NULL, "Cannot create snapshot\n"); + + /* Check that this current process is enumerated */ + te.dwSize = sizeof(te); + ok(pThread32First(hSnapshot, &te), "Thread cannot traverse\n"); + do + { + if (found) + { + if (te.th32OwnerProcessID != PtrToUlong(curr_pid)) break; + + if (matched_idx >= 0) + { + thread_traversed[matched_idx++] = te.th32ThreadID; + if (matched_idx >= NUM_THREADS) break; + } + else if (thread_ids[0] == te.th32ThreadID) + { + matched_idx = 0; + thread_traversed[matched_idx++] = te.th32ThreadID; + } + } + else if (te.th32OwnerProcessID == PtrToUlong(curr_pid)) + { + found = TRUE; + first_tid = te.th32ThreadID; + } + } + while (pThread32Next(hSnapshot, &te)); + + ok(found, "Couldn't find self and/or sub-process in process list\n"); + + /* Check if the thread order is strictly consistent */ + found = FALSE; + for (i = 0; i < NUM_THREADS; i++) + { + if (thread_traversed[i] != thread_ids[i]) + { + found = TRUE; + break; + } + /* Reset data */ + thread_traversed[i] = 0; + } + ok(found == FALSE, "The thread order is not strictly consistent\n"); + + /* Determine the order by NtQuerySystemInformation function */ + + while ((status = NtQuerySystemInformation(SystemProcessInformation, + pcs_buffer, buf_size, &buf_size)) == STATUS_INFO_LENGTH_MISMATCH) + { + free(pcs_buffer); + pcs_buffer = malloc(buf_size); + } + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + found = FALSE; + matched_idx = -1; + + do + { + spi = (SYSTEM_PROCESS_INFORMATION*)&pcs_buffer[pcs_offset]; + if (spi->UniqueProcessId == curr_pid) + { + found = TRUE; + break; + } + pcs_offset += spi->NextEntryOffset; + } while (spi->NextEntryOffset != 0); + + ok(found && spi, "No process found\n"); + for (i = 0; i < spi->dwThreadCount; i++) + { + tid = HandleToULong(spi->ti[i].ClientId.UniqueThread); + if (matched_idx > 0) + { + thread_traversed[matched_idx++] = tid; + if (matched_idx >= NUM_THREADS) break; + } + else if (tid == thread_ids[0]) + { + matched_idx = 0; + thread_traversed[matched_idx++] = tid; + } + } + free(pcs_buffer); + + ok(matched_idx > 0, "No thread id match found\n"); + + found = FALSE; + for (i = 0; i < NUM_THREADS; i++) + { + if (thread_traversed[i] != thread_ids[i]) + { + found = TRUE; + break; + } + } + ok(found == FALSE, "wrong order in NtQuerySystemInformation function\n"); + + SetEvent(ev); + WaitForMultipleObjects( NUM_THREADS, threads, TRUE, WAIT_TIME ); + for (i = 0; i < NUM_THREADS; i++) + CloseHandle(threads[i]); + CloseHandle(ev); + CloseHandle(hSnapshot); + + return first_tid; +} + +static void test_main_thread(DWORD curr_pid, DWORD main_tid) +{ + HANDLE thread; + DWORD tid = 0; + int error; + + /* Check that the main thread id is first one in this thread. */ + tid = get_id_thread(ULongToPtr(curr_pid)); + ok(tid == main_tid, "The first thread id returned is not the main thread id\n"); + + /* Check that the main thread id is first one in other thread. */ + thread = CreateThread(NULL, 0, get_id_thread, ULongToPtr(curr_pid), 0, NULL); + error = WaitForSingleObject(thread, WAIT_TIME); + ok(error == WAIT_OBJECT_0, "Thread did not complete within timelimit\n"); + + ok(GetExitCodeThread(thread, &tid), "Could not retrieve exit code\n"); + ok(tid == main_tid, "The first thread id returned is not the main thread id\n"); +} + static void test_thread(DWORD curr_pid, DWORD sub_pcs_pid) { HANDLE hSnapshot; THREADENTRY32 te; MODULEENTRY32 me; - int num = 0; unsigned curr_found = 0; unsigned sub_found = 0; - + hSnapshot = pCreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); ok(hSnapshot != NULL, "Cannot create snapshot\n"); @@ -171,8 +339,7 @@ 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++; if (winetest_debug > 1) - trace("PID=%x TID=%x %d\n", te.th32OwnerProcessID, te.th32ThreadID, te.tpBasePri); - num++; + trace("PID=%lx TID=%lx %ld\n", te.th32OwnerProcessID, te.th32ThreadID, te.tpBasePri); } while (pThread32Next( hSnapshot, &te )); } ok(curr_found, "couldn't find self in thread list\n"); @@ -188,8 +355,7 @@ 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++; if (winetest_debug > 1) - trace("PID=%x TID=%x %d\n", te.th32OwnerProcessID, te.th32ThreadID, te.tpBasePri); - num--; + trace("PID=%lx TID=%lx %ld\n", te.th32OwnerProcessID, te.th32ThreadID, te.tpBasePri); } while (pThread32Next( hSnapshot, &te )); } ok(curr_found, "couldn't find self in thread list\n"); @@ -217,8 +383,6 @@ static const char* sub_expected_modules[] = "ntdll.dll" }; -#define NUM_OF(x) (sizeof(x) / sizeof(x[0])) - static void test_module(DWORD pid, const char* expected[], unsigned num_expected) { HANDLE hSnapshot; @@ -229,7 +393,7 @@ static void test_module(DWORD pid, const char* expected[], unsigned num_expected unsigned i; int num = 0; - ok(NUM_OF(found) >= num_expected, "Internal: bump found[] size\n"); + ok(ARRAY_SIZE(found) >= num_expected, "Internal: bump found[] size\n"); hSnapshot = pCreateToolhelp32Snapshot( TH32CS_SNAPMODULE, pid ); ok(hSnapshot != NULL, "Cannot create snapshot\n"); @@ -240,7 +404,7 @@ static void test_module(DWORD pid, const char* expected[], unsigned num_expected { do { - trace("PID=%x base=%p size=%x %s %s\n", + trace("PID=%lx base=%p size=%lx %s %s\n", me.th32ProcessID, me.modBaseAddr, me.modBaseSize, me.szExePath, me.szModule); ok(me.th32ProcessID == pid, "wrong returned process id\n"); for (i = 0; i < num_expected; i++) @@ -259,7 +423,7 @@ static void test_module(DWORD pid, const char* expected[], unsigned num_expected { do { - trace("PID=%x base=%p size=%x %s %s\n", + trace("PID=%lx base=%p size=%lx %s %s\n", me.th32ProcessID, me.modBaseAddr, me.modBaseSize, me.szExePath, me.szModule); for (i = 0; i < num_expected; i++) if (!lstrcmpiA(expected[i], me.szModule)) found[i]++; @@ -286,13 +450,14 @@ START_TEST(toolhelp) DWORD pid = GetCurrentProcessId(); int r; char *p, module[MAX_PATH]; - char buffer[MAX_PATH]; + char buffer[MAX_PATH + 21]; SECURITY_ATTRIBUTES sa; PROCESS_INFORMATION info; STARTUPINFOA startup; HANDLE ev1, ev2; DWORD w; HANDLE hkernel32 = GetModuleHandleA("kernel32"); + HANDLE hntdll = GetModuleHandleA("ntdll.dll"); pCreateToolhelp32Snapshot = (VOID *) GetProcAddress(hkernel32, "CreateToolhelp32Snapshot"); pModule32First = (VOID *) GetProcAddress(hkernel32, "Module32First"); @@ -301,11 +466,13 @@ START_TEST(toolhelp) pProcess32Next = (VOID *) GetProcAddress(hkernel32, "Process32Next"); pThread32First = (VOID *) GetProcAddress(hkernel32, "Thread32First"); pThread32Next = (VOID *) GetProcAddress(hkernel32, "Thread32Next"); + pNtQuerySystemInformation = (VOID *) GetProcAddress(hntdll, "NtQuerySystemInformation"); if (!pCreateToolhelp32Snapshot || !pModule32First || !pModule32Next || !pProcess32First || !pProcess32Next || - !pThread32First || !pThread32Next) + !pThread32First || !pThread32Next || + !pNtQuerySystemInformation) { win_skip("Needed functions are not available, most likely running on Windows NT\n"); return; @@ -327,7 +494,7 @@ START_TEST(toolhelp) startup.dwFlags = STARTF_USESHOWWINDOW; startup.wShowWindow = SW_SHOWNORMAL; - sprintf(buffer, "%s tests/toolhelp.c %lu %lu", selfname, (DWORD_PTR)ev1, (DWORD_PTR)ev2); + sprintf(buffer, "%s toolhelp %Iu %Iu", selfname, (DWORD_PTR)ev1, (DWORD_PTR)ev2); ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &info), "CreateProcess\n"); /* wait for child to be initialized */ w = WaitForSingleObject(ev1, WAIT_TIME); @@ -341,9 +508,10 @@ START_TEST(toolhelp) test_process(pid, info.dwProcessId); test_thread(pid, info.dwProcessId); - test_module(pid, curr_expected_modules, NUM_OF(curr_expected_modules)); - test_module(info.dwProcessId, sub_expected_modules, NUM_OF(sub_expected_modules)); + test_main_thread(pid, GetCurrentThreadId()); + test_module(pid, curr_expected_modules, ARRAY_SIZE(curr_expected_modules)); + test_module(info.dwProcessId, sub_expected_modules, ARRAY_SIZE(sub_expected_modules)); SetEvent(ev2); - winetest_wait_child_process( info.hProcess ); + wait_child_process( info.hProcess ); } diff --git a/modules/rostests/winetests/kernel32/version.c b/modules/rostests/winetests/kernel32/version.c index 5f7a9bb03f5..1add5963414 100644 --- a/modules/rostests/winetests/kernel32/version.c +++ b/modules/rostests/winetests/kernel32/version.c @@ -18,16 +18,28 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "ntstatus.h" +#define WIN32_NO_STATUS #include "wine/test.h" #include "winbase.h" #include "winternl.h" +#include "appmodel.h" static BOOL (WINAPI * pGetProductInfo)(DWORD, DWORD, DWORD, DWORD, DWORD *); +static UINT (WINAPI * pEnumSystemFirmwareTables)(DWORD, void *, DWORD); +static UINT (WINAPI * pGetSystemFirmwareTable)(DWORD, DWORD, void *, DWORD); +static LONG (WINAPI * pPackageIdFromFullName)(const WCHAR *, UINT32, UINT32 *, BYTE *); +static NTSTATUS (WINAPI * pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, void *, ULONG, ULONG *); static NTSTATUS (WINAPI * pRtlGetVersion)(RTL_OSVERSIONINFOEXW *); #define GET_PROC(func) \ p##func = (void *)GetProcAddress(hmod, #func); +/* Firmware table providers */ +#define ACPI 0x41435049 +#define FIRM 0x4649524D +#define RSMB 0x52534D42 + static void init_function_pointers(void) { HMODULE hmod; @@ -35,9 +47,13 @@ static void init_function_pointers(void) hmod = GetModuleHandleA("kernel32.dll"); GET_PROC(GetProductInfo); + GET_PROC(EnumSystemFirmwareTables); + GET_PROC(GetSystemFirmwareTable); + GET_PROC(PackageIdFromFullName); hmod = GetModuleHandleA("ntdll.dll"); + GET_PROC(NtQuerySystemInformation); GET_PROC(RtlGetVersion); } @@ -65,7 +81,12 @@ static void test_GetProductInfo(void) DWORD *entry = table; +#if defined(__REACTOS__) && DLL_EXPORT_VERSION >= 0x600 + /* FIXME: GetProductInfo is a STUB on ReactOS */ + if (is_reactos() || !pGetProductInfo) +#else if (!pGetProductInfo) +#endif { /* Not present before Vista */ win_skip("GetProductInfo() not available\n"); @@ -81,10 +102,10 @@ static void test_GetProductInfo(void) if (entry[0] >= 6) ok(res && (product > PRODUCT_UNDEFINED) && (product <= PRODUCT_ENTERPRISE_S_N_EVALUATION), - "got %d and 0x%x (expected TRUE and a valid PRODUCT_* value)\n", res, product); + "got %ld and 0x%lx (expected TRUE and a valid PRODUCT_* value)\n", res, product); else ok(!res && !product && (GetLastError() == 0xdeadbeef), - "got %d and 0x%x with 0x%x (expected FALSE and PRODUCT_UNDEFINED with LastError untouched)\n", + "got %ld and 0x%lx with 0x%lx (expected FALSE and PRODUCT_UNDEFINED with LastError untouched)\n", res, product, GetLastError()); entry+= 4; @@ -94,7 +115,7 @@ static void test_GetProductInfo(void) SetLastError(0xdeadbeef); res = pGetProductInfo(6, 1, 0, 0, NULL); ok( (!res) && (GetLastError() == 0xdeadbeef), - "got %d with 0x%x (expected FALSE with LastError untouched\n", res, GetLastError()); + "got %ld with 0x%lx (expected FALSE with LastError untouched\n", res, GetLastError()); } static void test_GetVersionEx(void) @@ -115,7 +136,7 @@ static void test_GetVersionEx(void) ok(!ret, "Expected GetVersionExA to fail\n"); ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER || GetLastError() == 0xdeadbeef /* Win9x */, - "Expected ERROR_INSUFFICIENT_BUFFER or 0xdeadbeef (Win9x), got %d\n", + "Expected ERROR_INSUFFICIENT_BUFFER or 0xdeadbeef (Win9x), got %ld\n", GetLastError()); SetLastError(0xdeadbeef); @@ -124,7 +145,7 @@ static void test_GetVersionEx(void) ok(!ret, "Expected GetVersionExA to fail\n"); ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER || GetLastError() == 0xdeadbeef /* Win9x */, - "Expected ERROR_INSUFFICIENT_BUFFER or 0xdeadbeef (Win9x), got %d\n", + "Expected ERROR_INSUFFICIENT_BUFFER or 0xdeadbeef (Win9x), got %ld\n", GetLastError()); SetLastError(0xdeadbeef); @@ -133,7 +154,7 @@ static void test_GetVersionEx(void) ok(!ret, "Expected GetVersionExA to fail\n"); ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER || GetLastError() == 0xdeadbeef /* Win9x */, - "Expected ERROR_INSUFFICIENT_BUFFER or 0xdeadbeef (Win9x), got %d\n", + "Expected ERROR_INSUFFICIENT_BUFFER or 0xdeadbeef (Win9x), got %ld\n", GetLastError()); SetLastError(0xdeadbeef); @@ -141,7 +162,7 @@ static void test_GetVersionEx(void) ret = GetVersionExA(&infoA); ok(ret, "Expected GetVersionExA to succeed\n"); ok(GetLastError() == 0xdeadbeef, - "Expected 0xdeadbeef, got %d\n", GetLastError()); + "Expected 0xdeadbeef, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); infoExA.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXA); @@ -181,8 +202,6 @@ static void test_VerifyVersionInfo(void) DWORD condition3; DWORD typemask4; DWORD condition4; - - BOOL todo; } verify_version_tests[] = { { @@ -598,12 +617,12 @@ static void test_VerifyVersionInfo(void) if (rtlinfo.dwMajorVersion != 6 || rtlinfo.dwMinorVersion != 2) { - win_skip("GetVersionEx and VerifyVersionInfo are faking values\n"); + skip("GetVersionEx and VerifyVersionInfo are faking values\n"); return; } } - for (i = 0; i < sizeof(verify_version_tests)/sizeof(verify_version_tests[0]); i++) + for (i = 0; i < ARRAY_SIZE(verify_version_tests); i++) { struct verify_version_test *test = &verify_version_tests[i]; DWORD srcinfo = test->srcinfo; @@ -653,12 +672,9 @@ static void test_VerifyVersionInfo(void) SetLastError(0xdeadbeef); ret = VerifyVersionInfoA(&info, test->verifymask, mask); - todo_wine_if(test->todo) - { ok(test->err ? !ret : ret, "%u: unexpected return value %d.\n", i, ret); if (!ret) - ok(GetLastError() == test->err, "%u: unexpected error code %d, expected %d.\n", i, GetLastError(), test->err); - } + ok(GetLastError() == test->err, "%u: unexpected error code %ld, expected %ld.\n", i, GetLastError(), test->err); } /* test handling of version numbers */ @@ -669,21 +685,21 @@ static void test_VerifyVersionInfo(void) ret = VerifyVersionInfoA(&info, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, VerSetConditionMask(VerSetConditionMask(0, VER_MINORVERSION, VER_GREATER_EQUAL), VER_MAJORVERSION, VER_GREATER_EQUAL)); - ok(ret, "VerifyVersionInfoA failed with error %d\n", GetLastError()); + ok(ret, "VerifyVersionInfoA failed with error %ld\n", GetLastError()); info.dwMinorVersion = 0; info.wServicePackMajor = 10; ret = VerifyVersionInfoA(&info, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, VerSetConditionMask(VerSetConditionMask(0, VER_MINORVERSION, VER_GREATER_EQUAL), VER_MAJORVERSION, VER_GREATER_EQUAL)); - ok(ret, "VerifyVersionInfoA failed with error %d\n", GetLastError()); + ok(ret, "VerifyVersionInfoA failed with error %ld\n", GetLastError()); info.wServicePackMajor = 0; info.wServicePackMinor = 10; ret = VerifyVersionInfoA(&info, VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, VerSetConditionMask(VerSetConditionMask(0, VER_MINORVERSION, VER_GREATER_EQUAL), VER_MAJORVERSION, VER_GREATER_EQUAL)); - ok(ret, "VerifyVersionInfoA failed with error %d\n", GetLastError()); + ok(ret, "VerifyVersionInfoA failed with error %ld\n", GetLastError()); /* test bad dwOSVersionInfoSize */ info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXA); @@ -691,14 +707,444 @@ static void test_VerifyVersionInfo(void) info.dwOSVersionInfoSize = 0; ret = VerifyVersionInfoA(&info, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL)); - ok(ret, "VerifyVersionInfoA failed with error %d\n", GetLastError()); + ok(ret, "VerifyVersionInfoA failed with error %ld\n", GetLastError()); +} + +static void test_SystemFirmwareTable(void) +{ + static const ULONG min_sfti_len = FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer); + ULONG expected_len; + UINT len; + NTSTATUS status; + SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti; + UCHAR *smbios_table; + + if (!pGetSystemFirmwareTable || !pEnumSystemFirmwareTables) + { + win_skip("SystemFirmwareTable functions not available\n"); + return; + } + + sfti = HeapAlloc(GetProcessHeap(), 0, sizeof(*sfti)); + ok(!!sfti, "Failed to allocate memory\n"); + sfti->ProviderSignature = RSMB; + sfti->Action = SystemFirmwareTable_Get; + sfti->TableID = 0; + status = pNtQuerySystemInformation(SystemFirmwareTableInformation, sfti, min_sfti_len, &expected_len); + if (expected_len == 0) /* xp, 2003 */ + { + win_skip("SystemFirmwareTableInformation is not available\n"); + HeapFree(GetProcessHeap(), 0, sfti); + return; + } +#ifdef __REACTOS__ + ok( status == STATUS_BUFFER_TOO_SMALL || broken(status == STATUS_INVALID_DEVICE_REQUEST) /* Vista x64 ROS testbot */, "NtQuerySystemInformation failed %lx\n", status ); +#else + ok( status == STATUS_BUFFER_TOO_SMALL, "NtQuerySystemInformation failed %lx\n", status ); +#endif + sfti = HeapReAlloc(GetProcessHeap(), 0, sfti, expected_len); + status = pNtQuerySystemInformation(SystemFirmwareTableInformation, sfti, expected_len, &expected_len); +#ifdef __REACTOS__ + ok( !status || broken(status == STATUS_INVALID_DEVICE_REQUEST) /* Vista x64 ROS testbot */, "NtQuerySystemInformation failed %lx\n", status ); +#else + ok( !status, "NtQuerySystemInformation failed %lx\n", status ); +#endif + + expected_len -= min_sfti_len; + ok( sfti->TableBufferLength == expected_len, "wrong len %lu/%lx\n", + sfti->TableBufferLength, expected_len ); + len = pGetSystemFirmwareTable(RSMB, 0, NULL, 0); + ok(len == expected_len, "Expected length %lu, got %u\n", expected_len, len); + + smbios_table = HeapAlloc(GetProcessHeap(), 0, expected_len); + len = pGetSystemFirmwareTable(RSMB, 0, smbios_table, expected_len); + ok(len == expected_len, "Expected length %lu, got %u\n", expected_len, len); + ok(len == 0 || !memcmp(smbios_table, sfti->TableBuffer, 6), + "Expected prologue %02x %02x %02x %02x %02x %02x, got %02x %02x %02x %02x %02x %02x\n", + sfti->TableBuffer[0], sfti->TableBuffer[1], sfti->TableBuffer[2], + sfti->TableBuffer[3], sfti->TableBuffer[4], sfti->TableBuffer[5], + smbios_table[0], smbios_table[1], smbios_table[2], + smbios_table[3], smbios_table[4], smbios_table[5]); + HeapFree(GetProcessHeap(), 0, smbios_table); + + sfti->Action = SystemFirmwareTable_Enumerate; + status = pNtQuerySystemInformation(SystemFirmwareTableInformation, sfti, min_sfti_len, &expected_len); + ok( status == STATUS_BUFFER_TOO_SMALL, "NtQuerySystemInformation failed %lx\n", status ); + sfti = HeapReAlloc(GetProcessHeap(), 0, sfti, expected_len); + status = pNtQuerySystemInformation(SystemFirmwareTableInformation, sfti, expected_len, &expected_len); + ok( !status, "NtQuerySystemInformation failed %lx\n", status ); + ok( expected_len == min_sfti_len + sizeof(UINT), "wrong len %lu\n", expected_len ); + ok( sfti->TableBufferLength == sizeof(UINT), "wrong len %lu\n", sfti->TableBufferLength ); + ok( *(UINT *)sfti->TableBuffer == 0, "wrong table id %x\n", *(UINT *)sfti->TableBuffer ); + + len = pEnumSystemFirmwareTables( RSMB, NULL, 0 ); + ok( len == sizeof(UINT), "wrong len %u\n", len ); + smbios_table = malloc( len ); + len = pEnumSystemFirmwareTables( RSMB, smbios_table, len ); + ok( len == sizeof(UINT), "wrong len %u\n", len ); + ok( *(UINT *)smbios_table == 0, "wrong table id %x\n", *(UINT *)smbios_table ); + free( smbios_table ); + + HeapFree(GetProcessHeap(), 0, sfti); +} + +static const struct +{ + UINT32 code; + const WCHAR *name; + BOOL broken; +} +arch_data[] = +{ + {PROCESSOR_ARCHITECTURE_INTEL, L"X86"}, + {PROCESSOR_ARCHITECTURE_ARM, L"Arm"}, + {PROCESSOR_ARCHITECTURE_AMD64, L"X64"}, + {PROCESSOR_ARCHITECTURE_NEUTRAL, L"Neutral"}, + {PROCESSOR_ARCHITECTURE_ARM64, L"Arm64", TRUE /* Before Win10. */}, + {PROCESSOR_ARCHITECTURE_UNKNOWN, L"Unknown", TRUE /* Before Win10 1709. */}, +}; + +static const WCHAR *arch_string_from_code(UINT32 arch) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(arch_data); ++i) + if (arch_data[i].code == arch) + return arch_data[i].name; + + return NULL; +} + +static unsigned int get_package_str_size(const WCHAR *str) +{ + return str ? (lstrlenW(str) + 1) * sizeof(*str) : 0; +} + +static unsigned int get_package_id_size(const PACKAGE_ID *id) +{ + return sizeof(*id) + get_package_str_size(id->name) + + get_package_str_size(id->resourceId) + 14 * sizeof(WCHAR); +} + +static void packagefullname_from_packageid(WCHAR *buffer, size_t count, const PACKAGE_ID *id) +{ + swprintf(buffer, count, L"%s_%u.%u.%u.%u_%s_%s_%s", id->name, id->version.Major, + id->version.Minor, id->version.Build, id->version.Revision, + arch_string_from_code(id->processorArchitecture), id->resourceId, + id->publisherId); +} + +static void test_PackageIdFromFullName(void) +{ + static const PACKAGE_ID test_package_id = + { + 0, PROCESSOR_ARCHITECTURE_INTEL, + {{.Major = 1, .Minor = 2, .Build = 3, .Revision = 4}}, + (WCHAR *)L"TestPackage", NULL, + (WCHAR *)L"TestResourceId", (WCHAR *)L"0abcdefghjkme" + }; + UINT32 size, expected_size; + PACKAGE_ID test_id; + WCHAR fullname[512]; + BYTE id_buffer[512]; + unsigned int i; + PACKAGE_ID *id; + LONG ret; + + if (!pPackageIdFromFullName) + { + win_skip("PackageIdFromFullName not available.\n"); + return; + } +#ifdef __REACTOS__ + if (GetNTVersion() < _WIN32_WINNT_WIN10) { + skip("test_PackageIdFromFullName() broken on Win8.1 and older\n"); + return; + } +#endif + + packagefullname_from_packageid(fullname, ARRAY_SIZE(fullname), &test_package_id); + + id = (PACKAGE_ID *)id_buffer; + + memset(id_buffer, 0xcc, sizeof(id_buffer)); + expected_size = get_package_id_size(&test_package_id); + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(fullname, 0, &size, id_buffer); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %lu.\n", ret); + ok(size == expected_size, "Got unexpected length %u, expected %u.\n", size, expected_size); + ok(!lstrcmpW(id->name, test_package_id.name), "Got unexpected name %s.\n", debugstr_w(id->name)); + ok(!lstrcmpW(id->resourceId, test_package_id.resourceId), "Got unexpected resourceId %s.\n", + debugstr_w(id->resourceId)); + ok(!lstrcmpW(id->publisherId, test_package_id.publisherId), "Got unexpected publisherId %s.\n", + debugstr_w(id->publisherId)); + ok(!id->publisher, "Got unexpected publisher %s.\n", debugstr_w(id->publisher)); + ok(id->processorArchitecture == PROCESSOR_ARCHITECTURE_INTEL, "Got unexpected processorArchitecture %u.\n", + id->processorArchitecture); + ok(id->version.Version == 0x0001000200030004, "Got unexpected Version %s.\n", + wine_dbgstr_longlong(id->version.Version)); + ok((BYTE *)id->name == id_buffer + sizeof(*id), "Got unexpected name %p, buffer %p.\n", id->name, id_buffer); + ok((BYTE *)id->resourceId == (BYTE *)id->name + (lstrlenW(id->name) + 1) * 2, + "Got unexpected resourceId %p, buffer %p.\n", id->resourceId, id_buffer); + ok((BYTE *)id->publisherId == (BYTE *)id->resourceId + (lstrlenW(id->resourceId) + 1) * 2, + "Got unexpected publisherId %p, buffer %p.\n", id->resourceId, id_buffer); + + ret = pPackageIdFromFullName(fullname, 0, NULL, id_buffer); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %ld.\n", ret); + + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(NULL, 0, &size, id_buffer); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %ld.\n", ret); + ok(size == sizeof(id_buffer), "Got unexpected size %u.\n", size); + + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(fullname, 0, &size, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %ld.\n", ret); + ok(size == sizeof(id_buffer), "Got unexpected size %u.\n", size); + + size = expected_size - 1; + ret = pPackageIdFromFullName(fullname, 0, &size, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %ld.\n", ret); + ok(size == expected_size - 1, "Got unexpected size %u.\n", size); + + size = expected_size - 1; + ret = pPackageIdFromFullName(fullname, 0, &size, id_buffer); + ok(ret == ERROR_INSUFFICIENT_BUFFER, "Got unexpected ret %ld.\n", ret); + ok(size == expected_size, "Got unexpected size %u.\n", size); + + size = 0; + ret = pPackageIdFromFullName(fullname, 0, &size, NULL); + ok(ret == ERROR_INSUFFICIENT_BUFFER, "Got unexpected ret %ld.\n", ret); + ok(size == expected_size, "Got unexpected size %u.\n", size); + + for (i = 0; i < ARRAY_SIZE(arch_data); ++i) + { + test_id = test_package_id; + test_id.processorArchitecture = arch_data[i].code; + packagefullname_from_packageid(fullname, ARRAY_SIZE(fullname), &test_id); + size = expected_size; + ret = pPackageIdFromFullName(fullname, 0, &size, id_buffer); + ok(ret == ERROR_SUCCESS || broken(arch_data[i].broken && ret == ERROR_INVALID_PARAMETER), + "Got unexpected ret %lu.\n", ret); + if (ret != ERROR_SUCCESS) + continue; + ok(size == expected_size, "Got unexpected length %u, expected %u.\n", size, expected_size); + ok(id->processorArchitecture == arch_data[i].code, "Got unexpected processorArchitecture %u, arch %S.\n", + id->processorArchitecture, arch_data[i].name); + } + + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(L"TestPackage_1.2.3.4_X86_TestResourceId_0abcdefghjkme", 0, &size, id_buffer); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %lu.\n", ret); + + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(L"TestPackage_1.2.3.4_X86_TestResourceId_abcdefghjkme", 0, &size, id_buffer); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); + + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(L"TestPackage_1.2.3.4_X86_TestResourceId_0abcdefghjkmee", 0, &size, id_buffer); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); + + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(L"TestPackage_1.2.3_X86_TestResourceId_0abcdefghjkme", 0, &size, id_buffer); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); + + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(L"TestPackage_1.2.3.4_X86_TestResourceId_0abcdefghjkme_", 0, &size, id_buffer); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); + + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(L"TestPackage_1.2.3.4_X86__0abcdefghjkme", 0, &size, id_buffer); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %lu.\n", ret); + ok(!lstrcmpW(id->resourceId, L""), "Got unexpected resourceId %s.\n", debugstr_w(id->resourceId)); + + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(L"TestPackage_1.2.3.4_X86_0abcdefghjkme", 0, &size, id_buffer); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); +} + +#define TEST_VERSION_WIN7 1 +#define TEST_VERSION_WIN8 2 +#define TEST_VERSION_WIN8_1 4 +#define TEST_VERSION_WIN10 8 + +static const struct +{ + unsigned int pe_version_major, pe_version_minor; + unsigned int manifest_versions; + unsigned int expected_major, expected_minor; +} +test_pe_os_version_tests[] = +{ + { 4, 0, 0, 6, 2}, + { 4, 0, TEST_VERSION_WIN10, 10, 0}, + { 6, 3, TEST_VERSION_WIN8, 6, 2}, + {10, 0, 0, 10, 0}, + { 6, 3, 0, 6, 3}, + { 6, 4, 0, 6, 3}, + { 9, 0, 0, 6, 3}, + {11, 0, 0, 10, 0}, + {10, 0, + TEST_VERSION_WIN7 | TEST_VERSION_WIN8 | TEST_VERSION_WIN8_1, + 6, 3}, +}; + +static void test_pe_os_version_child(unsigned int test) +{ + OSVERSIONINFOEXA info; + BOOL ret; + + info.dwOSVersionInfoSize = sizeof(info); + ret = GetVersionExA((OSVERSIONINFOA *)&info); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + ok(info.dwMajorVersion == test_pe_os_version_tests[test].expected_major, + "Test %u, expected major version %u, got %lu.\n", test, test_pe_os_version_tests[test].expected_major, + info.dwMajorVersion); + ok(info.dwMinorVersion == test_pe_os_version_tests[test].expected_minor, + "Test %u, expected minor version %u, got %lu.\n", test, test_pe_os_version_tests[test].expected_minor, + info.dwMinorVersion); +} + +static void test_pe_os_version(void) +{ + static const char manifest_header[] = + "" + "\n" + "\t\n" + "\t\t\n"; + static const char manifest_footer[] = + "\t\t\n" + "\t\n" + "\n"; + static const char *version_guids[] = + { + "{35138b9a-5d96-4fbd-8e2d-a2440225f93a}", + "{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}", + "{1f676c76-80e1-4239-95bb-83d0f6d0da78}", + "{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}", + }; + LONG hdr_offset, offset_major, offset_minor; + char str[MAX_PATH], tmp_exe_name[9]; + RTL_OSVERSIONINFOEXW rtlinfo; + STARTUPINFOA si = { 0 }; + PROCESS_INFORMATION pi; + DWORD result, code; + unsigned int i, j; + HANDLE file; + char **argv; + DWORD size; + BOOL ret; + + winetest_get_mainargs( &argv ); + + if (!pRtlGetVersion) + { + win_skip("RtlGetVersion is not supported, skipping tests.\n"); + return; + } + + rtlinfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW); + ok(!pRtlGetVersion(&rtlinfo), "RtlGetVersion failed.\n"); + if (rtlinfo.dwMajorVersion < 10) + { + skip("Too old Windows version %lu.%lu, skipping tests.\n", rtlinfo.dwMajorVersion, rtlinfo.dwMinorVersion); + return; + } + + file = CreateFileA(argv[0], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + ok(file != INVALID_HANDLE_VALUE, "CreateFile failed, GetLastError() %lu.\n", GetLastError()); + SetFilePointer(file, 0x3c, NULL, FILE_BEGIN); + ReadFile(file, &hdr_offset, sizeof(hdr_offset), &size, NULL); + CloseHandle(file); + + offset_major = hdr_offset + FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, MajorOperatingSystemVersion); + offset_minor = hdr_offset + FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, MinorOperatingSystemVersion); + + si.cb = sizeof(si); + + for (i = 0; i < ARRAY_SIZE(test_pe_os_version_tests); ++i) + { + sprintf(tmp_exe_name, "tmp%u.exe", i); + ret = CopyFileA(argv[0], tmp_exe_name, FALSE); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + + file = CreateFileA(tmp_exe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + ok(file != INVALID_HANDLE_VALUE, "CreateFile failed, GetLastError() %lu.\n", GetLastError()); + + SetFilePointer(file, offset_major, NULL, FILE_BEGIN); + WriteFile(file, &test_pe_os_version_tests[i].pe_version_major, + sizeof(test_pe_os_version_tests[i].pe_version_major), &size, NULL); + SetFilePointer(file, offset_minor, NULL, FILE_BEGIN); + WriteFile(file, &test_pe_os_version_tests[i].pe_version_minor, + sizeof(test_pe_os_version_tests[i].pe_version_minor), &size, NULL); + + CloseHandle(file); + + sprintf(str, "%s.manifest", tmp_exe_name); + file = CreateFileA(str, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + ok(file != INVALID_HANDLE_VALUE, "CreateFile failed, GetLastError() %lu.\n", GetLastError()); + + WriteFile(file, manifest_header, strlen(manifest_header), &size, NULL); + for (j = 0; j < ARRAY_SIZE(version_guids); ++j) + { + if (test_pe_os_version_tests[i].manifest_versions & (1 << j)) + { + sprintf(str, "\t\t\t\n", version_guids[j]); + WriteFile(file, str, strlen(str), &size, NULL); + } + } + WriteFile(file, manifest_footer, strlen(manifest_footer), &size, NULL); + + CloseHandle(file); + + sprintf(str, "%s version pe_os_version %u", tmp_exe_name, i); + + ret = CreateProcessA(NULL, str, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + CloseHandle(pi.hThread); + result = WaitForSingleObject(pi.hProcess, 10000); + ok(result == WAIT_OBJECT_0, "Got unexpected result %#lx.\n", result); + + ret = GetExitCodeProcess(pi.hProcess, &code); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + ok(!code, "Test %u failed.\n", i); + + CloseHandle(pi.hProcess); + + DeleteFileA(tmp_exe_name); + sprintf(str, "%s.manifest", tmp_exe_name); + DeleteFileA(str); + } } START_TEST(version) { + char **argv; + int argc; + + argc = winetest_get_mainargs( &argv ); + init_function_pointers(); + if (argc >= 4) + { + if (!strcmp(argv[2], "pe_os_version")) + { + unsigned int test; + + test = atoi(argv[3]); + test_pe_os_version_child(test); + } + return; + } + test_GetProductInfo(); test_GetVersionEx(); test_VerifyVersionInfo(); + test_pe_os_version(); + test_SystemFirmwareTable(); + test_PackageIdFromFullName(); } diff --git a/modules/rostests/winetests/kernel32/virtual.c b/modules/rostests/winetests/kernel32/virtual.c index 9eab4da7bb2..c60d0b7ed06 100644 --- a/modules/rostests/winetests/kernel32/virtual.c +++ b/modules/rostests/winetests/kernel32/virtual.c @@ -18,51 +18,47 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "precomp.h" +#include +#include -#include +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winnt.h" +#include "winternl.h" +#include "winerror.h" +#include "winuser.h" +#include "excpt.h" +#include "wine/test.h" #define NUM_THREADS 4 #define MAPPING_SIZE 0x100000 -static HINSTANCE hkernel32, hntdll; -static LPVOID (WINAPI *pVirtualAllocEx)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD); -static BOOL (WINAPI *pVirtualFreeEx)(HANDLE, LPVOID, SIZE_T, DWORD); +static HINSTANCE hkernel32, hkernelbase, hntdll; +static SYSTEM_INFO si; +static BOOL is_wow64; static UINT (WINAPI *pGetWriteWatch)(DWORD,LPVOID,SIZE_T,LPVOID*,ULONG_PTR*,ULONG*); static UINT (WINAPI *pResetWriteWatch)(LPVOID,SIZE_T); static NTSTATUS (WINAPI *pNtAreMappedFilesTheSame)(PVOID,PVOID); static NTSTATUS (WINAPI *pNtCreateSection)(HANDLE *, ACCESS_MASK, const OBJECT_ATTRIBUTES *, const LARGE_INTEGER *, ULONG, ULONG, HANDLE ); -static NTSTATUS (WINAPI *pNtMapViewOfSection)(HANDLE, HANDLE, PVOID *, ULONG, SIZE_T, const LARGE_INTEGER *, SIZE_T *, ULONG, ULONG, ULONG); +static NTSTATUS (WINAPI *pNtMapViewOfSection)(HANDLE, HANDLE, PVOID *, ULONG_PTR, SIZE_T, const LARGE_INTEGER *, SIZE_T *, ULONG, ULONG, ULONG); static DWORD (WINAPI *pNtUnmapViewOfSection)(HANDLE, PVOID); -static NTSTATUS (WINAPI *pNtQuerySection)(HANDLE, SECTION_INFORMATION_CLASS, void *, ULONG, ULONG *); +static NTSTATUS (WINAPI *pNtQuerySection)(HANDLE, SECTION_INFORMATION_CLASS, void *, SIZE_T, SIZE_T *); static PVOID (WINAPI *pRtlAddVectoredExceptionHandler)(ULONG, PVECTORED_EXCEPTION_HANDLER); static ULONG (WINAPI *pRtlRemoveVectoredExceptionHandler)(PVOID); static BOOL (WINAPI *pGetProcessDEPPolicy)(HANDLE, LPDWORD, PBOOL); static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL); static NTSTATUS (WINAPI *pNtProtectVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG, ULONG *); -static NTSTATUS (WINAPI *pNtAllocateVirtualMemory)(HANDLE, PVOID *, ULONG, SIZE_T *, ULONG, ULONG); -static NTSTATUS (WINAPI *pNtFreeVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG); +static NTSTATUS (WINAPI *pNtReadVirtualMemory)(HANDLE,const void *,void *,SIZE_T, SIZE_T *); +static NTSTATUS (WINAPI *pNtWriteVirtualMemory)(HANDLE, void *, const void *, SIZE_T, SIZE_T *); +#ifndef __REACTOS__ // TODO: Enable when kernelbase is fixed. ROSTESTS-414 +static BOOL (WINAPI *pPrefetchVirtualMemory)(HANDLE, ULONG_PTR, PWIN32_MEMORY_RANGE_ENTRY, ULONG); +#endif /* ############################### */ -static UINT_PTR page_mask = 0xfff; -#define ROUND_SIZE(addr,size) \ - (((SIZE_T)(size) + ((UINT_PTR)(addr) & page_mask) + page_mask) & ~page_mask) - -static PIMAGE_NT_HEADERS image_nt_header(HMODULE module) -{ - IMAGE_NT_HEADERS *ret = NULL; - IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)module; - - if (dos->e_magic == IMAGE_DOS_SIGNATURE) - { - ret = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew); - if (ret->Signature != IMAGE_NT_SIGNATURE) ret = NULL; - } - return ret; -} - static HANDLE create_target_process(const char *arg) { char **argv; @@ -75,9 +71,9 @@ static HANDLE create_target_process(const char *arg) winetest_get_mainargs( &argv ); sprintf(cmdline, "%s %s %s", argv[0], argv[1], arg); ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); - ok(ret, "error: %u\n", GetLastError()); + ok(ret, "error: %lu\n", GetLastError()); ret = CloseHandle(pi.hThread); - ok(ret, "error %u\n", GetLastError()); + ok(ret, "error %lu\n", GetLastError()); return pi.hProcess; } @@ -87,24 +83,29 @@ static void test_VirtualAllocEx(void) char *src, *dst; SIZE_T bytes_written = 0, bytes_read = 0, i; void *addr1, *addr2; - BOOL b; + BOOL b, ret; DWORD old_prot; MEMORY_BASIC_INFORMATION info; HANDLE hProcess; + NTSTATUS status; - /* not exported in all windows-versions */ - if ((!pVirtualAllocEx) || (!pVirtualFreeEx)) { - win_skip("Virtual{Alloc,Free}Ex not available\n"); - return; - } + /* Same process */ + addr1 = VirtualAllocEx(GetCurrentProcess(), NULL, alloc_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + ok(!!addr1, "Failed to allocated, error %lu.\n", GetLastError()); + ret = VirtualFreeEx(NULL, addr1, 0, MEM_RELEASE); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Unexpected value %d, error %lu.\n", ret, GetLastError()); + addr2 = VirtualAllocEx(NULL, NULL, alloc_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + ok(!addr2 && GetLastError() == ERROR_INVALID_HANDLE, "Unexpected value %p, error %lu.\n", addr2, GetLastError()); + ret = VirtualFreeEx(GetCurrentProcess(), addr1, 0, MEM_RELEASE); + ok(ret, "Unexpected value %d, error %lu.\n", ret, GetLastError()); hProcess = create_target_process("sleep"); ok(hProcess != NULL, "Can't start process\n"); SetLastError(0xdeadbeef); - addr1 = pVirtualAllocEx(hProcess, NULL, alloc_size, MEM_COMMIT, + addr1 = VirtualAllocEx(hProcess, NULL, alloc_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); - ok(addr1 != NULL, "VirtualAllocEx error %u\n", GetLastError()); + ok(addr1 != NULL, "VirtualAllocEx error %lu\n", GetLastError()); src = VirtualAlloc( NULL, alloc_size, MEM_COMMIT, PAGE_READWRITE ); dst = VirtualAlloc( NULL, alloc_size, MEM_COMMIT, PAGE_READWRITE ); @@ -112,42 +113,149 @@ static void test_VirtualAllocEx(void) src[i] = i & 0xff; b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written); - ok(b && (bytes_written == alloc_size), "%lu bytes written\n", + ok(b && (bytes_written == alloc_size), "%Iu bytes written\n", bytes_written); b = ReadProcessMemory(hProcess, addr1, dst, alloc_size, &bytes_read); - ok(b && (bytes_read == alloc_size), "%lu bytes read\n", bytes_read); + ok(b && (bytes_read == alloc_size), "%Iu bytes read\n", bytes_read); ok(!memcmp(src, dst, alloc_size), "Data from remote process differs\n"); + bytes_written = 0xdeadbeef; + status = pNtWriteVirtualMemory( hProcess, addr1, src, alloc_size, &bytes_written ); + ok( status == STATUS_SUCCESS, "wrong status %lx\n", status ); + ok( bytes_written == alloc_size, "%Iu bytes written\n", bytes_written ); + bytes_read = 0xdeadbeef; + memset( dst, 0, alloc_size ); + status = pNtReadVirtualMemory( hProcess, addr1, dst, alloc_size, &bytes_read ); + ok( status == STATUS_SUCCESS, "wrong status %lx\n", status ); + ok( bytes_read == alloc_size, "%Iu bytes read\n", bytes_read ); + ok(!memcmp(src, dst, alloc_size), "Data from remote process differs\n"); + + /* test 0 length */ + bytes_written = 0xdeadbeef; + b = WriteProcessMemory(hProcess, addr1, src, 0, &bytes_written); + ok((b && !bytes_written) || broken(!b && GetLastError() == ERROR_INVALID_PARAMETER), "write failed: %lu\n", GetLastError()); + bytes_read = 0xdeadbeef; + b = ReadProcessMemory(hProcess, addr1, src, 0, &bytes_read); + ok(b && !bytes_read, "read failed: %lu\n", GetLastError()); + bytes_written = 0xdeadbeef; + status = pNtWriteVirtualMemory( hProcess, addr1, src, 0, &bytes_written ); + ok( status == STATUS_SUCCESS, "wrong status %lx\n", status ); + ok( bytes_written == 0, "%Iu bytes written\n", bytes_written ); + bytes_read = 0xdeadbeef; + status = pNtReadVirtualMemory( hProcess, addr1, src, 0, &bytes_read ); + ok( status == STATUS_SUCCESS, "wrong status %lx\n", status ); + ok( !bytes_read, "%Iu bytes read\n", bytes_read ); /* test invalid source buffers */ b = VirtualProtect( src + 0x2000, 0x2000, PAGE_NOACCESS, &old_prot ); - ok( b, "VirtualProtect failed error %u\n", GetLastError() ); + ok( b, "VirtualProtect failed error %lu\n", GetLastError() ); + bytes_written = 0xdeadbeef; b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written); ok( !b, "WriteProcessMemory succeeded\n" ); ok( GetLastError() == ERROR_NOACCESS || GetLastError() == ERROR_PARTIAL_COPY, /* vista */ - "wrong error %u\n", GetLastError() ); - ok( bytes_written == 0, "%lu bytes written\n", bytes_written ); + "wrong error %lu\n", GetLastError() ); + ok( bytes_written == 0, "%Iu bytes written\n", bytes_written ); + bytes_read = 0xdeadbeef; b = ReadProcessMemory(hProcess, addr1, src, alloc_size, &bytes_read); ok( !b, "ReadProcessMemory succeeded\n" ); - ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() ); - ok( bytes_read == 0, "%lu bytes written\n", bytes_read ); + ok( GetLastError() == ERROR_NOACCESS || + GetLastError() == ERROR_PARTIAL_COPY, /* win10 v1607+ */ + "wrong error %lu\n", GetLastError() ); + if (GetLastError() == ERROR_NOACCESS) + ok( bytes_read == 0, "%Iu bytes read\n", bytes_read ); + else + ok( bytes_read == 0x2000, "%Iu bytes read\n", bytes_read ); + bytes_written = 0xdeadbeef; + status = pNtWriteVirtualMemory( hProcess, addr1, src, alloc_size, &bytes_written ); + ok( status == STATUS_PARTIAL_COPY, "wrong status %lx\n", status ); + ok( bytes_written == 0, "%Iu bytes written\n", bytes_written ); + bytes_read = 0xdeadbeef; + status = pNtReadVirtualMemory( hProcess, addr1, src, alloc_size, &bytes_read ); + ok( status == STATUS_PARTIAL_COPY || status == STATUS_ACCESS_VIOLATION, "wrong status %lx\n", status ); + ok( bytes_read == (status == STATUS_PARTIAL_COPY ? 0x2000 : 0), "%Iu bytes read\n", bytes_read ); b = VirtualProtect( src, 0x2000, PAGE_NOACCESS, &old_prot ); - ok( b, "VirtualProtect failed error %u\n", GetLastError() ); + ok( b, "VirtualProtect failed error %lu\n", GetLastError() ); + bytes_written = 0xdeadbeef; b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written); ok( !b, "WriteProcessMemory succeeded\n" ); ok( GetLastError() == ERROR_NOACCESS || GetLastError() == ERROR_PARTIAL_COPY, /* vista */ - "wrong error %u\n", GetLastError() ); - ok( bytes_written == 0, "%lu bytes written\n", bytes_written ); + "wrong error %lu\n", GetLastError() ); + ok( bytes_written == 0, "%Iu bytes written\n", bytes_written ); + bytes_read = 0xdeadbeef; b = ReadProcessMemory(hProcess, addr1, src, alloc_size, &bytes_read); ok( !b, "ReadProcessMemory succeeded\n" ); - ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() ); - ok( bytes_read == 0, "%lu bytes written\n", bytes_read ); + ok( GetLastError() == ERROR_NOACCESS || + GetLastError() == ERROR_PARTIAL_COPY, /* win10 v1607+ */ + "wrong error %lu\n", GetLastError() ); + ok( bytes_read == 0, "%Iu bytes read\n", bytes_read ); + bytes_written = 0xdeadbeef; + status = pNtWriteVirtualMemory( hProcess, addr1, src, alloc_size, &bytes_written ); + ok( status == STATUS_PARTIAL_COPY, "wrong status %lx\n", status ); + ok( bytes_written == 0, "%Iu bytes written\n", bytes_written ); + bytes_read = 0xdeadbeef; + status = pNtReadVirtualMemory( hProcess, addr1, src, alloc_size, &bytes_read ); + ok( status == STATUS_PARTIAL_COPY || status == STATUS_ACCESS_VIOLATION, "wrong status %lx\n", status ); + ok( bytes_read == 0, "%Iu bytes read\n", bytes_read ); + b = VirtualProtect( src, alloc_size, PAGE_READWRITE, &old_prot ); + ok( b, "VirtualProtect failed error %lu\n", GetLastError() ); - b = pVirtualFreeEx(hProcess, addr1, 0, MEM_RELEASE); - ok(b != 0, "VirtualFreeEx, error %u\n", GetLastError()); + /* test readonly buffers */ + + b = VirtualProtectEx( hProcess, addr1, alloc_size, PAGE_READONLY, &old_prot ); + ok( b, "VirtualProtectEx, error %lu\n", GetLastError() ); + bytes_written = 0xdeadbeef; + b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written); + ok( !b, "WriteProcessMemory succeeded\n" ); + if (!b) ok( GetLastError() == ERROR_NOACCESS, "wrong error %lu\n", GetLastError() ); + ok( bytes_written == 0xdeadbeef, "%Iu bytes written\n", bytes_written ); + status = pNtWriteVirtualMemory( hProcess, addr1, src, alloc_size, &bytes_written ); + todo_wine + ok( status == STATUS_PARTIAL_COPY || broken(status == STATUS_ACCESS_VIOLATION), + "wrong status %lx\n", status ); + todo_wine + ok( bytes_written == 0, "%Iu bytes written\n", bytes_written ); + + b = VirtualProtectEx( hProcess, addr1, alloc_size, PAGE_EXECUTE_READ, &old_prot ); + ok( b, "VirtualProtectEx, error %lu\n", GetLastError() ); + bytes_written = 0xdeadbeef; + b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written); + ok( b, "WriteProcessMemory failed\n" ); + ok( bytes_written == alloc_size, "%Iu bytes written\n", bytes_written ); + bytes_written = 0xdeadbeef; + status = pNtWriteVirtualMemory( hProcess, addr1, src, alloc_size, &bytes_written ); + todo_wine + ok( status == STATUS_PARTIAL_COPY || broken(status == STATUS_ACCESS_VIOLATION), + "wrong status %lx\n", status ); + todo_wine + ok( bytes_written == 0, "%Iu bytes written\n", bytes_written ); + + b = VirtualProtectEx( hProcess, addr1, 0x2000, PAGE_EXECUTE_READWRITE, &old_prot ); + ok( b, "VirtualProtectEx, error %lu\n", GetLastError() ); + bytes_written = 0xdeadbeef; + b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written); + todo_wine + ok( !b || broken(b), /* <= win10 1507 */ "WriteProcessMemory succeeded\n" ); + bytes_written = 0xdeadbeef; + status = pNtWriteVirtualMemory( hProcess, addr1, src, alloc_size, &bytes_written ); + todo_wine + ok( status == STATUS_PARTIAL_COPY || broken(status == STATUS_SUCCESS), /* <= win10 1507 */ + "wrong status %lx\n", status ); + ok( bytes_written == (status ? 0x2000 : alloc_size), "%Iu bytes written\n", bytes_written ); + + b = VirtualProtectEx( hProcess, (char *)addr1 + 0x2000, alloc_size - 0x2000, PAGE_READONLY, &old_prot ); + ok( b, "VirtualProtectEx, error %lu\n", GetLastError() ); + bytes_written = 0xdeadbeef; + b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written); + todo_wine + ok( !b || broken(b), /* <= win10 1507 */ "WriteProcessMemory succeeded\n" ); + status = pNtWriteVirtualMemory( hProcess, addr1, src, alloc_size, &bytes_written ); + todo_wine + ok( status == STATUS_PARTIAL_COPY || broken(status == STATUS_SUCCESS), /* <= win10 1507 */ + "wrong status %lx\n", status ); + ok( bytes_written == (status ? 0x2000 : alloc_size), "%Iu bytes written\n", bytes_written ); VirtualFree( src, 0, MEM_RELEASE ); VirtualFree( dst, 0, MEM_RELEASE ); @@ -157,12 +265,12 @@ static void test_VirtualAllocEx(void) */ SetLastError(0xdeadbeef); - addr1 = pVirtualAllocEx(hProcess, 0, 0, MEM_RESERVE, PAGE_NOACCESS); + addr1 = VirtualAllocEx(hProcess, 0, 0, MEM_RESERVE, PAGE_NOACCESS); ok(addr1 == NULL, "VirtualAllocEx should fail on zero-sized allocation\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "got %u, expected ERROR_INVALID_PARAMETER\n", GetLastError()); + "got %lu, expected ERROR_INVALID_PARAMETER\n", GetLastError()); - addr1 = pVirtualAllocEx(hProcess, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS); + addr1 = VirtualAllocEx(hProcess, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS); ok(addr1 != NULL, "VirtualAllocEx failed\n"); /* test a not committed memory */ @@ -170,19 +278,19 @@ static void test_VirtualAllocEx(void) ok(VirtualQueryEx(hProcess, addr1, &info, sizeof(info)) == sizeof(info), "VirtualQueryEx failed\n"); ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1); ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1); - ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect); - ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize); - ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State); - ok(info.Protect == 0, "%x != PAGE_NOACCESS\n", info.Protect); - ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type); + ok(info.AllocationProtect == PAGE_NOACCESS, "%lx != PAGE_NOACCESS\n", info.AllocationProtect); + ok(info.RegionSize == 0x10000, "%Ix != 0x10000\n", info.RegionSize); + ok(info.State == MEM_RESERVE, "%lx != MEM_RESERVE\n", info.State); + ok(info.Protect == 0, "%lx != PAGE_NOACCESS\n", info.Protect); + ok(info.Type == MEM_PRIVATE, "%lx != MEM_PRIVATE\n", info.Type); SetLastError(0xdeadbeef); ok(!VirtualProtectEx(hProcess, addr1, 0xFFFC, PAGE_READONLY, &old_prot), "VirtualProtectEx should fail on a not committed memory\n"); ok(GetLastError() == ERROR_INVALID_ADDRESS, - "got %u, expected ERROR_INVALID_ADDRESS\n", GetLastError()); + "got %lu, expected ERROR_INVALID_ADDRESS\n", GetLastError()); - addr2 = pVirtualAllocEx(hProcess, addr1, 0x1000, MEM_COMMIT, PAGE_NOACCESS); + addr2 = VirtualAllocEx(hProcess, addr1, 0x1000, MEM_COMMIT, PAGE_NOACCESS); ok(addr1 == addr2, "VirtualAllocEx failed\n"); /* test a committed memory */ @@ -190,42 +298,42 @@ static void test_VirtualAllocEx(void) "VirtualQueryEx failed\n"); ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1); ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1); - ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect); - ok(info.RegionSize == 0x1000, "%lx != 0x1000\n", info.RegionSize); - ok(info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State); + ok(info.AllocationProtect == PAGE_NOACCESS, "%lx != PAGE_NOACCESS\n", info.AllocationProtect); + ok(info.RegionSize == 0x1000, "%Ix != 0x1000\n", info.RegionSize); + ok(info.State == MEM_COMMIT, "%lx != MEM_COMMIT\n", info.State); /* this time NT reports PAGE_NOACCESS as well */ - ok(info.Protect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.Protect); - ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type); + ok(info.Protect == PAGE_NOACCESS, "%lx != PAGE_NOACCESS\n", info.Protect); + ok(info.Type == MEM_PRIVATE, "%lx != MEM_PRIVATE\n", info.Type); /* this should fail, since not the whole range is committed yet */ SetLastError(0xdeadbeef); ok(!VirtualProtectEx(hProcess, addr1, 0xFFFC, PAGE_READONLY, &old_prot), "VirtualProtectEx should fail on a not committed memory\n"); ok(GetLastError() == ERROR_INVALID_ADDRESS, - "got %u, expected ERROR_INVALID_ADDRESS\n", GetLastError()); + "got %lu, expected ERROR_INVALID_ADDRESS\n", GetLastError()); old_prot = 0; ok(VirtualProtectEx(hProcess, addr1, 0x1000, PAGE_READONLY, &old_prot), "VirtualProtectEx failed\n"); - ok(old_prot == PAGE_NOACCESS, "wrong old protection: got %04x instead of PAGE_NOACCESS\n", old_prot); + ok(old_prot == PAGE_NOACCESS, "wrong old protection: got %04lx instead of PAGE_NOACCESS\n", old_prot); old_prot = 0; ok(VirtualProtectEx(hProcess, addr1, 0x1000, PAGE_READWRITE, &old_prot), "VirtualProtectEx failed\n"); - ok(old_prot == PAGE_READONLY, "wrong old protection: got %04x instead of PAGE_READONLY\n", old_prot); + ok(old_prot == PAGE_READONLY, "wrong old protection: got %04lx instead of PAGE_READONLY\n", old_prot); - ok(!pVirtualFreeEx(hProcess, addr1, 0x10000, 0), + ok(!VirtualFreeEx(hProcess, addr1, 0x10000, 0), "VirtualFreeEx should fail with type 0\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "got %u, expected ERROR_INVALID_PARAMETER\n", GetLastError()); + "got %lu, expected ERROR_INVALID_PARAMETER\n", GetLastError()); - ok(pVirtualFreeEx(hProcess, addr1, 0x10000, MEM_DECOMMIT), "VirtualFreeEx failed\n"); + ok(VirtualFreeEx(hProcess, addr1, 0x10000, MEM_DECOMMIT), "VirtualFreeEx failed\n"); /* if the type is MEM_RELEASE, size must be 0 */ - ok(!pVirtualFreeEx(hProcess, addr1, 1, MEM_RELEASE), + ok(!VirtualFreeEx(hProcess, addr1, 1, MEM_RELEASE), "VirtualFreeEx should fail\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "got %u, expected ERROR_INVALID_PARAMETER\n", GetLastError()); + "got %lu, expected ERROR_INVALID_PARAMETER\n", GetLastError()); - ok(pVirtualFreeEx(hProcess, addr1, 0, MEM_RELEASE), "VirtualFreeEx failed\n"); + ok(VirtualFreeEx(hProcess, addr1, 0, MEM_RELEASE), "VirtualFreeEx failed\n"); TerminateProcess(hProcess, 0); CloseHandle(hProcess); @@ -236,14 +344,12 @@ static void test_VirtualAlloc(void) void *addr1, *addr2; DWORD old_prot; MEMORY_BASIC_INFORMATION info; - NTSTATUS status; - SIZE_T size; SetLastError(0xdeadbeef); addr1 = VirtualAlloc(0, 0, MEM_RESERVE, PAGE_NOACCESS); ok(addr1 == NULL, "VirtualAlloc should fail on zero-sized allocation\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "got %d, expected ERROR_INVALID_PARAMETER\n", GetLastError()); + "got %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError()); addr1 = VirtualAlloc(0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS); ok(addr1 != NULL, "VirtualAlloc failed\n"); @@ -253,17 +359,17 @@ static void test_VirtualAlloc(void) "VirtualQuery failed\n"); ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1); ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1); - ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect); - ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize); - ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State); - ok(info.Protect == 0, "%x != PAGE_NOACCESS\n", info.Protect); - ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type); + ok(info.AllocationProtect == PAGE_NOACCESS, "%lx != PAGE_NOACCESS\n", info.AllocationProtect); + ok(info.RegionSize == 0x10000, "%Ix != 0x10000\n", info.RegionSize); + ok(info.State == MEM_RESERVE, "%lx != MEM_RESERVE\n", info.State); + ok(info.Protect == 0, "%lx != PAGE_NOACCESS\n", info.Protect); + ok(info.Type == MEM_PRIVATE, "%lx != MEM_PRIVATE\n", info.Type); SetLastError(0xdeadbeef); ok(!VirtualProtect(addr1, 0xFFFC, PAGE_READONLY, &old_prot), "VirtualProtect should fail on a not committed memory\n"); ok( GetLastError() == ERROR_INVALID_ADDRESS, - "got %d, expected ERROR_INVALID_ADDRESS\n", GetLastError()); + "got %ld, expected ERROR_INVALID_ADDRESS\n", GetLastError()); addr2 = VirtualAlloc(addr1, 0x1000, MEM_COMMIT, PAGE_NOACCESS); ok(addr1 == addr2, "VirtualAlloc failed\n"); @@ -273,99 +379,168 @@ static void test_VirtualAlloc(void) "VirtualQuery failed\n"); ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1); ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1); - ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect); - ok(info.RegionSize == 0x1000, "%lx != 0x1000\n", info.RegionSize); - ok(info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State); + ok(info.AllocationProtect == PAGE_NOACCESS, "%lx != PAGE_NOACCESS\n", info.AllocationProtect); + ok(info.RegionSize == 0x1000, "%Ix != 0x1000\n", info.RegionSize); + ok(info.State == MEM_COMMIT, "%lx != MEM_COMMIT\n", info.State); /* this time NT reports PAGE_NOACCESS as well */ - ok(info.Protect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.Protect); - ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type); + ok(info.Protect == PAGE_NOACCESS, "%lx != PAGE_NOACCESS\n", info.Protect); + ok(info.Type == MEM_PRIVATE, "%lx != MEM_PRIVATE\n", info.Type); /* this should fail, since not the whole range is committed yet */ SetLastError(0xdeadbeef); ok(!VirtualProtect(addr1, 0xFFFC, PAGE_READONLY, &old_prot), "VirtualProtect should fail on a not committed memory\n"); ok( GetLastError() == ERROR_INVALID_ADDRESS, - "got %d, expected ERROR_INVALID_ADDRESS\n", GetLastError()); + "got %ld, expected ERROR_INVALID_ADDRESS\n", GetLastError()); ok(VirtualProtect(addr1, 0x1000, PAGE_READONLY, &old_prot), "VirtualProtect failed\n"); ok(old_prot == PAGE_NOACCESS, - "wrong old protection: got %04x instead of PAGE_NOACCESS\n", old_prot); + "wrong old protection: got %04lx instead of PAGE_NOACCESS\n", old_prot); ok(VirtualProtect(addr1, 0x1000, PAGE_READWRITE, &old_prot), "VirtualProtect failed\n"); ok(old_prot == PAGE_READONLY, - "wrong old protection: got %04x instead of PAGE_READONLY\n", old_prot); + "wrong old protection: got %04lx instead of PAGE_READONLY\n", old_prot); ok(VirtualQuery(addr1, &info, sizeof(info)) == sizeof(info), "VirtualQuery failed\n"); - ok(info.RegionSize == 0x1000, "%lx != 0x1000\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); + ok(info.RegionSize == 0x1000, "%Ix != 0x1000\n", info.RegionSize); + ok(info.State == MEM_COMMIT, "%lx != MEM_COMMIT\n", info.State); + ok(info.Protect == PAGE_READWRITE, "%lx != PAGE_READWRITE\n", info.Protect); memset( addr1, 0x55, 20 ); - ok( *(DWORD *)addr1 == 0x55555555, "wrong data %x\n", *(DWORD *)addr1 ); + ok( *(DWORD *)addr1 == 0x55555555, "wrong data %lx\n", *(DWORD *)addr1 ); addr2 = VirtualAlloc( addr1, 0x1000, MEM_RESET, PAGE_NOACCESS ); - ok( addr2 == addr1, "VirtualAlloc failed err %u\n", GetLastError() ); - ok( *(DWORD *)addr1 == 0x55555555 || *(DWORD *)addr1 == 0, "wrong data %x\n", *(DWORD *)addr1 ); + ok( addr2 == addr1, "VirtualAlloc failed err %lu\n", GetLastError() ); + ok( *(DWORD *)addr1 == 0x55555555 || *(DWORD *)addr1 == 0, "wrong data %lx\n", *(DWORD *)addr1 ); ok(VirtualQuery(addr1, &info, sizeof(info)) == sizeof(info), "VirtualQuery failed\n"); - ok(info.RegionSize == 0x1000, "%lx != 0x1000\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); + ok(info.RegionSize == 0x1000, "%Ix != 0x1000\n", info.RegionSize); + ok(info.State == MEM_COMMIT, "%lx != MEM_COMMIT\n", info.State); + ok(info.Protect == PAGE_READWRITE, "%lx != PAGE_READWRITE\n", info.Protect); addr2 = VirtualAlloc( (char *)addr1 + 0x1000, 0x1000, MEM_RESET, PAGE_NOACCESS ); ok( (char *)addr2 == (char *)addr1 + 0x1000, "VirtualAlloc failed\n" ); ok(VirtualQuery(addr2, &info, sizeof(info)) == sizeof(info), "VirtualQuery failed\n"); - ok(info.RegionSize == 0xf000, "%lx != 0xf000\n", info.RegionSize); - ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State); - ok(info.Protect == 0, "%x != 0\n", info.Protect); + ok(info.RegionSize == 0xf000, "%Ix != 0xf000\n", info.RegionSize); + ok(info.State == MEM_RESERVE, "%lx != MEM_RESERVE\n", info.State); + ok(info.Protect == 0, "%lx != 0\n", info.Protect); addr2 = VirtualAlloc( (char *)addr1 + 0xf000, 0x2000, MEM_RESET, PAGE_NOACCESS ); ok( !addr2, "VirtualAlloc failed\n" ); - ok( GetLastError() == ERROR_INVALID_ADDRESS, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_ADDRESS, "wrong error %lu\n", GetLastError() ); /* 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()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\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()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\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()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\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()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError()); SetLastError(0xdeadbeef); ok(!VirtualProtect(addr1, 0x1000, 0, &old_prot), "VirtualProtect succeeded\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\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()); + "got %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError()); SetLastError(0xdeadbeef); ok(!VirtualFree(addr1, 0, MEM_FREE), "VirtualFree should fail with type MEM_FREE\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "got %d, expected ERROR_INVALID_PARAMETER\n", GetLastError()); + "got %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError()); ok(VirtualFree(addr1, 0x10000, MEM_DECOMMIT), "VirtualFree failed\n"); /* if the type is MEM_RELEASE, size must be 0 */ ok(!VirtualFree(addr1, 1, MEM_RELEASE), "VirtualFree should fail\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, - "got %d, expected ERROR_INVALID_PARAMETER\n", GetLastError()); + "got %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError()); + + ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n"); + + /* PAGE_NOCACHE cannot be set per page in recent Windows */ + addr1 = VirtualAlloc( NULL, 0x2000, MEM_COMMIT, PAGE_READWRITE | PAGE_NOCACHE ); + ok( addr1 != NULL, "VirtualAlloc failed\n"); + ok(VirtualQuery(addr1, &info, sizeof(info)) == sizeof(info), "VirtualQuery failed\n"); + ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1); + ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1); + ok(info.AllocationProtect == (PAGE_READWRITE | PAGE_NOCACHE), + "wrong protect %lx\n", info.AllocationProtect); + ok(info.RegionSize == 0x2000, "wrong size %Ix\n", info.RegionSize); + ok(info.State == MEM_COMMIT, "wrong state %lx\n", info.State); + ok(info.Protect == (PAGE_READWRITE | PAGE_NOCACHE), "wrong protect %lx\n", info.Protect); + ok(info.Type == MEM_PRIVATE, "wrong type %lx\n", info.Type); + + ok(VirtualProtect(addr1, 0x1000, PAGE_READWRITE, &old_prot), "VirtualProtect failed\n"); + ok( old_prot == (PAGE_READWRITE | PAGE_NOCACHE), "wrong protect %lx\n", old_prot ); + ok(VirtualQuery(addr1, &info, sizeof(info)) == sizeof(info), "VirtualQuery failed\n"); + ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1); + ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1); + ok(info.AllocationProtect == (PAGE_READWRITE | PAGE_NOCACHE), + "wrong protect %lx\n", info.AllocationProtect); + ok(info.RegionSize == 0x2000 || broken(info.RegionSize == 0x1000), + "wrong size %Ix\n", info.RegionSize); + ok(info.State == MEM_COMMIT, "wrong state %lx\n", info.State); + ok(info.Protect == (PAGE_READWRITE | PAGE_NOCACHE) || broken(info.Protect == PAGE_READWRITE), + "wrong protect %lx\n", info.Protect); + ok(info.Type == MEM_PRIVATE, "wrong type %lx\n", info.Type); + + ok(VirtualProtect(addr1, 0x1000, PAGE_READONLY, &old_prot), "VirtualProtect failed\n"); + ok( old_prot == (PAGE_READWRITE | PAGE_NOCACHE) || broken(old_prot == PAGE_READWRITE), + "wrong protect %lx\n", old_prot ); + ok(VirtualQuery(addr1, &info, sizeof(info)) == sizeof(info), "VirtualQuery failed\n"); + ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1); + ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1); + ok(info.AllocationProtect == (PAGE_READWRITE | PAGE_NOCACHE), + "wrong protect %lx\n", info.AllocationProtect); + ok(info.RegionSize == 0x1000, "wrong size %Ix\n", info.RegionSize); + ok(info.State == MEM_COMMIT, "wrong state %lx\n", info.State); + ok(info.Protect == (PAGE_READONLY | PAGE_NOCACHE) || broken(info.Protect == PAGE_READONLY), + "wrong protect %lx\n", info.Protect); + ok(info.Type == MEM_PRIVATE, "wrong type %lx\n", info.Type); + + ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n"); + + addr1 = VirtualAlloc( NULL, 0x2000, MEM_COMMIT, PAGE_READWRITE ); + ok( addr1 != NULL, "VirtualAlloc failed\n"); + ok(VirtualQuery(addr1, &info, sizeof(info)) == sizeof(info), "VirtualQuery failed\n"); + ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1); + ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1); + ok(info.AllocationProtect == PAGE_READWRITE, + "wrong protect %lx\n", info.AllocationProtect); + ok(info.RegionSize == 0x2000, "wrong size %Ix\n", info.RegionSize); + ok(info.State == MEM_COMMIT, "wrong state %lx\n", info.State); + ok(info.Protect == PAGE_READWRITE, "wrong protect %lx\n", info.Protect); + ok(info.Type == MEM_PRIVATE, "wrong type %lx\n", info.Type); + + ok(VirtualProtect(addr1, 0x1000, PAGE_READONLY | PAGE_NOCACHE, &old_prot), "VirtualProtect failed\n"); + ok( old_prot == PAGE_READWRITE, "wrong protect %lx\n", old_prot ); + ok(VirtualQuery(addr1, &info, sizeof(info)) == sizeof(info), "VirtualQuery failed\n"); + ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1); + ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1); + ok(info.AllocationProtect == PAGE_READWRITE, "wrong protect %lx\n", info.AllocationProtect); + ok(info.RegionSize == 0x1000, "wrong size %Ix\n", info.RegionSize); + ok(info.State == MEM_COMMIT, "wrong state %lx\n", info.State); + ok(info.Protect == PAGE_READONLY || broken(info.Protect == (PAGE_READONLY | PAGE_NOCACHE)), + "wrong protect %lx\n", info.Protect); + ok(info.Type == MEM_PRIVATE, "wrong type %lx\n", info.Type); ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n"); @@ -377,52 +552,11 @@ static void test_VirtualAlloc(void) addr2 = VirtualAlloc(addr1, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); ok(addr2 == addr1, "VirtualAlloc returned %p, expected %p\n", addr2, addr1); - /* allocation conflicts because of 64k align */ - size = 0x1000; - addr2 = (char *)addr1 + 0x1000; - status = pNtAllocateVirtualMemory(GetCurrentProcess(), &addr2, 0, &size, - MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); - ok(status == STATUS_CONFLICTING_ADDRESSES, "NtAllocateVirtualMemory returned %08x\n", status); - - /* it should conflict, even when zero_bits is explicitly set */ - size = 0x1000; - addr2 = (char *)addr1 + 0x1000; - status = pNtAllocateVirtualMemory(GetCurrentProcess(), &addr2, 12, &size, - MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); - todo_wine - ok(status == STATUS_CONFLICTING_ADDRESSES, "NtAllocateVirtualMemory returned %08x\n", status); - if (status == STATUS_SUCCESS) ok(VirtualFree(addr2, 0, MEM_RELEASE), "VirtualFree failed\n"); - - /* 21 zero bits is valid */ - size = 0x1000; - addr2 = NULL; - status = pNtAllocateVirtualMemory(GetCurrentProcess(), &addr2, 21, &size, - MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); - ok(status == STATUS_SUCCESS || status == STATUS_NO_MEMORY, - "NtAllocateVirtualMemory returned %08x\n", status); - if (status == STATUS_SUCCESS) ok(VirtualFree(addr2, 0, MEM_RELEASE), "VirtualFree failed\n"); - - /* 22 zero bits is invalid */ - size = 0x1000; - addr2 = NULL; - status = pNtAllocateVirtualMemory(GetCurrentProcess(), &addr2, 22, &size, - MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); - ok(status == STATUS_INVALID_PARAMETER_3, "NtAllocateVirtualMemory returned %08x\n", status); - if (status == STATUS_SUCCESS) ok(VirtualFree(addr2, 0, MEM_RELEASE), "VirtualFree failed\n"); - /* AT_ROUND_TO_PAGE flag is not supported for VirtualAlloc */ SetLastError(0xdeadbeef); addr2 = VirtualAlloc(addr1, 0x1000, MEM_RESERVE | MEM_COMMIT | AT_ROUND_TO_PAGE, PAGE_EXECUTE_READWRITE); ok(!addr2, "VirtualAlloc unexpectedly succeeded\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d, expected ERROR_INVALID_PARAMETER\n", GetLastError()); - - /* AT_ROUND_TO_PAGE flag is not supported for NtAllocateVirtualMemory */ - size = 0x1000; - addr2 = (char *)addr1 + 0x1000; - status = pNtAllocateVirtualMemory(GetCurrentProcess(), &addr2, 0, &size, MEM_RESERVE | - MEM_COMMIT | AT_ROUND_TO_PAGE, PAGE_EXECUTE_READWRITE); - todo_wine - ok(status == STATUS_INVALID_PARAMETER_5, "NtAllocateVirtualMemory returned %08x\n", status); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError()); ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n"); } @@ -439,12 +573,12 @@ static void test_MapViewOfFile(void) BOOL ret; SIZE_T size; NTSTATUS status; - ULONG info_size; + SIZE_T info_size; LARGE_INTEGER map_size; SetLastError(0xdeadbeef); file = CreateFileA( testfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 ); - ok( file != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() ); + ok( file != INVALID_HANDLE_VALUE, "CreateFile error %lu\n", GetLastError() ); SetFilePointer( file, 12288, NULL, FILE_BEGIN ); SetEndOfFile( file ); @@ -452,56 +586,56 @@ static void test_MapViewOfFile(void) SetLastError(0xdeadbeef); mapping = CreateFileMappingA( file, NULL, PAGE_READWRITE, 0, 4096, NULL ); - ok( mapping != 0, "CreateFileMapping error %u\n", GetLastError() ); + ok( mapping != 0, "CreateFileMapping error %lu\n", GetLastError() ); SetLastError(0xdeadbeef); ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 ); - ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() ); + ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %lu\n", GetLastError() ); UnmapViewOfFile( ptr ); SetLastError(0xdeadbeef); ptr = MapViewOfFile( mapping, FILE_MAP_COPY, 0, 0, 4096 ); - ok( ptr != NULL, "MapViewOfFile FILE_MAP_COPY error %u\n", GetLastError() ); + ok( ptr != NULL, "MapViewOfFile FILE_MAP_COPY error %lu\n", GetLastError() ); UnmapViewOfFile( ptr ); SetLastError(0xdeadbeef); ptr = MapViewOfFile( mapping, 0, 0, 0, 4096 ); - ok( ptr != NULL, "MapViewOfFile 0 error %u\n", GetLastError() ); + ok( ptr != NULL, "MapViewOfFile 0 error %lu\n", GetLastError() ); UnmapViewOfFile( ptr ); SetLastError(0xdeadbeef); ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 4096 ); - ok( ptr != NULL, "MapViewOfFile FILE_MAP_WRITE error %u\n", GetLastError() ); + ok( ptr != NULL, "MapViewOfFile FILE_MAP_WRITE error %lu\n", GetLastError() ); UnmapViewOfFile( ptr ); ret = DuplicateHandle( GetCurrentProcess(), mapping, GetCurrentProcess(), &map2, FILE_MAP_READ|FILE_MAP_WRITE, FALSE, 0 ); - ok( ret, "DuplicateHandle failed error %u\n", GetLastError()); + ok( ret, "DuplicateHandle failed error %lu\n", GetLastError()); ptr = MapViewOfFile( map2, FILE_MAP_WRITE, 0, 0, 4096 ); - ok( ptr != NULL, "MapViewOfFile FILE_MAP_WRITE error %u\n", GetLastError() ); + ok( ptr != NULL, "MapViewOfFile FILE_MAP_WRITE error %lu\n", GetLastError() ); UnmapViewOfFile( ptr ); CloseHandle( map2 ); ret = DuplicateHandle( GetCurrentProcess(), mapping, GetCurrentProcess(), &map2, FILE_MAP_READ, FALSE, 0 ); - ok( ret, "DuplicateHandle failed error %u\n", GetLastError()); + ok( ret, "DuplicateHandle failed error %lu\n", GetLastError()); SetLastError(0xdeadbeef); ptr = MapViewOfFile( map2, FILE_MAP_WRITE, 0, 0, 4096 ); ok( !ptr, "MapViewOfFile succeeded\n" ); - ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() ); + ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %ld\n", GetLastError() ); CloseHandle( map2 ); ret = DuplicateHandle( GetCurrentProcess(), mapping, GetCurrentProcess(), &map2, 0, FALSE, 0 ); - ok( ret, "DuplicateHandle failed error %u\n", GetLastError()); + ok( ret, "DuplicateHandle failed error %lu\n", GetLastError()); SetLastError(0xdeadbeef); ptr = MapViewOfFile( map2, 0, 0, 0, 4096 ); ok( !ptr, "MapViewOfFile succeeded\n" ); - ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() ); + ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %ld\n", GetLastError() ); CloseHandle( map2 ); ret = DuplicateHandle( GetCurrentProcess(), mapping, GetCurrentProcess(), &map2, FILE_MAP_READ, FALSE, 0 ); - ok( ret, "DuplicateHandle failed error %u\n", GetLastError()); + ok( ret, "DuplicateHandle failed error %lu\n", GetLastError()); ptr = MapViewOfFile( map2, 0, 0, 0, 4096 ); - ok( ptr != NULL, "MapViewOfFile NO_ACCESS error %u\n", GetLastError() ); + ok( ptr != NULL, "MapViewOfFile NO_ACCESS error %lu\n", GetLastError() ); UnmapViewOfFile( ptr ); CloseHandle( map2 ); @@ -511,56 +645,56 @@ static void test_MapViewOfFile(void) SetLastError(0xdeadbeef); mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 4096, NULL ); - ok( mapping != 0, "CreateFileMapping error %u\n", GetLastError() ); + ok( mapping != 0, "CreateFileMapping error %lu\n", GetLastError() ); SetLastError(0xdeadbeef); ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 ); - ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() ); + ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %lu\n", GetLastError() ); UnmapViewOfFile( ptr ); SetLastError(0xdeadbeef); ptr = MapViewOfFile( mapping, FILE_MAP_COPY, 0, 0, 4096 ); - ok( ptr != NULL, "MapViewOfFile FILE_MAP_COPY error %u\n", GetLastError() ); + ok( ptr != NULL, "MapViewOfFile FILE_MAP_COPY error %lu\n", GetLastError() ); UnmapViewOfFile( ptr ); SetLastError(0xdeadbeef); ptr = MapViewOfFile( mapping, 0, 0, 0, 4096 ); - ok( ptr != NULL, "MapViewOfFile 0 error %u\n", GetLastError() ); + ok( ptr != NULL, "MapViewOfFile 0 error %lu\n", GetLastError() ); UnmapViewOfFile( ptr ); SetLastError(0xdeadbeef); ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 4096 ); ok( !ptr, "MapViewOfFile FILE_MAP_WRITE succeeded\n" ); ok( GetLastError() == ERROR_INVALID_PARAMETER || - GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() ); + GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %ld\n", GetLastError() ); CloseHandle( mapping ); /* copy-on-write mapping */ SetLastError(0xdeadbeef); mapping = CreateFileMappingA( file, NULL, PAGE_WRITECOPY, 0, 4096, NULL ); - ok( mapping != 0, "CreateFileMapping error %u\n", GetLastError() ); + ok( mapping != 0, "CreateFileMapping error %lu\n", GetLastError() ); SetLastError(0xdeadbeef); ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 ); - ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() ); + ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %lu\n", GetLastError() ); UnmapViewOfFile( ptr ); SetLastError(0xdeadbeef); ptr = MapViewOfFile( mapping, FILE_MAP_COPY, 0, 0, 4096 ); - ok( ptr != NULL, "MapViewOfFile FILE_MAP_COPY error %u\n", GetLastError() ); + ok( ptr != NULL, "MapViewOfFile FILE_MAP_COPY error %lu\n", GetLastError() ); UnmapViewOfFile( ptr ); SetLastError(0xdeadbeef); ptr = MapViewOfFile( mapping, 0, 0, 0, 4096 ); - ok( ptr != NULL, "MapViewOfFile 0 error %u\n", GetLastError() ); + ok( ptr != NULL, "MapViewOfFile 0 error %lu\n", GetLastError() ); UnmapViewOfFile( ptr ); SetLastError(0xdeadbeef); ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 4096 ); ok( !ptr, "MapViewOfFile FILE_MAP_WRITE succeeded\n" ); ok( GetLastError() == ERROR_INVALID_PARAMETER || - GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() ); + GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %ld\n", GetLastError() ); CloseHandle( mapping ); /* no access mapping */ @@ -568,29 +702,29 @@ static void test_MapViewOfFile(void) SetLastError(0xdeadbeef); mapping = CreateFileMappingA( file, NULL, PAGE_NOACCESS, 0, 4096, NULL ); ok( !mapping, "CreateFileMappingA succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error %d\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error %ld\n", GetLastError() ); CloseHandle( file ); /* now try read-only file */ SetLastError(0xdeadbeef); file = CreateFileA( testfile, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0 ); - ok( file != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() ); + ok( file != INVALID_HANDLE_VALUE, "CreateFile error %lu\n", GetLastError() ); SetLastError(0xdeadbeef); mapping = CreateFileMappingA( file, NULL, PAGE_READWRITE, 0, 4096, NULL ); ok( !mapping, "CreateFileMapping PAGE_READWRITE succeeded\n" ); ok( GetLastError() == ERROR_INVALID_PARAMETER || - GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() ); + GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %ld\n", GetLastError() ); SetLastError(0xdeadbeef); mapping = CreateFileMappingA( file, NULL, PAGE_WRITECOPY, 0, 4096, NULL ); - ok( mapping != 0, "CreateFileMapping PAGE_WRITECOPY error %u\n", GetLastError() ); + ok( mapping != 0, "CreateFileMapping PAGE_WRITECOPY error %lu\n", GetLastError() ); CloseHandle( mapping ); SetLastError(0xdeadbeef); mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 4096, NULL ); - ok( mapping != 0, "CreateFileMapping PAGE_READONLY error %u\n", GetLastError() ); + ok( mapping != 0, "CreateFileMapping PAGE_READONLY error %lu\n", GetLastError() ); CloseHandle( mapping ); CloseHandle( file ); @@ -598,25 +732,25 @@ static void test_MapViewOfFile(void) SetLastError(0xdeadbeef); file = CreateFileA( testfile, 0, 0, NULL, OPEN_EXISTING, 0, 0 ); - ok( file != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() ); + ok( file != INVALID_HANDLE_VALUE, "CreateFile error %lu\n", GetLastError() ); SetLastError(0xdeadbeef); mapping = CreateFileMappingA( file, NULL, PAGE_READWRITE, 0, 4096, NULL ); ok( !mapping, "CreateFileMapping PAGE_READWRITE succeeded\n" ); ok( GetLastError() == ERROR_INVALID_PARAMETER || - GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() ); + GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %ld\n", GetLastError() ); SetLastError(0xdeadbeef); mapping = CreateFileMappingA( file, NULL, PAGE_WRITECOPY, 0, 4096, NULL ); ok( !mapping, "CreateFileMapping PAGE_WRITECOPY succeeded\n" ); ok( GetLastError() == ERROR_INVALID_PARAMETER || - GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() ); + GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %ld\n", GetLastError() ); SetLastError(0xdeadbeef); mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 4096, NULL ); ok( !mapping, "CreateFileMapping PAGE_READONLY succeeded\n" ); ok( GetLastError() == ERROR_INVALID_PARAMETER || - GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() ); + GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %ld\n", GetLastError() ); CloseHandle( file ); DeleteFileA( testfile ); @@ -630,82 +764,83 @@ static void test_MapViewOfFile(void) name = "Foo"; file = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4090, name ); } - ok( file != 0, "CreateFileMapping PAGE_READWRITE error %u\n", GetLastError() ); + ok( file != 0, "CreateFileMapping PAGE_READWRITE error %lu\n", GetLastError() ); SetLastError(0xdeadbeef); mapping = OpenFileMappingA( FILE_MAP_READ, FALSE, name ); - ok( mapping != 0, "OpenFileMapping FILE_MAP_READ error %u\n", GetLastError() ); + ok( mapping != 0, "OpenFileMapping FILE_MAP_READ error %lu\n", GetLastError() ); SetLastError(0xdeadbeef); ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 0 ); ok( !ptr, "MapViewOfFile FILE_MAP_WRITE succeeded\n" ); - ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() ); + ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %ld\n", GetLastError() ); SetLastError(0xdeadbeef); ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 ); - ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() ); + ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %lu\n", GetLastError() ); SetLastError(0xdeadbeef); size = VirtualQuery( ptr, &info, sizeof(info) ); ok( size == sizeof(info), - "VirtualQuery error %u\n", GetLastError() ); + "VirtualQuery error %lu\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 ); + ok( info.AllocationProtect == PAGE_READONLY, "%lx != PAGE_READONLY\n", info.AllocationProtect ); + ok( info.RegionSize == 4096, "%Ix != 4096\n", info.RegionSize ); + ok( info.State == MEM_COMMIT, "%lx != MEM_COMMIT\n", info.State ); + ok( info.Protect == PAGE_READONLY, "%lx != PAGE_READONLY\n", info.Protect ); UnmapViewOfFile( ptr ); status = pNtQuerySection( mapping, SectionBasicInformation, §ion_info, sizeof(section_info), &info_size ); - ok( status == STATUS_ACCESS_DENIED, "NtQuerySection failed err %x\n", status ); + ok( status == STATUS_ACCESS_DENIED, "NtQuerySection failed err %lx\n", status ); CloseHandle( mapping ); mapping = OpenFileMappingA( FILE_MAP_READ | SECTION_QUERY, FALSE, name ); - ok( mapping != 0, "OpenFileMapping FILE_MAP_READ error %u\n", GetLastError() ); + ok( mapping != 0, "OpenFileMapping FILE_MAP_READ error %lu\n", GetLastError() ); + info_size = (SIZE_T)0xdeadbeef << 16; status = pNtQuerySection( mapping, SectionBasicInformation, §ion_info, sizeof(section_info), &info_size ); - ok( !status, "NtQuerySection failed err %x\n", status ); - ok( info_size == sizeof(section_info), "NtQuerySection wrong size %u\n", info_size ); - ok( section_info.Attributes == SEC_COMMIT, "NtQuerySection wrong attr %08x\n", + ok( !status, "NtQuerySection failed err %lx\n", status ); + ok( info_size == sizeof(section_info), "NtQuerySection wrong size %Iu\n", info_size ); + ok( section_info.Attributes == SEC_COMMIT, "NtQuerySection wrong attr %08lx\n", section_info.Attributes ); ok( section_info.BaseAddress == NULL, "NtQuerySection wrong base %p\n", section_info.BaseAddress ); - ok( section_info.Size.QuadPart == info.RegionSize, "NtQuerySection wrong size %x%08x / %08lx\n", + ok( section_info.Size.QuadPart == info.RegionSize, "NtQuerySection wrong size %lx%08lx / %08Ix\n", section_info.Size.u.HighPart, section_info.Size.u.LowPart, info.RegionSize ); CloseHandle( mapping ); SetLastError(0xdeadbeef); mapping = OpenFileMappingA( FILE_MAP_WRITE, FALSE, name ); - ok( mapping != 0, "OpenFileMapping FILE_MAP_WRITE error %u\n", GetLastError() ); + ok( mapping != 0, "OpenFileMapping FILE_MAP_WRITE error %lu\n", GetLastError() ); SetLastError(0xdeadbeef); ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 ); ok( !ptr, "MapViewOfFile succeeded\n" ); - ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() ); + ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %ld\n", GetLastError() ); SetLastError(0xdeadbeef); ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 0 ); - ok( ptr != NULL, "MapViewOfFile FILE_MAP_WRITE error %u\n", GetLastError() ); + ok( ptr != NULL, "MapViewOfFile FILE_MAP_WRITE error %lu\n", GetLastError() ); SetLastError(0xdeadbeef); size = VirtualQuery( ptr, &info, sizeof(info) ); ok( size == sizeof(info), - "VirtualQuery error %u\n", GetLastError() ); + "VirtualQuery error %lu\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 ); + ok( info.AllocationProtect == PAGE_READWRITE, "%lx != PAGE_READWRITE\n", info.AllocationProtect ); + ok( info.RegionSize == 4096, "%Ix != 4096\n", info.RegionSize ); + ok( info.State == MEM_COMMIT, "%lx != MEM_COMMIT\n", info.State ); + ok( info.Protect == PAGE_READWRITE, "%lx != PAGE_READWRITE\n", info.Protect ); UnmapViewOfFile( ptr ); status = pNtQuerySection( mapping, SectionBasicInformation, §ion_info, sizeof(section_info), &info_size ); - ok( status == STATUS_ACCESS_DENIED, "NtQuerySection failed err %x\n", status ); + ok( status == STATUS_ACCESS_DENIED, "NtQuerySection failed err %lx\n", status ); CloseHandle( mapping ); mapping = OpenFileMappingA( FILE_MAP_WRITE | SECTION_QUERY, FALSE, name ); - ok( mapping != 0, "OpenFileMapping FILE_MAP_WRITE error %u\n", GetLastError() ); + ok( mapping != 0, "OpenFileMapping FILE_MAP_WRITE error %lu\n", GetLastError() ); status = pNtQuerySection( mapping, SectionBasicInformation, §ion_info, sizeof(section_info), &info_size ); - ok( !status, "NtQuerySection failed err %x\n", status ); - ok( info_size == sizeof(section_info), "NtQuerySection wrong size %u\n", info_size ); - ok( section_info.Attributes == SEC_COMMIT, "NtQuerySection wrong attr %08x\n", + ok( !status, "NtQuerySection failed err %lx\n", status ); + ok( info_size == sizeof(section_info), "NtQuerySection wrong size %Iu\n", info_size ); + ok( section_info.Attributes == SEC_COMMIT, "NtQuerySection wrong attr %08lx\n", section_info.Attributes ); ok( section_info.BaseAddress == NULL, "NtQuerySection wrong base %p\n", section_info.BaseAddress ); - ok( section_info.Size.QuadPart == info.RegionSize, "NtQuerySection wrong size %x%08x / %08lx\n", + ok( section_info.Size.QuadPart == info.RegionSize, "NtQuerySection wrong size %lx%08lx / %08Ix\n", section_info.Size.u.HighPart, section_info.Size.u.LowPart, info.RegionSize ); CloseHandle( mapping ); @@ -713,109 +848,203 @@ static void test_MapViewOfFile(void) /* read/write mapping with SEC_RESERVE */ mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | SEC_RESERVE, 0, MAPPING_SIZE, NULL); - ok(mapping != INVALID_HANDLE_VALUE, "CreateFileMappingA failed with error %d\n", GetLastError()); + ok(mapping != 0, "CreateFileMappingA failed with error %ld\n", GetLastError()); status = pNtQuerySection( mapping, SectionBasicInformation, §ion_info, sizeof(section_info), NULL ); - ok( !status, "NtQuerySection failed err %x\n", status ); - ok( section_info.Attributes == SEC_RESERVE, "NtQuerySection wrong attr %08x\n", + ok( !status, "NtQuerySection failed err %lx\n", status ); + ok( section_info.Attributes == SEC_RESERVE, "NtQuerySection wrong attr %08lx\n", section_info.Attributes ); ok( section_info.BaseAddress == NULL, "NtQuerySection wrong base %p\n", section_info.BaseAddress ); - ok( section_info.Size.QuadPart == MAPPING_SIZE, "NtQuerySection wrong size %x%08x / %08x\n", + ok( section_info.Size.QuadPart == MAPPING_SIZE, "NtQuerySection wrong size %lx%08lx / %08x\n", section_info.Size.u.HighPart, section_info.Size.u.LowPart, MAPPING_SIZE ); ptr = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0); - ok(ptr != NULL, "MapViewOfFile failed with error %d\n", GetLastError()); + ok(ptr != NULL, "MapViewOfFile failed with error %ld\n", GetLastError()); ptr2 = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0); - ok( ptr2 != NULL, "MapViewOfFile failed with error %d\n", GetLastError()); + ok( ptr2 != NULL, "MapViewOfFile failed with error %ld\n", GetLastError()); ok( ptr != ptr2, "MapViewOfFile returned same pointer\n" ); ret = VirtualQuery(ptr, &info, sizeof(info)); - ok(ret, "VirtualQuery failed with error %d\n", GetLastError()); + ok(ret, "VirtualQuery failed with error %ld\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.RegionSize == MAPPING_SIZE, "RegionSize should have been 0x%x but was 0x%lx\n", MAPPING_SIZE, info.RegionSize); - ok(info.State == MEM_RESERVE, "State should have been MEM_RESERVE instead of 0x%x\n", info.State); + ok(info.RegionSize == MAPPING_SIZE, "RegionSize should have been 0x%x but was 0x%Ix\n", MAPPING_SIZE, info.RegionSize); + ok(info.State == MEM_RESERVE, "State should have been MEM_RESERVE instead of 0x%lx\n", info.State); 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); + "AllocationProtect should have been PAGE_READWRITE but was 0x%lx\n", info.AllocationProtect); + ok(info.Protect == 0, "Protect should have been 0 instead of 0x%lx\n", info.Protect); + ok(info.Type == MEM_MAPPED, "Type should have been MEM_MAPPED instead of 0x%lx\n", info.Type); ret = VirtualQuery(ptr2, &info, sizeof(info)); - ok(ret, "VirtualQuery failed with error %d\n", GetLastError()); + ok(ret, "VirtualQuery failed with error %ld\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); + "AllocationProtect should have been PAGE_READWRITE but was 0x%lx\n", info.AllocationProtect); ok(info.RegionSize == MAPPING_SIZE, - "RegionSize should have been 0x%x but was 0x%lx\n", MAPPING_SIZE, 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); + "RegionSize should have been 0x%x but was 0x%Ix\n", MAPPING_SIZE, info.RegionSize); + ok(info.State == MEM_RESERVE, "State should have been MEM_RESERVE instead of 0x%lx\n", info.State); + ok(info.Protect == 0, "Protect should have been 0 instead of 0x%lx\n", info.Protect); + ok(info.Type == MEM_MAPPED, "Type should have been MEM_MAPPED instead of 0x%lx\n", info.Type); ptr = VirtualAlloc(ptr, 0x10000, MEM_COMMIT, PAGE_READONLY); - ok(ptr != NULL, "VirtualAlloc failed with error %d\n", GetLastError()); + ok(ptr != NULL, "VirtualAlloc failed with error %ld\n", GetLastError()); ret = VirtualQuery(ptr, &info, sizeof(info)); - ok(ret, "VirtualQuery failed with error %d\n", GetLastError()); + ok(ret, "VirtualQuery failed with error %ld\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.RegionSize == 0x10000, "RegionSize should have been 0x10000 but was 0x%lx\n", info.RegionSize); - ok(info.State == MEM_COMMIT, "State should have been MEM_COMMIT instead of 0x%x\n", info.State); - ok(info.Protect == PAGE_READONLY, "Protect should have been PAGE_READONLY instead of 0x%x\n", info.Protect); + ok(info.RegionSize == 0x10000, "RegionSize should have been 0x10000 but was 0x%Ix\n", info.RegionSize); + ok(info.State == MEM_COMMIT, "State should have been MEM_COMMIT instead of 0x%lx\n", info.State); + ok(info.Protect == PAGE_READONLY, "Protect should have been PAGE_READONLY instead of 0x%lx\n", info.Protect); 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); + "AllocationProtect should have been PAGE_READWRITE but was 0x%lx\n", info.AllocationProtect); + ok(info.Type == MEM_MAPPED, "Type should have been MEM_MAPPED instead of 0x%lx\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(ret, "VirtualQuery failed with error %ld\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); + "AllocationProtect should have been PAGE_READWRITE but was 0x%lx\n", info.AllocationProtect); ok(info.RegionSize == 0x10000, - "RegionSize should have been 0x10000 but was 0x%lx\n", info.RegionSize); + "RegionSize should have been 0x10000 but was 0x%Ix\n", info.RegionSize); ok(info.State == MEM_COMMIT, - "State should have been MEM_COMMIT instead of 0x%x\n", info.State); + "State should have been MEM_COMMIT instead of 0x%lx\n", info.State); ok(info.Protect == PAGE_READWRITE, - "Protect should have been PAGE_READWRITE 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); + "Protect should have been PAGE_READWRITE instead of 0x%lx\n", info.Protect); + ok(info.Type == MEM_MAPPED, "Type should have been MEM_MAPPED instead of 0x%lx\n", info.Type); addr = VirtualAlloc( ptr, MAPPING_SIZE, MEM_RESET, PAGE_READONLY ); - ok( addr == ptr, "VirtualAlloc failed with error %u\n", GetLastError() ); + ok( addr == ptr, "VirtualAlloc failed with error %lu\n", GetLastError() ); ret = VirtualFree( ptr, 0x10000, MEM_DECOMMIT ); ok( !ret, "VirtualFree succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "VirtualFree failed with %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "VirtualFree failed with %lu\n", GetLastError() ); ret = UnmapViewOfFile(ptr2); - ok(ret, "UnmapViewOfFile failed with error %d\n", GetLastError()); + ok(ret, "UnmapViewOfFile failed with error %ld\n", GetLastError()); ret = UnmapViewOfFile(ptr); - ok(ret, "UnmapViewOfFile failed with error %d\n", GetLastError()); + ok(ret, "UnmapViewOfFile failed with error %ld\n", GetLastError()); + CloseHandle(mapping); + + /* same thing with SEC_COMMIT */ + mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | SEC_COMMIT, 0, MAPPING_SIZE, NULL); + ok(mapping != 0, "CreateFileMappingA failed with error %ld\n", GetLastError()); + status = pNtQuerySection( mapping, SectionBasicInformation, §ion_info, + sizeof(section_info), NULL ); + ok( !status, "NtQuerySection failed err %lx\n", status ); + ok( section_info.Attributes == SEC_COMMIT, "NtQuerySection wrong attr %08lx\n", + section_info.Attributes ); + ok( section_info.BaseAddress == NULL, "NtQuerySection wrong base %p\n", section_info.BaseAddress ); + ok( section_info.Size.QuadPart == MAPPING_SIZE, "NtQuerySection wrong size %lx%08lx / %08x\n", + section_info.Size.u.HighPart, section_info.Size.u.LowPart, MAPPING_SIZE ); + + ptr = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0); + ok(ptr != NULL, "MapViewOfFile failed with error %ld\n", GetLastError()); + + ret = VirtualQuery(ptr, &info, sizeof(info)); + ok(ret, "VirtualQuery failed with error %ld\n", GetLastError()); + ok(info.BaseAddress == ptr, "wrong BaseAddress %p/%p\n", ptr, info.BaseAddress); + ok(info.AllocationBase == ptr, "wrong AllocationBase %p/%p\n", ptr, info.AllocationBase); + ok(info.RegionSize == MAPPING_SIZE, "wrong RegionSize 0x%Ix\n", info.RegionSize); + ok(info.State == MEM_COMMIT, "wrong State 0x%lx\n", info.State); + ok(info.AllocationProtect == PAGE_READWRITE, "wrong AllocationProtect 0x%lx\n", info.AllocationProtect); + ok(info.Protect == PAGE_READWRITE, "wrong Protect 0x%lx\n", info.Protect); + ok(info.Type == MEM_MAPPED, "wrong Type 0x%lx\n", info.Type); + + ptr = VirtualAlloc(ptr, 0x10000, MEM_COMMIT, PAGE_READONLY); + ok(ptr != NULL, "VirtualAlloc failed with error %ld\n", GetLastError()); + + ret = VirtualQuery(ptr, &info, sizeof(info)); + ok(ret, "VirtualQuery failed with error %ld\n", GetLastError()); + ok(info.BaseAddress == ptr, "wrong BaseAddress %p/%p\n", ptr, info.BaseAddress); + ok(info.AllocationBase == ptr, "wrong AllocationBase %p/%p\n", ptr, info.AllocationBase); + ok(info.RegionSize == 0x10000, "wrong RegionSize 0x%Ix\n", info.RegionSize); + ok(info.State == MEM_COMMIT, "wrong State 0x%lx\n", info.State); + ok(info.AllocationProtect == PAGE_READWRITE, "wrong AllocationProtect 0x%lx\n", info.AllocationProtect); + ok(info.Protect == PAGE_READONLY, "wrong Protect 0x%lx\n", info.Protect); + ok(info.Type == MEM_MAPPED, "wrong Type 0x%lx\n", info.Type); + + addr = VirtualAlloc( ptr, MAPPING_SIZE, MEM_RESET, PAGE_READONLY ); + ok( addr == ptr, "VirtualAlloc failed with error %lu\n", GetLastError() ); + + ret = VirtualFree( ptr, 0x10000, MEM_DECOMMIT ); + ok( !ret, "VirtualFree succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "VirtualFree failed with %lu\n", GetLastError() ); + + ret = UnmapViewOfFile(ptr); + ok(ret, "UnmapViewOfFile failed with error %ld\n", GetLastError()); + CloseHandle(mapping); + + /* same thing with SEC_NOCACHE (only supported on recent Windows versions) */ + mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | SEC_COMMIT | SEC_NOCACHE, + 0, MAPPING_SIZE, NULL); + ok(mapping != 0, "CreateFileMappingA failed with error %ld\n", GetLastError()); + status = pNtQuerySection( mapping, SectionBasicInformation, §ion_info, + sizeof(section_info), NULL ); + ok( !status, "NtQuerySection failed err %lx\n", status ); + ok( section_info.Attributes == (SEC_COMMIT | SEC_NOCACHE) || + broken(section_info.Attributes == SEC_COMMIT), + "NtQuerySection wrong attr %08lx\n", section_info.Attributes ); + if (section_info.Attributes & SEC_NOCACHE) + { + ptr = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0); + ok(ptr != NULL, "MapViewOfFile failed with error %ld\n", GetLastError()); + + ret = VirtualQuery(ptr, &info, sizeof(info)); + ok(ret, "VirtualQuery failed with error %ld\n", GetLastError()); + ok(info.BaseAddress == ptr, "wrong BaseAddress %p/%p\n", ptr, info.BaseAddress); + ok(info.AllocationBase == ptr, "wrong AllocationBase %p/%p\n", ptr, info.AllocationBase); + ok(info.RegionSize == MAPPING_SIZE, "wrong RegionSize 0x%Ix\n", info.RegionSize); + ok(info.State == MEM_COMMIT, "wrong State 0x%lx\n", info.State); + ok(info.AllocationProtect == (PAGE_READWRITE | PAGE_NOCACHE), + "wrong AllocationProtect 0x%lx\n", info.AllocationProtect); + ok(info.Protect == (PAGE_READWRITE | PAGE_NOCACHE), "wrong Protect 0x%lx\n", info.Protect); + ok(info.Type == MEM_MAPPED, "wrong Type 0x%lx\n", info.Type); + + ptr = VirtualAlloc(ptr, 0x10000, MEM_COMMIT, PAGE_READONLY); + ok(ptr != NULL, "VirtualAlloc failed with error %ld\n", GetLastError()); + + ret = VirtualQuery(ptr, &info, sizeof(info)); + ok(ret, "VirtualQuery failed with error %ld\n", GetLastError()); + ok(info.BaseAddress == ptr, "wrong BaseAddress %p/%p\n", ptr, info.BaseAddress); + ok(info.AllocationBase == ptr, "wrong AllocationBase %p/%p\n", ptr, info.AllocationBase); + ok(info.RegionSize == 0x10000, "wrong RegionSize 0x%Ix\n", info.RegionSize); + ok(info.State == MEM_COMMIT, "wrong State 0x%lx\n", info.State); + ok(info.AllocationProtect == (PAGE_READWRITE | PAGE_NOCACHE), + "wrong AllocationProtect 0x%lx\n", info.AllocationProtect); + ok(info.Protect == (PAGE_READONLY | PAGE_NOCACHE), "wrong Protect 0x%lx\n", info.Protect); + ok(info.Type == MEM_MAPPED, "wrong Type 0x%lx\n", info.Type); + + ret = UnmapViewOfFile(ptr); + ok(ret, "UnmapViewOfFile failed with error %ld\n", GetLastError()); + } CloseHandle(mapping); addr = VirtualAlloc(NULL, 0x10000, MEM_COMMIT, PAGE_READONLY ); - ok( addr != NULL, "VirtualAlloc failed with error %u\n", GetLastError() ); + ok( addr != NULL, "VirtualAlloc failed with error %lu\n", GetLastError() ); SetLastError(0xdeadbeef); ok( !UnmapViewOfFile(addr), "UnmapViewOfFile should fail on VirtualAlloc mem\n" ); ok( GetLastError() == ERROR_INVALID_ADDRESS, - "got %u, expected ERROR_INVALID_ADDRESS\n", GetLastError()); + "got %lu, expected ERROR_INVALID_ADDRESS\n", GetLastError()); SetLastError(0xdeadbeef); ok( !UnmapViewOfFile((char *)addr + 0x3000), "UnmapViewOfFile should fail on VirtualAlloc mem\n" ); ok( GetLastError() == ERROR_INVALID_ADDRESS, - "got %u, expected ERROR_INVALID_ADDRESS\n", GetLastError()); + "got %lu, expected ERROR_INVALID_ADDRESS\n", GetLastError()); SetLastError(0xdeadbeef); ok( !UnmapViewOfFile((void *)0xdeadbeef), "UnmapViewOfFile should fail on VirtualAlloc mem\n" ); ok( GetLastError() == ERROR_INVALID_ADDRESS, - "got %u, expected ERROR_INVALID_ADDRESS\n", GetLastError()); + "got %lu, expected ERROR_INVALID_ADDRESS\n", GetLastError()); ok( VirtualFree(addr, 0, MEM_RELEASE), "VirtualFree failed\n" ); @@ -823,491 +1052,284 @@ static void test_MapViewOfFile(void) name = "Foo"; SetLastError(0xdeadbeef); mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, MAPPING_SIZE, name); - ok( mapping != 0, "CreateFileMappingA failed with error %d\n", GetLastError() ); + ok( mapping != 0, "CreateFileMappingA failed with error %ld\n", GetLastError() ); SetLastError(0xdeadbeef); ptr = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0); - ok( ptr != NULL, "MapViewOfFile failed with error %d\n", GetLastError() ); + ok( ptr != NULL, "MapViewOfFile failed with error %ld\n", GetLastError() ); SetLastError(0xdeadbeef); map2 = OpenFileMappingA(FILE_MAP_READ, FALSE, name); - ok( map2 != 0, "OpenFileMappingA failed with error %d\n", GetLastError() ); + ok( map2 != 0, "OpenFileMappingA failed with error %ld\n", GetLastError() ); SetLastError(0xdeadbeef); ret = CloseHandle(map2); - ok(ret, "CloseHandle error %d\n", GetLastError()); + ok(ret, "CloseHandle error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = CloseHandle(mapping); - ok(ret, "CloseHandle error %d\n", GetLastError()); + ok(ret, "CloseHandle error %ld\n", GetLastError()); ret = IsBadReadPtr(ptr, MAPPING_SIZE); ok( !ret, "memory is not accessible\n" ); ret = VirtualQuery(ptr, &info, sizeof(info)); - ok(ret, "VirtualQuery error %d\n", GetLastError()); + ok(ret, "VirtualQuery error %ld\n", GetLastError()); ok(info.BaseAddress == ptr, "got %p != expected %p\n", info.BaseAddress, ptr); - ok(info.RegionSize == MAPPING_SIZE, "got %#lx != expected %#x\n", info.RegionSize, MAPPING_SIZE); - ok(info.Protect == PAGE_READWRITE, "got %#x != expected PAGE_READWRITE\n", info.Protect); + ok(info.RegionSize == MAPPING_SIZE, "got %#Ix != expected %#x\n", info.RegionSize, MAPPING_SIZE); + ok(info.Protect == PAGE_READWRITE, "got %#lx != expected PAGE_READWRITE\n", info.Protect); ok(info.AllocationBase == ptr, "%p != %p\n", info.AllocationBase, ptr); - ok(info.AllocationProtect == PAGE_READWRITE, "%#x != PAGE_READWRITE\n", info.AllocationProtect); - ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State); - ok(info.Type == MEM_MAPPED, "%#x != MEM_MAPPED\n", info.Type); + ok(info.AllocationProtect == PAGE_READWRITE, "%#lx != PAGE_READWRITE\n", info.AllocationProtect); + ok(info.State == MEM_COMMIT, "%#lx != MEM_COMMIT\n", info.State); + ok(info.Type == MEM_MAPPED, "%#lx != MEM_MAPPED\n", info.Type); SetLastError(0xdeadbeef); map2 = OpenFileMappingA(FILE_MAP_READ, FALSE, name); - todo_wine ok( map2 == 0, "OpenFileMappingA succeeded\n" ); - todo_wine - ok( GetLastError() == ERROR_FILE_NOT_FOUND, "OpenFileMappingA set error %d\n", GetLastError() ); + ok( GetLastError() == ERROR_FILE_NOT_FOUND, "OpenFileMappingA set error %ld\n", GetLastError() ); if (map2) CloseHandle(map2); /* FIXME: remove once Wine is fixed */ SetLastError(0xdeadbeef); mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, MAPPING_SIZE, name); ok( mapping != 0, "CreateFileMappingA failed\n" ); - todo_wine - ok( GetLastError() == ERROR_SUCCESS, "CreateFileMappingA set error %d\n", GetLastError() ); + ok( GetLastError() == ERROR_SUCCESS, "CreateFileMappingA set error %ld\n", GetLastError() ); SetLastError(0xdeadbeef); ret = CloseHandle(mapping); - ok(ret, "CloseHandle error %d\n", GetLastError()); + ok(ret, "CloseHandle error %ld\n", GetLastError()); ret = IsBadReadPtr(ptr, MAPPING_SIZE); ok( !ret, "memory is not accessible\n" ); ret = VirtualQuery(ptr, &info, sizeof(info)); - ok(ret, "VirtualQuery error %d\n", GetLastError()); + ok(ret, "VirtualQuery error %ld\n", GetLastError()); ok(info.BaseAddress == ptr, "got %p != expected %p\n", info.BaseAddress, ptr); - ok(info.RegionSize == MAPPING_SIZE, "got %#lx != expected %#x\n", info.RegionSize, MAPPING_SIZE); - ok(info.Protect == PAGE_READWRITE, "got %#x != expected PAGE_READWRITE\n", info.Protect); + ok(info.RegionSize == MAPPING_SIZE, "got %#Ix != expected %#x\n", info.RegionSize, MAPPING_SIZE); + ok(info.Protect == PAGE_READWRITE, "got %#lx != expected PAGE_READWRITE\n", info.Protect); ok(info.AllocationBase == ptr, "%p != %p\n", info.AllocationBase, ptr); - ok(info.AllocationProtect == PAGE_READWRITE, "%#x != PAGE_READWRITE\n", info.AllocationProtect); - ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State); - ok(info.Type == MEM_MAPPED, "%#x != MEM_MAPPED\n", info.Type); + ok(info.AllocationProtect == PAGE_READWRITE, "%#lx != PAGE_READWRITE\n", info.AllocationProtect); + ok(info.State == MEM_COMMIT, "%#lx != MEM_COMMIT\n", info.State); + ok(info.Type == MEM_MAPPED, "%#lx != MEM_MAPPED\n", info.Type); SetLastError(0xdeadbeef); ret = UnmapViewOfFile(ptr); - ok( ret, "UnmapViewOfFile failed with error %d\n", GetLastError() ); + ok( ret, "UnmapViewOfFile failed with error %ld\n", GetLastError() ); ret = IsBadReadPtr(ptr, MAPPING_SIZE); ok( ret, "memory is accessible\n" ); ret = VirtualQuery(ptr, &info, sizeof(info)); - ok(ret, "VirtualQuery error %d\n", GetLastError()); + ok(ret, "VirtualQuery error %ld\n", GetLastError()); ok(info.BaseAddress == ptr, "got %p != expected %p\n", info.BaseAddress, ptr); - ok(info.Protect == PAGE_NOACCESS, "got %#x != expected PAGE_NOACCESS\n", info.Protect); + ok(info.Protect == PAGE_NOACCESS, "got %#lx != expected PAGE_NOACCESS\n", info.Protect); ok(info.AllocationBase == NULL, "%p != NULL\n", info.AllocationBase); - ok(info.AllocationProtect == 0, "%#x != 0\n", info.AllocationProtect); - ok(info.State == MEM_FREE, "%#x != MEM_FREE\n", info.State); - ok(info.Type == 0, "%#x != 0\n", info.Type); + ok(info.AllocationProtect == 0, "%#lx != 0\n", info.AllocationProtect); + ok(info.State == MEM_FREE, "%#lx != MEM_FREE\n", info.State); + ok(info.Type == 0, "%#lx != 0\n", info.Type); SetLastError(0xdeadbeef); file = CreateFileA(testfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); - ok( file != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() ); + ok( file != INVALID_HANDLE_VALUE, "CreateFile error %lu\n", GetLastError() ); SetFilePointer(file, 4096, NULL, FILE_BEGIN); SetEndOfFile(file); SetLastError(0xdeadbeef); mapping = CreateFileMappingA(file, NULL, PAGE_READWRITE, 0, MAPPING_SIZE, name); - ok( mapping != 0, "CreateFileMappingA failed with error %d\n", GetLastError() ); + ok( mapping != 0, "CreateFileMappingA failed with error %ld\n", GetLastError() ); SetLastError(0xdeadbeef); ptr = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0); - ok( ptr != NULL, "MapViewOfFile failed with error %d\n", GetLastError() ); + ok( ptr != NULL, "MapViewOfFile failed with error %ld\n", GetLastError() ); SetLastError(0xdeadbeef); map2 = OpenFileMappingA(FILE_MAP_READ, FALSE, name); - ok( map2 != 0, "OpenFileMappingA failed with error %d\n", GetLastError() ); + ok( map2 != 0, "OpenFileMappingA failed with error %ld\n", GetLastError() ); SetLastError(0xdeadbeef); ret = CloseHandle(map2); - ok(ret, "CloseHandle error %d\n", GetLastError()); + ok(ret, "CloseHandle error %ld\n", GetLastError()); status = pNtQuerySection( mapping, SectionBasicInformation, §ion_info, sizeof(section_info), &info_size ); - ok( !status, "NtQuerySection failed err %x\n", status ); - ok( info_size == sizeof(section_info), "NtQuerySection wrong size %u\n", info_size ); - ok( section_info.Attributes == SEC_FILE, "NtQuerySection wrong attr %08x\n", + ok( !status, "NtQuerySection failed err %lx\n", status ); + ok( info_size == sizeof(section_info), "NtQuerySection wrong size %Iu\n", info_size ); + ok( section_info.Attributes == SEC_FILE, "NtQuerySection wrong attr %08lx\n", section_info.Attributes ); ok( section_info.BaseAddress == NULL, "NtQuerySection wrong base %p\n", section_info.BaseAddress ); - ok( section_info.Size.QuadPart == MAPPING_SIZE, "NtQuerySection wrong size %x%08x\n", + ok( section_info.Size.QuadPart == MAPPING_SIZE, "NtQuerySection wrong size %lx%08lx\n", section_info.Size.u.HighPart, section_info.Size.u.LowPart ); SetLastError(0xdeadbeef); ret = CloseHandle(mapping); - ok(ret, "CloseHandle error %d\n", GetLastError()); + ok(ret, "CloseHandle error %ld\n", GetLastError()); ret = IsBadReadPtr(ptr, MAPPING_SIZE); ok( !ret, "memory is not accessible\n" ); ret = VirtualQuery(ptr, &info, sizeof(info)); - ok(ret, "VirtualQuery error %d\n", GetLastError()); + ok(ret, "VirtualQuery error %ld\n", GetLastError()); ok(info.BaseAddress == ptr, "got %p != expected %p\n", info.BaseAddress, ptr); - ok(info.RegionSize == MAPPING_SIZE, "got %#lx != expected %#x\n", info.RegionSize, MAPPING_SIZE); - ok(info.Protect == PAGE_READWRITE, "got %#x != expected PAGE_READWRITE\n", info.Protect); + ok(info.RegionSize == MAPPING_SIZE, "got %#Ix != expected %#x\n", info.RegionSize, MAPPING_SIZE); + ok(info.Protect == PAGE_READWRITE, "got %#lx != expected PAGE_READWRITE\n", info.Protect); ok(info.AllocationBase == ptr, "%p != %p\n", info.AllocationBase, ptr); - ok(info.AllocationProtect == PAGE_READWRITE, "%#x != PAGE_READWRITE\n", info.AllocationProtect); - ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State); - ok(info.Type == MEM_MAPPED, "%#x != MEM_MAPPED\n", info.Type); + ok(info.AllocationProtect == PAGE_READWRITE, "%#lx != PAGE_READWRITE\n", info.AllocationProtect); + ok(info.State == MEM_COMMIT, "%#lx != MEM_COMMIT\n", info.State); + ok(info.Type == MEM_MAPPED, "%#lx != MEM_MAPPED\n", info.Type); SetLastError(0xdeadbeef); map2 = OpenFileMappingA(FILE_MAP_READ, FALSE, name); - todo_wine ok( map2 == 0, "OpenFileMappingA succeeded\n" ); - todo_wine - ok( GetLastError() == ERROR_FILE_NOT_FOUND, "OpenFileMappingA set error %d\n", GetLastError() ); + ok( GetLastError() == ERROR_FILE_NOT_FOUND, "OpenFileMappingA set error %ld\n", GetLastError() ); CloseHandle(map2); SetLastError(0xdeadbeef); mapping = CreateFileMappingA(file, NULL, PAGE_READWRITE, 0, MAPPING_SIZE, name); ok( mapping != 0, "CreateFileMappingA failed\n" ); - todo_wine - ok( GetLastError() == ERROR_SUCCESS, "CreateFileMappingA set error %d\n", GetLastError() ); + ok( GetLastError() == ERROR_SUCCESS, "CreateFileMappingA set error %ld\n", GetLastError() ); SetLastError(0xdeadbeef); ret = CloseHandle(mapping); - ok(ret, "CloseHandle error %d\n", GetLastError()); + ok(ret, "CloseHandle error %ld\n", GetLastError()); ret = IsBadReadPtr(ptr, MAPPING_SIZE); ok( !ret, "memory is not accessible\n" ); ret = VirtualQuery(ptr, &info, sizeof(info)); - ok(ret, "VirtualQuery error %d\n", GetLastError()); + ok(ret, "VirtualQuery error %ld\n", GetLastError()); ok(info.BaseAddress == ptr, "got %p != expected %p\n", info.BaseAddress, ptr); - ok(info.RegionSize == MAPPING_SIZE, "got %#lx != expected %#x\n", info.RegionSize, MAPPING_SIZE); - ok(info.Protect == PAGE_READWRITE, "got %#x != expected PAGE_READWRITE\n", info.Protect); + ok(info.RegionSize == MAPPING_SIZE, "got %#Ix != expected %#x\n", info.RegionSize, MAPPING_SIZE); + ok(info.Protect == PAGE_READWRITE, "got %#lx != expected PAGE_READWRITE\n", info.Protect); ok(info.AllocationBase == ptr, "%p != %p\n", info.AllocationBase, ptr); - ok(info.AllocationProtect == PAGE_READWRITE, "%#x != PAGE_READWRITE\n", info.AllocationProtect); - ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State); - ok(info.Type == MEM_MAPPED, "%#x != MEM_MAPPED\n", info.Type); + ok(info.AllocationProtect == PAGE_READWRITE, "%#lx != PAGE_READWRITE\n", info.AllocationProtect); + ok(info.State == MEM_COMMIT, "%#lx != MEM_COMMIT\n", info.State); + ok(info.Type == MEM_MAPPED, "%#lx != MEM_MAPPED\n", info.Type); SetLastError(0xdeadbeef); ret = UnmapViewOfFile(ptr); - ok( ret, "UnmapViewOfFile failed with error %d\n", GetLastError() ); + ok( ret, "UnmapViewOfFile failed with error %ld\n", GetLastError() ); ret = IsBadReadPtr(ptr, MAPPING_SIZE); ok( ret, "memory is accessible\n" ); ret = VirtualQuery(ptr, &info, sizeof(info)); - ok(ret, "VirtualQuery error %d\n", GetLastError()); + ok(ret, "VirtualQuery error %ld\n", GetLastError()); ok(info.BaseAddress == ptr, "got %p != expected %p\n", info.BaseAddress, ptr); - ok(info.Protect == PAGE_NOACCESS, "got %#x != expected PAGE_NOACCESS\n", info.Protect); + ok(info.Protect == PAGE_NOACCESS, "got %#lx != expected PAGE_NOACCESS\n", info.Protect); ok(info.AllocationBase == NULL, "%p != NULL\n", info.AllocationBase); - ok(info.AllocationProtect == 0, "%#x != 0\n", info.AllocationProtect); - ok(info.State == MEM_FREE, "%#x != MEM_FREE\n", info.State); - ok(info.Type == 0, "%#x != 0\n", info.Type); + ok(info.AllocationProtect == 0, "%#lx != 0\n", info.AllocationProtect); + ok(info.State == MEM_FREE, "%#lx != MEM_FREE\n", info.State); + ok(info.Type == 0, "%#lx != 0\n", info.Type); mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 12288, NULL ); - ok( mapping != NULL, "CreateFileMappingA failed with error %u\n", GetLastError() ); + ok( mapping != NULL, "CreateFileMappingA failed with error %lu\n", GetLastError() ); ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 12288 ); - ok( ptr != NULL, "MapViewOfFile failed with error %u\n", GetLastError() ); + ok( ptr != NULL, "MapViewOfFile failed with error %lu\n", GetLastError() ); ret = UnmapViewOfFile( (char *)ptr + 100 ); - ok( ret, "UnmapViewOfFile failed with error %u\n", GetLastError() ); + ok( ret, "UnmapViewOfFile failed with error %lu\n", GetLastError() ); ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 12288 ); - ok( ptr != NULL, "MapViewOfFile failed with error %u\n", GetLastError() ); + ok( ptr != NULL, "MapViewOfFile failed with error %lu\n", GetLastError() ); ret = UnmapViewOfFile( (char *)ptr + 4096 ); - ok( ret, "UnmapViewOfFile failed with error %u\n", GetLastError() ); + ok( ret, "UnmapViewOfFile failed with error %lu\n", GetLastError() ); ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 12288 ); - ok( ptr != NULL, "MapViewOfFile failed with error %u\n", GetLastError() ); + ok( ptr != NULL, "MapViewOfFile failed with error %lu\n", GetLastError() ); ret = UnmapViewOfFile( (char *)ptr + 4096 + 100 ); - ok( ret, "UnmapViewOfFile failed with error %u\n", GetLastError() ); + ok( ret, "UnmapViewOfFile failed with error %lu\n", GetLastError() ); CloseHandle(mapping); mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 36, NULL ); - ok( mapping != NULL, "CreateFileMappingA failed with error %u\n", GetLastError() ); + ok( mapping != NULL, "CreateFileMappingA failed with error %lu\n", GetLastError() ); status = pNtQuerySection( mapping, SectionBasicInformation, §ion_info, sizeof(section_info), &info_size ); - ok( !status, "NtQuerySection failed err %x\n", status ); - ok( info_size == sizeof(section_info), "NtQuerySection wrong size %u\n", info_size ); - ok( section_info.Attributes == SEC_FILE, "NtQuerySection wrong attr %08x\n", + ok( !status, "NtQuerySection failed err %lx\n", status ); + ok( info_size == sizeof(section_info), "NtQuerySection wrong size %Iu\n", info_size ); + ok( section_info.Attributes == SEC_FILE, "NtQuerySection wrong attr %08lx\n", section_info.Attributes ); ok( section_info.BaseAddress == NULL, "NtQuerySection wrong base %p\n", section_info.BaseAddress ); - ok( section_info.Size.QuadPart == 36, "NtQuerySection wrong size %x%08x\n", + ok( section_info.Size.QuadPart == 36, "NtQuerySection wrong size %lx%08lx\n", section_info.Size.u.HighPart, section_info.Size.u.LowPart ); CloseHandle(mapping); SetFilePointer(file, 0x3456, NULL, FILE_BEGIN); SetEndOfFile(file); mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 0, NULL ); - ok( mapping != NULL, "CreateFileMappingA failed with error %u\n", GetLastError() ); + ok( mapping != NULL, "CreateFileMappingA failed with error %lu\n", GetLastError() ); status = pNtQuerySection( mapping, SectionBasicInformation, §ion_info, sizeof(section_info), &info_size ); - ok( !status, "NtQuerySection failed err %x\n", status ); - ok( info_size == sizeof(section_info), "NtQuerySection wrong size %u\n", info_size ); - ok( section_info.Attributes == SEC_FILE, "NtQuerySection wrong attr %08x\n", + ok( !status, "NtQuerySection failed err %lx\n", status ); + ok( info_size == sizeof(section_info), "NtQuerySection wrong size %Iu\n", info_size ); + ok( section_info.Attributes == SEC_FILE, "NtQuerySection wrong attr %08lx\n", section_info.Attributes ); ok( section_info.BaseAddress == NULL, "NtQuerySection wrong base %p\n", section_info.BaseAddress ); - ok( section_info.Size.QuadPart == 0x3456, "NtQuerySection wrong size %x%08x\n", + ok( section_info.Size.QuadPart == 0x3456, "NtQuerySection wrong size %lx%08lx\n", section_info.Size.u.HighPart, section_info.Size.u.LowPart ); CloseHandle(mapping); map_size.QuadPart = 0x3457; status = pNtCreateSection( &mapping, SECTION_QUERY | SECTION_MAP_READ, NULL, &map_size, PAGE_READONLY, SEC_COMMIT, file ); - ok( status == STATUS_SECTION_TOO_BIG, "NtCreateSection failed %x\n", status ); + ok( status == STATUS_SECTION_TOO_BIG, "NtCreateSection failed %lx\n", status ); status = pNtCreateSection( &mapping, SECTION_QUERY | SECTION_MAP_READ, NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file ); - ok( status == STATUS_INVALID_IMAGE_NOT_MZ, "NtCreateSection failed %x\n", status ); + ok( status == STATUS_INVALID_IMAGE_NOT_MZ, "NtCreateSection failed %lx\n", status ); if (!status) CloseHandle( mapping ); map_size.QuadPart = 0x3452; status = pNtCreateSection( &mapping, SECTION_QUERY | SECTION_MAP_READ, NULL, &map_size, PAGE_READONLY, SEC_COMMIT, file ); - ok( !status, "NtCreateSection failed %x\n", status ); + ok( !status, "NtCreateSection failed %lx\n", status ); status = pNtQuerySection( mapping, SectionBasicInformation, §ion_info, sizeof(section_info), NULL ); - ok( !status, "NtQuerySection failed err %x\n", status ); - ok( section_info.Attributes == SEC_FILE, "NtQuerySection wrong attr %08x\n", + ok( !status, "NtQuerySection failed err %lx\n", status ); + ok( section_info.Attributes == SEC_FILE, "NtQuerySection wrong attr %08lx\n", section_info.Attributes ); ok( section_info.BaseAddress == NULL, "NtQuerySection wrong base %p\n", section_info.BaseAddress ); - ok( section_info.Size.QuadPart == 0x3452, "NtQuerySection wrong size %x%08x\n", + ok( section_info.Size.QuadPart == 0x3452, "NtQuerySection wrong size %lx%08lx\n", section_info.Size.u.HighPart, section_info.Size.u.LowPart ); size = map_size.QuadPart; status = pNtMapViewOfSection( mapping, GetCurrentProcess(), &ptr, 0, 0, NULL, &size, ViewShare, 0, PAGE_READONLY ); - ok( !status, "NtMapViewOfSection failed err %x\n", status ); + ok( !status, "NtMapViewOfSection failed err %lx\n", status ); pNtUnmapViewOfSection( GetCurrentProcess(), ptr ); size = map_size.QuadPart + 1; status = pNtMapViewOfSection( mapping, GetCurrentProcess(), &ptr, 0, 0, NULL, &size, ViewShare, 0, PAGE_READONLY ); - ok( status == STATUS_INVALID_VIEW_SIZE, "NtMapViewOfSection failed err %x\n", status ); + ok( status == STATUS_INVALID_VIEW_SIZE, "NtMapViewOfSection failed err %lx\n", status ); CloseHandle(mapping); status = pNtCreateSection( &mapping, SECTION_QUERY | SECTION_MAP_READ, NULL, &map_size, PAGE_READONLY, SEC_COMMIT, 0 ); - ok( !status, "NtCreateSection failed %x\n", status ); + ok( !status, "NtCreateSection failed %lx\n", status ); status = pNtQuerySection( mapping, SectionBasicInformation, §ion_info, sizeof(section_info), NULL ); - ok( !status, "NtQuerySection failed err %x\n", status ); - ok( section_info.Attributes == SEC_COMMIT, "NtQuerySection wrong attr %08x\n", + ok( !status, "NtQuerySection failed err %lx\n", status ); + ok( section_info.Attributes == SEC_COMMIT, "NtQuerySection wrong attr %08lx\n", section_info.Attributes ); ok( section_info.BaseAddress == NULL, "NtQuerySection wrong base %p\n", section_info.BaseAddress ); - ok( section_info.Size.QuadPart == 0x4000, "NtQuerySection wrong size %x%08x\n", + ok( section_info.Size.QuadPart == 0x4000, "NtQuerySection wrong size %lx%08lx\n", section_info.Size.u.HighPart, section_info.Size.u.LowPart ); status = pNtQuerySection( mapping, SectionBasicInformation, §ion_info, sizeof(section_info)-1, NULL ); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtQuerySection failed err %x\n", status ); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtQuerySection failed err %lx\n", status ); status = pNtQuerySection( mapping, SectionBasicInformation, §ion_info, sizeof(section_info)+1, NULL ); - ok( !status, "NtQuerySection failed err %x\n", status ); + ok( !status, "NtQuerySection failed err %lx\n", status ); status = pNtQuerySection( mapping, SectionImageInformation, &image_info, sizeof(image_info)-1, NULL ); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtQuerySection failed err %x\n", status ); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtQuerySection failed err %lx\n", status ); status = pNtQuerySection( mapping, SectionImageInformation, &image_info, sizeof(image_info), NULL ); - ok( status == STATUS_SECTION_NOT_IMAGE, "NtQuerySection failed err %x\n", status ); + ok( status == STATUS_SECTION_NOT_IMAGE, "NtQuerySection failed err %lx\n", status ); status = pNtQuerySection( mapping, SectionImageInformation, &image_info, sizeof(image_info)+1, NULL ); - ok( status == STATUS_SECTION_NOT_IMAGE, "NtQuerySection failed err %x\n", status ); + ok( status == STATUS_SECTION_NOT_IMAGE, "NtQuerySection failed err %lx\n", status ); + if (sizeof(SIZE_T) > sizeof(int)) + { + status = pNtQuerySection( mapping, SectionImageInformation, &image_info, + sizeof(image_info) + ((SIZE_T)0x10000000 << 8), NULL ); + todo_wine + ok( status == STATUS_ACCESS_VIOLATION, "NtQuerySection wrong err %lx\n", status ); + } CloseHandle(mapping); SetFilePointer(file, 0, NULL, FILE_BEGIN); SetEndOfFile(file); status = pNtCreateSection( &mapping, SECTION_QUERY | SECTION_MAP_READ, NULL, NULL, PAGE_READONLY, SEC_COMMIT, file ); - ok( status == STATUS_MAPPED_FILE_SIZE_ZERO, "NtCreateSection failed %x\n", status ); + ok( status == STATUS_MAPPED_FILE_SIZE_ZERO, "NtCreateSection failed %lx\n", status ); status = pNtCreateSection( &mapping, SECTION_QUERY | SECTION_MAP_READ, NULL, NULL, PAGE_READONLY, SEC_IMAGE, file ); - ok( status == STATUS_INVALID_FILE_FOR_SECTION, "NtCreateSection failed %x\n", status ); + ok( status == STATUS_INVALID_FILE_FOR_SECTION, "NtCreateSection failed %lx\n", status ); CloseHandle(file); DeleteFileA(testfile); } -static void test_NtMapViewOfSection(void) -{ - HANDLE hProcess; - - static const char testfile[] = "testfile.xxx"; - static const char data[] = "test data for NtMapViewOfSection"; - char buffer[sizeof(data)]; - HANDLE file, mapping; - void *ptr, *ptr2; - BOOL is_wow64, ret; - DWORD status, written; - SIZE_T size, result; - LARGE_INTEGER offset; - - if (!pNtMapViewOfSection || !pNtUnmapViewOfSection) - { - win_skip( "NtMapViewOfSection not available\n" ); - return; - } - - file = CreateFileA( testfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 ); - ok( file != INVALID_HANDLE_VALUE, "Failed to create test file\n" ); - WriteFile( file, data, sizeof(data), &written, NULL ); - SetFilePointer( file, 4096, NULL, FILE_BEGIN ); - SetEndOfFile( file ); - - /* read/write mapping */ - - mapping = CreateFileMappingA( file, NULL, PAGE_READWRITE, 0, 4096, NULL ); - ok( mapping != 0, "CreateFileMapping failed\n" ); - - hProcess = create_target_process("sleep"); - ok(hProcess != NULL, "Can't start process\n"); - - ptr = NULL; - size = 0; - offset.QuadPart = 0; - status = pNtMapViewOfSection( mapping, hProcess, &ptr, 0, 0, &offset, &size, 1, 0, PAGE_READWRITE ); - ok( !status, "NtMapViewOfSection failed status %x\n", status ); - ok( !((ULONG_PTR)ptr & 0xffff), "returned memory %p is not aligned to 64k\n", ptr ); - - ret = ReadProcessMemory( hProcess, ptr, buffer, sizeof(buffer), &result ); - ok( ret, "ReadProcessMemory failed\n" ); - ok( result == sizeof(buffer), "ReadProcessMemory didn't read all data (%lx)\n", result ); - ok( !memcmp( buffer, data, sizeof(buffer) ), "Wrong data read\n" ); - - /* for some unknown reason NtMapViewOfSection fails with STATUS_NO_MEMORY when zero_bits != 0 ? */ - ptr2 = NULL; - size = 0; - offset.QuadPart = 0; - status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 12, 0, &offset, &size, 1, 0, PAGE_READWRITE ); - todo_wine - ok( status == STATUS_NO_MEMORY, "NtMapViewOfSection returned %x\n", status ); - if (status == STATUS_SUCCESS) - { - status = pNtUnmapViewOfSection( hProcess, ptr2 ); - ok( !status, "NtUnmapViewOfSection failed status %x\n", status ); - } - - ptr2 = NULL; - size = 0; - status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 16, 0, &offset, &size, 1, 0, PAGE_READWRITE ); - todo_wine - ok( status == STATUS_NO_MEMORY, "NtMapViewOfSection returned %x\n", status ); - if (status == STATUS_SUCCESS) - { - status = pNtUnmapViewOfSection( hProcess, ptr2 ); - ok( !status, "NtUnmapViewOfSection failed status %x\n", status ); - } - - /* 22 zero bits isn't acceptable */ - ptr2 = NULL; - size = 0; - status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 22, 0, &offset, &size, 1, 0, PAGE_READWRITE ); - ok( status == STATUS_INVALID_PARAMETER_4, "NtMapViewOfSection returned %x\n", status ); - if (status == STATUS_SUCCESS) - { - status = pNtUnmapViewOfSection( hProcess, ptr2 ); - ok( !status, "NtUnmapViewOfSection failed status %x\n", status ); - } - - /* mapping at the same page conflicts */ - ptr2 = ptr; - size = 0; - offset.QuadPart = 0; - status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, &size, 1, 0, PAGE_READWRITE ); - ok( status == STATUS_CONFLICTING_ADDRESSES, "NtMapViewOfSection returned %x\n", status ); - - /* offset has to be aligned */ - ptr2 = ptr; - size = 0; - offset.QuadPart = 1; - status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, &size, 1, 0, PAGE_READWRITE ); - ok( status == STATUS_MAPPED_ALIGNMENT, "NtMapViewOfSection returned %x\n", status ); - - /* ptr has to be aligned */ - ptr2 = (char *)ptr + 42; - size = 0; - offset.QuadPart = 0; - status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, &size, 1, 0, PAGE_READWRITE ); - ok( status == STATUS_MAPPED_ALIGNMENT, "NtMapViewOfSection returned %x\n", status ); - - /* still not 64k aligned */ - ptr2 = (char *)ptr + 0x1000; - size = 0; - offset.QuadPart = 0; - status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, &size, 1, 0, PAGE_READWRITE ); - ok( status == STATUS_MAPPED_ALIGNMENT, "NtMapViewOfSection returned %x\n", status ); - - /* zero_bits != 0 is not allowed when an address is set */ - ptr2 = (char *)ptr + 0x1000; - size = 0; - offset.QuadPart = 0; - status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 12, 0, &offset, &size, 1, 0, PAGE_READWRITE ); - ok( status == STATUS_INVALID_PARAMETER_4, "NtMapViewOfSection returned %x\n", status ); - - ptr2 = (char *)ptr + 0x1000; - size = 0; - offset.QuadPart = 0; - status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 16, 0, &offset, &size, 1, 0, PAGE_READWRITE ); - ok( status == STATUS_INVALID_PARAMETER_4, "NtMapViewOfSection returned %x\n", status ); - - ptr2 = (char *)ptr + 0x1001; - size = 0; - offset.QuadPart = 0; - status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 16, 0, &offset, &size, 1, 0, PAGE_READWRITE ); - ok( status == STATUS_INVALID_PARAMETER_4, "NtMapViewOfSection returned %x\n", status ); - - ptr2 = (char *)ptr + 0x1000; - size = 0; - offset.QuadPart = 1; - status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 16, 0, &offset, &size, 1, 0, PAGE_READWRITE ); - ok( status == STATUS_INVALID_PARAMETER_4, "NtMapViewOfSection returned %x\n", status ); - - if (sizeof(void *) == sizeof(int) && (!pIsWow64Process || - !pIsWow64Process( GetCurrentProcess(), &is_wow64 ) || !is_wow64)) - { - /* new memory region conflicts with previous mapping */ - ptr2 = ptr; - size = 0; - offset.QuadPart = 0; - status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, - &size, 1, AT_ROUND_TO_PAGE, PAGE_READWRITE ); - ok( status == STATUS_CONFLICTING_ADDRESSES, "NtMapViewOfSection returned %x\n", status ); - - ptr2 = (char *)ptr + 42; - size = 0; - offset.QuadPart = 0; - status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, - &size, 1, AT_ROUND_TO_PAGE, PAGE_READWRITE ); - ok( status == STATUS_CONFLICTING_ADDRESSES, "NtMapViewOfSection returned %x\n", status ); - - /* in contrary to regular NtMapViewOfSection, only 4kb align is enforced */ - ptr2 = (char *)ptr + 0x1000; - size = 0; - offset.QuadPart = 0; - status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, - &size, 1, AT_ROUND_TO_PAGE, PAGE_READWRITE ); - ok( status == STATUS_SUCCESS, "NtMapViewOfSection returned %x\n", status ); - ok( (char *)ptr2 == (char *)ptr + 0x1000, - "expected address %p, got %p\n", (char *)ptr + 0x1000, ptr2 ); - status = pNtUnmapViewOfSection( hProcess, ptr2 ); - ok( !status, "NtUnmapViewOfSection failed status %x\n", status ); - - /* the address is rounded down if not on a page boundary */ - ptr2 = (char *)ptr + 0x1001; - size = 0; - offset.QuadPart = 0; - status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, - &size, 1, AT_ROUND_TO_PAGE, PAGE_READWRITE ); - ok( status == STATUS_SUCCESS, "NtMapViewOfSection returned %x\n", status ); - ok( (char *)ptr2 == (char *)ptr + 0x1000, - "expected address %p, got %p\n", (char *)ptr + 0x1000, ptr2 ); - status = pNtUnmapViewOfSection( hProcess, ptr2 ); - ok( !status, "NtUnmapViewOfSection failed status %x\n", status ); - - ptr2 = (char *)ptr + 0x2000; - size = 0; - offset.QuadPart = 0; - status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, - &size, 1, AT_ROUND_TO_PAGE, PAGE_READWRITE ); - ok( status == STATUS_SUCCESS, "NtMapViewOfSection returned %x\n", status ); - ok( (char *)ptr2 == (char *)ptr + 0x2000, - "expected address %p, got %p\n", (char *)ptr + 0x2000, ptr2 ); - status = pNtUnmapViewOfSection( hProcess, ptr2 ); - ok( !status, "NtUnmapViewOfSection failed status %x\n", status ); - } - else - { - ptr2 = (char *)ptr + 0x1000; - size = 0; - offset.QuadPart = 0; - status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, - &size, 1, AT_ROUND_TO_PAGE, PAGE_READWRITE ); - todo_wine - ok( status == STATUS_INVALID_PARAMETER_9, "NtMapViewOfSection returned %x\n", status ); - } - - status = pNtUnmapViewOfSection( hProcess, ptr ); - ok( !status, "NtUnmapViewOfSection failed status %x\n", status ); - - CloseHandle( mapping ); - CloseHandle( file ); - DeleteFileA( testfile ); - - TerminateProcess(hProcess, 0); - CloseHandle(hProcess); -} static void test_NtAreMappedFilesTheSame(void) { @@ -1325,73 +1347,73 @@ static void test_NtAreMappedFilesTheSame(void) file = CreateFileA( testfile, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0 ); - ok( file != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() ); + ok( file != INVALID_HANDLE_VALUE, "CreateFile error %lu\n", GetLastError() ); SetFilePointer( file, 4096, NULL, FILE_BEGIN ); SetEndOfFile( file ); mapping = CreateFileMappingA( file, NULL, PAGE_READWRITE, 0, 4096, NULL ); - ok( mapping != 0, "CreateFileMapping error %u\n", GetLastError() ); + ok( mapping != 0, "CreateFileMapping error %lu\n", GetLastError() ); ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 ); - ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() ); + ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %lu\n", GetLastError() ); file2 = CreateFileA( testfile, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 ); - ok( file2 != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() ); + ok( file2 != INVALID_HANDLE_VALUE, "CreateFile error %lu\n", GetLastError() ); map2 = CreateFileMappingA( file2, NULL, PAGE_READONLY, 0, 4096, NULL ); - ok( map2 != 0, "CreateFileMapping error %u\n", GetLastError() ); + ok( map2 != 0, "CreateFileMapping error %lu\n", GetLastError() ); ptr2 = MapViewOfFile( map2, FILE_MAP_READ, 0, 0, 4096 ); - ok( ptr2 != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() ); + ok( ptr2 != NULL, "MapViewOfFile FILE_MAP_READ error %lu\n", GetLastError() ); status = pNtAreMappedFilesTheSame( ptr, ptr2 ); - ok( status == STATUS_NOT_SAME_DEVICE, "NtAreMappedFilesTheSame returned %x\n", status ); + ok( status == STATUS_NOT_SAME_DEVICE, "NtAreMappedFilesTheSame returned %lx\n", status ); UnmapViewOfFile( ptr2 ); ptr2 = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 ); - ok( ptr2 != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() ); + ok( ptr2 != NULL, "MapViewOfFile FILE_MAP_READ error %lu\n", GetLastError() ); status = pNtAreMappedFilesTheSame( ptr, ptr2 ); - ok( status == STATUS_NOT_SAME_DEVICE, "NtAreMappedFilesTheSame returned %x\n", status ); + ok( status == STATUS_NOT_SAME_DEVICE, "NtAreMappedFilesTheSame returned %lx\n", status ); UnmapViewOfFile( ptr2 ); CloseHandle( map2 ); map2 = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 4096, NULL ); - ok( map2 != 0, "CreateFileMapping error %u\n", GetLastError() ); + ok( map2 != 0, "CreateFileMapping error %lu\n", GetLastError() ); ptr2 = MapViewOfFile( map2, FILE_MAP_READ, 0, 0, 4096 ); - ok( ptr2 != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() ); + ok( ptr2 != NULL, "MapViewOfFile FILE_MAP_READ error %lu\n", GetLastError() ); status = pNtAreMappedFilesTheSame( ptr, ptr2 ); - ok( status == STATUS_NOT_SAME_DEVICE, "NtAreMappedFilesTheSame returned %x\n", status ); + ok( status == STATUS_NOT_SAME_DEVICE, "NtAreMappedFilesTheSame returned %lx\n", status ); UnmapViewOfFile( ptr2 ); CloseHandle( map2 ); CloseHandle( file2 ); status = pNtAreMappedFilesTheSame( ptr, ptr ); ok( status == STATUS_SUCCESS || broken(status == STATUS_NOT_SAME_DEVICE), - "NtAreMappedFilesTheSame returned %x\n", status ); + "NtAreMappedFilesTheSame returned %lx\n", status ); status = pNtAreMappedFilesTheSame( ptr, (char *)ptr + 30 ); ok( status == STATUS_SUCCESS || broken(status == STATUS_NOT_SAME_DEVICE), - "NtAreMappedFilesTheSame returned %x\n", status ); + "NtAreMappedFilesTheSame returned %lx\n", status ); status = pNtAreMappedFilesTheSame( ptr, GetModuleHandleA("kernel32.dll") ); - ok( status == STATUS_NOT_SAME_DEVICE, "NtAreMappedFilesTheSame returned %x\n", status ); + ok( status == STATUS_NOT_SAME_DEVICE, "NtAreMappedFilesTheSame returned %lx\n", status ); status = pNtAreMappedFilesTheSame( ptr, (void *)0xdeadbeef ); ok( status == STATUS_CONFLICTING_ADDRESSES || status == STATUS_INVALID_ADDRESS, - "NtAreMappedFilesTheSame returned %x\n", status ); + "NtAreMappedFilesTheSame returned %lx\n", status ); status = pNtAreMappedFilesTheSame( ptr, NULL ); - ok( status == STATUS_INVALID_ADDRESS, "NtAreMappedFilesTheSame returned %x\n", status ); + ok( status == STATUS_INVALID_ADDRESS, "NtAreMappedFilesTheSame returned %lx\n", status ); status = pNtAreMappedFilesTheSame( ptr, (void *)GetProcessHeap() ); - ok( status == STATUS_CONFLICTING_ADDRESSES, "NtAreMappedFilesTheSame returned %x\n", status ); + ok( status == STATUS_CONFLICTING_ADDRESSES, "NtAreMappedFilesTheSame returned %lx\n", status ); status = pNtAreMappedFilesTheSame( NULL, NULL ); - ok( status == STATUS_INVALID_ADDRESS, "NtAreMappedFilesTheSame returned %x\n", status ); + ok( status == STATUS_INVALID_ADDRESS, "NtAreMappedFilesTheSame returned %lx\n", status ); ptr2 = VirtualAlloc( NULL, 0x10000, MEM_COMMIT, PAGE_READWRITE ); - ok( ptr2 != NULL, "VirtualAlloc error %u\n", GetLastError() ); + ok( ptr2 != NULL, "VirtualAlloc error %lu\n", GetLastError() ); status = pNtAreMappedFilesTheSame( ptr, ptr2 ); - ok( status == STATUS_CONFLICTING_ADDRESSES, "NtAreMappedFilesTheSame returned %x\n", status ); + ok( status == STATUS_CONFLICTING_ADDRESSES, "NtAreMappedFilesTheSame returned %lx\n", status ); VirtualFree( ptr2, 0, MEM_RELEASE ); UnmapViewOfFile( ptr ); @@ -1400,44 +1422,50 @@ static void test_NtAreMappedFilesTheSame(void) status = pNtAreMappedFilesTheSame( GetModuleHandleA("ntdll.dll"), GetModuleHandleA("kernel32.dll") ); - ok( status == STATUS_NOT_SAME_DEVICE, "NtAreMappedFilesTheSame returned %x\n", status ); + ok( status == STATUS_NOT_SAME_DEVICE, "NtAreMappedFilesTheSame returned %lx\n", status ); status = pNtAreMappedFilesTheSame( GetModuleHandleA("kernel32.dll"), GetModuleHandleA("kernel32.dll") ); - ok( status == STATUS_SUCCESS, "NtAreMappedFilesTheSame returned %x\n", status ); + ok( status == STATUS_SUCCESS, "NtAreMappedFilesTheSame returned %lx\n", status ); status = pNtAreMappedFilesTheSame( GetModuleHandleA("kernel32.dll"), (char *)GetModuleHandleA("kernel32.dll") + 4096 ); - ok( status == STATUS_SUCCESS, "NtAreMappedFilesTheSame returned %x\n", status ); + ok( status == STATUS_SUCCESS, "NtAreMappedFilesTheSame returned %lx\n", status ); GetSystemDirectoryA( path, MAX_PATH ); strcat( path, "\\kernel32.dll" ); file = CreateFileA( path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 ); - ok( file != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() ); + ok( file != INVALID_HANDLE_VALUE, "CreateFile error %lu\n", GetLastError() ); mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 4096, NULL ); - ok( mapping != 0, "CreateFileMapping error %u\n", GetLastError() ); + ok( mapping != 0, "CreateFileMapping error %lu\n", GetLastError() ); ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 ); - ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() ); + ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %lu\n", GetLastError() ); status = pNtAreMappedFilesTheSame( ptr, GetModuleHandleA("kernel32.dll") ); - ok( status == STATUS_NOT_SAME_DEVICE, "NtAreMappedFilesTheSame returned %x\n", status ); + ok( status == STATUS_NOT_SAME_DEVICE, "NtAreMappedFilesTheSame returned %lx\n", status ); + status = pNtAreMappedFilesTheSame( GetModuleHandleA("kernel32.dll"), ptr ); + todo_wine + ok( status == STATUS_SUCCESS, "NtAreMappedFilesTheSame returned %lx\n", status ); UnmapViewOfFile( ptr ); CloseHandle( mapping ); mapping = CreateFileMappingA( file, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL ); - ok( mapping != 0, "CreateFileMapping error %u\n", GetLastError() ); + ok( mapping != 0, "CreateFileMapping error %lu\n", GetLastError() ); ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 ); - ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() ); + ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %lu\n", GetLastError() ); status = pNtAreMappedFilesTheSame( ptr, GetModuleHandleA("kernel32.dll") ); - todo_wine - ok( status == STATUS_SUCCESS, "NtAreMappedFilesTheSame returned %x\n", status ); + ok( status == STATUS_SUCCESS, "NtAreMappedFilesTheSame returned %lx\n", status ); + status = pNtAreMappedFilesTheSame( GetModuleHandleA("kernel32.dll"), ptr ); + ok( status == STATUS_SUCCESS, "NtAreMappedFilesTheSame returned %lx\n", status ); file2 = CreateFileA( path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 ); - ok( file2 != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() ); + ok( file2 != INVALID_HANDLE_VALUE, "CreateFile error %lu\n", GetLastError() ); map2 = CreateFileMappingA( file2, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL ); - ok( map2 != 0, "CreateFileMapping error %u\n", GetLastError() ); + ok( map2 != 0, "CreateFileMapping error %lu\n", GetLastError() ); ptr2 = MapViewOfFile( map2, FILE_MAP_READ, 0, 0, 0 ); - ok( ptr2 != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() ); + ok( ptr2 != NULL, "MapViewOfFile FILE_MAP_READ error %lu\n", GetLastError() ); status = pNtAreMappedFilesTheSame( ptr, ptr2 ); - ok( status == STATUS_SUCCESS, "NtAreMappedFilesTheSame returned %x\n", status ); + ok( status == STATUS_SUCCESS, "NtAreMappedFilesTheSame returned %lx\n", status ); + status = pNtAreMappedFilesTheSame( ptr2, ptr ); + ok( status == STATUS_SUCCESS, "NtAreMappedFilesTheSame returned %lx\n", status ); UnmapViewOfFile( ptr2 ); CloseHandle( map2 ); CloseHandle( file2 ); @@ -1451,41 +1479,151 @@ static void test_NtAreMappedFilesTheSame(void) static void test_CreateFileMapping(void) { - HANDLE handle, handle2; + HANDLE handle, handle2, file[3]; + char path[MAX_PATH], filename[MAX_PATH]; + unsigned int i; + NTSTATUS status; + + static const struct { DWORD file, flags, error, attrs; } sec_flag_tests[] = + { + /* anonymous mapping */ + { 0, SEC_RESERVE, 0 }, /* 0 */ + { 0, SEC_RESERVE | SEC_NOCACHE, 0 }, + { 0, SEC_RESERVE | SEC_LARGE_PAGES, ERROR_INVALID_PARAMETER }, + { 0, SEC_RESERVE | SEC_WRITECOMBINE, 0 }, + { 0, SEC_COMMIT, 0 }, + { 0, SEC_COMMIT | SEC_NOCACHE, 0 }, /* 5 */ + { 0, SEC_COMMIT | SEC_WRITECOMBINE, 0 }, + { 0, SEC_RESERVE | SEC_COMMIT, ERROR_INVALID_PARAMETER }, + { 0, SEC_IMAGE, ERROR_BAD_EXE_FORMAT }, + { 0, SEC_IMAGE | SEC_RESERVE, ERROR_INVALID_PARAMETER }, + { 0, SEC_IMAGE | SEC_COMMIT, ERROR_INVALID_PARAMETER }, /* 10 */ + { 0, SEC_NOCACHE, ERROR_INVALID_PARAMETER }, + { 0, SEC_LARGE_PAGES, ERROR_INVALID_PARAMETER }, + { 0, SEC_WRITECOMBINE, ERROR_INVALID_PARAMETER }, + { 0, SEC_FILE, ERROR_INVALID_PARAMETER }, + { 0, SEC_FILE | SEC_RESERVE, ERROR_INVALID_PARAMETER }, /* 15 */ + { 0, SEC_FILE | SEC_COMMIT, ERROR_INVALID_PARAMETER }, + { 0, 0, 0, SEC_COMMIT }, + /* normal file */ + { 1, SEC_RESERVE, 0, SEC_FILE }, + { 1, SEC_RESERVE | SEC_NOCACHE, 0, SEC_FILE | SEC_NOCACHE }, + { 1, SEC_RESERVE | SEC_LARGE_PAGES, ERROR_INVALID_PARAMETER }, /* 20 */ + { 1, SEC_RESERVE | SEC_WRITECOMBINE, 0, SEC_FILE | SEC_WRITECOMBINE }, + { 1, SEC_COMMIT, 0, SEC_FILE }, + { 1, SEC_COMMIT | SEC_NOCACHE, 0, SEC_FILE | SEC_NOCACHE }, + { 1, SEC_COMMIT | SEC_LARGE_PAGES, ERROR_INVALID_PARAMETER }, + { 1, SEC_COMMIT | SEC_WRITECOMBINE, 0, SEC_FILE | SEC_WRITECOMBINE }, /* 25 */ + { 1, SEC_RESERVE | SEC_COMMIT, ERROR_INVALID_PARAMETER }, + { 1, SEC_IMAGE, ERROR_BAD_EXE_FORMAT }, + { 1, SEC_IMAGE | SEC_RESERVE, ERROR_INVALID_PARAMETER }, + { 1, SEC_IMAGE | SEC_COMMIT, ERROR_INVALID_PARAMETER }, + { 1, SEC_NOCACHE, ERROR_INVALID_PARAMETER }, /* 30 */ + { 1, SEC_LARGE_PAGES, ERROR_INVALID_PARAMETER }, + { 1, SEC_WRITECOMBINE, ERROR_INVALID_PARAMETER }, + { 1, SEC_FILE, ERROR_INVALID_PARAMETER }, + { 1, SEC_FILE | SEC_RESERVE, ERROR_INVALID_PARAMETER }, + { 1, SEC_FILE | SEC_COMMIT, ERROR_INVALID_PARAMETER }, /* 35 */ + { 1, 0, 0, SEC_FILE }, + /* PE image file */ + { 2, SEC_IMAGE, 0, SEC_FILE | SEC_IMAGE }, + { 2, SEC_IMAGE | SEC_FILE, ERROR_INVALID_PARAMETER }, + { 2, SEC_IMAGE | SEC_NOCACHE, 0, SEC_FILE | SEC_IMAGE }, + { 2, SEC_IMAGE | SEC_LARGE_PAGES, ERROR_INVALID_PARAMETER }, /* 40 */ + { 2, SEC_IMAGE | SEC_WRITECOMBINE, ERROR_INVALID_PARAMETER }, + { 2, SEC_IMAGE | SEC_RESERVE, ERROR_INVALID_PARAMETER }, + { 2, SEC_IMAGE | SEC_COMMIT, ERROR_INVALID_PARAMETER }, + }; /* 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()); + ok( handle != NULL, "CreateFileMapping failed with error %lu\n", GetLastError()); + ok( GetLastError() == 0, "wrong error %lu\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()); + ok( handle2 != NULL, "CreateFileMapping failed with error %ld\n", GetLastError()); + ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %lu\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()); + ok( handle2 != NULL, "CreateFileMapping failed with error %ld\n", GetLastError()); + ok( GetLastError() == 0, "wrong error %lu\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()); + ok( handle2 != NULL, "OpenFileMapping failed with error %ld\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, "wrong error %u\n", GetLastError()); + ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError()); CloseHandle( handle ); + + /* test SEC_* flags */ + + file[0] = INVALID_HANDLE_VALUE; + GetTempPathA( MAX_PATH, path ); + GetTempFileNameA( path, "map", 0, filename ); + + file[1] = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( file[1] != INVALID_HANDLE_VALUE, "CreateFile error %lu\n", GetLastError() ); + SetFilePointer( file[1], 0x2000, NULL, FILE_BEGIN ); + SetEndOfFile( file[1] ); + + GetSystemDirectoryA( path, MAX_PATH ); + strcat( path, "\\kernel32.dll" ); + file[2] = CreateFileA( path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 ); + ok( file[2] != INVALID_HANDLE_VALUE, "CreateFile error %lu\n", GetLastError() ); + + for (i = 0; i < ARRAY_SIZE(sec_flag_tests); i++) + { + DWORD flags = sec_flag_tests[i].flags; + DWORD perm = sec_flag_tests[i].file == 2 ? PAGE_READONLY : PAGE_READWRITE; + SetLastError( 0xdeadbeef ); + handle = CreateFileMappingA( file[sec_flag_tests[i].file], NULL, + flags | perm, 0, 0x1000, "Wine Test Mapping" ); + if (sec_flag_tests[i].error) + { + ok( !handle, "%u: CreateFileMapping succeeded\n", i ); + ok( GetLastError() == sec_flag_tests[i].error, "%u: wrong error %lu\n", i, GetLastError()); + } + else + { + /* SEC_WRITECOMBINE and SEC_IMAGE_NO_EXECUTE not supported on older Windows */ + BOOL new_flags = ((flags & SEC_WRITECOMBINE) || + ((flags & SEC_IMAGE_NO_EXECUTE) == SEC_IMAGE_NO_EXECUTE)); + ok( handle != NULL || broken(new_flags), + "%u: CreateFileMapping failed with error %lu\n", i, GetLastError()); + ok( GetLastError() == 0 || broken(new_flags && GetLastError() == ERROR_INVALID_PARAMETER), + "%u: wrong error %lu\n", i, GetLastError()); + } + + if (handle) + { + SECTION_BASIC_INFORMATION info; + DWORD expect = sec_flag_tests[i].attrs ? sec_flag_tests[i].attrs : sec_flag_tests[i].flags; + + status = pNtQuerySection( handle, SectionBasicInformation, &info, sizeof(info), NULL ); + ok( !status, "%u: NtQuerySection failed err %lx\n", i, status ); + /* SEC_NOCACHE not supported on older Windows */ + ok( info.Attributes == expect || broken( info.Attributes == (expect & ~SEC_NOCACHE) ), + "%u: NtQuerySection wrong attr %08lx\n", i, info.Attributes ); + CloseHandle( handle ); + } + } + CloseHandle( file[1] ); + CloseHandle( file[2] ); + DeleteFileA( filename ); } static void test_IsBadReadPtr(void) @@ -1511,6 +1649,12 @@ static void test_IsBadReadPtr(void) ret = IsBadReadPtr(&stackvar, sizeof(char)); ok(ret == FALSE, "Expected IsBadReadPtr to return FALSE, got %d\n", ret); + + ret = IsBadReadPtr((char *)NtCurrentTeb()->DeallocationStack + 4096, sizeof(DWORD)); + ok(ret == TRUE, "Expected IsBadReadPtr to return TRUE, got %d\n", ret); + + ret = IsBadReadPtr((char *)NtCurrentTeb()->DeallocationStack + 4096, sizeof(DWORD)); + ok(ret == TRUE, "Expected IsBadReadPtr to return TRUE, got %d\n", ret); } static void test_IsBadWritePtr(void) @@ -1536,6 +1680,12 @@ static void test_IsBadWritePtr(void) ret = IsBadWritePtr(&stackval, sizeof(char)); ok(ret == FALSE, "Expected IsBadWritePtr to return FALSE, got %d\n", ret); + + ret = IsBadWritePtr((char *)NtCurrentTeb()->DeallocationStack + 4096, sizeof(DWORD)); + ok(ret == TRUE, "Expected IsBadWritePtr to return TRUE, got %d\n", ret); + + ret = IsBadWritePtr((char *)NtCurrentTeb()->DeallocationStack + 4096, sizeof(DWORD)); + ok(ret == TRUE, "Expected IsBadWritePtr to return TRUE, got %d\n", ret); } static void test_IsBadCodePtr(void) @@ -1554,19 +1704,44 @@ static void test_IsBadCodePtr(void) ok(ret == FALSE, "Expected IsBadCodePtr to return FALSE, got %d\n", ret); } +struct read_pipe_args +{ + HANDLE pipe; + int index; + void *base; + DWORD size; +}; + +static const char testdata[] = "Hello World"; + +static DWORD CALLBACK read_pipe( void *arg ) +{ + struct read_pipe_args *args = arg; + DWORD num_bytes; + BOOL success = ConnectNamedPipe( args->pipe, NULL ); + ok( success || GetLastError() == ERROR_PIPE_CONNECTED, + "%u: ConnectNamedPipe failed %lu\n", args->index, GetLastError() ); + + success = ReadFile( args->pipe, args->base, args->size, &num_bytes, NULL ); + ok( success, "%u: ReadFile failed %lu\n", args->index, GetLastError() ); + ok( num_bytes == sizeof(testdata), "%u: wrong number of bytes read %lu\n", args->index, num_bytes ); + ok( !memcmp( args->base, testdata, sizeof(testdata)), + "%u: didn't receive expected data\n", args->index ); + return 0; +} + static void test_write_watch(void) { static const char pipename[] = "\\\\.\\pipe\\test_write_watch_pipe"; - static const char testdata[] = "Hello World"; DWORD ret, size, old_prot, num_bytes; MEMORY_BASIC_INFORMATION info; - HANDLE readpipe, writepipe; - OVERLAPPED overlapped; + HANDLE readpipe, writepipe, file; + OVERLAPPED overlapped, *overlapped2; void *results[64]; ULONG_PTR count; - ULONG pagesize; + ULONG i, pagesize; BOOL success; - char *base; + char path[MAX_PATH], filename[MAX_PATH], *base; if (!pGetWriteWatch || !pResetWriteWatch) { @@ -1582,195 +1757,349 @@ static void test_write_watch(void) win_skip( "MEM_WRITE_WATCH not supported\n" ); return; } - ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() ); + ok( base != NULL, "VirtualAlloc failed %lu\n", GetLastError() ); ret = VirtualQuery( base, &info, sizeof(info) ); - ok(ret, "VirtualQuery failed %u\n", GetLastError()); + ok(ret, "VirtualQuery failed %lu\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 ); + ok( info.AllocationProtect == PAGE_READWRITE, "wrong AllocationProtect %lx\n", info.AllocationProtect ); + ok( info.RegionSize == size, "wrong RegionSize 0x%Ix\n", info.RegionSize ); + ok( info.State == MEM_COMMIT, "wrong State 0x%lx\n", info.State ); + ok( info.Protect == PAGE_READWRITE, "wrong Protect 0x%lx\n", info.Protect ); + ok( info.Type == MEM_PRIVATE, "wrong Type 0x%lx\n", info.Type ); count = 64; SetLastError( 0xdeadbeef ); ret = pGetWriteWatch( 0, NULL, size, results, &count, &pagesize ); - ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret ); + ok( ret == ~0u, "GetWriteWatch succeeded %lu\n", ret ); ok( GetLastError() == ERROR_INVALID_PARAMETER || broken( GetLastError() == 0xdeadbeef ), /* win98 */ - "wrong error %u\n", GetLastError() ); + "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); ret = pGetWriteWatch( 0, GetModuleHandleW(NULL), size, results, &count, &pagesize ); if (ret) { - ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( ret == ~0u, "GetWriteWatch succeeded %lu\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); } else /* win98 */ { - ok( count == 0, "wrong count %lu\n", count ); + ok( count == 0, "wrong count %Iu\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 ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 0, "wrong count %Iu\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( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 1, "wrong count %Iu\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( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 1, "wrong count %Iu\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 ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 0, "wrong count %Iu\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( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 2, "wrong count %Iu\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( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 1, "wrong count %Iu\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() ); + ok( !ret, "pResetWriteWatch failed %lu\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( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 1, "wrong count %Iu\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( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 3, "wrong count %Iu\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( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 1, "wrong count %Iu\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( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 2, "wrong count %Iu\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 ); + ok( ret, "VirtualProtect failed error %lu\n", GetLastError() ); + ok( old_prot == PAGE_READWRITE, "wrong old prot %lx\n", old_prot ); ret = VirtualQuery( base, &info, sizeof(info) ); - ok(ret, "VirtualQuery failed %u\n", GetLastError()); + ok(ret, "VirtualQuery failed %lu\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 ); + ok( info.RegionSize == 3*pagesize, "wrong RegionSize 0x%Ix\n", info.RegionSize ); + ok( info.State == MEM_COMMIT, "wrong State 0x%lx\n", info.State ); + ok( info.Protect == PAGE_READONLY, "wrong Protect 0x%lx\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 ); + ok( ret, "VirtualProtect failed error %lu\n", GetLastError() ); + ok( old_prot == PAGE_READONLY, "wrong old prot %lx\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( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 2, "wrong count %Iu\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(ret, "VirtualQuery failed %lu\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 ); + ok( info.RegionSize == size, "wrong RegionSize 0x%Ix\n", info.RegionSize ); + ok( info.State == MEM_COMMIT, "wrong State 0x%lx\n", info.State ); + ok( info.Protect == PAGE_READWRITE, "wrong Protect 0x%lx\n", info.Protect ); /* ReadFile should trigger write watches */ + for (i = 0; i < 2; i++) + { + memset( &overlapped, 0, sizeof(overlapped) ); + overlapped.hEvent = CreateEventA( NULL, TRUE, FALSE, NULL ); + + readpipe = CreateNamedPipeA( pipename, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_INBOUND, + (i ? PIPE_TYPE_MESSAGE : PIPE_TYPE_BYTE) | PIPE_WAIT, 1, 1024, 1024, + NMPWAIT_USE_DEFAULT_WAIT, NULL ); + ok( readpipe != INVALID_HANDLE_VALUE, "CreateNamedPipeA failed %lu\n", GetLastError() ); + + success = ConnectNamedPipe( readpipe, &overlapped ); + ok( !success, "%lu: ConnectNamedPipe unexpectedly succeeded\n", i ); + ok( GetLastError() == ERROR_IO_PENDING, "%lu: expected ERROR_IO_PENDING, got %lu\n", + i, GetLastError() ); + + writepipe = CreateFileA( pipename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL ); + ok( writepipe != INVALID_HANDLE_VALUE, "%lu: CreateFileA failed %lu\n", i, GetLastError() ); + + ret = WaitForSingleObject( overlapped.hEvent, 1000 ); + ok( ret == WAIT_OBJECT_0, "%lu: expected WAIT_OBJECT_0, got %lu\n", i, ret ); + + memset( base, 0, size ); + + count = 64; + ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); + ok( !ret, "%lu: GetWriteWatch failed %lu\n", i, GetLastError() ); + ok( count == 16, "%lu: wrong count %Iu\n", i, count ); + + success = ReadFile( readpipe, base, size, NULL, &overlapped ); + ok( !success, "%lu: ReadFile unexpectedly succeeded\n", i ); + ok( GetLastError() == ERROR_IO_PENDING, "%lu: expected ERROR_IO_PENDING, got %lu\n", + i, GetLastError() ); + + count = 64; + ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); + ok( !ret, "%lu: GetWriteWatch failed %lu\n", i, GetLastError() ); + ok( count == 16, "%lu: wrong count %Iu\n", i, count ); + + num_bytes = 0; + success = WriteFile( writepipe, testdata, sizeof(testdata), &num_bytes, NULL ); + ok( success, "%lu: WriteFile failed %lu\n", i, GetLastError() ); + ok( num_bytes == sizeof(testdata), "%lu: wrong number of bytes written %lu\n", i, num_bytes ); + + num_bytes = 0; + success = GetOverlappedResult( readpipe, &overlapped, &num_bytes, TRUE ); + ok( success, "%lu: GetOverlappedResult failed %lu\n", i, GetLastError() ); + ok( num_bytes == sizeof(testdata), "%lu: wrong number of bytes read %lu\n", i, num_bytes ); + ok( !memcmp( base, testdata, sizeof(testdata)), "%lu: didn't receive expected data\n", i ); + + count = 64; + memset( results, 0, sizeof(results) ); + ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); + ok( !ret, "%lu: GetWriteWatch failed %lu\n", i, GetLastError() ); + ok( count == 1, "%lu: wrong count %Iu\n", i, count ); + ok( results[0] == base, "%lu: wrong result %p\n", i, results[0] ); + + CloseHandle( readpipe ); + CloseHandle( writepipe ); + CloseHandle( overlapped.hEvent ); + } + + for (i = 0; i < 2; i++) + { + struct read_pipe_args args; + HANDLE thread; + + readpipe = CreateNamedPipeA( pipename, PIPE_ACCESS_INBOUND, + (i ? PIPE_TYPE_MESSAGE : PIPE_TYPE_BYTE) | PIPE_WAIT, 1, 1024, 1024, + NMPWAIT_USE_DEFAULT_WAIT, NULL ); + ok( readpipe != INVALID_HANDLE_VALUE, "CreateNamedPipeA failed %lu\n", GetLastError() ); + + memset( base, 0, size ); + + count = 64; + ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); + ok( !ret, "%lu: GetWriteWatch failed %lu\n", i, GetLastError() ); + ok( count == 16, "%lu: wrong count %Iu\n", i, count ); + + args.pipe = readpipe; + args.index = i; + args.base = base; + args.size = size; + thread = CreateThread( NULL, 0, read_pipe, &args, 0, NULL ); + + writepipe = CreateFileA( pipename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL ); + ok( writepipe != INVALID_HANDLE_VALUE, "%lu: CreateFileA failed %lu\n", i, GetLastError() ); + Sleep( 200 ); + + count = 64; + ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); + ok( !ret, "%lu: GetWriteWatch failed %lu\n", i, GetLastError() ); + ok( count == 16, "%lu: wrong count %Iu\n", i, count ); + + num_bytes = 0; + success = WriteFile( writepipe, testdata, sizeof(testdata), &num_bytes, NULL ); + ok( success, "%lu: WriteFile failed %lu\n", i, GetLastError() ); + ok( num_bytes == sizeof(testdata), "%lu: wrong number of bytes written %lu\n", i, num_bytes ); + WaitForSingleObject( thread, 10000 ); + + count = 64; + memset( results, 0, sizeof(results) ); + ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); + ok( !ret, "%lu: GetWriteWatch failed %lu\n", i, GetLastError() ); + ok( count == 1, "%lu: wrong count %Iu\n", i, count ); + ok( results[0] == base, "%lu: wrong result %p\n", i, results[0] ); + + CloseHandle( readpipe ); + CloseHandle( writepipe ); + CloseHandle( thread ); + } + + GetTempPathA( MAX_PATH, path ); + GetTempFileNameA( path, "map", 0, filename ); + file = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( file != INVALID_HANDLE_VALUE, "CreateFile error %lu\n", GetLastError() ); + SetFilePointer( file, 2 * pagesize + 3, NULL, FILE_BEGIN ); + SetEndOfFile( file ); + SetFilePointer( file, 0, NULL, FILE_BEGIN ); + + success = ReadFile( file, base, size, &num_bytes, NULL ); + ok( success, "ReadFile failed %lu\n", GetLastError() ); + ok( num_bytes == 2 * pagesize + 3, "wrong bytes %lu\n", num_bytes ); + + count = 64; + ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 16, "wrong count %Iu\n", count ); + + success = ReadFile( file, base, size, &num_bytes, NULL ); + ok( success, "ReadFile failed %lu\n", GetLastError() ); + ok( num_bytes == 0, "wrong bytes %lu\n", num_bytes ); + + count = 64; + ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 16, "wrong count %Iu\n", count ); + + CloseHandle( file ); + DeleteFileA( filename ); + + success = ReadFile( (HANDLE)0xdead, base, size, &num_bytes, NULL ); + ok( !success, "ReadFile succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %lu\n", GetLastError() ); + + count = 64; + ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 0, "wrong count %Iu\n", count ); + + /* OVERLAPPED structure write watch */ memset( &overlapped, 0, sizeof(overlapped) ); overlapped.hEvent = CreateEventA( NULL, TRUE, FALSE, NULL ); readpipe = CreateNamedPipeA( pipename, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_INBOUND, - PIPE_TYPE_BYTE | PIPE_WAIT, 1, 1024, 1024, + PIPE_TYPE_MESSAGE | PIPE_WAIT, 1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL ); - ok( readpipe != INVALID_HANDLE_VALUE, "CreateNamedPipeA failed %u\n", GetLastError() ); + ok( readpipe != INVALID_HANDLE_VALUE, "CreateNamedPipeA failed %lu\n", GetLastError() ); success = ConnectNamedPipe( readpipe, &overlapped ); ok( !success, "ConnectNamedPipe unexpectedly succeeded\n" ); - ok( GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %u\n", GetLastError() ); + ok( GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %lu\n", GetLastError() ); writepipe = CreateFileA( pipename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL ); - ok( writepipe != INVALID_HANDLE_VALUE, "CreateFileA failed %u\n", GetLastError() ); + ok( writepipe != INVALID_HANDLE_VALUE, "CreateFileA failed %lu\n", GetLastError() ); ret = WaitForSingleObject( overlapped.hEvent, 1000 ); - ok( ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", ret ); + ok( ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %lu\n", ret ); memset( base, 0, size ); + overlapped2 = (OVERLAPPED*)(base + size - sizeof(*overlapped2)); + overlapped2->hEvent = CreateEventA( NULL, TRUE, FALSE, NULL ); count = 64; ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); - ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); - ok( count == 16, "wrong count %lu\n", count ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 16, "wrong count %Iu\n", count ); - success = ReadFile( readpipe, base, size, NULL, &overlapped ); + success = ReadFile( readpipe, base, sizeof(testdata), NULL, overlapped2 ); ok( !success, "ReadFile unexpectedly succeeded\n" ); - ok( GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %u\n", GetLastError() ); + ok( GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %lu\n", GetLastError() ); + overlapped2->Internal = 0xdeadbeef; count = 64; ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); - ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); - ok( count == 16, "wrong count %lu\n", count ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 2, "wrong count %Iu\n", count ); num_bytes = 0; success = WriteFile( writepipe, testdata, sizeof(testdata), &num_bytes, NULL ); - ok( success, "WriteFile failed %u\n", GetLastError() ); - ok( num_bytes == sizeof(testdata), "wrong number of bytes written\n" ); + ok( success, "WriteFile failed %lu\n", GetLastError() ); + ok( num_bytes == sizeof(testdata), "wrong number of bytes written %lu\n", num_bytes ); num_bytes = 0; - success = GetOverlappedResult( readpipe, &overlapped, &num_bytes, TRUE ); - ok( success, "GetOverlappedResult failed %u\n", GetLastError() ); - ok( num_bytes == sizeof(testdata), "wrong number of bytes read\n" ); + success = GetOverlappedResult( readpipe, overlapped2, &num_bytes, TRUE ); + ok( success, "GetOverlappedResult failed %lu\n", GetLastError() ); + ok( num_bytes == sizeof(testdata), "wrong number of bytes read %lu\n", num_bytes ); ok( !memcmp( base, testdata, sizeof(testdata)), "didn't receive expected data\n" ); count = 64; memset( results, 0, sizeof(results) ); ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); - ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); - todo_wine ok( count == 1, "wrong count %lu\n", count ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 2, "wrong count %Iu\n", count ); ok( results[0] == base, "wrong result %p\n", results[0] ); CloseHandle( readpipe ); CloseHandle( writepipe ); CloseHandle( overlapped.hEvent ); + CloseHandle( overlapped2->hEvent ); /* some invalid parameter tests */ @@ -1779,139 +2108,139 @@ static void test_write_watch(void) 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() ); + ok( ret == ~0u, "GetWriteWatch succeeded %lu\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\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() ); + ok( ret == ~0u, "GetWriteWatch succeeded %lu\n", ret ); + ok( GetLastError() == ERROR_NOACCESS, "wrong error %lu\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() ); + ok( ret == ~0u, "GetWriteWatch succeeded %lu\n", ret ); + ok( GetLastError() == ERROR_NOACCESS, "wrong error %lu\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() ); + ok( ret == ~0u, "GetWriteWatch succeeded %lu\n", ret ); + ok( GetLastError() == ERROR_NOACCESS, "wrong error %lu\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() ); + ok( ret == ~0u, "GetWriteWatch succeeded %lu\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\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() ); + ok( ret == ~0u, "GetWriteWatch succeeded %lu\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\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() ); + ok( ret == ~0u, "GetWriteWatch succeeded %lu\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\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() ); + ok( ret == ~0u, "GetWriteWatch succeeded %lu\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\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() ); + ok( ret == ~0u, "GetWriteWatch succeeded %lu\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\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() ); + ok( ret == ~0u, "ResetWriteWatch succeeded %lu\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); ret = pResetWriteWatch( GetModuleHandleW(NULL), size ); - ok( ret == ~0u, "ResetWriteWatch succeeded %u\n", ret ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( ret == ~0u, "ResetWriteWatch succeeded %lu\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\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() ); + ok( ret == ERROR_INVALID_PARAMETER, "GetWriteWatch succeeded %lu\n", ret ); + ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() ); count = 0; ret = pGetWriteWatch( 0, base, size, NULL, &count, &pagesize ); - ok( !ret, "GetWriteWatch failed %u\n", ret ); + ok( !ret, "GetWriteWatch failed %lu\n", ret ); count = 64; ret = pGetWriteWatch( 0xdeadbeef, base, size, results, &count, &pagesize ); - ok( !ret, "GetWriteWatch failed %u\n", ret ); + ok( !ret, "GetWriteWatch failed %lu\n", ret ); count = 64; ret = pGetWriteWatch( 0, base, 0, results, &count, &pagesize ); - ok( !ret, "GetWriteWatch failed %u\n", ret ); + ok( !ret, "GetWriteWatch failed %lu\n", ret ); ret = pResetWriteWatch( base, 0 ); - ok( !ret, "ResetWriteWatch failed %u\n", ret ); + ok( !ret, "ResetWriteWatch failed %lu\n", ret ); ret = pResetWriteWatch( GetModuleHandleW(NULL), size ); - ok( !ret, "ResetWriteWatch failed %u\n", ret ); + ok( !ret, "ResetWriteWatch failed %lu\n", ret ); } VirtualFree( base, 0, MEM_RELEASE ); base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_WRITE_WATCH, PAGE_READWRITE ); - ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() ); + ok( base != NULL, "VirtualAlloc failed %lu\n", GetLastError() ); VirtualFree( base, 0, MEM_RELEASE ); base = VirtualAlloc( 0, size, MEM_WRITE_WATCH, PAGE_READWRITE ); ok( !base, "VirtualAlloc succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\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() ); + ok( base != NULL, "VirtualAlloc failed %lu\n", GetLastError() ); base = VirtualAlloc( base, size, MEM_COMMIT, PAGE_NOACCESS ); - ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() ); + ok( base != NULL, "VirtualAlloc failed %lu\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 ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 0, "wrong count %Iu\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 ); + ok( ret, "VirtualProtect failed error %lu\n", GetLastError() ); + ok( old_prot == PAGE_NOACCESS, "wrong old prot %lx\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 ); + ok( ret, "VirtualProtect failed error %lu\n", GetLastError() ); + ok( old_prot == PAGE_READWRITE, "wrong old prot %lx\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( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 1, "wrong count %Iu\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() ); + ok( ret, "VirtualFree failed %lu\n", GetLastError() ); count = 64; ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); - ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); ok( count == 1 || broken(count == 0), /* win98 */ - "wrong count %lu\n", count ); + "wrong count %Iu\n", count ); if (count) ok( results[0] == base + 5*pagesize, "wrong result %p\n", results[0] ); VirtualFree( base, 0, MEM_RELEASE ); @@ -1974,12 +2303,12 @@ static void test_stack_commit(void) DWORD result; call_on_stack = VirtualAlloc( 0, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE ); - ok( call_on_stack != NULL, "VirtualAlloc failed %u\n", GetLastError() ); + ok( call_on_stack != NULL, "VirtualAlloc failed %lu\n", GetLastError() ); memcpy( call_on_stack, code_call_on_stack, sizeof(code_call_on_stack) ); /* allocate a new stack, only the first guard page is committed */ new_stack = VirtualAlloc( 0, 0x400000, MEM_RESERVE, PAGE_READWRITE ); - ok( new_stack != NULL, "VirtualAlloc failed %u\n", GetLastError() ); + ok( new_stack != NULL, "VirtualAlloc failed %lu\n", GetLastError() ); new_stack_base = (char *)new_stack + 0x400000; VirtualAlloc( (char *)new_stack_base - 0x1000, 0x1000, MEM_COMMIT, PAGE_READWRITE | PAGE_GUARD ); @@ -1997,7 +2326,7 @@ static void test_stack_commit(void) NtCurrentTeb()->Tib.StackBase = old_stack_base; NtCurrentTeb()->Tib.StackLimit = old_stack_limit; - ok( result == 42, "expected 42, got %u\n", result ); + ok( result == 42, "expected 42, got %lu\n", result ); VirtualFree( new_stack, 0, MEM_RELEASE ); VirtualFree( call_on_stack, 0, MEM_RELEASE ); @@ -2011,11 +2340,11 @@ static LONG num_guard_page_calls; static DWORD guard_page_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) { - trace( "exception: %08x flags:%x addr:%p\n", + trace( "exception: %08lx flags:%lx addr:%p\n", rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress ); - ok( rec->NumberParameters == 2, "NumberParameters is %d instead of 2\n", rec->NumberParameters ); - ok( rec->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION, "ExceptionCode is %08x instead of %08x\n", + ok( rec->NumberParameters == 2, "NumberParameters is %ld instead of 2\n", rec->NumberParameters ); + ok( rec->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION, "ExceptionCode is %08lx instead of %08lx\n", rec->ExceptionCode, STATUS_GUARD_PAGE_VIOLATION ); InterlockedIncrement( &num_guard_page_calls ); @@ -2029,7 +2358,7 @@ static void test_guard_page(void) EXCEPTION_REGISTRATION_RECORD frame; MEMORY_BASIC_INFORMATION info; DWORD ret, size, old_prot; - int *value, old_value; + LONG *value, old_value; void *results[64]; ULONG_PTR count; ULONG pagesize; @@ -2038,63 +2367,63 @@ static void test_guard_page(void) size = 0x1000; base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE | PAGE_GUARD ); - ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() ); - value = (int *)base; + ok( base != NULL, "VirtualAlloc failed %lu\n", GetLastError() ); + value = (LONG *)base; /* verify info structure */ ret = VirtualQuery( base, &info, sizeof(info) ); - ok( ret, "VirtualQuery failed %u\n", GetLastError()); + ok( ret, "VirtualQuery failed %lu\n", GetLastError()); ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base ); - ok( info.AllocationProtect == (PAGE_READWRITE | PAGE_GUARD), "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 | PAGE_GUARD), "wrong Protect 0x%x\n", info.Protect ); - ok( info.Type == MEM_PRIVATE, "wrong Type 0x%x\n", info.Type ); + ok( info.AllocationProtect == (PAGE_READWRITE | PAGE_GUARD), "wrong AllocationProtect %lx\n", info.AllocationProtect ); + ok( info.RegionSize == size, "wrong RegionSize 0x%Ix\n", info.RegionSize ); + ok( info.State == MEM_COMMIT, "wrong State 0x%lx\n", info.State ); + ok( info.Protect == (PAGE_READWRITE | PAGE_GUARD), "wrong Protect 0x%lx\n", info.Protect ); + ok( info.Type == MEM_PRIVATE, "wrong Type 0x%lx\n", info.Type ); /* put some initial value into the memory */ success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); - ok( old_prot == (PAGE_READWRITE | PAGE_GUARD), "wrong old prot %x\n", old_prot ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); + ok( old_prot == (PAGE_READWRITE | PAGE_GUARD), "wrong old prot %lx\n", old_prot ); *value = 1; *(value + 1) = 2; success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); - ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); + ok( old_prot == PAGE_READWRITE, "wrong old prot %lx\n", old_prot ); /* test behaviour of VirtualLock - first attempt should fail */ SetLastError( 0xdeadbeef ); success = VirtualLock( base, size ); ok( !success, "VirtualLock unexpectedly succeeded\n" ); todo_wine - ok( GetLastError() == STATUS_GUARD_PAGE_VIOLATION, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == STATUS_GUARD_PAGE_VIOLATION, "wrong error %lu\n", GetLastError() ); success = VirtualLock( base, size ); todo_wine - ok( success, "VirtualLock failed %u\n", GetLastError() ); + ok( success, "VirtualLock failed %lu\n", GetLastError() ); if (success) { - ok( *value == 1, "memory block contains wrong value, expected 1, got 0x%x\n", *value ); + ok( *value == 1, "memory block contains wrong value, expected 1, got 0x%lx\n", *value ); success = VirtualUnlock( base, size ); - ok( success, "VirtualUnlock failed %u\n", GetLastError() ); + ok( success, "VirtualUnlock failed %lu\n", GetLastError() ); } /* check info structure again, PAGE_GUARD should be removed now */ ret = VirtualQuery( base, &info, sizeof(info) ); - ok( ret, "VirtualQuery failed %u\n", GetLastError()); + ok( ret, "VirtualQuery failed %lu\n", GetLastError()); ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base ); - ok( info.AllocationProtect == (PAGE_READWRITE | PAGE_GUARD), "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.AllocationProtect == (PAGE_READWRITE | PAGE_GUARD), "wrong AllocationProtect %lx\n", info.AllocationProtect ); + ok( info.RegionSize == size, "wrong RegionSize 0x%Ix\n", info.RegionSize ); + ok( info.State == MEM_COMMIT, "wrong State 0x%lx\n", info.State ); todo_wine - ok( info.Protect == PAGE_READWRITE, "wrong Protect 0x%x\n", info.Protect ); - ok( info.Type == MEM_PRIVATE, "wrong Type 0x%x\n", info.Type ); + ok( info.Protect == PAGE_READWRITE, "wrong Protect 0x%lx\n", info.Protect ); + ok( info.Type == MEM_PRIVATE, "wrong Type 0x%lx\n", info.Type ); success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); todo_wine - ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot ); + ok( old_prot == PAGE_READWRITE, "wrong old prot %lx\n", old_prot ); /* test directly accessing the memory - we need to setup an exception handler first */ frame.Handler = guard_page_handler; @@ -2104,19 +2433,19 @@ static void test_guard_page(void) InterlockedExchange( &num_guard_page_calls, 0 ); InterlockedExchange( &old_value, *value ); /* exception handler increments value by 0x100 */ *value = 2; - ok( old_value == 0x101, "memory block contains wrong value, expected 0x101, got 0x%x\n", old_value ); - ok( num_guard_page_calls == 1, "expected one callback of guard page handler, got %d calls\n", num_guard_page_calls ); + ok( old_value == 0x101, "memory block contains wrong value, expected 0x101, got 0x%lx\n", old_value ); + ok( num_guard_page_calls == 1, "expected one callback of guard page handler, got %ld calls\n", num_guard_page_calls ); NtCurrentTeb()->Tib.ExceptionList = frame.Prev; /* check info structure again, PAGE_GUARD should be removed now */ ret = VirtualQuery( base, &info, sizeof(info) ); - ok( ret, "VirtualQuery failed %u\n", GetLastError()); - ok( info.Protect == PAGE_READWRITE, "wrong Protect 0x%x\n", info.Protect ); + ok( ret, "VirtualQuery failed %lu\n", GetLastError()); + ok( info.Protect == PAGE_READWRITE, "wrong Protect 0x%lx\n", info.Protect ); success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); - ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); + ok( old_prot == PAGE_READWRITE, "wrong old prot %lx\n", old_prot ); /* test accessing second integer in memory */ frame.Handler = guard_page_handler; @@ -2125,19 +2454,19 @@ static void test_guard_page(void) InterlockedExchange( &num_guard_page_calls, 0 ); old_value = *(value + 1); - ok( old_value == 0x102, "memory block contains wrong value, expected 0x102, got 0x%x\n", old_value ); - ok( *value == 2, "memory block contains wrong value, expected 2, got 0x%x\n", *value ); - ok( num_guard_page_calls == 1, "expected one callback of guard page handler, got %d calls\n", num_guard_page_calls ); + ok( old_value == 0x102, "memory block contains wrong value, expected 0x102, got 0x%lx\n", old_value ); + ok( *value == 2, "memory block contains wrong value, expected 2, got 0x%lx\n", *value ); + ok( num_guard_page_calls == 1, "expected one callback of guard page handler, got %ld calls\n", num_guard_page_calls ); NtCurrentTeb()->Tib.ExceptionList = frame.Prev; success = VirtualLock( base, size ); - ok( success, "VirtualLock failed %u\n", GetLastError() ); + ok( success, "VirtualLock failed %lu\n", GetLastError() ); if (success) { - ok( *value == 2, "memory block contains wrong value, expected 2, got 0x%x\n", *value ); + ok( *value == 2, "memory block contains wrong value, expected 2, got 0x%lx\n", *value ); success = VirtualUnlock( base, size ); - ok( success, "VirtualUnlock failed %u\n", GetLastError() ); + ok( success, "VirtualUnlock failed %lu\n", GetLastError() ); } VirtualFree( base, 0, MEM_RELEASE ); @@ -2155,22 +2484,22 @@ static void test_guard_page(void) win_skip( "MEM_WRITE_WATCH not supported\n" ); return; } - ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() ); - value = (int *)base; + ok( base != NULL, "VirtualAlloc failed %lu\n", GetLastError() ); + value = (LONG *)base; ret = VirtualQuery( base, &info, sizeof(info) ); - ok( ret, "VirtualQuery failed %u\n", GetLastError() ); + ok( ret, "VirtualQuery failed %lu\n", GetLastError() ); ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base ); - ok( info.AllocationProtect == (PAGE_READWRITE | PAGE_GUARD), "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 | PAGE_GUARD), "wrong Protect 0x%x\n", info.Protect ); - ok( info.Type == MEM_PRIVATE, "wrong Type 0x%x\n", info.Type ); + ok( info.AllocationProtect == (PAGE_READWRITE | PAGE_GUARD), "wrong AllocationProtect %lx\n", info.AllocationProtect ); + ok( info.RegionSize == size, "wrong RegionSize 0x%Ix\n", info.RegionSize ); + ok( info.State == MEM_COMMIT, "wrong State 0x%lx\n", info.State ); + ok( info.Protect == (PAGE_READWRITE | PAGE_GUARD), "wrong Protect 0x%lx\n", info.Protect ); + ok( info.Type == MEM_PRIVATE, "wrong Type 0x%lx\n", info.Type ); 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 ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 0, "wrong count %Iu\n", count ); /* writing to a page should trigger should trigger guard page, even if write watch is set */ frame.Handler = guard_page_handler; @@ -2180,18 +2509,18 @@ static void test_guard_page(void) InterlockedExchange( &num_guard_page_calls, 0 ); *value = 1; *(value + 1) = 2; - ok( num_guard_page_calls == 1, "expected one callback of guard page handler, got %d calls\n", num_guard_page_calls ); + ok( num_guard_page_calls == 1, "expected one callback of guard page handler, got %ld calls\n", num_guard_page_calls ); NtCurrentTeb()->Tib.ExceptionList = frame.Prev; 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( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 1, "wrong count %Iu\n", count ); ok( results[0] == base, "wrong result %p\n", results[0] ); success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); /* write watch is triggered from inside of the guard page handler */ frame.Handler = guard_page_handler; @@ -2200,49 +2529,49 @@ static void test_guard_page(void) InterlockedExchange( &num_guard_page_calls, 0 ); old_value = *(value + 1); /* doesn't trigger write watch */ - ok( old_value == 0x102, "memory block contains wrong value, expected 0x102, got 0x%x\n", old_value ); - ok( *value == 1, "memory block contains wrong value, expected 1, got 0x%x\n", *value ); - ok( num_guard_page_calls == 1, "expected one callback of guard page handler, got %d calls\n", num_guard_page_calls ); + ok( old_value == 0x102, "memory block contains wrong value, expected 0x102, got 0x%lx\n", old_value ); + ok( *value == 1, "memory block contains wrong value, expected 1, got 0x%lx\n", *value ); + ok( num_guard_page_calls == 1, "expected one callback of guard page handler, got %ld calls\n", num_guard_page_calls ); NtCurrentTeb()->Tib.ExceptionList = frame.Prev; 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( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 1, "wrong count %Iu\n", count ); ok( results[0] == base, "wrong result %p\n", results[0] ); success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); /* test behaviour of VirtualLock - first attempt should fail without triggering write watches */ SetLastError( 0xdeadbeef ); success = VirtualLock( base, size ); ok( !success, "VirtualLock unexpectedly succeeded\n" ); todo_wine - ok( GetLastError() == STATUS_GUARD_PAGE_VIOLATION, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == STATUS_GUARD_PAGE_VIOLATION, "wrong error %lu\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 ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 0, "wrong count %Iu\n", count ); success = VirtualLock( base, size ); todo_wine - ok( success, "VirtualLock failed %u\n", GetLastError() ); + ok( success, "VirtualLock failed %lu\n", GetLastError() ); if (success) { - ok( *value == 1, "memory block contains wrong value, expected 1, got 0x%x\n", *value ); + ok( *value == 1, "memory block contains wrong value, expected 1, got 0x%lx\n", *value ); success = VirtualUnlock( base, size ); - ok( success, "VirtualUnlock failed %u\n", GetLastError() ); + ok( success, "VirtualUnlock failed %lu\n", GetLastError() ); } count = 64; results[0] = (void *)0xdeadbeef; ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); - ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); todo_wine - ok( count == 1 || broken(count == 0) /* Windows 8 */, "wrong count %lu\n", count ); + ok( count == 1 || broken(count == 0) /* Windows 8 */, "wrong count %Iu\n", count ); todo_wine ok( results[0] == base || broken(results[0] == (void *)0xdeadbeef) /* Windows 8 */, "wrong result %p\n", results[0] ); @@ -2257,13 +2586,13 @@ static DWORD execute_fault_seh_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTR ULONG flags = MEM_EXECUTE_OPTION_ENABLE; DWORD err; - trace( "exception: %08x flags:%x addr:%p info[0]:%ld info[1]:%p\n", + trace( "exception: %08lx flags:%lx addr:%p info[0]:%Id info[1]:%p\n", rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, rec->ExceptionInformation[0], (void *)rec->ExceptionInformation[1] ); - ok( rec->NumberParameters == 2, "NumberParameters is %d instead of 2\n", rec->NumberParameters ); + ok( rec->NumberParameters == 2, "NumberParameters is %ld instead of 2\n", rec->NumberParameters ); ok( rec->ExceptionCode == STATUS_ACCESS_VIOLATION || rec->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION, - "ExceptionCode is %08x instead of STATUS_ACCESS_VIOLATION or STATUS_GUARD_PAGE_VIOLATION\n", rec->ExceptionCode ); + "ExceptionCode is %08lx instead of STATUS_ACCESS_VIOLATION or STATUS_GUARD_PAGE_VIOLATION\n", rec->ExceptionCode ); NtQueryInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &flags, sizeof(flags), NULL ); @@ -2271,7 +2600,7 @@ static DWORD execute_fault_seh_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTR { err = IsProcessorFeaturePresent( PF_NX_ENABLED ) ? EXCEPTION_EXECUTE_FAULT : EXCEPTION_READ_FAULT; - ok( rec->ExceptionInformation[0] == err, "ExceptionInformation[0] is %d instead of %d\n", + ok( rec->ExceptionInformation[0] == err, "ExceptionInformation[0] is %ld instead of %ld\n", (DWORD)rec->ExceptionInformation[0], err ); InterlockedIncrement( &num_guard_page_calls ); @@ -2282,12 +2611,22 @@ static DWORD execute_fault_seh_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTR BOOL success; err = (flags & MEM_EXECUTE_OPTION_DISABLE) ? EXCEPTION_EXECUTE_FAULT : EXCEPTION_READ_FAULT; - ok( rec->ExceptionInformation[0] == err, "ExceptionInformation[0] is %d instead of %d\n", +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) { +#endif + ok( rec->ExceptionInformation[0] == err, "ExceptionInformation[0] is %ld instead of %ld\n", (DWORD)rec->ExceptionInformation[0], err ); +#ifdef __REACTOS__ + } +#endif success = VirtualProtect( (void *)rec->ExceptionInformation[1], 16, PAGE_EXECUTE_READWRITE, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); - ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); +#ifdef __REACTOS__ + ok( old_prot == PAGE_READWRITE || broken(old_prot == PAGE_NOACCESS) /* WS03 */, "wrong old prot %lx\n", old_prot ); +#else + ok( old_prot == PAGE_READWRITE, "wrong old prot %lx\n", old_prot ); +#endif InterlockedIncrement( &num_execute_fault_calls ); } @@ -2301,13 +2640,13 @@ static LONG CALLBACK execute_fault_vec_handler( EXCEPTION_POINTERS *ExceptionInf DWORD old_prot; BOOL success; - trace( "exception: %08x flags:%x addr:%p info[0]:%ld info[1]:%p\n", + trace( "exception: %08lx flags:%lx addr:%p info[0]:%Id info[1]:%p\n", rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, rec->ExceptionInformation[0], (void *)rec->ExceptionInformation[1] ); - ok( rec->NumberParameters == 2, "NumberParameters is %d instead of 2\n", rec->NumberParameters ); + ok( rec->NumberParameters == 2, "NumberParameters is %ld instead of 2\n", rec->NumberParameters ); ok( rec->ExceptionCode == STATUS_ACCESS_VIOLATION, - "ExceptionCode is %08x instead of STATUS_ACCESS_VIOLATION\n", rec->ExceptionCode ); + "ExceptionCode is %08lx instead of STATUS_ACCESS_VIOLATION\n", rec->ExceptionCode ); if (rec->ExceptionCode == STATUS_ACCESS_VIOLATION) InterlockedIncrement( &num_execute_fault_calls ); @@ -2316,8 +2655,8 @@ static LONG CALLBACK execute_fault_vec_handler( EXCEPTION_POINTERS *ExceptionInf return EXCEPTION_CONTINUE_SEARCH; success = VirtualProtect( (void *)rec->ExceptionInformation[1], 16, PAGE_EXECUTE_READWRITE, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); - ok( old_prot == PAGE_NOACCESS, "wrong old prot %x\n", old_prot ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); + ok( old_prot == PAGE_NOACCESS, "wrong old prot %lx\n", old_prot ); return EXCEPTION_CONTINUE_EXECUTION; } @@ -2370,7 +2709,7 @@ static LRESULT CALLBACK atl_test_func( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR { DWORD arg = (DWORD)hWnd; if (uMsg == WM_USER) - ok( arg == 0x11223344, "arg is 0x%08x instead of 0x11223344\n", arg ); + ok( arg == 0x11223344, "arg is 0x%08lx instead of 0x11223344\n", arg ); else ok( arg != 0x11223344, "arg is unexpectedly 0x11223344\n" ); return 43; @@ -2400,24 +2739,25 @@ static void test_atl_thunk_emulation( ULONG dep_flags ) char *base; HWND hWnd; - trace( "Running DEP tests with ProcessExecuteFlags = %d\n", dep_flags ); + trace( "Running DEP tests with ProcessExecuteFlags = %ld\n", dep_flags ); NtQueryInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &old_flags, sizeof(old_flags), NULL ); if (old_flags != dep_flags) { ret = NtSetInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &dep_flags, sizeof(dep_flags) ); - if (ret == STATUS_INVALID_INFO_CLASS) /* Windows 2000 */ + if (ret == STATUS_INVALID_INFO_CLASS /* Windows 2000 */ || + ret == STATUS_ACCESS_DENIED) { - win_skip( "Skipping DEP tests with ProcessExecuteFlags = %d\n", dep_flags ); + win_skip( "Skipping DEP tests with ProcessExecuteFlags = %ld\n", dep_flags ); return; } - ok( !ret, "NtSetInformationProcess failed with status %08x\n", ret ); + ok( !ret, "NtSetInformationProcess failed with status %08lx\n", ret ); restore_flags = TRUE; } size = 0x1000; base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE ); - ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() ); + ok( base != NULL, "VirtualAlloc failed %lu\n", GetLastError() ); /* Check result of GetProcessDEPPolicy */ if (!pGetProcessDEPPolicy) @@ -2438,10 +2778,10 @@ static void test_atl_thunk_emulation( ULONG dep_flags ) *(DWORD *)(base + 6) = (DWORD_PTR)pGetProcessDEPPolicy - (DWORD_PTR)(base + 10); success = VirtualProtect( base, size, PAGE_EXECUTE_READWRITE, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); success = get_dep_policy( GetCurrentProcess(), &policy_flags, &policy_permanent ); - ok( success, "GetProcessDEPPolicy failed %u\n", GetLastError() ); + ok( success, "GetProcessDEPPolicy failed %lu\n", GetLastError() ); ret = 0; if (dep_flags & MEM_EXECUTE_OPTION_DISABLE) @@ -2449,7 +2789,7 @@ static void test_atl_thunk_emulation( ULONG dep_flags ) if (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION) ret |= PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION; - ok( policy_flags == ret, "expected policy flags %d, got %d\n", ret, policy_flags ); + ok( policy_flags == ret, "expected policy flags %ld, got %ld\n", ret, policy_flags ); ok( !policy_permanent || broken(policy_permanent == 0x44), "expected policy permanent FALSE, got %d\n", policy_permanent ); } @@ -2464,7 +2804,7 @@ static void test_atl_thunk_emulation( ULONG dep_flags ) * prevent crashes while creating the window. */ success = VirtualProtect( base, size, PAGE_EXECUTE_READWRITE, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); memset( &wc, 0, sizeof(wc) ); wc.cbSize = sizeof(wc); @@ -2475,56 +2815,64 @@ static void test_atl_thunk_emulation( ULONG dep_flags ) wc.lpszClassName = cls_name; wc.lpfnWndProc = (WNDPROC)base; success = RegisterClassExA(&wc) != 0; - ok( success, "RegisterClassExA failed %u\n", GetLastError() ); + ok( success, "RegisterClassExA failed %lu\n", GetLastError() ); hWnd = CreateWindowExA(0, cls_name, "Test", WS_TILEDWINDOW, 0, 0, 640, 480, 0, 0, 0, 0); - ok( hWnd != 0, "CreateWindowExA failed %u\n", GetLastError() ); + ok( hWnd != 0, "CreateWindowExA failed %lu\n", GetLastError() ); ret = SendMessageA(hWnd, WM_USER, 0, 0); - ok( ret == 42, "SendMessage returned unexpected result %d\n", ret ); + ok( ret == 42, "SendMessage returned unexpected result %ld\n", ret ); /* At first try with an instruction which is not recognized as proper ATL thunk * by the Windows ATL Thunk Emulator. Removing execute permissions will lead to * STATUS_ACCESS_VIOLATION exceptions when DEP is enabled. */ success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); ret = send_message_excpt( hWnd, WM_USER, 0, 0 ); - ok( ret == 42, "call returned wrong result, expected 42, got %d\n", ret ); - ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls ); + ok( ret == 42, "call returned wrong result, expected 42, got %ld\n", ret ); + ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %ld exceptions\n", num_guard_page_calls ); if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && !IsProcessorFeaturePresent( PF_NX_ENABLED )) { trace( "DEP hardware support is not available\n" ); - ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); + ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); dep_flags = MEM_EXECUTE_OPTION_ENABLE; } else if (dep_flags & MEM_EXECUTE_OPTION_DISABLE) { trace( "DEP hardware support is available\n" ); - ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); +#ifdef __REACTOS__ + ok( num_execute_fault_calls == 1 || broken(num_execute_fault_calls == 0) /* WS03 */, "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#else + ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#endif } else - ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); + ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); /* Now a bit more complicated, the page containing the code is protected with * PAGE_GUARD memory protection. */ success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); ret = send_message_excpt( hWnd, WM_USER, 0, 0 ); - ok( ret == 42, "call returned wrong result, expected 42, got %d\n", ret ); - ok( num_guard_page_calls == 1, "expected one STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls ); + ok( ret == 42, "call returned wrong result, expected 42, got %ld\n", ret ); + ok( num_guard_page_calls == 1, "expected one STATUS_GUARD_PAGE_VIOLATION exception, got %ld exceptions\n", num_guard_page_calls ); if (dep_flags & MEM_EXECUTE_OPTION_DISABLE) - ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); +#ifdef __REACTOS__ + ok( num_execute_fault_calls == 1 || broken(num_execute_fault_calls == 0) /* WS03 */, "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#else + ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#endif else - ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); + ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); ret = send_message_excpt( hWnd, WM_USER, 0, 0 ); - ok( ret == 42, "call returned wrong result, expected 42, got %d\n", ret ); - ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls ); - ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); + ok( ret == 42, "call returned wrong result, expected 42, got %ld\n", ret ); + ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %ld exceptions\n", num_guard_page_calls ); + ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); /* Now test with a proper ATL thunk instruction. */ @@ -2532,43 +2880,51 @@ static void test_atl_thunk_emulation( ULONG dep_flags ) *(DWORD *)(base + 9) = (DWORD_PTR)atl_test_func - (DWORD_PTR)(base + 13); success = VirtualProtect( base, size, PAGE_EXECUTE_READWRITE, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); ret = SendMessageA(hWnd, WM_USER, 0, 0); - ok( ret == 43, "SendMessage returned unexpected result %d\n", ret ); + ok( ret == 43, "SendMessage returned unexpected result %ld\n", ret ); /* Try executing with PAGE_READWRITE protection. */ success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); ret = send_message_excpt( hWnd, WM_USER, 0, 0 ); - ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret ); - ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls ); + ok( ret == 43, "call returned wrong result, expected 43, got %ld\n", ret ); + ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %ld exceptions\n", num_guard_page_calls ); if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION)) - ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); +#ifdef __REACTOS__ + ok( num_execute_fault_calls == 1 || broken(num_execute_fault_calls == 0) /* WS03 */, "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#else + ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#endif else - ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); + ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); /* Now a bit more complicated, the page containing the code is protected with * PAGE_GUARD memory protection. */ success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); /* the same, but with PAGE_GUARD set */ ret = send_message_excpt( hWnd, WM_USER, 0, 0 ); - ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret ); - ok( num_guard_page_calls == 1, "expected one STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls ); + ok( ret == 43, "call returned wrong result, expected 43, got %ld\n", ret ); + ok( num_guard_page_calls == 1, "expected one STATUS_GUARD_PAGE_VIOLATION exception, got %ld exceptions\n", num_guard_page_calls ); if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION)) - ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); +#ifdef __REACTOS__ + ok( num_execute_fault_calls == 1 || broken(num_execute_fault_calls == 0) /* WS03 */, "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#else + ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#endif else - ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); + ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); ret = send_message_excpt( hWnd, WM_USER, 0, 0 ); - ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret ); - ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls ); - ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); + ok( ret == 43, "call returned wrong result, expected 43, got %ld\n", ret ); + ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %ld exceptions\n", num_guard_page_calls ); + ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); /* The following test shows that on Windows, even a vectored exception handler * cannot intercept internal exceptions thrown by the ATL thunk emulation layer. */ @@ -2580,7 +2936,7 @@ static void test_atl_thunk_emulation( ULONG dep_flags ) PVOID vectored_handler; success = VirtualProtect( base, size, PAGE_NOACCESS, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); vectored_handler = pRtlAddVectoredExceptionHandler( TRUE, &execute_fault_vec_handler ); ok( vectored_handler != 0, "RtlAddVectoredExceptionHandler failed\n" ); @@ -2589,8 +2945,12 @@ static void test_atl_thunk_emulation( ULONG dep_flags ) pRtlRemoveVectoredExceptionHandler( vectored_handler ); - ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret ); - ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); + ok( ret == 43, "call returned wrong result, expected 43, got %ld\n", ret ); +#ifdef __REACTOS__ + ok( num_execute_fault_calls == 1 || broken(num_execute_fault_calls == 2) /* WS03 */, "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#else + ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#endif } else win_skip( "RtlAddVectoredExceptionHandler or RtlRemoveVectoredExceptionHandler not found\n" ); @@ -2602,67 +2962,83 @@ static void test_atl_thunk_emulation( ULONG dep_flags ) *(DWORD *)(base + 6) = (DWORD_PTR)atl_test_func - (DWORD_PTR)(base + 10); success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); ret = send_message_excpt( hWnd, WM_USER + 1, 0, 0 ); /* FIXME: we don't check the content of the register ECX yet */ - ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret ); - ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls ); + ok( ret == 43, "call returned wrong result, expected 43, got %ld\n", ret ); + ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %ld exceptions\n", num_guard_page_calls ); if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION)) - ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); +#ifdef __REACTOS__ + ok( num_execute_fault_calls == 1 || broken(num_execute_fault_calls == 0) /* WS03 */, "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#else + ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#endif else - ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); + ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); memcpy( base, code_atl3, sizeof(code_atl3) ); *(DWORD *)(base + 6) = (DWORD_PTR)atl_test_func; success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); ret = send_message_excpt( hWnd, WM_USER + 1, 0, 0 ); /* FIXME: we don't check the content of the registers ECX/EDX yet */ - ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret ); - ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls ); + ok( ret == 43, "call returned wrong result, expected 43, got %ld\n", ret ); + ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %ld exceptions\n", num_guard_page_calls ); if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION)) - ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); +#ifdef __REACTOS__ + ok( num_execute_fault_calls == 1 || broken(num_execute_fault_calls == 0) /* WS03 */, "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#else + ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#endif else - ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); + ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); memcpy( base, code_atl4, sizeof(code_atl4) ); *(DWORD *)(base + 6) = (DWORD_PTR)atl_test_func; success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); ret = send_message_excpt( hWnd, WM_USER + 1, 0, 0 ); /* FIXME: We don't check the content of the registers EAX/ECX yet */ - ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret ); - ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls ); + ok( ret == 43, "call returned wrong result, expected 43, got %ld\n", ret ); + ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %ld exceptions\n", num_guard_page_calls ); if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION)) - ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); +#ifdef __REACTOS__ + ok( num_execute_fault_calls == 1 || broken(num_execute_fault_calls == 0) /* WS03 */, "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#else + ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#endif else if (dep_flags & MEM_EXECUTE_OPTION_DISABLE) ok( num_execute_fault_calls == 0 || broken(num_execute_fault_calls == 1) /* Windows XP */, - "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); + "expected no STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); else - ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); + ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); memcpy( base, code_atl5, sizeof(code_atl5) ); success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); - ret = (DWORD_PTR)atl5_test_func; - ret = call_proc_excpt( (void *)base, &ret - 1 ); + results[1] = atl5_test_func; + ret = call_proc_excpt( (void *)base, results ); /* FIXME: We don't check the content of the registers EAX/ECX yet */ - ok( ret == 44, "call returned wrong result, expected 44, got %d\n", ret ); - ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls ); + ok( ret == 44, "call returned wrong result, expected 44, got %ld\n", ret ); + ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %ld exceptions\n", num_guard_page_calls ); if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION)) - ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); +#ifdef __REACTOS__ + ok( num_execute_fault_calls == 1 || broken(num_execute_fault_calls == 0) /* WS03 */, "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#else + ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#endif else if (dep_flags & MEM_EXECUTE_OPTION_DISABLE) ok( num_execute_fault_calls == 0 || broken(num_execute_fault_calls == 1) /* Windows XP */, - "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); + "expected no STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); else - ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); + ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); /* Restore the JMP instruction, set to executable, and then destroy the Window */ @@ -2670,12 +3046,12 @@ static void test_atl_thunk_emulation( ULONG dep_flags ) *(DWORD *)(base + 1) = (DWORD_PTR)jmp_test_func - (DWORD_PTR)(base + 5); success = VirtualProtect( base, size, PAGE_EXECUTE_READWRITE, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); DestroyWindow( hWnd ); success = UnregisterClassA( cls_name, GetModuleHandleA(0) ); - ok( success, "UnregisterClass failed %u\n", GetLastError() ); + ok( success, "UnregisterClass failed %lu\n", GetLastError() ); VirtualFree( base, 0, MEM_RELEASE ); @@ -2687,26 +3063,26 @@ static void test_atl_thunk_emulation( ULONG dep_flags ) win_skip( "MEM_WRITE_WATCH not supported\n" ); goto out; } - ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() ); + ok( base != NULL, "VirtualAlloc failed %lu\n", GetLastError() ); count = 64; ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); - ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); - ok( count == 0, "wrong count %lu\n", count ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 0, "wrong count %Iu\n", count ); memcpy( base, code_jmp, sizeof(code_jmp) ); *(DWORD *)(base + 1) = (DWORD_PTR)jmp_test_func - (DWORD_PTR)(base + 5); 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( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 1, "wrong count %Iu\n", count ); ok( results[0] == base, "wrong result %p\n", results[0] ); /* Create a new window class and associated Window (see above) */ success = VirtualProtect( base, size, PAGE_EXECUTE_READWRITE, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); memset( &wc, 0, sizeof(wc) ); wc.cbSize = sizeof(wc); @@ -2717,67 +3093,75 @@ static void test_atl_thunk_emulation( ULONG dep_flags ) wc.lpszClassName = cls_name; wc.lpfnWndProc = (WNDPROC)base; success = RegisterClassExA(&wc) != 0; - ok( success, "RegisterClassExA failed %u\n", GetLastError() ); + ok( success, "RegisterClassExA failed %lu\n", GetLastError() ); hWnd = CreateWindowExA(0, cls_name, "Test", WS_TILEDWINDOW, 0, 0, 640, 480, 0, 0, 0, 0); - ok( hWnd != 0, "CreateWindowExA failed %u\n", GetLastError() ); + ok( hWnd != 0, "CreateWindowExA failed %lu\n", GetLastError() ); ret = SendMessageA(hWnd, WM_USER, 0, 0); - ok( ret == 42, "SendMessage returned unexpected result %d\n", ret ); + ok( ret == 42, "SendMessage returned unexpected result %ld\n", ret ); count = 64; ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); - ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); - ok( count == 0, "wrong count %lu\n", count ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 0, "wrong count %Iu\n", count ); /* At first try with an instruction which is not recognized as proper ATL thunk * by the Windows ATL Thunk Emulator. Removing execute permissions will lead to * STATUS_ACCESS_VIOLATION exceptions when DEP is enabled. */ success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); ret = send_message_excpt( hWnd, WM_USER, 0, 0 ); - ok( ret == 42, "call returned wrong result, expected 42, got %d\n", ret ); - ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls ); + ok( ret == 42, "call returned wrong result, expected 42, got %ld\n", ret ); + ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %ld exceptions\n", num_guard_page_calls ); if (dep_flags & MEM_EXECUTE_OPTION_DISABLE) - ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); +#ifdef __REACTOS__ + ok( num_execute_fault_calls == 1 || broken(num_execute_fault_calls == 0) /* WS03 */, "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#else + ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#endif else - ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); + ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); count = 64; ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); - ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); - ok( count == 0, "wrong count %lu\n", count ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 0, "wrong count %Iu\n", count ); ret = send_message_excpt( hWnd, WM_USER, 0, 0 ); - ok( ret == 42, "call returned wrong result, expected 42, got %d\n", ret ); - ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls ); - ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); + ok( ret == 42, "call returned wrong result, expected 42, got %ld\n", ret ); + ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %ld exceptions\n", num_guard_page_calls ); + ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); /* Now a bit more complicated, the page containing the code is protected with * PAGE_GUARD memory protection. */ success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); ret = send_message_excpt( hWnd, WM_USER, 0, 0 ); - ok( ret == 42, "call returned wrong result, expected 42, got %d\n", ret ); - ok( num_guard_page_calls == 1, "expected one STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls ); + ok( ret == 42, "call returned wrong result, expected 42, got %ld\n", ret ); + ok( num_guard_page_calls == 1, "expected one STATUS_GUARD_PAGE_VIOLATION exception, got %ld exceptions\n", num_guard_page_calls ); if (dep_flags & MEM_EXECUTE_OPTION_DISABLE) - ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); +#ifdef __REACTOS__ + ok( num_execute_fault_calls == 1 || broken(num_execute_fault_calls == 0) /* WS03 */, "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#else + ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#endif else - ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); + ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); ret = send_message_excpt( hWnd, WM_USER, 0, 0 ); - ok( ret == 42, "call returned wrong result, expected 42, got %d\n", ret ); - ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls ); - ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); + ok( ret == 42, "call returned wrong result, expected 42, got %ld\n", ret ); + ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %ld exceptions\n", num_guard_page_calls ); + ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); count = 64; ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); - ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); - ok( count == 0 || broken(count == 1) /* Windows 8 */, "wrong count %lu\n", count ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 0 || broken(count == 1) /* Windows 8 */, "wrong count %Iu\n", count ); /* Now test with a proper ATL thunk instruction. */ @@ -2786,63 +3170,71 @@ static void test_atl_thunk_emulation( ULONG dep_flags ) 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( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 1, "wrong count %Iu\n", count ); ok( results[0] == base, "wrong result %p\n", results[0] ); success = VirtualProtect( base, size, PAGE_EXECUTE_READWRITE, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); ret = SendMessageA(hWnd, WM_USER, 0, 0); - ok( ret == 43, "SendMessage returned unexpected result %d\n", ret ); + ok( ret == 43, "SendMessage returned unexpected result %ld\n", ret ); /* Try executing with PAGE_READWRITE protection. */ success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); ret = send_message_excpt( hWnd, WM_USER, 0, 0 ); - ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret ); - ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls ); + ok( ret == 43, "call returned wrong result, expected 43, got %ld\n", ret ); + ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %ld exceptions\n", num_guard_page_calls ); if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION)) - ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); +#ifdef __REACTOS__ + ok( num_execute_fault_calls == 1 || broken(num_execute_fault_calls == 0), "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#else + ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#endif else - ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); + ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); count = 64; ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); - ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); - ok( count == 0, "wrong count %lu\n", count ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 0, "wrong count %Iu\n", count ); ret = send_message_excpt( hWnd, WM_USER, 0, 0 ); - ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret ); - ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls ); - ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); + ok( ret == 43, "call returned wrong result, expected 43, got %ld\n", ret ); + ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %ld exceptions\n", num_guard_page_calls ); + ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); /* Now a bit more complicated, the page containing the code is protected with * PAGE_GUARD memory protection. */ success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); /* the same, but with PAGE_GUARD set */ ret = send_message_excpt( hWnd, WM_USER, 0, 0 ); - ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret ); - ok( num_guard_page_calls == 1, "expected one STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls ); + ok( ret == 43, "call returned wrong result, expected 43, got %ld\n", ret ); + ok( num_guard_page_calls == 1, "expected one STATUS_GUARD_PAGE_VIOLATION exception, got %ld exceptions\n", num_guard_page_calls ); if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION)) - ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); +#ifdef __REACTOS__ + ok( num_execute_fault_calls == 1 || broken(num_execute_fault_calls == 0) /* WS03 */, "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#else + ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); +#endif else - ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); + ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); ret = send_message_excpt( hWnd, WM_USER, 0, 0 ); - ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret ); - ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls ); - ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); + ok( ret == 43, "call returned wrong result, expected 43, got %ld\n", ret ); + ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %ld exceptions\n", num_guard_page_calls ); + ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %ld exceptions\n", num_execute_fault_calls ); count = 64; ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); - ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); - ok( count == 0 || broken(count == 1) /* Windows 8 */, "wrong count %lu\n", count ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 0 || broken(count == 1) /* Windows 8 */, "wrong count %Iu\n", count ); /* Restore the JMP instruction, set to executable, and then destroy the Window */ @@ -2851,17 +3243,17 @@ static void test_atl_thunk_emulation( ULONG dep_flags ) 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( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 1, "wrong count %Iu\n", count ); ok( results[0] == base, "wrong result %p\n", results[0] ); success = VirtualProtect( base, size, PAGE_EXECUTE_READWRITE, &old_prot ); - ok( success, "VirtualProtect failed %u\n", GetLastError() ); + ok( success, "VirtualProtect failed %lu\n", GetLastError() ); DestroyWindow( hWnd ); success = UnregisterClassA( cls_name, GetModuleHandleA(0) ); - ok( success, "UnregisterClass failed %u\n", GetLastError() ); + ok( success, "UnregisterClass failed %lu\n", GetLastError() ); VirtualFree( base, 0, MEM_RELEASE ); @@ -2869,10 +3261,9 @@ out: if (restore_flags) { ret = NtSetInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &old_flags, sizeof(old_flags) ); - ok( !ret, "NtSetInformationProcess failed with status %08x\n", ret ); + ok( !ret, "NtSetInformationProcess failed with status %08lx\n", ret ); } } - #endif /* __i386__ */ static void test_VirtualProtect(void) @@ -2918,84 +3309,80 @@ static void test_VirtualProtect(void) char *base, *ptr; DWORD ret, old_prot, rw_prot, exec_prot, i, j; MEMORY_BASIC_INFORMATION info; - SYSTEM_INFO si; void *addr; SIZE_T size; NTSTATUS status; - GetSystemInfo(&si); - trace("system page size %#x\n", si.dwPageSize); - SetLastError(0xdeadbeef); base = VirtualAlloc(0, si.dwPageSize, MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS); - ok(base != NULL, "VirtualAlloc failed %d\n", GetLastError()); + ok(base != NULL, "VirtualAlloc failed %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = VirtualProtect(base, si.dwPageSize, PAGE_READONLY, NULL); ok(!ret, "VirtualProtect should fail\n"); - ok(GetLastError() == ERROR_NOACCESS, "expected ERROR_NOACCESS, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_NOACCESS, "expected ERROR_NOACCESS, got %ld\n", GetLastError()); old_prot = 0xdeadbeef; ret = VirtualProtect(base, si.dwPageSize, PAGE_NOACCESS, &old_prot); - ok(ret, "VirtualProtect failed %d\n", GetLastError()); - ok(old_prot == PAGE_NOACCESS, "got %#x != expected PAGE_NOACCESS\n", old_prot); + ok(ret, "VirtualProtect failed %ld\n", GetLastError()); + ok(old_prot == PAGE_NOACCESS, "got %#lx != expected PAGE_NOACCESS\n", old_prot); addr = base; size = si.dwPageSize; status = pNtProtectVirtualMemory(GetCurrentProcess(), &addr, &size, PAGE_READONLY, NULL); - ok(status == STATUS_ACCESS_VIOLATION, "NtProtectVirtualMemory should fail, got %08x\n", status); + ok(status == STATUS_ACCESS_VIOLATION, "NtProtectVirtualMemory should fail, got %08lx\n", status); addr = base; size = si.dwPageSize; old_prot = 0xdeadbeef; status = pNtProtectVirtualMemory(GetCurrentProcess(), &addr, &size, PAGE_NOACCESS, &old_prot); - ok(status == STATUS_SUCCESS, "NtProtectVirtualMemory should succeed, got %08x\n", status); - ok(old_prot == PAGE_NOACCESS, "got %#x != expected PAGE_NOACCESS\n", old_prot); + ok(status == STATUS_SUCCESS, "NtProtectVirtualMemory should succeed, got %08lx\n", status); + ok(old_prot == PAGE_NOACCESS, "got %#lx != expected PAGE_NOACCESS\n", old_prot); - for (i = 0; i < sizeof(td)/sizeof(td[0]); i++) + for (i = 0; i < ARRAY_SIZE(td); i++) { SetLastError(0xdeadbeef); ret = VirtualQuery(base, &info, sizeof(info)); - ok(ret, "VirtualQuery failed %d\n", GetLastError()); - ok(info.BaseAddress == base, "%d: got %p != expected %p\n", i, info.BaseAddress, base); - ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize); - ok(info.Protect == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, info.Protect); - ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base); - ok(info.AllocationProtect == PAGE_NOACCESS, "%d: %#x != PAGE_NOACCESS\n", i, info.AllocationProtect); - ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State); - ok(info.Type == MEM_PRIVATE, "%d: %#x != MEM_PRIVATE\n", i, info.Type); + ok(ret, "VirtualQuery failed %ld\n", GetLastError()); + ok(info.BaseAddress == base, "%ld: got %p != expected %p\n", i, info.BaseAddress, base); + ok(info.RegionSize == si.dwPageSize, "%ld: got %#Ix != expected %#lx\n", i, info.RegionSize, si.dwPageSize); + ok(info.Protect == PAGE_NOACCESS, "%ld: got %#lx != expected PAGE_NOACCESS\n", i, info.Protect); + ok(info.AllocationBase == base, "%ld: %p != %p\n", i, info.AllocationBase, base); + ok(info.AllocationProtect == PAGE_NOACCESS, "%ld: %#lx != PAGE_NOACCESS\n", i, info.AllocationProtect); + ok(info.State == MEM_COMMIT, "%ld: %#lx != MEM_COMMIT\n", i, info.State); + ok(info.Type == MEM_PRIVATE, "%ld: %#lx != MEM_PRIVATE\n", i, info.Type); old_prot = 0xdeadbeef; SetLastError(0xdeadbeef); ret = VirtualProtect(base, si.dwPageSize, td[i].prot_set, &old_prot); if (td[i].prot_get) { - ok(ret, "%d: VirtualProtect error %d\n", i, GetLastError()); - ok(old_prot == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, old_prot); + ok(ret, "%ld: VirtualProtect error %ld\n", i, GetLastError()); + ok(old_prot == PAGE_NOACCESS, "%ld: got %#lx != expected PAGE_NOACCESS\n", i, old_prot); SetLastError(0xdeadbeef); ret = VirtualQuery(base, &info, sizeof(info)); - ok(ret, "VirtualQuery failed %d\n", GetLastError()); - ok(info.BaseAddress == base, "%d: got %p != expected %p\n", i, info.BaseAddress, base); - ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize); - ok(info.Protect == td[i].prot_get, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot_get); - ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base); - ok(info.AllocationProtect == PAGE_NOACCESS, "%d: %#x != PAGE_NOACCESS\n", i, info.AllocationProtect); - ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State); - ok(info.Type == MEM_PRIVATE, "%d: %#x != MEM_PRIVATE\n", i, info.Type); + ok(ret, "VirtualQuery failed %ld\n", GetLastError()); + ok(info.BaseAddress == base, "%ld: got %p != expected %p\n", i, info.BaseAddress, base); + ok(info.RegionSize == si.dwPageSize, "%ld: got %#Ix != expected %#lx\n", i, info.RegionSize, si.dwPageSize); + ok(info.Protect == td[i].prot_get, "%ld: got %#lx != expected %#lx\n", i, info.Protect, td[i].prot_get); + ok(info.AllocationBase == base, "%ld: %p != %p\n", i, info.AllocationBase, base); + ok(info.AllocationProtect == PAGE_NOACCESS, "%ld: %#lx != PAGE_NOACCESS\n", i, info.AllocationProtect); + ok(info.State == MEM_COMMIT, "%ld: %#lx != MEM_COMMIT\n", i, info.State); + ok(info.Type == MEM_PRIVATE, "%ld: %#lx != MEM_PRIVATE\n", i, info.Type); } else { - ok(!ret, "%d: VirtualProtect should fail\n", i); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError()); + ok(!ret, "%ld: VirtualProtect should fail\n", i); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "%ld: expected ERROR_INVALID_PARAMETER, got %ld\n", i, GetLastError()); } old_prot = 0xdeadbeef; SetLastError(0xdeadbeef); ret = VirtualProtect(base, si.dwPageSize, PAGE_NOACCESS, &old_prot); - ok(ret, "%d: VirtualProtect error %d\n", i, GetLastError()); + ok(ret, "%ld: VirtualProtect error %ld\n", i, GetLastError()); if (td[i].prot_get) - ok(old_prot == td[i].prot_get, "%d: got %#x != expected %#x\n", i, old_prot, td[i].prot_get); + ok(old_prot == td[i].prot_get, "%ld: got %#lx != expected %#lx\n", i, old_prot, td[i].prot_get); else - ok(old_prot == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, old_prot); + ok(old_prot == PAGE_NOACCESS, "%ld: got %#lx != expected PAGE_NOACCESS\n", i, old_prot); } exec_prot = 0; @@ -3012,19 +3399,19 @@ static void test_VirtualProtect(void) ptr = VirtualAlloc(base, si.dwPageSize, MEM_COMMIT, prot); if ((rw_prot && exec_prot) || (!rw_prot && !exec_prot)) { - ok(!ptr, "VirtualAlloc(%02x) should fail\n", prot); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + ok(!ptr, "VirtualAlloc(%02lx) should fail\n", prot); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); } else { if (prot & (PAGE_WRITECOPY | PAGE_EXECUTE_WRITECOPY)) { - ok(!ptr, "VirtualAlloc(%02x) should fail\n", prot); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + ok(!ptr, "VirtualAlloc(%02lx) should fail\n", prot); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); } else { - ok(ptr != NULL, "VirtualAlloc(%02x) error %d\n", prot, GetLastError()); + ok(ptr != NULL, "VirtualAlloc(%02lx) error %ld\n", prot, GetLastError()); ok(ptr == base, "expected %p, got %p\n", base, ptr); } } @@ -3033,18 +3420,18 @@ static void test_VirtualProtect(void) ret = VirtualProtect(base, si.dwPageSize, prot, &old_prot); if ((rw_prot && exec_prot) || (!rw_prot && !exec_prot)) { - ok(!ret, "VirtualProtect(%02x) should fail\n", prot); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + ok(!ret, "VirtualProtect(%02lx) should fail\n", prot); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); } else { if (prot & (PAGE_WRITECOPY | PAGE_EXECUTE_WRITECOPY)) { - ok(!ret, "VirtualProtect(%02x) should fail\n", prot); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + ok(!ret, "VirtualProtect(%02lx) should fail\n", prot); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); } else - ok(ret, "VirtualProtect(%02x) error %d\n", prot, GetLastError()); + ok(ret, "VirtualProtect(%02lx) error %ld\n", prot, GetLastError()); } rw_prot = 1 << j; @@ -3115,30 +3502,26 @@ static void test_VirtualAlloc_protection(void) char *base, *ptr; DWORD ret, i; MEMORY_BASIC_INFORMATION info; - SYSTEM_INFO si; - GetSystemInfo(&si); - trace("system page size %#x\n", si.dwPageSize); - - for (i = 0; i < sizeof(td)/sizeof(td[0]); i++) + for (i = 0; i < ARRAY_SIZE(td); i++) { SetLastError(0xdeadbeef); base = VirtualAlloc(0, si.dwPageSize, MEM_COMMIT, td[i].prot); if (td[i].success) { - ok(base != NULL, "%d: VirtualAlloc failed %d\n", i, GetLastError()); + ok(base != NULL, "%ld: VirtualAlloc failed %ld\n", i, GetLastError()); SetLastError(0xdeadbeef); ret = VirtualQuery(base, &info, sizeof(info)); - ok(ret, "VirtualQuery failed %d\n", GetLastError()); - ok(info.BaseAddress == base, "%d: got %p != expected %p\n", i, info.BaseAddress, base); - ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize); - ok(info.Protect == td[i].prot, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot); - ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base); - ok(info.AllocationProtect == td[i].prot, "%d: %#x != %#x\n", i, info.AllocationProtect, td[i].prot); - ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State); - ok(info.Type == MEM_PRIVATE, "%d: %#x != MEM_PRIVATE\n", i, info.Type); + ok(ret, "VirtualQuery failed %ld\n", GetLastError()); + ok(info.BaseAddress == base, "%ld: got %p != expected %p\n", i, info.BaseAddress, base); + ok(info.RegionSize == si.dwPageSize, "%ld: got %#Ix != expected %#lx\n", i, info.RegionSize, si.dwPageSize); + ok(info.Protect == td[i].prot, "%ld: got %#lx != expected %#lx\n", i, info.Protect, td[i].prot); + ok(info.AllocationBase == base, "%ld: %p != %p\n", i, info.AllocationBase, base); + ok(info.AllocationProtect == td[i].prot, "%ld: %#lx != %#lx\n", i, info.AllocationProtect, td[i].prot); + ok(info.State == MEM_COMMIT, "%ld: %#lx != MEM_COMMIT\n", i, info.State); + ok(info.Type == MEM_PRIVATE, "%ld: %#lx != MEM_PRIVATE\n", i, info.Type); if (is_mem_writable(info.Protect)) { @@ -3146,20 +3529,20 @@ static void test_VirtualAlloc_protection(void) SetLastError(0xdeadbeef); ret = VirtualQuery(base, &info, sizeof(info)); - ok(ret, "VirtualQuery failed %d\n", GetLastError()); - ok(info.Protect == td[i].prot, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot); + ok(ret, "VirtualQuery failed %ld\n", GetLastError()); + ok(info.Protect == td[i].prot, "%ld: got %#lx != expected %#lx\n", i, info.Protect, td[i].prot); } SetLastError(0xdeadbeef); ptr = VirtualAlloc(base, si.dwPageSize, MEM_COMMIT, td[i].prot); - ok(ptr == base, "%d: VirtualAlloc failed %d\n", i, GetLastError()); + ok(ptr == base, "%ld: VirtualAlloc failed %ld\n", i, GetLastError()); VirtualFree(base, 0, MEM_RELEASE); } else { - ok(!base, "%d: VirtualAlloc should fail\n", i); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError()); + ok(!base, "%ld: VirtualAlloc should fail\n", i); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "%ld: expected ERROR_INVALID_PARAMETER, got %ld\n", i, GetLastError()); } } } @@ -3207,27 +3590,23 @@ static void test_CreateFileMapping_protection(void) { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, FALSE, PAGE_NOACCESS } /* 0xf0 */ }; char *base, *ptr; - DWORD ret, i, alloc_prot, prot, old_prot; + DWORD ret, i, alloc_prot, old_prot; MEMORY_BASIC_INFORMATION info; - SYSTEM_INFO si; char temp_path[MAX_PATH]; char file_name[MAX_PATH]; HANDLE hfile, hmap; BOOL page_exec_supported = TRUE; - GetSystemInfo(&si); - trace("system page size %#x\n", si.dwPageSize); - GetTempPathA(MAX_PATH, temp_path); GetTempFileNameA(temp_path, "map", 0, file_name); SetLastError(0xdeadbeef); hfile = CreateFileA(file_name, GENERIC_READ|GENERIC_WRITE|GENERIC_EXECUTE, 0, NULL, CREATE_ALWAYS, 0, 0); - ok(hfile != INVALID_HANDLE_VALUE, "CreateFile(%s) error %d\n", file_name, GetLastError()); + ok(hfile != INVALID_HANDLE_VALUE, "CreateFile(%s) error %ld\n", file_name, GetLastError()); SetFilePointer(hfile, si.dwPageSize, NULL, FILE_BEGIN); SetEndOfFile(hfile); - for (i = 0; i < sizeof(td)/sizeof(td[0]); i++) + for (i = 0; i < ARRAY_SIZE(td); i++) { SetLastError(0xdeadbeef); hmap = CreateFileMappingW(hfile, NULL, td[i].prot | SEC_COMMIT, 0, si.dwPageSize, NULL); @@ -3236,63 +3615,51 @@ static void test_CreateFileMapping_protection(void) { if (!hmap) { - trace("%d: CreateFileMapping(%04x) failed: %d\n", i, td[i].prot, GetLastError()); + trace("%ld: CreateFileMapping(%04lx) failed: %ld\n", i, td[i].prot, GetLastError()); /* NT4 and win2k don't support EXEC on file mappings */ if (td[i].prot == PAGE_EXECUTE_READ || td[i].prot == PAGE_EXECUTE_READWRITE) { page_exec_supported = FALSE; - ok(broken(!hmap), "%d: CreateFileMapping doesn't support PAGE_EXECUTE\n", i); + ok(broken(!hmap), "%ld: CreateFileMapping doesn't support PAGE_EXECUTE\n", i); continue; } /* Vista+ supports PAGE_EXECUTE_WRITECOPY, earlier versions don't */ if (td[i].prot == PAGE_EXECUTE_WRITECOPY) { page_exec_supported = FALSE; - ok(broken(!hmap), "%d: CreateFileMapping doesn't support PAGE_EXECUTE_WRITECOPY\n", i); + ok(broken(!hmap), "%ld: CreateFileMapping doesn't support PAGE_EXECUTE_WRITECOPY\n", i); continue; } } - ok(hmap != 0, "%d: CreateFileMapping(%04x) error %d\n", i, td[i].prot, GetLastError()); + ok(hmap != 0, "%ld: CreateFileMapping(%04lx) error %ld\n", i, td[i].prot, GetLastError()); base = MapViewOfFile(hmap, FILE_MAP_READ, 0, 0, 0); - ok(base != NULL, "%d: MapViewOfFile failed %d\n", i, GetLastError()); + ok(base != NULL, "%ld: MapViewOfFile failed %ld\n", i, GetLastError()); SetLastError(0xdeadbeef); ret = VirtualQuery(base, &info, sizeof(info)); - ok(ret, "VirtualQuery failed %d\n", GetLastError()); - ok(info.BaseAddress == base, "%d: got %p != expected %p\n", i, info.BaseAddress, base); - ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize); - ok(info.Protect == PAGE_READONLY, "%d: got %#x != expected PAGE_READONLY\n", i, info.Protect); - ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base); - ok(info.AllocationProtect == PAGE_READONLY, "%d: %#x != PAGE_READONLY\n", i, info.AllocationProtect); - ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State); - ok(info.Type == MEM_MAPPED, "%d: %#x != MEM_MAPPED\n", i, info.Type); - - if (is_mem_writable(info.Protect)) - { - base[0] = 0xfe; - - SetLastError(0xdeadbeef); - ret = VirtualQuery(base, &info, sizeof(info)); - ok(ret, "VirtualQuery failed %d\n", GetLastError()); - ok(info.Protect == td[i].prot, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot); - } + ok(ret, "VirtualQuery failed %ld\n", GetLastError()); + ok(info.BaseAddress == base, "%ld: got %p != expected %p\n", i, info.BaseAddress, base); + ok(info.RegionSize == si.dwPageSize, "%ld: got %#Ix != expected %#lx\n", i, info.RegionSize, si.dwPageSize); + ok(info.Protect == PAGE_READONLY, "%ld: got %#lx != expected PAGE_READONLY\n", i, info.Protect); + ok(info.AllocationBase == base, "%ld: %p != %p\n", i, info.AllocationBase, base); + ok(info.AllocationProtect == PAGE_READONLY, "%ld: %#lx != PAGE_READONLY\n", i, info.AllocationProtect); + ok(info.State == MEM_COMMIT, "%ld: %#lx != MEM_COMMIT\n", i, info.State); + ok(info.Type == MEM_MAPPED, "%ld: %#lx != MEM_MAPPED\n", i, info.Type); SetLastError(0xdeadbeef); ptr = VirtualAlloc(base, si.dwPageSize, MEM_COMMIT, td[i].prot); - ok(!ptr, "%d: VirtualAlloc(%02x) should fail\n", i, td[i].prot); - /* FIXME: remove once Wine is fixed */ - todo_wine_if (td[i].prot == PAGE_WRITECOPY || td[i].prot == PAGE_EXECUTE_WRITECOPY) - ok(GetLastError() == ERROR_ACCESS_DENIED, "%d: expected ERROR_ACCESS_DENIED, got %d\n", i, GetLastError()); + ok(!ptr, "%ld: VirtualAlloc(%02lx) should fail\n", i, td[i].prot); + ok(GetLastError() == ERROR_ACCESS_DENIED, "%ld: expected ERROR_ACCESS_DENIED, got %ld\n", i, GetLastError()); SetLastError(0xdeadbeef); ret = VirtualProtect(base, si.dwPageSize, td[i].prot, &old_prot); if (td[i].prot == PAGE_READONLY || td[i].prot == PAGE_WRITECOPY) - ok(ret, "%d: VirtualProtect(%02x) error %d\n", i, td[i].prot, GetLastError()); + ok(ret, "%ld: VirtualProtect(%02lx) error %ld\n", i, td[i].prot, GetLastError()); else { - ok(!ret, "%d: VirtualProtect(%02x) should fail\n", i, td[i].prot); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError()); + ok(!ret, "%ld: VirtualProtect(%02lx) should fail\n", i, td[i].prot); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "%ld: expected ERROR_INVALID_PARAMETER, got %ld\n", i, GetLastError()); } UnmapViewOfFile(base); @@ -3300,8 +3667,8 @@ static void test_CreateFileMapping_protection(void) } else { - ok(!hmap, "%d: CreateFileMapping should fail\n", i); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError()); + ok(!hmap, "%ld: CreateFileMapping should fail\n", i); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "%ld: expected ERROR_INVALID_PARAMETER, got %ld\n", i, GetLastError()); } } @@ -3309,30 +3676,30 @@ static void test_CreateFileMapping_protection(void) else alloc_prot = PAGE_READWRITE; SetLastError(0xdeadbeef); hmap = CreateFileMappingW(hfile, NULL, alloc_prot, 0, si.dwPageSize, NULL); - ok(hmap != 0, "%d: CreateFileMapping error %d\n", i, GetLastError()); + ok(hmap != 0, "%ld: CreateFileMapping error %ld\n", i, GetLastError()); - SetLastError(0xdeadbeef); - base = MapViewOfFile(hmap, FILE_MAP_READ | FILE_MAP_WRITE | (page_exec_supported ? FILE_MAP_EXECUTE : 0), 0, 0, 0); - ok(base != NULL, "MapViewOfFile failed %d\n", GetLastError()); - - old_prot = 0xdeadbeef; - SetLastError(0xdeadbeef); - ret = VirtualProtect(base, si.dwPageSize, PAGE_NOACCESS, &old_prot); - ok(ret, "VirtualProtect error %d\n", GetLastError()); - ok(old_prot == alloc_prot, "got %#x != expected %#x\n", old_prot, alloc_prot); - - for (i = 0; i < sizeof(td)/sizeof(td[0]); i++) + for (i = 0; i < ARRAY_SIZE(td); i++) { + SetLastError(0xdeadbeef); + base = MapViewOfFile(hmap, FILE_MAP_READ | FILE_MAP_WRITE | (page_exec_supported ? FILE_MAP_EXECUTE : 0), 0, 0, 0); + ok(base != NULL, "MapViewOfFile failed %ld\n", GetLastError()); + + old_prot = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = VirtualProtect(base, si.dwPageSize, PAGE_NOACCESS, &old_prot); + ok(ret, "VirtualProtect error %ld\n", GetLastError()); + ok(old_prot == alloc_prot, "got %#lx != expected %#lx\n", old_prot, alloc_prot); + SetLastError(0xdeadbeef); ret = VirtualQuery(base, &info, sizeof(info)); - ok(ret, "VirtualQuery failed %d\n", GetLastError()); - ok(info.BaseAddress == base, "%d: got %p != expected %p\n", i, info.BaseAddress, base); - ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize); - ok(info.Protect == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, info.Protect); - ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base); - ok(info.AllocationProtect == alloc_prot, "%d: %#x != %#x\n", i, info.AllocationProtect, alloc_prot); - ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State); - ok(info.Type == MEM_MAPPED, "%d: %#x != MEM_MAPPED\n", i, info.Type); + ok(ret, "VirtualQuery failed %ld\n", GetLastError()); + ok(info.BaseAddress == base, "%ld: got %p != expected %p\n", i, info.BaseAddress, base); + ok(info.RegionSize == si.dwPageSize, "%ld: got %#Ix != expected %#lx\n", i, info.RegionSize, si.dwPageSize); + ok(info.Protect == PAGE_NOACCESS, "%ld: got %#lx != expected PAGE_NOACCESS\n", i, info.Protect); + ok(info.AllocationBase == base, "%ld: %p != %p\n", i, info.AllocationBase, base); + ok(info.AllocationProtect == alloc_prot, "%ld: %#lx != %#lx\n", i, info.AllocationProtect, alloc_prot); + ok(info.State == MEM_COMMIT, "%ld: %#lx != MEM_COMMIT\n", i, info.State); + ok(info.Type == MEM_MAPPED, "%ld: %#lx != MEM_MAPPED\n", i, info.Type); old_prot = 0xdeadbeef; SetLastError(0xdeadbeef); @@ -3344,42 +3711,36 @@ static void test_CreateFileMapping_protection(void) /* win2k and XP don't support EXEC on file mappings */ if (td[i].prot == PAGE_EXECUTE) { - ok(broken(!ret), "%d: VirtualProtect doesn't support PAGE_EXECUTE\n", i); + ok(broken(!ret), "%ld: VirtualProtect doesn't support PAGE_EXECUTE\n", i); continue; } /* NT4 and win2k don't support EXEC on file mappings */ if (td[i].prot == PAGE_EXECUTE_READ || td[i].prot == PAGE_EXECUTE_READWRITE) { - ok(broken(!ret), "%d: VirtualProtect doesn't support PAGE_EXECUTE\n", i); + ok(broken(!ret), "%ld: VirtualProtect doesn't support PAGE_EXECUTE\n", i); continue; } /* Vista+ supports PAGE_EXECUTE_WRITECOPY, earlier versions don't */ if (td[i].prot == PAGE_EXECUTE_WRITECOPY) { - ok(broken(!ret), "%d: VirtualProtect doesn't support PAGE_EXECUTE_WRITECOPY\n", i); + ok(broken(!ret), "%ld: VirtualProtect doesn't support PAGE_EXECUTE_WRITECOPY\n", i); continue; } } - ok(ret, "%d: VirtualProtect error %d\n", i, GetLastError()); - ok(old_prot == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, old_prot); - - prot = td[i].prot; - /* looks strange but Windows doesn't do this for PAGE_WRITECOPY */ - if (prot == PAGE_EXECUTE_WRITECOPY) prot = PAGE_EXECUTE_READWRITE; + ok(ret, "%ld: VirtualProtect error %ld\n", i, GetLastError()); + ok(old_prot == PAGE_NOACCESS, "%ld: got %#lx != expected PAGE_NOACCESS\n", i, old_prot); SetLastError(0xdeadbeef); ret = VirtualQuery(base, &info, sizeof(info)); - ok(ret, "VirtualQuery failed %d\n", GetLastError()); - ok(info.BaseAddress == base, "%d: got %p != expected %p\n", i, info.BaseAddress, base); - ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize); - /* FIXME: remove the condition below once Wine is fixed */ - todo_wine_if (td[i].prot == PAGE_EXECUTE_WRITECOPY) - ok(info.Protect == prot, "%d: got %#x != expected %#x\n", i, info.Protect, prot); - ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base); - ok(info.AllocationProtect == alloc_prot, "%d: %#x != %#x\n", i, info.AllocationProtect, alloc_prot); - ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State); - ok(info.Type == MEM_MAPPED, "%d: %#x != MEM_MAPPED\n", i, info.Type); + ok(ret, "VirtualQuery failed %ld\n", GetLastError()); + ok(info.BaseAddress == base, "%ld: got %p != expected %p\n", i, info.BaseAddress, base); + ok(info.RegionSize == si.dwPageSize, "%ld: got %#Ix != expected %#lx\n", i, info.RegionSize, si.dwPageSize); + ok(info.Protect == td[i].prot, "%ld: got %#lx != expected %#lx\n", i, info.Protect, td[i].prot); + ok(info.AllocationBase == base, "%ld: %p != %p\n", i, info.AllocationBase, base); + ok(info.AllocationProtect == alloc_prot, "%ld: %#lx != %#lx\n", i, info.AllocationProtect, alloc_prot); + ok(info.State == MEM_COMMIT, "%ld: %#lx != MEM_COMMIT\n", i, info.State); + ok(info.Type == MEM_MAPPED, "%ld: %#lx != MEM_MAPPED\n", i, info.Type); if (is_mem_writable(info.Protect)) { @@ -3387,29 +3748,30 @@ static void test_CreateFileMapping_protection(void) SetLastError(0xdeadbeef); ret = VirtualQuery(base, &info, sizeof(info)); - ok(ret, "VirtualQuery failed %d\n", GetLastError()); + ok(ret, "VirtualQuery failed %ld\n", GetLastError()); /* FIXME: remove the condition below once Wine is fixed */ todo_wine_if (td[i].prot == PAGE_WRITECOPY || td[i].prot == PAGE_EXECUTE_WRITECOPY) - ok(info.Protect == td[i].prot_after_write, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot_after_write); + ok(info.Protect == td[i].prot_after_write, "%ld: got %#lx != expected %#lx\n", i, info.Protect, td[i].prot_after_write); } } else { - ok(!ret, "%d: VirtualProtect should fail\n", i); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError()); + ok(!ret, "%ld: VirtualProtect should fail\n", i); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "%ld: expected ERROR_INVALID_PARAMETER, got %ld\n", i, GetLastError()); continue; } old_prot = 0xdeadbeef; SetLastError(0xdeadbeef); ret = VirtualProtect(base, si.dwPageSize, PAGE_NOACCESS, &old_prot); - ok(ret, "%d: VirtualProtect error %d\n", i, GetLastError()); + ok(ret, "%ld: VirtualProtect error %ld\n", i, GetLastError()); /* FIXME: remove the condition below once Wine is fixed */ todo_wine_if (td[i].prot == PAGE_WRITECOPY || td[i].prot == PAGE_EXECUTE_WRITECOPY) - ok(old_prot == td[i].prot_after_write, "%d: got %#x != expected %#x\n", i, old_prot, td[i].prot_after_write); + ok(old_prot == td[i].prot_after_write, "%ld: got %#lx != expected %#lx\n", i, old_prot, td[i].prot_after_write); + + UnmapViewOfFile(base); } - UnmapViewOfFile(base); CloseHandle(hmap); CloseHandle(hfile); @@ -3419,51 +3781,35 @@ static void test_CreateFileMapping_protection(void) #define ACCESS_READ 0x01 #define ACCESS_WRITE 0x02 #define ACCESS_EXECUTE 0x04 -#define ACCESS_WRITECOPY 0x08 static DWORD page_prot_to_access(DWORD prot) { switch (prot) { - case PAGE_READWRITE: - return ACCESS_READ | ACCESS_WRITE; - - case PAGE_EXECUTE: - case PAGE_EXECUTE_READ: - return ACCESS_READ | ACCESS_EXECUTE; - - case PAGE_EXECUTE_READWRITE: - return ACCESS_READ | ACCESS_WRITE | ACCESS_WRITECOPY | ACCESS_EXECUTE; - - case PAGE_EXECUTE_WRITECOPY: - return ACCESS_READ | ACCESS_WRITECOPY | ACCESS_EXECUTE; - case PAGE_READONLY: - return ACCESS_READ; - case PAGE_WRITECOPY: return ACCESS_READ; - + case PAGE_READWRITE: + return ACCESS_READ | ACCESS_WRITE; + case PAGE_EXECUTE: + case PAGE_EXECUTE_READ: + case PAGE_EXECUTE_WRITECOPY: + return ACCESS_READ | ACCESS_EXECUTE; + case PAGE_EXECUTE_READWRITE: + return ACCESS_READ | ACCESS_WRITE | ACCESS_EXECUTE; default: return 0; } } -static BOOL is_compatible_protection(DWORD map_prot, DWORD view_prot, DWORD prot) +static BOOL is_compatible_protection(DWORD view_prot, DWORD prot) { - DWORD map_access, view_access, prot_access; + DWORD view_access, prot_access; - map_access = page_prot_to_access(map_prot); view_access = page_prot_to_access(view_prot); prot_access = page_prot_to_access(prot); - if (view_access == prot_access) return TRUE; - if (!view_access) return FALSE; - - if ((view_access & prot_access) != prot_access) return FALSE; - if ((map_access & prot_access) == prot_access) return TRUE; - - return FALSE; + return ((view_access & prot_access) == prot_access); } static DWORD map_prot_to_access(DWORD prot) @@ -3471,24 +3817,58 @@ static DWORD map_prot_to_access(DWORD prot) switch (prot) { case PAGE_READWRITE: + return SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_QUERY; case PAGE_EXECUTE_READWRITE: - return SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE | SECTION_MAP_EXECUTE_EXPLICIT | SECTION_QUERY; + return SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE | SECTION_QUERY; case PAGE_READONLY: case PAGE_WRITECOPY: + return SECTION_MAP_READ | SECTION_QUERY; case PAGE_EXECUTE: case PAGE_EXECUTE_READ: case PAGE_EXECUTE_WRITECOPY: - return SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_MAP_EXECUTE_EXPLICIT | SECTION_QUERY; + return SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_QUERY; default: return 0; } } +static DWORD map_prot_no_write(DWORD prot) +{ + switch (prot) + { + case PAGE_READWRITE: return PAGE_WRITECOPY; + case PAGE_EXECUTE_READWRITE: return PAGE_EXECUTE_WRITECOPY; + default: return prot; + } +} + +static DWORD map_prot_written(DWORD prot) +{ + switch (prot) + { + case PAGE_WRITECOPY: return PAGE_READWRITE; + case PAGE_EXECUTE_WRITECOPY: return PAGE_EXECUTE_READWRITE; + default: return prot; + } +} + +static DWORD file_access_to_prot( DWORD access ) +{ + BOOL exec = access & FILE_MAP_EXECUTE; + access &= ~FILE_MAP_EXECUTE; + + if (access == FILE_MAP_COPY) return exec ? PAGE_EXECUTE_WRITECOPY : PAGE_WRITECOPY; + if (access & FILE_MAP_WRITE) return exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; + if (access & FILE_MAP_READ) return exec ? PAGE_EXECUTE_READ : PAGE_READONLY; + return PAGE_NOACCESS; +} + static BOOL is_compatible_access(DWORD map_prot, DWORD view_prot) { DWORD access = map_prot_to_access(map_prot); - if (!view_prot) view_prot = SECTION_MAP_READ; - return (view_prot & access) == view_prot; + DWORD view_access = map_prot_to_access( file_access_to_prot( view_prot )); + if (!view_access) view_access = SECTION_MAP_READ; + return (view_access & access) == view_access; } static void *map_view_of_file(HANDLE handle, DWORD access) @@ -3497,7 +3877,6 @@ static void *map_view_of_file(HANDLE handle, DWORD access) LARGE_INTEGER offset; SIZE_T count; ULONG protect; - BOOL exec; void *addr; if (!pNtMapViewOfSection) return NULL; @@ -3506,50 +3885,20 @@ static void *map_view_of_file(HANDLE handle, DWORD access) offset.u.LowPart = 0; offset.u.HighPart = 0; - exec = access & FILE_MAP_EXECUTE; - access &= ~FILE_MAP_EXECUTE; - - if (access == FILE_MAP_COPY) - { - if (exec) - protect = PAGE_EXECUTE_WRITECOPY; - else - protect = PAGE_WRITECOPY; - } - else if (access & FILE_MAP_WRITE) - { - if (exec) - protect = PAGE_EXECUTE_READWRITE; - else - protect = PAGE_READWRITE; - } - else if (access & FILE_MAP_READ) - { - if (exec) - protect = PAGE_EXECUTE_READ; - else - protect = PAGE_READONLY; - } - else protect = PAGE_NOACCESS; - + protect = file_access_to_prot( access ); addr = NULL; status = pNtMapViewOfSection(handle, GetCurrentProcess(), &addr, 0, 0, &offset, &count, 1 /* ViewShare */, 0, protect); - if (status) - { - /* for simplicity */ - SetLastError(ERROR_ACCESS_DENIED); - addr = NULL; - } + if ((int)status < 0) addr = NULL; return addr; } -static void test_mapping(void) +static void test_mapping( HANDLE hfile, DWORD sec_flags, BOOL readonly ) { static const DWORD page_prot[] = { PAGE_NOACCESS, PAGE_READONLY, PAGE_READWRITE, PAGE_WRITECOPY, - PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY + PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY }; static const struct { @@ -3590,76 +3939,91 @@ static void test_mapping(void) { FILE_MAP_EXECUTE | SECTION_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_COPY, PAGE_EXECUTE_READWRITE } /* 0x2f */ }; void *base, *nt_base, *ptr; - DWORD i, j, k, ret, old_prot, prev_prot; - SYSTEM_INFO si; - char temp_path[MAX_PATH]; - char file_name[MAX_PATH]; - HANDLE hfile, hmap; + DWORD i, j, k, ret, old_prot, prev_prot, alloc_prot; + HANDLE hmap; MEMORY_BASIC_INFORMATION info, nt_info; + BOOL anon_mapping = (hfile == INVALID_HANDLE_VALUE); - GetSystemInfo(&si); - trace("system page size %#x\n", si.dwPageSize); - - GetTempPathA(MAX_PATH, temp_path); - GetTempFileNameA(temp_path, "map", 0, file_name); - - SetLastError(0xdeadbeef); - hfile = CreateFileA(file_name, GENERIC_READ|GENERIC_WRITE|GENERIC_EXECUTE, 0, NULL, CREATE_ALWAYS, 0, 0); - ok(hfile != INVALID_HANDLE_VALUE, "CreateFile(%s) error %d\n", file_name, GetLastError()); - SetFilePointer(hfile, si.dwPageSize, NULL, FILE_BEGIN); - SetEndOfFile(hfile); - - for (i = 0; i < sizeof(page_prot)/sizeof(page_prot[0]); i++) + trace( "testing %s mapping flags %08lx %s\n", anon_mapping ? "anonymous" : "file", + sec_flags, readonly ? "readonly file" : "" ); + for (i = 0; i < ARRAY_SIZE(page_prot); i++) { SetLastError(0xdeadbeef); - hmap = CreateFileMappingW(hfile, NULL, page_prot[i] | SEC_COMMIT, 0, si.dwPageSize, NULL); + hmap = CreateFileMappingW(hfile, NULL, page_prot[i] | sec_flags, 0, 2*si.dwPageSize, NULL); + + if (readonly && (page_prot[i] == PAGE_READWRITE || page_prot[i] == PAGE_EXECUTE_READ + || page_prot[i] == PAGE_EXECUTE_READWRITE || page_prot[i] == PAGE_EXECUTE_WRITECOPY)) + { + todo_wine_if(page_prot[i] == PAGE_EXECUTE_READ || page_prot[i] == PAGE_EXECUTE_WRITECOPY) + { + ok(!hmap, "%ld: CreateFileMapping(%04lx) should fail\n", i, page_prot[i]); + ok(GetLastError() == ERROR_ACCESS_DENIED || broken(GetLastError() == ERROR_INVALID_PARAMETER), + "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError()); + } + if (hmap) CloseHandle(hmap); + continue; + } if (page_prot[i] == PAGE_NOACCESS) { HANDLE hmap2; ok(!hmap, "CreateFileMapping(PAGE_NOACCESS) should fail\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); /* A trick to create a not accessible mapping */ SetLastError(0xdeadbeef); - hmap = CreateFileMappingW(hfile, NULL, PAGE_READWRITE | SEC_COMMIT, 0, si.dwPageSize, NULL); - ok(hmap != 0, "CreateFileMapping(PAGE_READWRITE) error %d\n", GetLastError()); + if (sec_flags & SEC_IMAGE) + hmap = CreateFileMappingW(hfile, NULL, PAGE_WRITECOPY | sec_flags, 0, si.dwPageSize, NULL); + else + hmap = CreateFileMappingW(hfile, NULL, PAGE_READONLY | sec_flags, 0, si.dwPageSize, NULL); + ok(hmap != 0, "CreateFileMapping(PAGE_READWRITE) error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = DuplicateHandle(GetCurrentProcess(), hmap, GetCurrentProcess(), &hmap2, 0, FALSE, 0); - ok(ret, "DuplicateHandle error %d\n", GetLastError()); + ok(ret, "DuplicateHandle error %ld\n", GetLastError()); CloseHandle(hmap); hmap = hmap2; } + if (page_prot[i] == PAGE_EXECUTE) + { + ok(!hmap, "CreateFileMapping(PAGE_EXECUTE) should fail\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); + continue; + } if (!hmap) { - trace("%d: CreateFileMapping(%04x) failed: %d\n", i, page_prot[i], GetLastError()); + trace("%ld: CreateFileMapping(%04lx) failed: %ld\n", i, page_prot[i], GetLastError()); + + if ((sec_flags & SEC_IMAGE) && + (page_prot[i] == PAGE_READWRITE || page_prot[i] == PAGE_EXECUTE_READWRITE)) + continue; /* SEC_IMAGE doesn't support write access */ /* NT4 and win2k don't support EXEC on file mappings */ if (page_prot[i] == PAGE_EXECUTE_READ || page_prot[i] == PAGE_EXECUTE_READWRITE) { - ok(broken(!hmap), "%d: CreateFileMapping doesn't support PAGE_EXECUTE\n", i); + ok(broken(!hmap), "%ld: CreateFileMapping doesn't support PAGE_EXECUTE\n", i); continue; } /* Vista+ supports PAGE_EXECUTE_WRITECOPY, earlier versions don't */ if (page_prot[i] == PAGE_EXECUTE_WRITECOPY) { - ok(broken(!hmap), "%d: CreateFileMapping doesn't support PAGE_EXECUTE_WRITECOPY\n", i); + ok(broken(!hmap), "%ld: CreateFileMapping doesn't support PAGE_EXECUTE_WRITECOPY\n", i); continue; } } - ok(hmap != 0, "%d: CreateFileMapping(%04x) error %d\n", i, page_prot[i], GetLastError()); + ok(hmap != 0, "%ld: CreateFileMapping(%04lx) error %ld\n", i, page_prot[i], GetLastError()); - for (j = 0; j < sizeof(view)/sizeof(view[0]); j++) + for (j = 0; j < ARRAY_SIZE(view); j++) { nt_base = map_view_of_file(hmap, view[j].access); if (nt_base) { SetLastError(0xdeadbeef); ret = VirtualQuery(nt_base, &nt_info, sizeof(nt_info)); - ok(ret, "%d: VirtualQuery failed %d\n", j, GetLastError()); + ok(ret, "%ld: VirtualQuery failed %ld\n", j, GetLastError()); UnmapViewOfFile(nt_base); } @@ -3669,125 +4033,269 @@ static void test_mapping(void) /* Vista+ supports FILE_MAP_EXECUTE properly, earlier versions don't */ ok(!nt_base == !base || broken((view[j].access & FILE_MAP_EXECUTE) && !nt_base != !base), - "%d: (%04x/%04x) NT %p kernel %p\n", j, page_prot[i], view[j].access, nt_base, base); + "%ld: (%04lx/%04lx) NT %p kernel %p\n", j, page_prot[i], view[j].access, nt_base, base); if (!is_compatible_access(page_prot[i], view[j].access)) { - ok(!base, "%d: MapViewOfFile(%04x/%04x) should fail\n", j, page_prot[i], view[j].access); - ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError()); + /* FILE_MAP_EXECUTE | FILE_MAP_COPY broken on XP */ + if (base != NULL && view[j].access == (FILE_MAP_EXECUTE | FILE_MAP_COPY)) + { + ok( broken(base != NULL), "%ld: MapViewOfFile(%04lx/%04lx) should fail\n", + j, page_prot[i], view[j].access); + UnmapViewOfFile( base ); + } + else + { + ok(!base, "%ld: MapViewOfFile(%04lx/%04lx) should fail\n", + j, page_prot[i], view[j].access); + ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %ld\n", GetLastError()); + } continue; } /* Vista+ properly supports FILE_MAP_EXECUTE, earlier versions don't */ if (!base && (view[j].access & FILE_MAP_EXECUTE)) { - ok(broken(!base), "%d: MapViewOfFile(%04x/%04x) failed %d\n", j, page_prot[i], view[j].access, GetLastError()); + ok(broken(!base), "%ld: MapViewOfFile(%04lx/%04lx) failed %ld\n", j, page_prot[i], view[j].access, GetLastError()); continue; } - ok(base != NULL, "%d: MapViewOfFile(%04x/%04x) failed %d\n", j, page_prot[i], view[j].access, GetLastError()); + ok(base != NULL, "%ld: MapViewOfFile(%04lx/%04lx) failed %ld\n", j, page_prot[i], view[j].access, GetLastError()); SetLastError(0xdeadbeef); ret = VirtualQuery(base, &info, sizeof(info)); - ok(ret, "%d: VirtualQuery failed %d\n", j, GetLastError()); - ok(info.BaseAddress == base, "%d: (%04x) got %p, expected %p\n", j, view[j].access, info.BaseAddress, base); - ok(info.RegionSize == si.dwPageSize, "%d: (%04x) got %#lx != expected %#x\n", j, view[j].access, info.RegionSize, si.dwPageSize); - ok(info.Protect == view[j].prot || - broken(view[j].prot == PAGE_EXECUTE_READ && info.Protect == PAGE_READONLY) || /* win2k */ - broken(view[j].prot == PAGE_EXECUTE_READWRITE && info.Protect == PAGE_READWRITE) || /* win2k */ - broken(view[j].prot == PAGE_EXECUTE_WRITECOPY && info.Protect == PAGE_NOACCESS), /* XP */ - "%d: (%04x) got %#x, expected %#x\n", j, view[j].access, info.Protect, view[j].prot); - ok(info.AllocationBase == base, "%d: (%04x) got %p, expected %p\n", j, view[j].access, info.AllocationBase, base); - ok(info.AllocationProtect == info.Protect, "%d: (%04x) got %#x, expected %#x\n", j, view[j].access, info.AllocationProtect, info.Protect); - ok(info.State == MEM_COMMIT, "%d: (%04x) got %#x, expected MEM_COMMIT\n", j, view[j].access, info.State); - ok(info.Type == MEM_MAPPED, "%d: (%04x) got %#x, expected MEM_MAPPED\n", j, view[j].access, info.Type); + ok(ret, "%ld: VirtualQuery failed %ld\n", j, GetLastError()); + ok(info.BaseAddress == base, "%ld: (%04lx) got %p, expected %p\n", j, view[j].access, info.BaseAddress, base); + ok(info.RegionSize == 2*si.dwPageSize || (info.RegionSize == si.dwPageSize && (sec_flags & SEC_IMAGE)), + "%ld: (%04lx) got %#Ix != expected %#lx\n", j, view[j].access, info.RegionSize, 2*si.dwPageSize); + if (sec_flags & SEC_IMAGE) + ok(info.Protect == PAGE_READONLY, + "%ld: (%04lx) got %#lx, expected %#lx\n", j, view[j].access, info.Protect, view[j].prot); + else + ok(info.Protect == view[j].prot || + broken(view[j].prot == PAGE_EXECUTE_READ && info.Protect == PAGE_READONLY) || /* win2k */ + broken(view[j].prot == PAGE_EXECUTE_READWRITE && info.Protect == PAGE_READWRITE) || /* win2k */ + broken(view[j].prot == PAGE_EXECUTE_WRITECOPY && info.Protect == PAGE_NOACCESS), /* XP */ + "%ld: (%04lx) got %#lx, expected %#lx\n", j, view[j].access, info.Protect, view[j].prot); + ok(info.AllocationBase == base, "%ld: (%04lx) got %p, expected %p\n", j, view[j].access, info.AllocationBase, base); + if (sec_flags & SEC_IMAGE) + ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%ld: (%04lx) got %#lx, expected %#lx\n", + j, view[j].access, info.AllocationProtect, info.Protect); + else + ok(info.AllocationProtect == info.Protect, "%ld: (%04lx) got %#lx, expected %#lx\n", + j, view[j].access, info.AllocationProtect, info.Protect); + ok(info.State == MEM_COMMIT, "%ld: (%04lx) got %#lx, expected MEM_COMMIT\n", j, view[j].access, info.State); + ok(info.Type == (sec_flags & SEC_IMAGE) ? SEC_IMAGE : MEM_MAPPED, + "%ld: (%04lx) got %#lx, expected MEM_MAPPED\n", j, view[j].access, info.Type); if (nt_base && base) { - ok(nt_info.RegionSize == info.RegionSize, "%d: (%04x) got %#lx != expected %#lx\n", j, view[j].access, nt_info.RegionSize, info.RegionSize); + ok(nt_info.RegionSize == info.RegionSize, "%ld: (%04lx) got %#Ix != expected %#Ix\n", j, view[j].access, nt_info.RegionSize, info.RegionSize); ok(nt_info.Protect == info.Protect /* Vista+ */ || broken(nt_info.AllocationProtect == PAGE_EXECUTE_WRITECOPY && info.Protect == PAGE_NOACCESS), /* XP */ - "%d: (%04x) got %#x, expected %#x\n", j, view[j].access, nt_info.Protect, info.Protect); + "%ld: (%04lx) got %#lx, expected %#lx\n", j, view[j].access, nt_info.Protect, info.Protect); ok(nt_info.AllocationProtect == info.AllocationProtect /* Vista+ */ || broken(nt_info.AllocationProtect == PAGE_EXECUTE_WRITECOPY && info.Protect == PAGE_NOACCESS), /* XP */ - "%d: (%04x) got %#x, expected %#x\n", j, view[j].access, nt_info.AllocationProtect, info.AllocationProtect); - ok(nt_info.State == info.State, "%d: (%04x) got %#x, expected %#x\n", j, view[j].access, nt_info.State, info.State); - ok(nt_info.Type == info.Type, "%d: (%04x) got %#x, expected %#x\n", j, view[j].access, nt_info.Type, info.Type); + "%ld: (%04lx) got %#lx, expected %#lx\n", j, view[j].access, nt_info.AllocationProtect, info.AllocationProtect); + ok(nt_info.State == info.State, "%ld: (%04lx) got %#lx, expected %#lx\n", j, view[j].access, nt_info.State, info.State); + ok(nt_info.Type == info.Type, "%ld: (%04lx) got %#lx, expected %#lx\n", j, view[j].access, nt_info.Type, info.Type); } prev_prot = info.Protect; + alloc_prot = info.AllocationProtect; - for (k = 0; k < sizeof(page_prot)/sizeof(page_prot[0]); k++) + for (k = 0; k < ARRAY_SIZE(page_prot); k++) { /*trace("map %#x, view %#x, requested prot %#x\n", page_prot[i], view[j].prot, page_prot[k]);*/ + DWORD actual_prot = (sec_flags & SEC_IMAGE) ? map_prot_no_write(page_prot[k]) : page_prot[k]; SetLastError(0xdeadbeef); old_prot = 0xdeadbeef; ret = VirtualProtect(base, si.dwPageSize, page_prot[k], &old_prot); - if (is_compatible_protection(page_prot[i], view[j].prot, page_prot[k])) + if (is_compatible_protection(alloc_prot, actual_prot)) { /* win2k and XP don't support EXEC on file mappings */ - if (!ret && page_prot[k] == PAGE_EXECUTE) + if (!ret && (page_prot[k] == PAGE_EXECUTE || page_prot[k] == PAGE_EXECUTE_WRITECOPY || view[j].prot == PAGE_EXECUTE_WRITECOPY)) { ok(broken(!ret), "VirtualProtect doesn't support PAGE_EXECUTE\n"); continue; } - /* NT4 and win2k don't support EXEC on file mappings */ - if (!ret && (page_prot[k] == PAGE_EXECUTE_READ || page_prot[k] == PAGE_EXECUTE_READWRITE)) - { - ok(broken(!ret), "VirtualProtect doesn't support PAGE_EXECUTE\n"); - continue; - } - /* Vista+ supports PAGE_EXECUTE_WRITECOPY, earlier versions don't */ - if (!ret && page_prot[k] == PAGE_EXECUTE_WRITECOPY) - { - ok(broken(!ret), "VirtualProtect doesn't support PAGE_EXECUTE_WRITECOPY\n"); - continue; - } - /* win2k and XP don't support PAGE_EXECUTE_WRITECOPY views properly */ - if (!ret && view[j].prot == PAGE_EXECUTE_WRITECOPY) - { - ok(broken(!ret), "VirtualProtect doesn't support PAGE_EXECUTE_WRITECOPY view properly\n"); - continue; - } - ok(ret, "VirtualProtect error %d, map %#x, view %#x, requested prot %#x\n", GetLastError(), page_prot[i], view[j].prot, page_prot[k]); - ok(old_prot == prev_prot, "got %#x, expected %#x\n", old_prot, prev_prot); - prev_prot = page_prot[k]; + todo_wine_if(readonly && page_prot[k] == PAGE_WRITECOPY && view[j].prot != PAGE_WRITECOPY) + ok(ret, "VirtualProtect error %ld, map %#lx, view %#lx, requested prot %#lx\n", GetLastError(), page_prot[i], view[j].prot, page_prot[k]); + todo_wine_if(readonly && page_prot[k] == PAGE_WRITECOPY && view[j].prot != PAGE_WRITECOPY) + ok(old_prot == prev_prot, "got %#lx, expected %#lx\n", old_prot, prev_prot); + prev_prot = actual_prot; + + ret = VirtualQuery(base, &info, sizeof(info)); + ok(ret, "%ld: VirtualQuery failed %ld\n", j, GetLastError()); + todo_wine_if(readonly && page_prot[k] == PAGE_WRITECOPY && view[j].prot != PAGE_WRITECOPY) + ok(info.Protect == actual_prot, + "VirtualProtect wrong prot, map %#lx, view %#lx, requested prot %#lx got %#lx\n", + page_prot[i], view[j].prot, page_prot[k], info.Protect ); } else { - /* NT4 doesn't fail on incompatible map and view */ - if (ret) - { - ok(broken(ret), "VirtualProtect should fail, map %#x, view %#x, requested prot %#x\n", page_prot[i], view[j].prot, page_prot[k]); - skip("Incompatible map and view are not properly handled on this platform\n"); - break; /* NT4 won't pass remaining tests */ - } - - ok(!ret, "VirtualProtect should fail, map %#x, view %#x, requested prot %#x\n", page_prot[i], view[j].prot, page_prot[k]); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + ok(!ret, "VirtualProtect should fail, map %#lx, view %#lx, requested prot %#lx\n", page_prot[i], view[j].prot, page_prot[k]); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); } } - for (k = 0; k < sizeof(page_prot)/sizeof(page_prot[0]); k++) + for (k = 0; k < ARRAY_SIZE(page_prot); k++) { /*trace("map %#x, view %#x, requested prot %#x\n", page_prot[i], view[j].prot, page_prot[k]);*/ SetLastError(0xdeadbeef); ptr = VirtualAlloc(base, si.dwPageSize, MEM_COMMIT, page_prot[k]); - ok(!ptr, "VirtualAlloc(%02x) should fail\n", page_prot[k]); - /* FIXME: remove once Wine is fixed */ - todo_wine_if (page_prot[k] == PAGE_WRITECOPY || page_prot[k] == PAGE_EXECUTE_WRITECOPY) - ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + if (anon_mapping) + { + if (is_compatible_protection(view[j].prot, page_prot[k])) + { + ok(ptr != NULL, "VirtualAlloc error %lu, map %#lx, view %#lx, requested prot %#lx\n", + GetLastError(), page_prot[i], view[j].prot, page_prot[k]); + } + else + { + /* versions <= Vista accept all protections without checking */ + ok(!ptr || broken(ptr != NULL), + "VirtualAlloc should fail, map %#lx, view %#lx, requested prot %#lx\n", + page_prot[i], view[j].prot, page_prot[k]); + if (!ptr) ok( GetLastError() == ERROR_INVALID_PARAMETER, + "wrong error %lu\n", GetLastError()); + } + if (ptr) + { + ret = VirtualQuery(base, &info, sizeof(info)); + ok(ret, "%ld: VirtualQuery failed %ld\n", j, GetLastError()); + ok(info.Protect == page_prot[k] || + /* if the mapping doesn't have write access, + * broken versions silently switch to WRITECOPY */ + broken( info.Protect == map_prot_no_write(page_prot[k]) ), + "VirtualAlloc wrong prot, map %#lx, view %#lx, requested prot %#lx got %#lx\n", + page_prot[i], view[j].prot, page_prot[k], info.Protect ); + } + } + else + { + ok(!ptr, "VirtualAlloc(%02lx) should fail\n", page_prot[k]); + ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError()); + } } + if (!anon_mapping && is_compatible_protection(alloc_prot, PAGE_WRITECOPY)) + { + ret = VirtualProtect(base, sec_flags & SEC_IMAGE ? si.dwPageSize : 2*si.dwPageSize, PAGE_WRITECOPY, &old_prot); + todo_wine_if(readonly && view[j].prot != PAGE_WRITECOPY) + ok(ret, "VirtualProtect error %ld, map %#lx, view %#lx\n", GetLastError(), page_prot[i], view[j].prot); + if (ret) *(DWORD*)base = 0xdeadbeef; + ret = VirtualQuery(base, &info, sizeof(info)); + ok(ret, "%ld: VirtualQuery failed %ld\n", j, GetLastError()); + todo_wine + ok(info.Protect == PAGE_READWRITE, "VirtualProtect wrong prot, map %#lx, view %#lx got %#lx\n", + page_prot[i], view[j].prot, info.Protect ); + todo_wine_if (!(sec_flags & SEC_IMAGE)) + ok(info.RegionSize == si.dwPageSize, "wrong region size %#Ix after write, map %#lx, view %#lx got %#lx\n", + info.RegionSize, page_prot[i], view[j].prot, info.Protect ); + + prev_prot = info.Protect; + alloc_prot = info.AllocationProtect; + + if (!(sec_flags & SEC_IMAGE)) + { + ret = VirtualQuery((char*)base + si.dwPageSize, &info, sizeof(info)); + ok(ret, "%ld: VirtualQuery failed %ld\n", j, GetLastError()); + todo_wine_if(readonly && view[j].prot != PAGE_WRITECOPY) + ok(info.Protect == PAGE_WRITECOPY, "wrong prot, map %#lx, view %#lx got %#lx\n", + page_prot[i], view[j].prot, info.Protect); + } + + for (k = 0; k < ARRAY_SIZE(page_prot); k++) + { + DWORD actual_prot = (sec_flags & SEC_IMAGE) ? map_prot_no_write(page_prot[k]) : page_prot[k]; + SetLastError(0xdeadbeef); + old_prot = 0xdeadbeef; + ret = VirtualProtect(base, si.dwPageSize, page_prot[k], &old_prot); + if (is_compatible_protection(alloc_prot, actual_prot)) + { + /* win2k and XP don't support EXEC on file mappings */ + if (!ret && (page_prot[k] == PAGE_EXECUTE || page_prot[k] == PAGE_EXECUTE_WRITECOPY || view[j].prot == PAGE_EXECUTE_WRITECOPY)) + { + ok(broken(!ret), "VirtualProtect doesn't support PAGE_EXECUTE\n"); + continue; + } + + todo_wine_if(readonly && page_prot[k] == PAGE_WRITECOPY && view[j].prot != PAGE_WRITECOPY) + ok(ret, "VirtualProtect error %ld, map %#lx, view %#lx, requested prot %#lx\n", GetLastError(), page_prot[i], view[j].prot, page_prot[k]); + todo_wine_if(readonly && page_prot[k] == PAGE_WRITECOPY && view[j].prot != PAGE_WRITECOPY) + ok(old_prot == prev_prot, "got %#lx, expected %#lx\n", old_prot, prev_prot); + + ret = VirtualQuery(base, &info, sizeof(info)); + ok(ret, "%ld: VirtualQuery failed %ld\n", j, GetLastError()); + todo_wine_if( map_prot_written( page_prot[k] ) != actual_prot ) + ok(info.Protect == map_prot_written( page_prot[k] ), + "VirtualProtect wrong prot, map %#lx, view %#lx, requested prot %#lx got %#lx\n", + page_prot[i], view[j].prot, page_prot[k], info.Protect ); + prev_prot = info.Protect; + } + else + { + ok(!ret, "VirtualProtect should fail, map %#lx, view %#lx, requested prot %#lx\n", page_prot[i], view[j].prot, page_prot[k]); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); + } + } + } UnmapViewOfFile(base); } CloseHandle(hmap); } +} - CloseHandle(hfile); - DeleteFileA(file_name); +static void test_mappings(void) +{ + char temp_path[MAX_PATH]; + char file_name[MAX_PATH]; + DWORD data, num_bytes; + HANDLE hfile; + + GetTempPathA(MAX_PATH, temp_path); + GetTempFileNameA(temp_path, "map", 0, file_name); + + hfile = CreateFileA(file_name, GENERIC_READ|GENERIC_WRITE|GENERIC_EXECUTE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(hfile != INVALID_HANDLE_VALUE, "CreateFile(%s) error %ld\n", file_name, GetLastError()); + SetFilePointer(hfile, 2*si.dwPageSize, NULL, FILE_BEGIN); + SetEndOfFile(hfile); + + test_mapping( hfile, SEC_COMMIT, FALSE ); + + /* test that file was not modified */ + SetFilePointer(hfile, 0, NULL, FILE_BEGIN); + ok(ReadFile(hfile, &data, sizeof(data), &num_bytes, NULL), "ReadFile failed\n"); + ok(num_bytes == sizeof(data), "num_bytes = %ld\n", num_bytes); + todo_wine + ok(!data, "data = %lx\n", data); + + CloseHandle( hfile ); + + hfile = CreateFileA(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); + ok(hfile != INVALID_HANDLE_VALUE, "CreateFile(%s) error %ld\n", file_name, GetLastError()); + + test_mapping( hfile, SEC_COMMIT, TRUE ); + + CloseHandle( hfile ); + DeleteFileA( file_name ); + + /* SEC_IMAGE mapping */ + GetSystemDirectoryA( file_name, MAX_PATH ); + strcat( file_name, "\\kernel32.dll" ); + + hfile = CreateFileA( file_name, GENERIC_READ|GENERIC_EXECUTE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); + ok(hfile != INVALID_HANDLE_VALUE, "CreateFile(%s) error %ld\n", file_name, GetLastError()); + + test_mapping( hfile, SEC_IMAGE, FALSE ); + + CloseHandle( hfile ); + + /* now anonymous mappings */ + test_mapping( INVALID_HANDLE_VALUE, SEC_COMMIT, FALSE ); } static void test_shared_memory(BOOL is_child) @@ -3797,17 +4305,17 @@ static void test_shared_memory(BOOL is_child) SetLastError(0xdeadbef); mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "winetest_virtual.c"); - ok(mapping != 0, "CreateFileMapping error %d\n", GetLastError()); + ok(mapping != 0, "CreateFileMapping error %ld\n", GetLastError()); if (is_child) - ok(GetLastError() == ERROR_ALREADY_EXISTS, "expected ERROR_ALREADY_EXISTS, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_ALREADY_EXISTS, "expected ERROR_ALREADY_EXISTS, got %ld\n", GetLastError()); SetLastError(0xdeadbef); p = MapViewOfFile(mapping, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, 4096); - ok(p != NULL, "MapViewOfFile error %d\n", GetLastError()); + ok(p != NULL, "MapViewOfFile error %ld\n", GetLastError()); if (is_child) { - ok(*p == 0x1a2b3c4d, "expected 0x1a2b3c4d in child, got %#x\n", *p); + ok(*p == 0x1a2b3c4d, "expected 0x1a2b3c4d in child, got %#lx\n", *p); } else { @@ -3822,8 +4330,8 @@ static void test_shared_memory(BOOL is_child) winetest_get_mainargs(&argv); sprintf(cmdline, "\"%s\" virtual sharedmem", argv[0]); ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); - ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError()); - winetest_wait_child_process(pi.hProcess); + ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError()); + wait_child_process(pi.hProcess); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } @@ -3839,13 +4347,13 @@ static void test_shared_memory_ro(BOOL is_child, DWORD child_access) SetLastError(0xdeadbef); mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "winetest_virtual.c_ro"); - ok(mapping != 0, "CreateFileMapping error %d\n", GetLastError()); + ok(mapping != 0, "CreateFileMapping error %ld\n", GetLastError()); if (is_child) - ok(GetLastError() == ERROR_ALREADY_EXISTS, "expected ERROR_ALREADY_EXISTS, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_ALREADY_EXISTS, "expected ERROR_ALREADY_EXISTS, got %ld\n", GetLastError()); SetLastError(0xdeadbef); p = MapViewOfFile(mapping, is_child ? child_access : FILE_MAP_READ, 0, 0, 4096); - ok(p != NULL, "MapViewOfFile error %d\n", GetLastError()); + ok(p != NULL, "MapViewOfFile error %ld\n", GetLastError()); if (is_child) { @@ -3860,248 +4368,111 @@ static void test_shared_memory_ro(BOOL is_child, DWORD child_access) DWORD ret; winetest_get_mainargs(&argv); - sprintf(cmdline, "\"%s\" virtual sharedmemro %x", argv[0], child_access); + sprintf(cmdline, "\"%s\" virtual sharedmemro %lx", argv[0], child_access); ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); - ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError()); - winetest_wait_child_process(pi.hProcess); + ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError()); + wait_child_process(pi.hProcess); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); if(child_access & FILE_MAP_WRITE) - ok(*p == 0xdeadbeef, "*p = %x, expected 0xdeadbeef\n", *p); + ok(*p == 0xdeadbeef, "*p = %lx, expected 0xdeadbeef\n", *p); else - ok(!*p, "*p = %x, expected 0\n", *p); + ok(!*p, "*p = %lx, expected 0\n", *p); } UnmapViewOfFile(p); CloseHandle(mapping); } -static void test_NtQuerySection(void) +static void test_PrefetchVirtualMemory(void) { - char path[MAX_PATH]; - HANDLE file, mapping; - void *p; - NTSTATUS status; - union - { - SECTION_BASIC_INFORMATION basic; - SECTION_IMAGE_INFORMATION image; - char buf[1024]; - } info; - IMAGE_NT_HEADERS *nt; - ULONG ret; - SIZE_T fsize, image_size; - SYSTEM_INFO si; +#ifdef __REACTOS__ + skip("Cannot build test_PrefetchVirtualMemory() until kernelbase is synced.\n"); +#else + WIN32_MEMORY_RANGE_ENTRY entries[2]; + char stackmem[] = "Test stack mem"; + static char testmem[] = "Test memory range data"; + unsigned int page_size = si.dwPageSize; + BOOL ret; - if (!pNtQuerySection) + if (!pPrefetchVirtualMemory) { - win_skip("NtQuerySection is not available\n"); + skip("no PrefetchVirtualMemory in kernelbase\n"); return; } - GetSystemInfo(&si); - page_mask = si.dwPageSize - 1; + ok( !pPrefetchVirtualMemory( GetCurrentProcess(), 0, NULL, 0 ), + "PrefetchVirtualMemory unexpected success on 0 entries\n" ); - GetSystemDirectoryA(path, sizeof(path)); - strcat(path, "\\kernel32.dll"); + entries[0].VirtualAddress = ULongToPtr(PtrToUlong(testmem) & -(ULONG_PTR)page_size); + entries[0].NumberOfBytes = page_size; + ret = pPrefetchVirtualMemory( GetCurrentProcess(), 1, entries, 0 ); + ok( ret || broken( is_wow64 && GetLastError() == ERROR_INVALID_PARAMETER ) /* win10 1507 */, + "PrefetchVirtualMemory unexpected status on 1 page-aligned entry: %ld\n", GetLastError() ); - SetLastError(0xdeadbef); - file = CreateFileA(path, GENERIC_READ|GENERIC_EXECUTE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); - ok(file != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError()); + entries[0].VirtualAddress = testmem; + entries[0].NumberOfBytes = sizeof(testmem); + ret = pPrefetchVirtualMemory( GetCurrentProcess(), 1, entries, 0 ); + ok( ret || broken( is_wow64 && GetLastError() == ERROR_INVALID_PARAMETER ) /* win10 1507 */, + "PrefetchVirtualMemory unexpected status on 1 entry: %ld\n", GetLastError() ); - fsize = GetFileSize(file, NULL); + entries[0].VirtualAddress = NULL; + entries[0].NumberOfBytes = page_size; + ret = pPrefetchVirtualMemory( GetCurrentProcess(), 1, entries, 0 ); + ok( ret ||broken( is_wow64 && GetLastError() == ERROR_INVALID_PARAMETER ) /* win10 1507 */, + "PrefetchVirtualMemory unexpected status on 1 unmapped entry: %ld\n", GetLastError() ); - SetLastError(0xdeadbef); - mapping = CreateFileMappingA(file, NULL, PAGE_EXECUTE_READ, 0, 0, NULL); - /* NT4 and win2k don't support EXEC on file mappings */ - if (!mapping) - mapping = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL); - ok(mapping != 0, "CreateFileMapping error %u\n", GetLastError()); + entries[0].VirtualAddress = ULongToPtr(PtrToUlong(testmem) & -(ULONG_PTR)page_size); + entries[0].NumberOfBytes = page_size; + entries[1].VirtualAddress = ULongToPtr(PtrToUlong(stackmem) & -(ULONG_PTR)page_size); + entries[1].NumberOfBytes = page_size; + ret = pPrefetchVirtualMemory( GetCurrentProcess(), 2, entries, 0 ); + ok( ret ||broken( is_wow64 && GetLastError() == ERROR_INVALID_PARAMETER ) /* win10 1507 */, + "PrefetchVirtualMemory unexpected status on 2 page-aligned entries: %ld\n", GetLastError() ); +#endif +} - status = pNtQuerySection(mapping, SectionBasicInformation, NULL, sizeof(info), &ret); - ok(status == STATUS_ACCESS_VIOLATION, "expected STATUS_ACCESS_VIOLATION, got %#x\n", status); +static void test_ReadProcessMemory(void) +{ + BYTE *buf; + DWORD old_prot; + SIZE_T copied; + HANDLE hproc; + void *ptr; + BOOL ret; - status = pNtQuerySection(mapping, SectionBasicInformation, &info, 0, NULL); - ok(status == STATUS_INFO_LENGTH_MISMATCH, "expected STATUS_INFO_LENGTH_MISMATCH, got %#x\n", status); + buf = malloc(2 * si.dwPageSize); + ok(buf != NULL, "OOM\n"); + ret = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), + &hproc, 0, FALSE, DUPLICATE_SAME_ACCESS); + ok(ret, "DuplicateHandle failed %lu\n", GetLastError()); + ptr = VirtualAlloc(NULL, 2 * si.dwPageSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + ok(ptr != NULL, "Virtual failed %lu\n", GetLastError()); + ret = VirtualProtect(((BYTE *)ptr) + si.dwPageSize, si.dwPageSize, PAGE_NOACCESS, &old_prot); + ok(ret, "VirtualProtect failed %lu\n", GetLastError()); - status = pNtQuerySection(mapping, SectionBasicInformation, &info, 0, &ret); - ok(status == STATUS_INFO_LENGTH_MISMATCH, "expected STATUS_INFO_LENGTH_MISMATCH, got %#x\n", status); + copied = 1; + ret = ReadProcessMemory(GetCurrentProcess(), ptr, buf, 2 * si.dwPageSize, &copied); + ok(!ret, "ReadProcessMemory succeeded\n"); + ok(!copied, "copied = %Id\n", copied); + ok(GetLastError() == ERROR_PARTIAL_COPY, "GetLastError() = %lu\n", GetLastError()); - memset(&info, 0x55, sizeof(info)); - ret = 0xdeadbeef; - status = pNtQuerySection(mapping, SectionBasicInformation, &info, sizeof(info), &ret); - ok(status == STATUS_SUCCESS, "NtQuerySection error %#x\n", status); - ok(ret == sizeof(info.basic), "wrong returned size %u\n", ret); - ok(info.basic.BaseAddress == NULL, "expected NULL, got %p\n", info.basic.BaseAddress); - ok(info.basic.Attributes == SEC_FILE, "expected SEC_FILE, got %#x\n", info.basic.Attributes); - ok(info.basic.Size.QuadPart == fsize, "expected %#lx, got %#x/%08x\n", fsize, info.basic.Size.HighPart, info.basic.Size.LowPart); + ret = ReadProcessMemory(GetCurrentProcess(), ptr, buf, si.dwPageSize, &copied); + ok(ret, "ReadProcessMemory failed %lu\n", GetLastError()); + ok(copied == si.dwPageSize, "copied = %Id\n", copied); - status = pNtQuerySection(mapping, SectionImageInformation, &info, sizeof(info.basic), &ret); - ok(status == STATUS_INFO_LENGTH_MISMATCH, "expected STATUS_INFO_LENGTH_MISMATCH, got %#x\n", status); + ret = ReadProcessMemory(hproc, ptr, buf, 2 * si.dwPageSize, &copied); + todo_wine ok(!ret, "ReadProcessMemory succeeded\n"); - status = pNtQuerySection(mapping, SectionImageInformation, &info, sizeof(info), &ret); - ok(status == STATUS_SECTION_NOT_IMAGE, "expected STATUS_SECTION_NOT_IMAGE, got %#x\n", status); + ret = ReadProcessMemory(hproc, ptr, buf, si.dwPageSize, &copied); + ok(ret, "ReadProcessMemory failed %lu\n", GetLastError()); + ok(copied == si.dwPageSize, "copied = %Id\n", copied); - SetLastError(0xdeadbef); - p = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0); - ok(p != NULL, "MapViewOfFile error %u\n", GetLastError()); - - nt = image_nt_header(p); - image_size = ROUND_SIZE(p, nt->OptionalHeader.SizeOfImage); - - memset(&info, 0x55, sizeof(info)); - ret = 0xdeadbeef; - status = pNtQuerySection(mapping, SectionBasicInformation, &info, sizeof(info), &ret); - ok(status == STATUS_SUCCESS, "NtQuerySection error %#x\n", status); - ok(ret == sizeof(info.basic), "wrong returned size %u\n", ret); - ok(info.basic.BaseAddress == NULL, "expected NULL, got %p\n", info.basic.BaseAddress); - ok(info.basic.Attributes == SEC_FILE, "expected SEC_FILE, got %#x\n", info.basic.Attributes); - ok(info.basic.Size.QuadPart == fsize, "expected %#lx, got %#x/%08x\n", fsize, info.basic.Size.HighPart, info.basic.Size.LowPart); - - UnmapViewOfFile(p); - CloseHandle(mapping); - - SetLastError(0xdeadbef); - mapping = CreateFileMappingA(file, NULL, PAGE_EXECUTE_READ|SEC_IMAGE, 0, 0, NULL); - /* NT4 and win2k don't support EXEC on file mappings */ - if (!mapping) - mapping = CreateFileMappingA(file, NULL, PAGE_READONLY|SEC_IMAGE, 0, 0, NULL); - ok(mapping != 0, "CreateFileMapping error %u\n", GetLastError()); - - memset(&info, 0x55, sizeof(info)); - ret = 0xdeadbeef; - status = pNtQuerySection(mapping, SectionBasicInformation, &info, sizeof(info), &ret); - ok(status == STATUS_SUCCESS, "NtQuerySection error %#x\n", status); - ok(ret == sizeof(info.basic), "wrong returned size %u\n", ret); - ok(info.basic.BaseAddress == NULL, "expected NULL, got %p\n", info.basic.BaseAddress); - ok(info.basic.Attributes == (SEC_FILE|SEC_IMAGE), "expected SEC_FILE|SEC_IMAGE, got %#x\n", info.basic.Attributes); - ok(info.basic.Size.QuadPart == image_size, "expected %#lx, got %#x/%08x\n", image_size, info.basic.Size.HighPart, info.basic.Size.LowPart); - - status = pNtQuerySection(mapping, SectionImageInformation, NULL, sizeof(info), &ret); - ok(status == STATUS_ACCESS_VIOLATION, "expected STATUS_ACCESS_VIOLATION, got %#x\n", status); - - status = pNtQuerySection(mapping, SectionImageInformation, &info, 0, NULL); - ok(status == STATUS_INFO_LENGTH_MISMATCH, "expected STATUS_INFO_LENGTH_MISMATCH, got %#x\n", status); - - status = pNtQuerySection(mapping, SectionImageInformation, &info, 0, &ret); - ok(status == STATUS_INFO_LENGTH_MISMATCH, "expected STATUS_INFO_LENGTH_MISMATCH, got %#x\n", status); - - status = pNtQuerySection(mapping, SectionImageInformation, &info, sizeof(info.basic), &ret); - ok(status == STATUS_INFO_LENGTH_MISMATCH, "expected STATUS_INFO_LENGTH_MISMATCH, got %#x\n", status); - - SetLastError(0xdeadbef); - p = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0); - ok(p != NULL, "MapViewOfFile error %u\n", GetLastError()); - - nt = image_nt_header(p); - - memset(&info, 0x55, sizeof(info)); - ret = 0xdeadbeef; - status = pNtQuerySection(mapping, SectionImageInformation, &info, sizeof(info), &ret); - ok(status == STATUS_SUCCESS, "NtQuerySection error %#x\n", status); - ok(ret == sizeof(info.image), "wrong returned size %u\n", ret); - ok((ULONG_PTR)info.image.TransferAddress == nt->OptionalHeader.ImageBase + nt->OptionalHeader.AddressOfEntryPoint, - "expected %#lx, got %p\n", (SIZE_T)(nt->OptionalHeader.ImageBase + nt->OptionalHeader.AddressOfEntryPoint), info.image.TransferAddress); - ok(info.image.ZeroBits == 0, "expected 0, got %#x\n", info.image.ZeroBits); - ok(info.image.MaximumStackSize == nt->OptionalHeader.SizeOfStackReserve, "expected %#lx, got %#lx\n", (SIZE_T)nt->OptionalHeader.SizeOfStackReserve, info.image.MaximumStackSize); - ok(info.image.CommittedStackSize == nt->OptionalHeader.SizeOfStackCommit, "expected %#lx, got %#lx\n", (SIZE_T)nt->OptionalHeader.SizeOfStackCommit, info.image.CommittedStackSize); - ok(info.image.SubSystemType == nt->OptionalHeader.Subsystem, "expected %#x, got %#x\n", nt->OptionalHeader.Subsystem, info.image.SubSystemType); - ok(info.image.MinorSubsystemVersion == nt->OptionalHeader.MinorSubsystemVersion, "expected %#x, got %#x\n", nt->OptionalHeader.MinorSubsystemVersion, info.image.MinorSubsystemVersion); - ok(info.image.MajorSubsystemVersion == nt->OptionalHeader.MajorSubsystemVersion, "expected %#x, got %#x\n", nt->OptionalHeader.MajorSubsystemVersion, info.image.MajorSubsystemVersion); - ok(info.image.ImageCharacteristics == nt->FileHeader.Characteristics, "expected %#x, got %#x\n", nt->FileHeader.Characteristics, info.image.ImageCharacteristics); - ok(info.image.DllCharacteristics == nt->OptionalHeader.DllCharacteristics, "expected %#x, got %#x\n", nt->OptionalHeader.DllCharacteristics, info.image.DllCharacteristics); - ok(info.image.Machine == nt->FileHeader.Machine, "expected %#x, got %#x\n", nt->FileHeader.Machine, info.image.Machine); -todo_wine - ok(info.image.ImageContainsCode == TRUE, "expected 1, got %#x\n", info.image.ImageContainsCode); - - memset(&info, 0x55, sizeof(info)); - ret = 0xdeadbeef; - status = pNtQuerySection(mapping, SectionBasicInformation, &info, sizeof(info), &ret); - ok(status == STATUS_SUCCESS, "NtQuerySection error %#x\n", status); - ok(ret == sizeof(info.basic), "wrong returned size %u\n", ret); - ok(info.basic.BaseAddress == NULL, "expected NULL, got %p\n", info.basic.BaseAddress); - ok(info.basic.Attributes == (SEC_FILE|SEC_IMAGE), "expected SEC_FILE|SEC_IMAGE, got %#x\n", info.basic.Attributes); - ok(info.basic.Size.QuadPart == image_size, "expected %#lx, got %#x/%08x\n", image_size, info.basic.Size.HighPart, info.basic.Size.LowPart); - - UnmapViewOfFile(p); - CloseHandle(mapping); - - SetLastError(0xdeadbef); - mapping = CreateFileMappingA(file, NULL, PAGE_READONLY|SEC_COMMIT|SEC_NOCACHE, 0, 0, NULL); - ok(mapping != 0, "CreateFileMapping error %u\n", GetLastError()); - - memset(&info, 0x55, sizeof(info)); - ret = 0xdeadbeef; - status = pNtQuerySection(mapping, SectionBasicInformation, &info, sizeof(info), &ret); - ok(status == STATUS_SUCCESS, "NtQuerySection error %#x\n", status); - ok(ret == sizeof(info.basic), "wrong returned size %u\n", ret); - ok(info.basic.BaseAddress == NULL, "expected NULL, got %p\n", info.basic.BaseAddress); -todo_wine - ok(info.basic.Attributes == SEC_FILE, "expected SEC_FILE, got %#x\n", info.basic.Attributes); - ok(info.basic.Size.QuadPart == fsize, "expected %#lx, got %#x/%08x\n", fsize, info.basic.Size.HighPart, info.basic.Size.LowPart); - - CloseHandle(mapping); - - SetLastError(0xdeadbef); - mapping = CreateFileMappingA(file, NULL, PAGE_READONLY|SEC_RESERVE, 0, 0, NULL); - ok(mapping != 0, "CreateFileMapping error %u\n", GetLastError()); - - memset(&info, 0x55, sizeof(info)); - ret = 0xdeadbeef; - status = pNtQuerySection(mapping, SectionBasicInformation, &info, sizeof(info), &ret); - ok(status == STATUS_SUCCESS, "NtQuerySection error %#x\n", status); - ok(ret == sizeof(info.basic), "wrong returned size %u\n", ret); - ok(info.basic.BaseAddress == NULL, "expected NULL, got %p\n", info.basic.BaseAddress); - ok(info.basic.Attributes == SEC_FILE, "expected SEC_FILE, got %#x\n", info.basic.Attributes); - ok(info.basic.Size.QuadPart == fsize, "expected %#lx, got %#x/%08x\n", fsize, info.basic.Size.HighPart, info.basic.Size.LowPart); - - CloseHandle(mapping); - CloseHandle(file); - - SetLastError(0xdeadbef); - mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE|SEC_COMMIT, 0, 4096, NULL); - ok(mapping != 0, "CreateFileMapping error %u\n", GetLastError()); - - memset(&info, 0x55, sizeof(info)); - ret = 0xdeadbeef; - status = pNtQuerySection(mapping, SectionBasicInformation, &info, sizeof(info), &ret); - ok(status == STATUS_SUCCESS, "NtQuerySection error %#x\n", status); - ok(ret == sizeof(info.basic), "wrong returned size %u\n", ret); - ok(info.basic.BaseAddress == NULL, "expected NULL, got %p\n", info.basic.BaseAddress); - ok(info.basic.Attributes == SEC_COMMIT, "expected SEC_COMMIT, got %#x\n", info.basic.Attributes); - ok(info.basic.Size.QuadPart == 4096, "expected 4096, got %#x/%08x\n", info.basic.Size.HighPart, info.basic.Size.LowPart); - - SetLastError(0xdeadbef); - p = MapViewOfFile(mapping, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, 0); - ok(p != NULL, "MapViewOfFile error %u\n", GetLastError()); - - memset(&info, 0x55, sizeof(info)); - ret = 0xdeadbeef; - status = pNtQuerySection(mapping, SectionBasicInformation, &info, sizeof(info), &ret); - ok(status == STATUS_SUCCESS, "NtQuerySection error %#x\n", status); - ok(ret == sizeof(info.basic), "wrong returned size %u\n", ret); - ok(info.basic.BaseAddress == NULL, "expected NULL, got %p\n", info.basic.BaseAddress); - ok(info.basic.Attributes == SEC_COMMIT, "expected SEC_COMMIT, got %#x\n", info.basic.Attributes); - ok(info.basic.Size.QuadPart == 4096, "expected 4096, got %#x/%08x\n", info.basic.Size.HighPart, info.basic.Size.LowPart); - - UnmapViewOfFile(p); - CloseHandle(mapping); - - SetLastError(0xdeadbef); - mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READONLY|SEC_RESERVE, 0, 4096, NULL); - ok(mapping != 0, "CreateFileMapping error %u\n", GetLastError()); - - memset(&info, 0x55, sizeof(info)); - ret = 0xdeadbeef; - status = pNtQuerySection(mapping, SectionBasicInformation, &info, sizeof(info), &ret); - ok(status == STATUS_SUCCESS, "NtQuerySection error %#x\n", status); - ok(ret == sizeof(info.basic), "wrong returned size %u\n", ret); - ok(info.basic.BaseAddress == NULL, "expected NULL, got %p\n", info.basic.BaseAddress); - ok(info.basic.Attributes == SEC_RESERVE, "expected SEC_RESERVE, got %#x\n", info.basic.Attributes); - ok(info.basic.Size.QuadPart == 4096, "expected 4096, got %#x/%08x\n", info.basic.Size.HighPart, info.basic.Size.LowPart); - - CloseHandle(mapping); + ret = VirtualFree(ptr, 0, MEM_RELEASE); + ok(ret, "VirtualFree failed %lu\n", GetLastError()); + CloseHandle(hproc); + free(buf); } START_TEST(virtual) @@ -4110,14 +4481,12 @@ START_TEST(virtual) char **argv; argc = winetest_get_mainargs( &argv ); -#if defined(__REACTOS__) && defined(_M_AMD64) - if (!winetest_interactive) - { - skip("ROSTESTS-369: Skipping kernel32_winetest:virtual because it crashes on Windows Server 2003 x64-Testbot. Set winetest_interactive to run it anyway.\n"); +#if defined(__REACTOS__) && defined(SKIPBADHEAP_K32_WINETEST) + if (is_reactos()) { + ok(FALSE, "FIXME: These tests are too rough on ReactOS heap manager on x64. It will eventually finish but it takes over an hour to complete the test suite with it which isn't acceptable.\n"); return; } #endif - if (argc >= 3) { if (!strcmp(argv[2], "sleep")) @@ -4141,20 +4510,19 @@ START_TEST(virtual) BOOL ret; mem = VirtualAlloc(NULL, 1<<20, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE); - ok(mem != NULL, "VirtualAlloc failed %u\n", GetLastError()); + ok(mem != NULL, "VirtualAlloc failed %lu\n", GetLastError()); if (mem == NULL) break; ret = VirtualFree(mem, 0, MEM_RELEASE); - ok(ret, "VirtualFree failed %u\n", GetLastError()); + ok(ret, "VirtualFree failed %lu\n", GetLastError()); if (!ret) break; } return; } hkernel32 = GetModuleHandleA("kernel32.dll"); + hkernelbase = GetModuleHandleA("kernelbase.dll"); hntdll = GetModuleHandleA("ntdll.dll"); - pVirtualAllocEx = (void *) GetProcAddress(hkernel32, "VirtualAllocEx"); - pVirtualFreeEx = (void *) GetProcAddress(hkernel32, "VirtualFreeEx"); pGetWriteWatch = (void *) GetProcAddress(hkernel32, "GetWriteWatch"); pResetWriteWatch = (void *) GetProcAddress(hkernel32, "ResetWriteWatch"); pGetProcessDEPPolicy = (void *)GetProcAddress( hkernel32, "GetProcessDEPPolicy" ); @@ -4167,28 +4535,36 @@ START_TEST(virtual) pRtlAddVectoredExceptionHandler = (void *)GetProcAddress( hntdll, "RtlAddVectoredExceptionHandler" ); pRtlRemoveVectoredExceptionHandler = (void *)GetProcAddress( hntdll, "RtlRemoveVectoredExceptionHandler" ); pNtProtectVirtualMemory = (void *)GetProcAddress( hntdll, "NtProtectVirtualMemory" ); - pNtAllocateVirtualMemory = (void *)GetProcAddress( hntdll, "NtAllocateVirtualMemory" ); - pNtFreeVirtualMemory = (void *)GetProcAddress( hntdll, "NtFreeVirtualMemory" ); + pNtReadVirtualMemory = (void *)GetProcAddress( hntdll, "NtReadVirtualMemory" ); + pNtWriteVirtualMemory = (void *)GetProcAddress( hntdll, "NtWriteVirtualMemory" ); +#ifndef __REACTOS__ // TODO: Enable when kernelbase is fixed. ROSTESTS-414 + pPrefetchVirtualMemory = (void *)GetProcAddress( hkernelbase, "PrefetchVirtualMemory" ); +#endif + + GetSystemInfo(&si); + trace("system page size %#lx\n", si.dwPageSize); + + if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE; test_shared_memory(FALSE); test_shared_memory_ro(FALSE, FILE_MAP_READ|FILE_MAP_WRITE); test_shared_memory_ro(FALSE, FILE_MAP_COPY); test_shared_memory_ro(FALSE, FILE_MAP_COPY|FILE_MAP_WRITE); - test_mapping(); - test_NtQuerySection(); + test_mappings(); test_CreateFileMapping_protection(); test_VirtualAlloc_protection(); test_VirtualProtect(); test_VirtualAllocEx(); test_VirtualAlloc(); test_MapViewOfFile(); - test_NtMapViewOfSection(); test_NtAreMappedFilesTheSame(); test_CreateFileMapping(); test_IsBadReadPtr(); test_IsBadWritePtr(); test_IsBadCodePtr(); test_write_watch(); + test_PrefetchVirtualMemory(); + test_ReadProcessMemory(); #if defined(__i386__) || defined(__x86_64__) test_stack_commit(); #endif diff --git a/modules/rostests/winetests/kernel32/volume.c b/modules/rostests/winetests/kernel32/volume.c index a7be321a04a..b9438ad1909 100644 --- a/modules/rostests/winetests/kernel32/volume.c +++ b/modules/rostests/winetests/kernel32/volume.c @@ -18,11 +18,17 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "wine/test.h" +#include +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" #include "winbase.h" #include "winioctl.h" -#include -#include "wine/ddk/ntddcdvd.h" +#include "ntddstor.h" +#include "winternl.h" +#include "ddk/ntddcdvd.h" +#include "ddk/mountmgr.h" +#include "wine/test.h" #include struct COMPLETE_DVD_LAYER_DESCRIPTOR @@ -45,18 +51,15 @@ struct COMPLETE_DVD_MANUFACTURER_DESCRIPTOR C_ASSERT(sizeof(struct COMPLETE_DVD_MANUFACTURER_DESCRIPTOR) == 2053); static HINSTANCE hdll; -static BOOL (WINAPI * pGetVolumeNameForVolumeMountPointA)(LPCSTR, LPSTR, DWORD); -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); -static BOOL (WINAPI *pGetVolumeInformationA)(LPCSTR, LPSTR, DWORD, LPDWORD, LPDWORD, LPDWORD, LPSTR, DWORD); -static BOOL (WINAPI *pGetVolumePathNameA)(LPCSTR, LPSTR, DWORD); -static BOOL (WINAPI *pGetVolumePathNameW)(LPWSTR, LPWSTR, DWORD); static BOOL (WINAPI *pGetVolumePathNamesForVolumeNameA)(LPCSTR, LPSTR, DWORD, LPDWORD); static BOOL (WINAPI *pGetVolumePathNamesForVolumeNameW)(LPCWSTR, LPWSTR, DWORD, LPDWORD); +static BOOL (WINAPI *pCreateSymbolicLinkA)(const char *, const char *, DWORD); +static BOOL (WINAPI *pGetVolumeInformationByHandleW)(HANDLE, WCHAR *, DWORD, DWORD *, DWORD *, DWORD *, WCHAR *, DWORD); /* ############################### */ @@ -71,20 +74,22 @@ static void test_query_dos_deviceA(void) SetLastError(0xdeadbeef); ret = QueryDosDeviceA( NULL, NULL, 0 ); ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "QueryDosDeviceA(no buffer): returned %u, le=%u\n", ret, GetLastError()); + "QueryDosDeviceA(no buffer): returned %lu, le=%lu\n", ret, GetLastError()); buffer = HeapAlloc( GetProcessHeap(), 0, buflen ); SetLastError(0xdeadbeef); ret = QueryDosDeviceA( NULL, buffer, buflen ); ok((ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER), - "QueryDosDeviceA failed to return list, last error %u\n", GetLastError()); + "QueryDosDeviceA failed to return list, last error %lu\n", GetLastError()); if (ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) { p = buffer; for (;;) { - if (!strlen(p)) break; + if (!*p) break; ret2 = QueryDosDeviceA( p, buffer2, sizeof(buffer2) ); - ok(ret2, "QueryDosDeviceA failed to return current mapping for %s, last error %u\n", p, GetLastError()); + /* Win10+ exposes the security device which requires extra privileges to be queried. So skip it */ + ok(ret2 || broken( !strcmp( p, "MSSECFLTSYS" ) && GetLastError() == ERROR_ACCESS_DENIED ), + "QueryDosDeviceA failed to return current mapping for %s, last error %lu\n", p, GetLastError()); p += strlen(p) + 1; if (ret <= (p-buffer)) break; } @@ -94,7 +99,7 @@ static void test_query_dos_deviceA(void) /* Older W2K fails with ERROR_INSUFFICIENT_BUFFER when buflen is > 32767 */ ret = QueryDosDeviceA( drivestr, buffer, buflen - 1); ok(ret || GetLastError() == ERROR_FILE_NOT_FOUND, - "QueryDosDeviceA failed to return current mapping for %s, last error %u\n", drivestr, GetLastError()); + "QueryDosDeviceA failed to return current mapping for %s, last error %lu\n", drivestr, GetLastError()); if(ret) { for (p = buffer; *p; p++) *p = toupper(*p); if (strstr(buffer, "HARDDISK") || strstr(buffer, "RAMDISK")) found = TRUE; @@ -104,11 +109,12 @@ static void test_query_dos_deviceA(void) HeapFree( GetProcessHeap(), 0, buffer ); } -static void test_define_dos_deviceA(void) +static void test_dos_devices(void) { + char buf[MAX_PATH], buf2[400]; char drivestr[3]; - char buf[MAX_PATH]; - DWORD ret; + HANDLE file; + BOOL ret; /* Find an unused drive letter */ drivestr[1] = ':'; @@ -122,20 +128,65 @@ static void test_define_dos_deviceA(void) return; } - /* Map it to point to the current directory */ - ret = GetCurrentDirectoryA(sizeof(buf), buf); - ok(ret, "GetCurrentDir\n"); + ret = DefineDosDeviceA( 0, drivestr, "C:/windows/" ); + ok(ret, "failed to define drive %s, error %lu\n", drivestr, GetLastError()); - ret = DefineDosDeviceA(0, drivestr, buf); - todo_wine - ok(ret, "Could not make drive %s point to %s!\n", drivestr, buf); + ret = QueryDosDeviceA( drivestr, buf, sizeof(buf) ); + ok(ret, "failed to query drive %s, error %lu\n", drivestr, GetLastError()); + ok(!strcmp(buf, "\\??\\C:\\windows\\"), "got path %s\n", debugstr_a(buf)); - if (!ret) { - skip("can't test removing fake drive\n"); - } else { - ret = DefineDosDeviceA(DDD_REMOVE_DEFINITION, drivestr, NULL); - ok(ret, "Could not remove fake drive %s!\n", drivestr); - } + sprintf(buf, "%s/system32", drivestr); + file = CreateFileA( buf, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL ); + todo_wine ok(file != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError()); + CloseHandle( file ); + + /* but it's not a volume mount point */ + + sprintf(buf, "%s\\", drivestr); + ret = GetVolumeNameForVolumeMountPointA( buf, buf2, sizeof(buf2) ); + ok(!ret, "expected failure\n"); + todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError()); + + ret = DefineDosDeviceA(DDD_REMOVE_DEFINITION, drivestr, NULL); + ok(ret, "failed to remove drive %s, error %lu\n", drivestr, GetLastError()); + + ret = QueryDosDeviceA( drivestr, buf, sizeof(buf) ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "got error %lu\n", GetLastError()); + + sprintf(buf, "%s/system32", drivestr); + file = CreateFileA( buf, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL ); + ok(file == INVALID_HANDLE_VALUE, "expected failure\n"); + todo_wine ok(GetLastError() == ERROR_PATH_NOT_FOUND, "got error %lu\n", GetLastError()); + + /* try with DDD_RAW_TARGET_PATH */ + + ret = DefineDosDeviceA( DDD_RAW_TARGET_PATH, drivestr, "\\??\\C:\\windows\\" ); + ok(ret, "failed to define drive %s, error %lu\n", drivestr, GetLastError()); + + ret = QueryDosDeviceA( drivestr, buf, sizeof(buf) ); + ok(ret, "failed to query drive %s, error %lu\n", drivestr, GetLastError()); + ok(!strcmp(buf, "\\??\\C:\\windows\\"), "got path %s\n", debugstr_a(buf)); + + sprintf(buf, "%s/system32", drivestr); + file = CreateFileA( buf, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL ); + todo_wine ok(file != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError()); + CloseHandle( file ); + + sprintf(buf, "%s\\", drivestr); + ret = GetVolumeNameForVolumeMountPointA( buf, buf2, sizeof(buf2) ); + ok(!ret, "expected failure\n"); + todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError()); + + ret = DefineDosDeviceA(DDD_REMOVE_DEFINITION, drivestr, NULL); + ok(ret, "failed to remove drive %s, error %lu\n", drivestr, GetLastError()); + + ret = QueryDosDeviceA( drivestr, buf, sizeof(buf) ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "got error %lu\n", GetLastError()); } static void test_FindFirstVolume(void) @@ -153,12 +204,12 @@ static void test_FindFirstVolume(void) ok( handle == INVALID_HANDLE_VALUE, "succeeded with short buffer\n" ); ok( GetLastError() == ERROR_MORE_DATA || /* XP */ GetLastError() == ERROR_FILENAME_EXCED_RANGE, /* Vista */ - "wrong error %u\n", GetLastError() ); + "wrong error %lu\n", GetLastError() ); handle = pFindFirstVolumeA( volume, 49 ); ok( handle == INVALID_HANDLE_VALUE, "succeeded with short buffer\n" ); - ok( GetLastError() == ERROR_FILENAME_EXCED_RANGE, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_FILENAME_EXCED_RANGE, "wrong error %lu\n", GetLastError() ); handle = pFindFirstVolumeA( volume, 51 ); - ok( handle != INVALID_HANDLE_VALUE, "failed err %u\n", GetLastError() ); + ok( handle != INVALID_HANDLE_VALUE, "failed err %lu\n", GetLastError() ); if (handle != INVALID_HANDLE_VALUE) { do @@ -167,7 +218,7 @@ static void test_FindFirstVolume(void) ok( !memcmp( volume, "\\\\?\\Volume{", 11 ), "bad volume name %s\n", volume ); ok( !memcmp( volume + 47, "}\\", 2 ), "bad volume name %s\n", volume ); } while (pFindNextVolumeA( handle, volume, MAX_PATH )); - ok( GetLastError() == ERROR_NO_MORE_FILES, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_NO_MORE_FILES, "wrong error %lu\n", GetLastError() ); pFindVolumeClose( handle ); } } @@ -179,49 +230,43 @@ static void test_GetVolumeNameForVolumeMountPointA(void) DWORD len = sizeof(volume), reti; char temp_path[MAX_PATH]; - /* not present before w2k */ - if (!pGetVolumeNameForVolumeMountPointA) { - win_skip("GetVolumeNameForVolumeMountPointA not found\n"); - return; - } - reti = GetTempPathA(MAX_PATH, temp_path); - ok(reti != 0, "GetTempPathA error %d\n", GetLastError()); + ok(reti != 0, "GetTempPathA error %ld\n", GetLastError()); ok(reti < MAX_PATH, "temp path should fit into MAX_PATH\n"); - ret = pGetVolumeNameForVolumeMountPointA(path, volume, 0); + ret = GetVolumeNameForVolumeMountPointA(path, volume, 0); ok(ret == FALSE, "GetVolumeNameForVolumeMountPointA succeeded\n"); ok(GetLastError() == ERROR_FILENAME_EXCED_RANGE || GetLastError() == ERROR_INVALID_PARAMETER, /* Vista */ - "wrong error, last=%d\n", GetLastError()); + "wrong error, last=%ld\n", GetLastError()); if (0) { /* these crash on XP */ - ret = pGetVolumeNameForVolumeMountPointA(path, NULL, len); + ret = GetVolumeNameForVolumeMountPointA(path, NULL, len); ok(ret == FALSE, "GetVolumeNameForVolumeMountPointA succeeded\n"); - ret = pGetVolumeNameForVolumeMountPointA(NULL, volume, len); + ret = GetVolumeNameForVolumeMountPointA(NULL, volume, len); ok(ret == FALSE, "GetVolumeNameForVolumeMountPointA succeeded\n"); } - ret = pGetVolumeNameForVolumeMountPointA(path, volume, len); + ret = GetVolumeNameForVolumeMountPointA(path, volume, len); ok(ret == TRUE, "GetVolumeNameForVolumeMountPointA failed\n"); ok(!strncmp( volume, "\\\\?\\Volume{", 11), "GetVolumeNameForVolumeMountPointA failed to return valid string <%s>\n", volume); /* test with too small buffer */ - ret = pGetVolumeNameForVolumeMountPointA(path, volume, 10); + ret = GetVolumeNameForVolumeMountPointA(path, volume, 10); ok(ret == FALSE && GetLastError() == ERROR_FILENAME_EXCED_RANGE, - "GetVolumeNameForVolumeMountPointA failed, wrong error returned, was %d, should be ERROR_FILENAME_EXCED_RANGE\n", + "GetVolumeNameForVolumeMountPointA failed, wrong error returned, was %ld, should be ERROR_FILENAME_EXCED_RANGE\n", GetLastError()); /* Try on an arbitrary directory */ /* On FAT filesystems it seems that GetLastError() is set to ERROR_INVALID_FUNCTION. */ - ret = pGetVolumeNameForVolumeMountPointA(temp_path, volume, len); + ret = GetVolumeNameForVolumeMountPointA(temp_path, volume, len); ok(ret == FALSE && (GetLastError() == ERROR_NOT_A_REPARSE_POINT || GetLastError() == ERROR_INVALID_FUNCTION), - "GetVolumeNameForVolumeMountPointA failed on %s, last=%d\n", + "GetVolumeNameForVolumeMountPointA failed on %s, last=%ld\n", temp_path, GetLastError()); /* Try on a nonexistent dos drive */ @@ -233,16 +278,16 @@ static void test_GetVolumeNameForVolumeMountPointA(void) if (path[0] <= 'z') { path[2] = '\\'; - ret = pGetVolumeNameForVolumeMountPointA(path, volume, len); + ret = GetVolumeNameForVolumeMountPointA(path, volume, len); ok(ret == FALSE && GetLastError() == ERROR_FILE_NOT_FOUND, - "GetVolumeNameForVolumeMountPointA failed on %s, last=%d\n", + "GetVolumeNameForVolumeMountPointA failed on %s, last=%ld\n", path, GetLastError()); /* Try without trailing \ and on a nonexistent dos drive */ path[2] = 0; - ret = pGetVolumeNameForVolumeMountPointA(path, volume, len); + ret = GetVolumeNameForVolumeMountPointA(path, volume, len); ok(ret == FALSE && GetLastError() == ERROR_INVALID_NAME, - "GetVolumeNameForVolumeMountPointA failed on %s, last=%d\n", + "GetVolumeNameForVolumeMountPointA failed on %s, last=%ld\n", path, GetLastError()); } } @@ -251,29 +296,23 @@ static void test_GetVolumeNameForVolumeMountPointW(void) { BOOL ret; WCHAR volume[MAX_PATH], path[] = {'c',':','\\',0}; - DWORD len = sizeof(volume) / sizeof(WCHAR); + DWORD len = ARRAY_SIZE(volume); - /* not present before w2k */ - if (!pGetVolumeNameForVolumeMountPointW) { - win_skip("GetVolumeNameForVolumeMountPointW not found\n"); - return; - } - - ret = pGetVolumeNameForVolumeMountPointW(path, volume, 0); + ret = GetVolumeNameForVolumeMountPointW(path, volume, 0); ok(ret == FALSE, "GetVolumeNameForVolumeMountPointW succeeded\n"); ok(GetLastError() == ERROR_FILENAME_EXCED_RANGE || GetLastError() == ERROR_INVALID_PARAMETER, /* Vista */ - "wrong error, last=%d\n", GetLastError()); + "wrong error, last=%ld\n", GetLastError()); if (0) { /* these crash on XP */ - ret = pGetVolumeNameForVolumeMountPointW(path, NULL, len); + ret = GetVolumeNameForVolumeMountPointW(path, NULL, len); ok(ret == FALSE, "GetVolumeNameForVolumeMountPointW succeeded\n"); - ret = pGetVolumeNameForVolumeMountPointW(NULL, volume, len); + ret = GetVolumeNameForVolumeMountPointW(NULL, volume, len); ok(ret == FALSE, "GetVolumeNameForVolumeMountPointW succeeded\n"); } - ret = pGetVolumeNameForVolumeMountPointW(path, volume, len); + ret = GetVolumeNameForVolumeMountPointW(path, volume, len); ok(ret == TRUE, "GetVolumeNameForVolumeMountPointW failed\n"); } @@ -363,42 +402,37 @@ static void test_GetVolumeInformationA(void) char windowsdir[MAX_PATH+10]; char currentdir[MAX_PATH+1]; - ok( pGetVolumeInformationA != NULL, "GetVolumeInformationA not found\n"); - if(!pGetVolumeInformationA) { - return; - } - /* get windows drive letter and update strings for testing */ result = GetWindowsDirectoryA(windowsdir, sizeof(windowsdir)); ok(result < sizeof(windowsdir), "windowsdir is abnormally long!\n"); - ok(result != 0, "GetWindowsDirectory: error %d\n", GetLastError()); + ok(result != 0, "GetWindowsDirectory: error %ld\n", GetLastError()); Root_Colon[0] = windowsdir[0]; Root_Slash[0] = windowsdir[0]; Root_UNC[4] = windowsdir[0]; result = GetCurrentDirectoryA(MAX_PATH, currentdir); - ok(result, "GetCurrentDirectory: error %d\n", GetLastError()); + ok(result, "GetCurrentDirectory: error %ld\n", GetLastError()); /* Note that GetCurrentDir yields no trailing slash for subdirs */ /* check for NO error on no trailing \ when current dir is root dir */ ret = SetCurrentDirectoryA(Root_Slash); - ok(ret, "SetCurrentDirectory: error %d\n", GetLastError()); - ret = pGetVolumeInformationA(Root_Colon, vol_name_buf, vol_name_size, NULL, + ok(ret, "SetCurrentDirectory: error %ld\n", GetLastError()); + ret = GetVolumeInformationA(Root_Colon, vol_name_buf, vol_name_size, NULL, NULL, NULL, fs_name_buf, fs_name_len); - ok(ret, "GetVolumeInformationA root failed, last error %u\n", GetLastError()); + ok(ret, "GetVolumeInformationA root failed, last error %lu\n", GetLastError()); /* check for error on no trailing \ when current dir is subdir (windows) of queried drive */ ret = SetCurrentDirectoryA(windowsdir); - ok(ret, "SetCurrentDirectory: error %d\n", GetLastError()); + ok(ret, "SetCurrentDirectory: error %ld\n", GetLastError()); SetLastError(0xdeadbeef); - ret = pGetVolumeInformationA(Root_Colon, vol_name_buf, vol_name_size, NULL, + ret = GetVolumeInformationA(Root_Colon, vol_name_buf, vol_name_size, NULL, NULL, NULL, fs_name_buf, fs_name_len); ok(!ret && (GetLastError() == ERROR_INVALID_NAME), - "GetVolumeInformationA did%s fail, last error %u\n", ret ? " not":"", GetLastError()); + "GetVolumeInformationA did%s fail, last error %lu\n", ret ? " not":"", GetLastError()); /* reset current directory */ ret = SetCurrentDirectoryA(currentdir); - ok(ret, "SetCurrentDirectory: error %d\n", GetLastError()); + ok(ret, "SetCurrentDirectory: error %ld\n", GetLastError()); if (toupper(currentdir[0]) == toupper(windowsdir[0])) { skip("Please re-run from another device than %c:\n", windowsdir[0]); @@ -413,106 +447,102 @@ static void test_GetVolumeInformationA(void) ok(ret, "SetEnvironmentVariable %s failed\n", Root_Env); ret = SetCurrentDirectoryA(windowsdir); - ok(ret, "SetCurrentDirectory: error %d\n", GetLastError()); + ok(ret, "SetCurrentDirectory: error %ld\n", GetLastError()); ret = SetCurrentDirectoryA(currentdir); - ok(ret, "SetCurrentDirectory: error %d\n", GetLastError()); + ok(ret, "SetCurrentDirectory: error %ld\n", GetLastError()); /* windows dir is current on the root drive, call fails */ SetLastError(0xdeadbeef); - ret = pGetVolumeInformationA(Root_Colon, vol_name_buf, vol_name_size, NULL, + ret = GetVolumeInformationA(Root_Colon, vol_name_buf, vol_name_size, NULL, NULL, NULL, fs_name_buf, fs_name_len); ok(!ret && (GetLastError() == ERROR_INVALID_NAME), - "GetVolumeInformationA did%s fail, last error %u\n", ret ? " not":"", GetLastError()); + "GetVolumeInformationA did%s fail, last error %lu\n", ret ? " not":"", GetLastError()); /* Try normal drive letter with trailing \ */ - ret = pGetVolumeInformationA(Root_Slash, vol_name_buf, vol_name_size, NULL, + ret = GetVolumeInformationA(Root_Slash, vol_name_buf, vol_name_size, NULL, NULL, NULL, fs_name_buf, fs_name_len); - ok(ret, "GetVolumeInformationA with \\ failed, last error %u\n", GetLastError()); + ok(ret, "GetVolumeInformationA with \\ failed, last error %lu\n", GetLastError()); ret = SetCurrentDirectoryA(Root_Slash); - ok(ret, "SetCurrentDirectory: error %d\n", GetLastError()); + ok(ret, "SetCurrentDirectory: error %ld\n", GetLastError()); ret = SetCurrentDirectoryA(currentdir); - ok(ret, "SetCurrentDirectory: error %d\n", GetLastError()); + ok(ret, "SetCurrentDirectory: error %ld\n", GetLastError()); /* windows dir is STILL CURRENT on root drive; the call fails as before, */ /* proving that SetCurrentDir did not remember the other drive's directory */ SetLastError(0xdeadbeef); - ret = pGetVolumeInformationA(Root_Colon, vol_name_buf, vol_name_size, NULL, + ret = GetVolumeInformationA(Root_Colon, vol_name_buf, vol_name_size, NULL, NULL, NULL, fs_name_buf, fs_name_len); ok(!ret && (GetLastError() == ERROR_INVALID_NAME), - "GetVolumeInformationA did%s fail, last error %u\n", ret ? " not":"", GetLastError()); + "GetVolumeInformationA did%s fail, last error %lu\n", ret ? " not":"", GetLastError()); /* Now C:\ becomes the current directory on drive C: */ ret = SetEnvironmentVariableA(Root_Env, Root_Slash); /* set =C:=C:\ */ ok(ret, "SetEnvironmentVariable %s failed\n", Root_Env); /* \ is current on root drive, call succeeds */ - ret = pGetVolumeInformationA(Root_Colon, vol_name_buf, vol_name_size, NULL, + ret = GetVolumeInformationA(Root_Colon, vol_name_buf, vol_name_size, NULL, NULL, NULL, fs_name_buf, fs_name_len); - ok(ret, "GetVolumeInformationA failed, last error %u\n", GetLastError()); + ok(ret, "GetVolumeInformationA failed, last error %lu\n", GetLastError()); /* again, SetCurrentDirectory on another drive does not matter */ ret = SetCurrentDirectoryA(Root_Slash); - ok(ret, "SetCurrentDirectory: error %d\n", GetLastError()); + ok(ret, "SetCurrentDirectory: error %ld\n", GetLastError()); ret = SetCurrentDirectoryA(currentdir); - ok(ret, "SetCurrentDirectory: error %d\n", GetLastError()); + ok(ret, "SetCurrentDirectory: error %ld\n", GetLastError()); /* \ is current on root drive, call succeeds */ - ret = pGetVolumeInformationA(Root_Colon, vol_name_buf, vol_name_size, NULL, + ret = GetVolumeInformationA(Root_Colon, vol_name_buf, vol_name_size, NULL, NULL, NULL, fs_name_buf, fs_name_len); - ok(ret, "GetVolumeInformationA failed, last error %u\n", GetLastError()); + ok(ret, "GetVolumeInformationA failed, last error %lu\n", GetLastError()); } /* try null root directory to return "root of the current directory" */ - ret = pGetVolumeInformationA(NULL, vol_name_buf, vol_name_size, NULL, + ret = GetVolumeInformationA(NULL, vol_name_buf, vol_name_size, NULL, NULL, NULL, fs_name_buf, fs_name_len); - ok(ret, "GetVolumeInformationA failed on null root dir, last error %u\n", GetLastError()); + ok(ret, "GetVolumeInformationA failed on null root dir, last error %lu\n", GetLastError()); /* Try normal drive letter with trailing \ */ - ret = pGetVolumeInformationA(Root_Slash, vol_name_buf, vol_name_size, + ret = GetVolumeInformationA(Root_Slash, vol_name_buf, vol_name_size, &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len); - ok(ret, "GetVolumeInformationA failed, root=%s, last error=%u\n", Root_Slash, GetLastError()); + ok(ret, "GetVolumeInformationA failed, root=%s, last error=%lu\n", Root_Slash, GetLastError()); /* try again with drive letter and the "disable parsing" prefix */ SetLastError(0xdeadbeef); - ret = pGetVolumeInformationA(Root_UNC, vol_name_buf, vol_name_size, + ret = GetVolumeInformationA(Root_UNC, vol_name_buf, vol_name_size, &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len); - ok(ret, "GetVolumeInformationA did%s fail, root=%s, last error=%u\n", ret ? " not":"", Root_UNC, GetLastError()); + ok(ret, "GetVolumeInformationA did%s fail, root=%s, last error=%lu\n", ret ? " not":"", Root_UNC, GetLastError()); /* try again with device name space */ Root_UNC[2] = '.'; SetLastError(0xdeadbeef); - ret = pGetVolumeInformationA(Root_UNC, vol_name_buf, vol_name_size, + ret = GetVolumeInformationA(Root_UNC, vol_name_buf, vol_name_size, &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len); - ok(ret, "GetVolumeInformationA did%s fail, root=%s, last error=%u\n", ret ? " not":"", Root_UNC, GetLastError()); + ok(ret, "GetVolumeInformationA did%s fail, root=%s, last error=%lu\n", ret ? " not":"", Root_UNC, GetLastError()); /* try again with a directory off the root - should generate error */ if (windowsdir[strlen(windowsdir)-1] != '\\') strcat(windowsdir, "\\"); SetLastError(0xdeadbeef); - ret = pGetVolumeInformationA(windowsdir, vol_name_buf, vol_name_size, + ret = GetVolumeInformationA(windowsdir, vol_name_buf, vol_name_size, &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len); ok(!ret && (GetLastError()==ERROR_DIR_NOT_ROOT), - "GetVolumeInformationA did%s fail, root=%s, last error=%u\n", ret ? " not":"", windowsdir, GetLastError()); + "GetVolumeInformationA did%s fail, root=%s, last error=%lu\n", ret ? " not":"", windowsdir, GetLastError()); /* A subdir with trailing \ yields DIR_NOT_ROOT instead of INVALID_NAME */ if (windowsdir[strlen(windowsdir)-1] == '\\') windowsdir[strlen(windowsdir)-1] = 0; SetLastError(0xdeadbeef); - ret = pGetVolumeInformationA(windowsdir, vol_name_buf, vol_name_size, + ret = GetVolumeInformationA(windowsdir, vol_name_buf, vol_name_size, &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len); ok(!ret && (GetLastError()==ERROR_INVALID_NAME), - "GetVolumeInformationA did%s fail, root=%s, last error=%u\n", ret ? " not":"", windowsdir, GetLastError()); + "GetVolumeInformationA did%s fail, root=%s, last error=%lu\n", ret ? " not":"", windowsdir, GetLastError()); - if (!pGetVolumeNameForVolumeMountPointA) { - win_skip("GetVolumeNameForVolumeMountPointA not found\n"); - return; - } /* get the unique volume name for the windows drive */ - ret = pGetVolumeNameForVolumeMountPointA(Root_Slash, volume, MAX_PATH); + ret = GetVolumeNameForVolumeMountPointA(Root_Slash, volume, MAX_PATH); ok(ret == TRUE, "GetVolumeNameForVolumeMountPointA failed\n"); /* try again with unique volume name */ - ret = pGetVolumeInformationA(volume, vol_name_buf, vol_name_size, + ret = GetVolumeInformationA(volume, vol_name_buf, vol_name_size, &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len); - ok(ret, "GetVolumeInformationA failed, root=%s, last error=%u\n", volume, GetLastError()); + ok(ret, "GetVolumeInformationA failed, root=%s, last error=%lu\n", volume, GetLastError()); } /* Test to check that unique volume name from windows dir mount point */ @@ -528,28 +558,22 @@ static void test_enum_vols(void) BOOL found = FALSE; char windowsdir[MAX_PATH]; - if (!pGetVolumeNameForVolumeMountPointA) { - win_skip("GetVolumeNameForVolumeMountPointA not found\n"); - return; - } - /*get windows drive letter and update strings for testing */ ret = GetWindowsDirectoryA( windowsdir, sizeof(windowsdir) ); ok(ret < sizeof(windowsdir), "windowsdir is abnormally long!\n"); - ok(ret != 0, "GetWindowsDirectory: error %d\n", GetLastError()); + ok(ret != 0, "GetWindowsDirectory: error %ld\n", GetLastError()); path[0] = windowsdir[0]; /* get the unique volume name for the windows drive */ - ret = pGetVolumeNameForVolumeMountPointA( path, Volume_1, MAX_PATH ); + ret = GetVolumeNameForVolumeMountPointA( path, Volume_1, MAX_PATH ); ok(ret == TRUE, "GetVolumeNameForVolumeMountPointA failed\n"); ok(strlen(Volume_1) == 49, "GetVolumeNameForVolumeMountPointA returned wrong length name %s\n", Volume_1); /* get first unique volume name of list */ hFind = pFindFirstVolumeA( Volume_2, MAX_PATH ); - ok(hFind != INVALID_HANDLE_VALUE, "FindFirstVolume failed, err=%u\n", + ok(hFind != INVALID_HANDLE_VALUE, "FindFirstVolume failed, err=%lu\n", GetLastError()); - /* ReactOS */ - if (hFind != INVALID_HANDLE_VALUE) { + do { /* validate correct length of unique volume name */ @@ -562,7 +586,6 @@ static void test_enum_vols(void) } while (pFindNextVolumeA( hFind, Volume_2, MAX_PATH )); ok(found, "volume name %s not found by Find[First/Next]Volume\n", Volume_1); pFindVolumeClose( hFind ); - } } static void test_disk_extents(void) @@ -575,7 +598,7 @@ static void test_disk_extents(void) handle = CreateFileA( "\\\\.\\c:", GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 ); if (handle == INVALID_HANDLE_VALUE) { - win_skip("can't open c: drive %u\n", GetLastError()); + win_skip("can't open c: drive %lu\n", GetLastError()); return; } size = 0; @@ -587,14 +610,99 @@ static void test_disk_extents(void) CloseHandle( handle ); return; } - ok(ret, "DeviceIoControl failed %u\n", GetLastError()); - ok(size == 32, "expected 32, got %u\n", size); + ok(ret, "DeviceIoControl failed %lu\n", GetLastError()); + ok(size == 32, "expected 32, got %lu\n", size); CloseHandle( handle ); } +static void test_disk_query_property(void) +{ + STORAGE_PROPERTY_QUERY query = {0}; + STORAGE_DESCRIPTOR_HEADER header = {0}; + STORAGE_DEVICE_DESCRIPTOR descriptor = {0}; + DEVICE_SEEK_PENALTY_DESCRIPTOR seek_pen = {0}; + HANDLE handle; + DWORD error; + DWORD size; + BOOL ret; + + handle = CreateFileA("\\\\.\\PhysicalDrive0", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + 0, 0); + if (handle == INVALID_HANDLE_VALUE) + { + win_skip("can't open \\\\.\\PhysicalDrive0 %#lx\n", GetLastError()); + return; + } + + query.PropertyId = StorageDeviceProperty; + query.QueryType = PropertyStandardQuery; + + SetLastError(0xdeadbeef); + ret = DeviceIoControl(handle, IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(query), &header, sizeof(header), &size, + NULL); + error = GetLastError(); + ok(ret, "expect ret %#x, got %#x\n", TRUE, ret); + ok(error == 0xdeadbeef, "expect err %#x, got err %#lx\n", 0xdeadbeef, error); + ok(size == sizeof(header), "got size %ld\n", size); + ok(header.Version == sizeof(descriptor), "got header.Version %ld\n", header.Version); + ok(header.Size >= sizeof(descriptor), "got header.Size %ld\n", header.Size); + + SetLastError(0xdeadbeef); + ret = DeviceIoControl(handle, IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(query), &descriptor, sizeof(descriptor), + &size, NULL); + error = GetLastError(); + ok(ret, "expect ret %#x, got %#x\n", TRUE, ret); + ok(error == 0xdeadbeef, "expect err %#x, got err %#lx\n", 0xdeadbeef, error); + ok(size == sizeof(descriptor), "got size %ld\n", size); + ok(descriptor.Version == sizeof(descriptor), "got descriptor.Version %ld\n", descriptor.Version); + ok(descriptor.Size >= sizeof(descriptor), "got descriptor.Size %ld\n", descriptor.Size); + + + query.PropertyId = StorageDeviceSeekPenaltyProperty; + query.QueryType = PropertyStandardQuery; + SetLastError(0xdeadbeef); + ret = DeviceIoControl(handle, IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(query), &header, sizeof(header), &size, + NULL); + error = GetLastError(); + if (!ret && error == ERROR_INVALID_FUNCTION) + { + win_skip( "StorageDeviceSeekPenaltyProperty is not supported.\n" ); /* Win7 */ + } + else + { +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) { +#endif + ok(ret, "expect ret %#x, got %#x\n", TRUE, ret); + ok(error == 0xdeadbeef, "expect err %#x, got err %#lx\n", 0xdeadbeef, error); + ok(size == sizeof(header), "got size %ld\n", size); + ok(header.Version == sizeof(seek_pen), "got header.Version %ld\n", header.Version); + ok(header.Size == sizeof(seek_pen), "got header.Size %ld\n", header.Size); + + memset(&seek_pen, 0xcc, sizeof(seek_pen)); + ret = DeviceIoControl(handle, IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(query), &seek_pen, sizeof(seek_pen), + &size, NULL); + error = GetLastError(); + ok(ret || (error == ERROR_INVALID_FUNCTION /* Win8 VMs */ || (error == ERROR_GEN_FAILURE /* VMs */)), + "got ret %d, error %#lx\n", ret, error); + if (ret) + { + ok(size == sizeof(seek_pen), "got size %ld\n", size); + ok(seek_pen.Version == sizeof(seek_pen), "got %ld\n", seek_pen.Version); + ok(seek_pen.Size == sizeof(seek_pen), "got %ld\n", seek_pen.Size); + ok(seek_pen.IncursSeekPenalty == TRUE || seek_pen.IncursSeekPenalty == FALSE, "got %d.\n", seek_pen.IncursSeekPenalty); + } +#ifdef __REACTOS__ + } +#endif + } + + CloseHandle(handle); +} + static void test_GetVolumePathNameA(void) { - char volume_path[MAX_PATH], cwd[MAX_PATH]; + char volume_path[MAX_PATH], cwd[MAX_PATH], expect_path[MAX_PATH]; struct { const char *file_name; const char *path_name; @@ -606,19 +714,19 @@ static void test_GetVolumePathNameA(void) NULL, NULL, 0, ERROR_INVALID_PARAMETER, 0xdeadbeef /* winxp */ }, - { /* test 1: empty input, NULL output, 0 output length */ + { /* empty input, NULL output, 0 output length */ "", NULL, 0, ERROR_INVALID_PARAMETER, 0xdeadbeef /* winxp */ }, - { /* test 2: valid input, NULL output, 0 output length */ + { /* valid input, NULL output, 0 output length */ "C:\\", NULL, 0, ERROR_INVALID_PARAMETER, ERROR_FILENAME_EXCED_RANGE /* winxp */ }, - { /* test 3: valid input, valid output, 0 output length */ + { /* valid input, valid output, 0 output length */ "C:\\", "C:\\", 0, ERROR_INVALID_PARAMETER, ERROR_FILENAME_EXCED_RANGE /* winxp */ }, - { /* test 4: valid input, valid output, 1 output length */ + { /* valid input, valid output, 1 output length */ "C:\\", "C:\\", 1, ERROR_FILENAME_EXCED_RANGE, NO_ERROR }, @@ -626,174 +734,132 @@ static void test_GetVolumePathNameA(void) "C:\\", "C:\\", sizeof(volume_path), NO_ERROR, NO_ERROR }, - { /* test 6: lowercase input, uppercase output, valid output length */ + { /* lowercase input, uppercase output, valid output length */ "c:\\", "C:\\", sizeof(volume_path), NO_ERROR, NO_ERROR }, - { /* test 7: poor quality input, valid output, valid output length */ - "C::", "C:\\", sizeof(volume_path), - NO_ERROR, NO_ERROR - }, - { /* test 8: really bogus input, valid output, 1 output length */ + { /* really bogus input, valid output, 1 output length */ "\\\\$$$", "C:\\", 1, ERROR_INVALID_NAME, ERROR_FILENAME_EXCED_RANGE }, - { /* test 9: a reasonable DOS path that is guaranteed to exist */ + { /* a reasonable DOS path that is guaranteed to exist */ "C:\\windows\\system32", "C:\\", sizeof(volume_path), NO_ERROR, NO_ERROR }, - { /* test 10: a reasonable DOS path that shouldn't exist */ + { /* a reasonable DOS path that shouldn't exist */ "C:\\windows\\system32\\AnInvalidFolder", "C:\\", sizeof(volume_path), NO_ERROR, NO_ERROR }, - { /* test 11: a reasonable NT-converted DOS path that shouldn't exist */ + { /* test 10: a reasonable NT-converted DOS path that shouldn't exist */ "\\\\?\\C:\\AnInvalidFolder", "\\\\?\\C:\\", sizeof(volume_path), NO_ERROR, NO_ERROR }, - { /* test 12: an unreasonable NT-converted DOS path */ + { /* an unreasonable NT-converted DOS path */ "\\\\?\\InvalidDrive:\\AnInvalidFolder", "\\\\?\\InvalidDrive:\\" /* win2k, winxp */, sizeof(volume_path), ERROR_INVALID_NAME, NO_ERROR }, - { /* test 13: an unreasonable NT volume path */ + { /* an unreasonable NT volume path */ "\\\\?\\Volume{00000000-00-0000-0000-000000000000}\\AnInvalidFolder", "\\\\?\\Volume{00000000-00-0000-0000-000000000000}\\" /* win2k, winxp */, sizeof(volume_path), ERROR_INVALID_NAME, NO_ERROR }, - { /* test 14: an unreasonable NT-ish path */ + { /* an unreasonable NT-ish path */ "\\\\ReallyBogus\\InvalidDrive:\\AnInvalidFolder", "\\\\ReallyBogus\\InvalidDrive:\\" /* win2k, winxp */, sizeof(volume_path), ERROR_INVALID_NAME, NO_ERROR }, - { /* test 15: poor quality input, valid output, valid (but short) output length */ - "C::", "C:\\", 4, - NO_ERROR, ERROR_MORE_DATA - }, - { /* test 16: unused drive letter */ + { "M::", "C:\\", 4, ERROR_FILE_NOT_FOUND, ERROR_MORE_DATA }, - { /* test 17: an unreasonable DOS path */ - "InvalidDrive:\\AnInvalidFolder", "%CurrentDrive%\\", sizeof(volume_path), - NO_ERROR, NO_ERROR - }, - { /* test 18: a reasonable device path */ - "\\??\\CdRom0", "%CurrentDrive%\\", sizeof(volume_path), - NO_ERROR, NO_ERROR - }, - { /* test 19: an unreasonable device path */ - "\\??\\ReallyBogus", "%CurrentDrive%\\", sizeof(volume_path), - NO_ERROR, NO_ERROR - }, - { /* test 20 */ + { /* test 15 */ "C:", "C:", 2, ERROR_FILENAME_EXCED_RANGE, NO_ERROR }, - { /* test 21 */ + { "C:", "C:", 3, NO_ERROR, ERROR_FILENAME_EXCED_RANGE }, - { /* test 22 */ + { "C:\\", "C:", 2, ERROR_FILENAME_EXCED_RANGE, NO_ERROR }, - { /* test 23 */ + { "C:\\", "C:", 3, NO_ERROR, ERROR_FILENAME_EXCED_RANGE }, - { /* test 24 */ + { "C::", "C:", 2, ERROR_FILENAME_EXCED_RANGE, NO_ERROR }, - { /* test 25 */ + { /* test 20 */ "C::", "C:", 3, NO_ERROR, ERROR_FILENAME_EXCED_RANGE }, - { /* test 26 */ - "C::", "C:\\", 4, - NO_ERROR, ERROR_MORE_DATA - }, - { /* test 27 */ + { "C:\\windows\\system32\\AnInvalidFolder", "C:", 3, NO_ERROR, ERROR_FILENAME_EXCED_RANGE }, - { /* test 28 */ + { "\\\\?\\C:\\AnInvalidFolder", "\\\\?\\C:", 3, ERROR_FILENAME_EXCED_RANGE, NO_ERROR }, - { /* test 29 */ + { "\\\\?\\C:\\AnInvalidFolder", "\\\\?\\C:", 6, ERROR_FILENAME_EXCED_RANGE, NO_ERROR }, - { /* test 30 */ + { "\\\\?\\C:\\AnInvalidFolder", "\\\\?\\C:", 7, NO_ERROR, ERROR_FILENAME_EXCED_RANGE }, - { /* test 31 */ + { /* test 25 */ "\\\\?\\c:\\AnInvalidFolder", "\\\\?\\c:", 7, NO_ERROR, ERROR_FILENAME_EXCED_RANGE }, - { /* test 32 */ + { "C:/", "C:\\", 4, NO_ERROR, ERROR_MORE_DATA }, - { /* test 33 */ + { "M:/", "", 4, ERROR_FILE_NOT_FOUND, ERROR_MORE_DATA }, - { /* test 34 */ - "C:ABC:DEF:\\AnInvalidFolder", "C:\\", 4, - NO_ERROR, ERROR_MORE_DATA - }, - { /* test 35 */ + { "?:ABC:DEF:\\AnInvalidFolder", "?:\\" /* win2k, winxp */, sizeof(volume_path), ERROR_FILE_NOT_FOUND, NO_ERROR }, - { /* test 36 */ - "relative/path", "%CurrentDrive%\\", sizeof(volume_path), - NO_ERROR, NO_ERROR - }, - { /* test 37 */ - "/unix-style/absolute/path", "%CurrentDrive%\\", sizeof(volume_path), - NO_ERROR, NO_ERROR - }, - { /* test 38 */ - "\\??\\C:\\NonExistent", "%CurrentDrive%\\", sizeof(volume_path), - NO_ERROR, NO_ERROR - }, - { /* test 39 */ - "\\??\\M:\\NonExistent", "%CurrentDrive%\\", sizeof(volume_path), - NO_ERROR, NO_ERROR - }, - { /* test 40 */ - "somefile:def", "%CurrentDrive%\\", sizeof(volume_path), - NO_ERROR, NO_ERROR - }, - { /* test 41 */ + { "s:omefile", "S:\\" /* win2k, winxp */, sizeof(volume_path), ERROR_FILE_NOT_FOUND, NO_ERROR }, + { /* test 30: a reasonable forward slash path that is guaranteed to exist */ + "C:/windows/system32", "C:\\", sizeof(volume_path), + NO_ERROR, NO_ERROR + }, }; + + static const char *relative_tests[] = + { + "InvalidDrive:\\AnInvalidFolder", + "relative/path", + "somefile:def", + }; + + static const char *global_prefix_tests[] = + { + "\\??\\CdRom0", + "\\??\\ReallyBogus", + "\\??\\C:\\NonExistent", + "\\??\\M:\\NonExistent", + }; + BOOL ret, success; DWORD error; UINT i; - /* GetVolumePathNameA is not present before w2k */ - if (!pGetVolumePathNameA) - { - win_skip("required functions not found\n"); - return; - } - - /* Obtain the drive of the working directory */ - ret = GetCurrentDirectoryA( sizeof(cwd), cwd ); - ok( ret, "Failed to obtain the current working directory.\n" ); - cwd[2] = 0; - ret = SetEnvironmentVariableA( "CurrentDrive", cwd ); - ok( ret, "Failed to set an environment variable for the current working drive.\n" ); - - for (i=0; i %s\n", volume); SetLastError( 0xdeadbeef ); ret = pGetVolumePathNamesForVolumeNameA( NULL, NULL, 0, NULL ); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %u\n", error); + ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %lu\n", error); SetLastError( 0xdeadbeef ); ret = pGetVolumePathNamesForVolumeNameA( "", NULL, 0, NULL ); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %u\n", error); + ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %lu\n", error); SetLastError( 0xdeadbeef ); ret = pGetVolumePathNamesForVolumeNameA( volume, NULL, 0, NULL ); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_MORE_DATA, "expected ERROR_MORE_DATA got %u\n", error); + ok(error == ERROR_MORE_DATA, "expected ERROR_MORE_DATA got %lu\n", error); SetLastError( 0xdeadbeef ); ret = pGetVolumePathNamesForVolumeNameA( volume, buffer, 0, NULL ); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_MORE_DATA, "expected ERROR_MORE_DATA got %u\n", error); + ok(error == ERROR_MORE_DATA, "expected ERROR_MORE_DATA got %lu\n", error); memset( buffer, 0xff, sizeof(buffer) ); ret = pGetVolumePathNamesForVolumeNameA( volume, buffer, sizeof(buffer), NULL ); - ok(ret, "failed to get path names %u\n", GetLastError()); + ok(ret, "failed to get path names %lu\n", GetLastError()); ok(!strcmp( "C:\\", buffer ), "expected \"\\C:\" got \"%s\"\n", buffer); ok(!buffer[4], "expected double null-terminated buffer\n"); @@ -932,34 +1027,34 @@ static void test_GetVolumePathNamesForVolumeNameA(void) ret = pGetVolumePathNamesForVolumeNameA( NULL, NULL, 0, &len ); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %u\n", error); + ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %lu\n", error); len = 0; SetLastError( 0xdeadbeef ); ret = pGetVolumePathNamesForVolumeNameA( NULL, NULL, sizeof(buffer), &len ); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %u\n", error); + ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %lu\n", error); len = 0; SetLastError( 0xdeadbeef ); ret = pGetVolumePathNamesForVolumeNameA( NULL, buffer, sizeof(buffer), &len ); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %u\n", error); + ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %lu\n", error); len = 0; SetLastError( 0xdeadbeef ); ret = pGetVolumePathNamesForVolumeNameA( NULL, buffer, sizeof(buffer), &len ); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %u\n", error); + ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %lu\n", error); len = 0; memset( buffer, 0xff, sizeof(buffer) ); ret = pGetVolumePathNamesForVolumeNameA( volume, buffer, sizeof(buffer), &len ); - ok(ret, "failed to get path names %u\n", GetLastError()); - ok(len == 5 || broken(len == 2), "expected 5 got %u\n", len); + ok(ret, "failed to get path names %lu\n", GetLastError()); + ok(len == 5 || broken(len == 2), "expected 5 got %lu\n", len); ok(!strcmp( "C:\\", buffer ), "expected \"\\C:\" got \"%s\"\n", buffer); ok(!buffer[4], "expected double null-terminated buffer\n"); } @@ -975,80 +1070,73 @@ static void test_GetVolumePathNamesForVolumeNameW(void) WCHAR volume[MAX_PATH], buffer[MAX_PATH]; DWORD len, error; -#ifdef __REACTOS__ - /* due to failing all calls to GetVolumeNameForVolumeMountPointW, this - * buffer never gets initialized and could cause a buffer overflow later */ - volume[0] = '$'; - volume[1] = 0; -#endif /* __REACTOS__ */ - - if (!pGetVolumePathNamesForVolumeNameW || !pGetVolumeNameForVolumeMountPointW) + if (!pGetVolumePathNamesForVolumeNameW) { win_skip("required functions not found\n"); return; } - ret = pGetVolumeNameForVolumeMountPointW( drive_c, volume, sizeof(volume)/sizeof(volume[0]) ); - ok(ret, "failed to get volume name %u\n", GetLastError()); + ret = GetVolumeNameForVolumeMountPointW( drive_c, volume, ARRAY_SIZE(volume) ); + ok(ret, "failed to get volume name %lu\n", GetLastError()); SetLastError( 0xdeadbeef ); ret = pGetVolumePathNamesForVolumeNameW( empty, NULL, 0, NULL ); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %u\n", error); + ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %lu\n", error); SetLastError( 0xdeadbeef ); ret = pGetVolumePathNamesForVolumeNameW( volume, NULL, 0, NULL ); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_MORE_DATA, "expected ERROR_MORE_DATA got %u\n", error); + ok(error == ERROR_MORE_DATA, "expected ERROR_MORE_DATA got %lu\n", error); SetLastError( 0xdeadbeef ); ret = pGetVolumePathNamesForVolumeNameW( volume, buffer, 0, NULL ); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_MORE_DATA, "expected ERROR_MORE_DATA got %u\n", error); + ok(error == ERROR_MORE_DATA, "expected ERROR_MORE_DATA got %lu\n", error); if (0) { /* crash */ - ret = pGetVolumePathNamesForVolumeNameW( volume, NULL, sizeof(buffer), NULL ); - ok(ret, "failed to get path names %u\n", GetLastError()); + ret = pGetVolumePathNamesForVolumeNameW( volume, NULL, ARRAY_SIZE(buffer), NULL ); + ok(ret, "failed to get path names %lu\n", GetLastError()); } - ret = pGetVolumePathNamesForVolumeNameW( volume, buffer, sizeof(buffer), NULL ); - ok(ret, "failed to get path names %u\n", GetLastError()); + ret = pGetVolumePathNamesForVolumeNameW( volume, buffer, ARRAY_SIZE(buffer), NULL ); + ok(ret, "failed to get path names %lu\n", GetLastError()); len = 0; memset( buffer, 0xff, sizeof(buffer) ); - ret = pGetVolumePathNamesForVolumeNameW( volume, buffer, sizeof(buffer), &len ); - ok(ret, "failed to get path names %u\n", GetLastError()); - ok(len == 5, "expected 5 got %u\n", len); + ret = pGetVolumePathNamesForVolumeNameW( volume, buffer, ARRAY_SIZE(buffer), &len ); + ok(ret, "failed to get path names %lu\n", GetLastError()); + ok(len == 5, "expected 5 got %lu\n", len); ok(!buffer[4], "expected double null-terminated buffer\n"); len = 0; volume[1] = '?'; volume[lstrlenW( volume ) - 1] = 0; SetLastError( 0xdeadbeef ); - ret = pGetVolumePathNamesForVolumeNameW( volume, buffer, sizeof(buffer), &len ); + ret = pGetVolumePathNamesForVolumeNameW( volume, buffer, ARRAY_SIZE(buffer), &len ); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %u\n", error); + ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %lu\n", error); len = 0; volume[0] = '\\'; volume[1] = 0; SetLastError( 0xdeadbeef ); - ret = pGetVolumePathNamesForVolumeNameW( volume, buffer, sizeof(buffer), &len ); + ret = pGetVolumePathNamesForVolumeNameW( volume, buffer, ARRAY_SIZE(buffer), &len ); error = GetLastError(); ok(!ret, "expected failure\n"); - todo_wine ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got %u\n", error); + todo_wine ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got %lu\n", error); len = 0; lstrcpyW( volume, volume_null ); SetLastError( 0xdeadbeef ); - ret = pGetVolumePathNamesForVolumeNameW( volume, buffer, sizeof(buffer), &len ); + ret = pGetVolumePathNamesForVolumeNameW( volume, buffer, ARRAY_SIZE(buffer), &len ); error = GetLastError(); ok(!ret, "expected failure\n"); - ok(error == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND got %u\n", error); + ok(error == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND got %lu\n", error); } static void test_dvd_read_structure(HANDLE handle) @@ -1078,7 +1166,7 @@ static void test_dvd_read_structure(HANDLE handle) if(!ret) { - skip("IOCTL_DVD_READ_STRUCTURE not supported: %u\n", GetLastError()); + skip("IOCTL_DVD_READ_STRUCTURE not supported: %lu\n", GetLastError()); return; } @@ -1135,7 +1223,7 @@ static void test_dvd_read_structure(HANDLE handle) /* Strangely, with NULL lpOutBuffer, last error is insufficient buffer, not invalid parameter as we could expect */ ret = DeviceIoControl(handle, IOCTL_DVD_READ_STRUCTURE, &dvdReadStructure, sizeof(DVD_READ_STRUCTURE), NULL, sizeof(DVD_COPYRIGHT_DESCRIPTOR), &nbBytes, NULL); - ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "IOCTL_DVD_READ_STRUCTURE should have failed %d %u\n", ret, GetLastError()); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "IOCTL_DVD_READ_STRUCTURE should have failed %d %lu\n", ret, GetLastError()); for(i=0; iFileNameLength == wcslen(L"\\winetest_mnt") * sizeof(WCHAR), "got length %lu\n", name->FileNameLength); + ok(!wcsnicmp(name->FileName, L"\\winetest_mnt", wcslen(L"\\winetest_mnt")), "got name %s\n", + debugstr_wn(name->FileName, name->FileNameLength / sizeof(WCHAR))); + + CloseHandle( file ); + + file = CreateFileA( "C:\\winetest_mnt", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL ); + ok(file != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError()); + + status = NtQueryInformationFile( file, &io, &info, sizeof(info), FileAttributeTagInformation ); + ok(!status, "got status %#lx\n", status); + ok(!(info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + && (info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY), "got attributes %#lx\n", info.FileAttributes); + ok(!info.ReparseTag, "got reparse tag %#lx\n", info.ReparseTag); + + status = NtQueryInformationFile( file, &io, name, sizeof(name_buffer), FileNameInformation ); + ok(!status, "got status %#lx\n", status); + ok(name->FileNameLength == wcslen(L"\\") * sizeof(WCHAR), "got length %lu\n", name->FileNameLength); + ok(!wcsnicmp(name->FileName, L"\\", wcslen(L"\\")), "got name %s\n", + debugstr_wn(name->FileName, name->FileNameLength / sizeof(WCHAR))); + + CloseHandle( file ); + + ret = GetFileAttributesA( "C:\\winetest_mnt" ); + ok(ret != INVALID_FILE_ATTRIBUTES, "got error %lu\n", GetLastError()); + ok((ret & FILE_ATTRIBUTE_REPARSE_POINT) && (ret & FILE_ATTRIBUTE_DIRECTORY), "got attributes %#x\n", ret); + + file = CreateFileA( "C:\\winetest_mnt\\windows", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL ); + ok(file != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError()); + + status = NtQueryInformationFile( file, &io, name, sizeof(name_buffer), FileNameInformation ); + ok(!status, "got status %#lx\n", status); + ok(name->FileNameLength == wcslen(L"\\windows") * sizeof(WCHAR), "got length %lu\n", name->FileNameLength); + ok(!wcsnicmp(name->FileName, L"\\windows", wcslen(L"\\windows")), "got name %s\n", + debugstr_wn(name->FileName, name->FileNameLength / sizeof(WCHAR))); + + CloseHandle( file ); + + ret = GetVolumePathNameA( "C:\\winetest_mnt", path, sizeof(path) ); + ok(ret, "got error %lu\n", GetLastError()); + ok(!strcmp(path, "C:\\winetest_mnt\\"), "got %s\n", debugstr_a(path)); + SetLastError(0xdeadbeef); + ret = GetVolumeNameForVolumeMountPointA( "C:\\winetest_mnt", path, sizeof(path) ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_INVALID_NAME, "wrong error %lu\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = GetVolumeInformationA( "C:\\winetest_mnt", NULL, 0, NULL, NULL, NULL, NULL, 0 ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_INVALID_NAME, "wrong error %lu\n", GetLastError()); + + ret = GetVolumeNameForVolumeMountPointA( "C:\\winetest_mnt\\", path, sizeof(path) ); + ok(ret, "got error %lu\n", GetLastError()); + ok(!strcmp(path, volume_name), "expected %s, got %s\n", debugstr_a(volume_name), debugstr_a(path)); + ret = GetVolumeInformationA( "C:\\winetest_mnt\\", NULL, 0, NULL, NULL, NULL, NULL, 0 ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = GetVolumePathNameA( "C:\\winetest_mnt\\windows", path, sizeof(path) ); + ok(ret, "got error %lu\n", GetLastError()); + ok(!strcmp(path, "C:\\winetest_mnt\\"), "got %s\n", debugstr_a(path)); + SetLastError(0xdeadbeef); + ret = GetVolumeNameForVolumeMountPointA( "C:\\winetest_mnt\\windows\\", path, sizeof(path) ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_NOT_A_REPARSE_POINT, "wrong error %lu\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = GetVolumeInformationA( "C:\\winetest_mnt\\windows\\", NULL, 0, NULL, NULL, NULL, NULL, 0 ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_DIR_NOT_ROOT, "wrong error %lu\n", GetLastError()); + + ret = GetVolumePathNameA( "C:\\winetest_mnt\\nonexistent\\", path, sizeof(path) ); + ok(ret, "got error %lu\n", GetLastError()); + ok(!strcmp(path, "C:\\winetest_mnt\\"), "got %s\n", debugstr_a(path)); + SetLastError(0xdeadbeef); + ret = GetVolumeNameForVolumeMountPointA( "C:\\winetest_mnt\\nonexistent\\", path, sizeof(path) ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = GetVolumeInformationA( "C:\\winetest_mnt\\nonexistent\\", NULL, 0, NULL, NULL, NULL, NULL, 0 ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError()); + + ret = GetVolumePathNameA( "C:\\winetest_mnt\\winetest_mnt", path, sizeof(path) ); + ok(ret, "got error %lu\n", GetLastError()); + ok(!strcmp(path, "C:\\winetest_mnt\\winetest_mnt\\"), "got %s\n", debugstr_a(path)); + ret = GetVolumeNameForVolumeMountPointA( "C:\\winetest_mnt\\winetest_mnt\\", path, sizeof(path) ); + ok(ret, "got error %lu\n", GetLastError()); + ok(!strcmp(path, volume_name), "expected %s, got %s\n", debugstr_a(volume_name), debugstr_a(path)); + ret = GetVolumeInformationA( "C:\\winetest_mnt\\winetest_mnt\\", NULL, 0, NULL, NULL, NULL, NULL, 0 ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = GetVolumePathNameA( "C:/winetest_mnt/../winetest_mnt/.", path, sizeof(path) ); + ok(ret, "got error %lu\n", GetLastError()); + ok(!strcmp(path, "C:\\winetest_mnt\\"), "got %s\n", debugstr_a(path)); + ret = GetVolumeNameForVolumeMountPointA( "C:/winetest_mnt/../winetest_mnt/.\\", path, sizeof(path) ); + ok(ret, "got error %lu\n", GetLastError()); + ok(!strcmp(path, volume_name), "expected %s, got %s\n", debugstr_a(volume_name), debugstr_a(path)); + ret = GetVolumeInformationA( "C:/winetest_mnt/../winetest_mnt/.\\", NULL, 0, NULL, NULL, NULL, NULL, 0 ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = GetVolumePathNamesForVolumeNameA( volume_name, path, sizeof(path), &size ); + ok(ret, "got error %lu\n", GetLastError()); + got_path = FALSE; + for (p = path; *p; p += strlen(p) + 1) + { + if (!strcmp( p, "C:\\winetest_mnt\\" )) + got_path = TRUE; + ok(strcmp( p, "C:\\winetest_mnt\\winetest_mnt\\" ), "GetVolumePathNamesForVolumeName() should not recurse\n"); + } + ok(got_path, "mount point was not enumerated\n"); + + /* test interaction with symbolic links */ + + if (pCreateSymbolicLinkA) + { + ret = pCreateSymbolicLinkA( "C:\\winetest_link", "C:\\winetest_mnt\\", SYMBOLIC_LINK_FLAG_DIRECTORY ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = GetVolumePathNameA( "C:\\winetest_link\\", path, sizeof(path) ); + ok(ret, "got error %lu\n", GetLastError()); + ok(!strcmp(path, "C:\\"), "got %s\n", path); + SetLastError(0xdeadbeef); + ret = GetVolumeNameForVolumeMountPointA( "C:\\winetest_link\\", path, sizeof(path) ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER + || broken(GetLastError() == ERROR_SUCCESS) /* 2008 */, "wrong error %lu\n", GetLastError()); + ret = GetVolumeInformationA( "C:\\winetest_link\\", NULL, 0, NULL, NULL, NULL, NULL, 0 ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = GetVolumePathNameA( "C:\\winetest_link\\windows\\", path, sizeof(path) ); + ok(ret, "got error %lu\n", GetLastError()); + ok(!strcmp(path, "C:\\"), "got %s\n", path); + SetLastError(0xdeadbeef); + ret = GetVolumeNameForVolumeMountPointA( "C:\\winetest_link\\windows\\", path, sizeof(path) ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_NOT_A_REPARSE_POINT, "wrong error %lu\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = GetVolumeInformationA( "C:\\winetest_link\\windows\\", NULL, 0, NULL, NULL, NULL, NULL, 0 ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_DIR_NOT_ROOT, "wrong error %lu\n", GetLastError()); + + ret = GetVolumePathNameA( "C:\\winetest_link\\winetest_mnt", path, sizeof(path) ); + ok(ret, "got error %lu\n", GetLastError()); + ok(!strcmp(path, "C:\\winetest_link\\winetest_mnt\\"), "got %s\n", debugstr_a(path)); + ret = GetVolumeNameForVolumeMountPointA( "C:\\winetest_link\\winetest_mnt\\", path, sizeof(path) ); + ok(ret, "got error %lu\n", GetLastError()); + ok(!strcmp(path, volume_name), "expected %s, got %s\n", debugstr_a(volume_name), debugstr_a(path)); + ret = GetVolumeInformationA( "C:\\winetest_link\\winetest_mnt\\", NULL, 0, NULL, NULL, NULL, NULL, 0 ); + ok(ret, "got error %lu\n", GetLastError()); + + /* The following test makes it clear that when we encounter a symlink + * while resolving, we resolve *every* junction in the path, i.e. both + * mount points and symlinks. */ + ret = GetVolumePathNameA( "C:\\winetest_link\\winetest_mnt\\winetest_link\\windows\\", path, sizeof(path) ); + ok(ret, "got error %lu\n", GetLastError()); + ok(!strcmp(path, "C:\\") || !strcmp(path, "C:\\winetest_link\\winetest_mnt\\") /* 2008 */, + "got %s\n", debugstr_a(path)); + + file = CreateFileA( "C:\\winetest_link\\winetest_mnt\\winetest_link\\windows\\", 0, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL ); + ok(file != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError()); + + status = NtQueryInformationFile( file, &io, name, sizeof(name_buffer), FileNameInformation ); + ok(!status, "got status %#lx\n", status); + ok(name->FileNameLength == wcslen(L"\\windows") * sizeof(WCHAR), "got length %lu\n", name->FileNameLength); + ok(!wcsnicmp(name->FileName, L"\\windows", wcslen(L"\\windows")), "got name %s\n", + debugstr_wn(name->FileName, name->FileNameLength / sizeof(WCHAR))); + + CloseHandle( file ); + + ret = RemoveDirectoryA( "C:\\winetest_link\\" ); + ok(ret, "got error %lu\n", GetLastError()); + + /* The following cannot be automatically tested: + * + * Suppose C: and D: are mount points of different volumes. If C:/a is + * symlinked to D:/b, GetVolumePathName("C:\\a") will return "D:\\" if + * "a" is a directory, but "C:\\" if "a" is a file. + * Moreover, if D: is mounted at C:/mnt, and C:/a is symlinked to + * C:/mnt, GetVolumePathName("C:\\mnt\\b") will still return "D:\\". */ + } + + ret = DeleteVolumeMountPointA( "C:\\winetest_mnt\\" ); + ok(ret, "got error %lu\n", GetLastError()); + ret = RemoveDirectoryA( "C:\\winetest_mnt" ); + ok(ret, "got error %lu\n", GetLastError()); +} + +static void test_GetVolumeInformationByHandle(void) +{ + char DECLSPEC_ALIGN(8) buffer[50]; + FILE_FS_ATTRIBUTE_INFORMATION *attr_info = (void *)buffer; + FILE_FS_VOLUME_INFORMATION *volume_info = (void *)buffer; + DWORD serial, filename_len, flags; + WCHAR label[20], fsname[20]; + char volume[MAX_PATH+1]; + IO_STATUS_BLOCK io; + HANDLE file; + NTSTATUS status; + BOOL ret; + +#if defined(__REACTOS__) && DLL_EXPORT_VERSION >= 0x600 + /* FIXME: GetVolumeInformationByHandleW is a STUB on ReactOS! */ + if (is_reactos() || !pGetVolumeInformationByHandleW) +#else + if (!pGetVolumeInformationByHandleW) +#endif + { + win_skip("GetVolumeInformationByHandleW is not present.\n"); + return; + } + + file = CreateFileA( "C:/windows", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL ); + ok(file != INVALID_HANDLE_VALUE, "failed to open file, error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = pGetVolumeInformationByHandleW( INVALID_HANDLE_VALUE, label, ARRAY_SIZE(label), &serial, + &filename_len, &flags, fsname, ARRAY_SIZE(fsname) ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError()); + + ret = pGetVolumeInformationByHandleW( file, NULL, 0, NULL, NULL, NULL, NULL, 0 ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = pGetVolumeInformationByHandleW( file, label, ARRAY_SIZE(label), &serial, + &filename_len, &flags, fsname, ARRAY_SIZE(fsname) ); + ok(ret, "got error %lu\n", GetLastError()); + + memset(buffer, 0, sizeof(buffer)); + status = NtQueryVolumeInformationFile( file, &io, buffer, sizeof(buffer), FileFsAttributeInformation ); + ok(!status, "got status %#lx\n", status); + ok(flags == attr_info->FileSystemAttributes, "expected flags %#lx, got %#lx\n", + attr_info->FileSystemAttributes, flags); + ok(filename_len == attr_info->MaximumComponentNameLength, "expected filename_len %lu, got %lu\n", + attr_info->MaximumComponentNameLength, filename_len); + ok(!wcscmp( fsname, attr_info->FileSystemName ), "expected fsname %s, got %s\n", + debugstr_w( attr_info->FileSystemName ), debugstr_w( fsname )); + ok(wcslen( fsname ) == attr_info->FileSystemNameLength / sizeof(WCHAR), "got %Iu\n", wcslen( fsname )); + + SetLastError(0xdeadbeef); + ret = pGetVolumeInformationByHandleW( file, NULL, 0, NULL, &filename_len, &flags, fsname, 2 ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_BAD_LENGTH, "got error %lu\n", GetLastError()); + + memset(buffer, 0, sizeof(buffer)); + status = NtQueryVolumeInformationFile( file, &io, buffer, sizeof(buffer), FileFsVolumeInformation ); + ok(!status, "got status %#lx\n", status); + ok(serial == volume_info->VolumeSerialNumber, "expected serial %08lx, got %08lx\n", + volume_info->VolumeSerialNumber, serial); + ok(!wcscmp( label, volume_info->VolumeLabel ), "expected label %s, got %s\n", + debugstr_w( volume_info->VolumeLabel ), debugstr_w( label )); + ok(wcslen( label ) == volume_info->VolumeLabelLength / sizeof(WCHAR), "got %Iu\n", wcslen( label )); + + CloseHandle( file ); + + /* get the unique volume name for the windows drive */ + ret = GetVolumeNameForVolumeMountPointA("C:\\", volume, MAX_PATH); + ok(ret == TRUE, "GetVolumeNameForVolumeMountPointA failed\n"); + + /* try again with unique volume name */ + + file = CreateFileA( volume, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL ); + ok(file != INVALID_HANDLE_VALUE, "failed to open file, error %lu\n", GetLastError()); + + ret = pGetVolumeInformationByHandleW( file, label, ARRAY_SIZE(label), &serial, + &filename_len, &flags, fsname, ARRAY_SIZE(fsname) ); + ok(ret, "got error %lu\n", GetLastError()); + + memset(buffer, 0, sizeof(buffer)); + status = NtQueryVolumeInformationFile( file, &io, buffer, sizeof(buffer), FileFsVolumeInformation ); + ok(!status, "got status %#lx\n", status); + ok(serial == volume_info->VolumeSerialNumber, "expected serial %08lx, got %08lx\n", + volume_info->VolumeSerialNumber, serial); + ok(!wcscmp( label, volume_info->VolumeLabel ), "expected label %s, got %s\n", + debugstr_w( volume_info->VolumeLabel ), debugstr_w( label )); + ok(wcslen( label ) == volume_info->VolumeLabelLength / sizeof(WCHAR), "got %Iu\n", wcslen( label )); + + memset(buffer, 0, sizeof(buffer)); + status = NtQueryVolumeInformationFile( file, &io, buffer, sizeof(buffer), FileFsAttributeInformation ); + ok(!status, "got status %#lx\n", status); + ok(flags == attr_info->FileSystemAttributes, "expected flags %#lx, got %#lx\n", + attr_info->FileSystemAttributes, flags); + ok(filename_len == attr_info->MaximumComponentNameLength, "expected filename_len %lu, got %lu\n", + attr_info->MaximumComponentNameLength, filename_len); + ok(!wcscmp( fsname, attr_info->FileSystemName ), "expected fsname %s, got %s\n", + debugstr_w( attr_info->FileSystemName ), debugstr_w( fsname )); + ok(wcslen( fsname ) == attr_info->FileSystemNameLength / sizeof(WCHAR), "got %Iu\n", wcslen( fsname )); + + CloseHandle( file ); +} + +static void test_mountmgr_query_points(void) +{ + char input_buffer[64]; + MOUNTMGR_MOUNT_POINTS *output; + MOUNTMGR_MOUNT_POINT *input = (MOUNTMGR_MOUNT_POINT *)input_buffer; + IO_STATUS_BLOCK io; + NTSTATUS status; + HANDLE file; + + output = malloc(1024); + + file = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, 0, 0, NULL, OPEN_EXISTING, 0, NULL ); + ok(file != INVALID_HANDLE_VALUE, "failed to open mountmgr, error %lu\n", GetLastError()); + + io.Status = 0xdeadf00d; + io.Information = 0xdeadf00d; + status = NtDeviceIoControlFile( file, NULL, NULL, NULL, &io, + IOCTL_MOUNTMGR_QUERY_POINTS, NULL, 0, NULL, 0 ); + ok(status == STATUS_INVALID_PARAMETER, "got %#lx\n", status); + ok(io.Status == 0xdeadf00d, "got status %#lx\n", io.Status); + ok(io.Information == 0xdeadf00d, "got information %#Ix\n", io.Information); + + memset( input, 0, sizeof(*input) ); + + io.Status = 0xdeadf00d; + io.Information = 0xdeadf00d; + status = NtDeviceIoControlFile( file, NULL, NULL, NULL, &io, + IOCTL_MOUNTMGR_QUERY_POINTS, input, sizeof(*input) - 1, NULL, 0 ); + ok(status == STATUS_INVALID_PARAMETER, "got %#lx\n", status); + ok(io.Status == 0xdeadf00d, "got status %#lx\n", io.Status); + ok(io.Information == 0xdeadf00d, "got information %#Ix\n", io.Information); + + io.Status = 0xdeadf00d; + io.Information = 0xdeadf00d; + status = NtDeviceIoControlFile( file, NULL, NULL, NULL, &io, + IOCTL_MOUNTMGR_QUERY_POINTS, input, sizeof(*input), NULL, 0 ); + ok(status == STATUS_INVALID_PARAMETER, "got %#lx\n", status); + ok(io.Status == 0xdeadf00d, "got status %#lx\n", io.Status); + ok(io.Information == 0xdeadf00d, "got information %#Ix\n", io.Information); + + io.Status = 0xdeadf00d; + io.Information = 0xdeadf00d; + memset(output, 0xcc, sizeof(*output)); + status = NtDeviceIoControlFile( file, NULL, NULL, NULL, &io, + IOCTL_MOUNTMGR_QUERY_POINTS, input, sizeof(*input), output, sizeof(*output) - 1 ); + ok(status == STATUS_INVALID_PARAMETER, "got %#lx\n", status); + ok(io.Status == 0xdeadf00d, "got status %#lx\n", io.Status); + ok(io.Information == 0xdeadf00d, "got information %#Ix\n", io.Information); + ok(output->Size == 0xcccccccc, "got size %lu\n", output->Size); + ok(output->NumberOfMountPoints == 0xcccccccc, "got count %lu\n", output->NumberOfMountPoints); + + io.Status = 0xdeadf00d; + io.Information = 0xdeadf00d; + memset(output, 0xcc, sizeof(*output)); + status = NtDeviceIoControlFile( file, NULL, NULL, NULL, &io, + IOCTL_MOUNTMGR_QUERY_POINTS, input, sizeof(*input), output, sizeof(*output) ); + ok(status == STATUS_BUFFER_OVERFLOW, "got %#lx\n", status); + ok(io.Status == STATUS_BUFFER_OVERFLOW, "got status %#lx\n", io.Status); +#ifdef __REACTOS__ + todo_wine ok(io.Information == offsetof(MOUNTMGR_MOUNT_POINTS, MountPoints[0]) || broken(io.Information == sizeof(MOUNTMGR_MOUNT_POINTS)) /* WS03 */, "got information %#Ix\n", io.Information); +#else + todo_wine ok(io.Information == offsetof(MOUNTMGR_MOUNT_POINTS, MountPoints[0]), "got information %#Ix\n", io.Information); +#endif + ok(output->Size > offsetof(MOUNTMGR_MOUNT_POINTS, MountPoints[0]), "got size %lu\n", output->Size); + todo_wine ok(output->NumberOfMountPoints && output->NumberOfMountPoints != 0xcccccccc, + "got count %lu\n", output->NumberOfMountPoints); + + output = realloc(output, output->Size); + + io.Status = 0xdeadf00d; + io.Information = 0xdeadf00d; + status = NtDeviceIoControlFile( file, NULL, NULL, NULL, &io, + IOCTL_MOUNTMGR_QUERY_POINTS, input, sizeof(*input), output, output->Size ); + ok(!status, "got %#lx\n", status); + ok(!io.Status, "got status %#lx\n", io.Status); + ok(io.Information == output->Size, "got size %lu, information %#Ix\n", output->Size, io.Information); + ok(output->Size > offsetof(MOUNTMGR_MOUNT_POINTS, MountPoints[0]), "got size %lu\n", output->Size); + ok(output->NumberOfMountPoints && output->NumberOfMountPoints != 0xcccccccc, + "got count %lu\n", output->NumberOfMountPoints); + + CloseHandle( file ); + + free(output); +} + START_TEST(volume) { hdll = GetModuleHandleA("kernel32.dll"); - pGetVolumeNameForVolumeMountPointA = (void *) GetProcAddress(hdll, "GetVolumeNameForVolumeMountPointA"); - pGetVolumeNameForVolumeMountPointW = (void *) GetProcAddress(hdll, "GetVolumeNameForVolumeMountPointW"); 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"); - pGetVolumeInformationA = (void *) GetProcAddress(hdll, "GetVolumeInformationA"); - pGetVolumePathNameA = (void *) GetProcAddress(hdll, "GetVolumePathNameA"); - pGetVolumePathNameW = (void *) GetProcAddress(hdll, "GetVolumePathNameW"); pGetVolumePathNamesForVolumeNameA = (void *) GetProcAddress(hdll, "GetVolumePathNamesForVolumeNameA"); pGetVolumePathNamesForVolumeNameW = (void *) GetProcAddress(hdll, "GetVolumePathNamesForVolumeNameW"); + pCreateSymbolicLinkA = (void *) GetProcAddress(hdll, "CreateSymbolicLinkA"); + pGetVolumeInformationByHandleW = (void *) GetProcAddress(hdll, "GetVolumeInformationByHandleW"); test_query_dos_deviceA(); - test_define_dos_deviceA(); + test_dos_devices(); test_FindFirstVolume(); test_GetVolumePathNameA(); test_GetVolumePathNameW(); @@ -1243,7 +1776,11 @@ START_TEST(volume) test_GetVolumeInformationA(); test_enum_vols(); test_disk_extents(); + test_disk_query_property(); test_GetVolumePathNamesForVolumeNameA(); test_GetVolumePathNamesForVolumeNameW(); test_cdrom_ioctl(); + test_mounted_folder(); + test_GetVolumeInformationByHandle(); + test_mountmgr_query_points(); } diff --git a/modules/rostests/winetests/kernel32/wine_test.manifest b/modules/rostests/winetests/kernel32/wine_test.manifest new file mode 100644 index 00000000000..de77de3e201 --- /dev/null +++ b/modules/rostests/winetests/kernel32/wine_test.manifest @@ -0,0 +1,4 @@ + + + + diff --git a/modules/rostests/winetests/kernel32/winehacks.h b/modules/rostests/winetests/kernel32/winehacks.h new file mode 100644 index 00000000000..1ac79474aa9 --- /dev/null +++ b/modules/rostests/winetests/kernel32/winehacks.h @@ -0,0 +1,32 @@ +/* These definitions below are from Wine's headers, but for one reason or another + * cannot be currently imported. The ultimate goal should be to phase this header + * out entirely by importing these Wine headers unchanged into sdk/include/wine. + * + * Note: the header filenames correspond to Wine headers, they are often incompatible + * with our headers or Microsoft's corresponding header. + */ + +/* NTDEF.H */ +#define RTL_CONSTANT_STRING(s) { sizeof(s) - sizeof(s[0]), sizeof(s), (void*)s } +#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) + +/* WINBASE.H */ +typedef void *HPCON; + +typedef enum _MACHINE_ATTRIBUTES +{ + UserEnabled = 0x00000001, + KernelEnabled = 0x00000002, + Wow64Container = 0x00000004, +} MACHINE_ATTRIBUTES; + +typedef struct _PROCESS_MACHINE_INFORMATION { + USHORT ProcessMachine; + USHORT Res0; + MACHINE_ATTRIBUTES MachineAttributes; +} PROCESS_MACHINE_INFORMATION; + +/* WINCON.H */ +WINBASEAPI BOOL WINAPI CloseConsoleHandle(HANDLE); +WINBASEAPI HANDLE WINAPI DuplicateConsoleHandle(HANDLE,DWORD,BOOL,DWORD); +WINBASEAPI HANDLE WINAPI GetConsoleInputWaitHandle(void);