From f0475a03cbd7c5a17e0eccff320fd99838643fed Mon Sep 17 00:00:00 2001 From: "Carl J. Bialorucki" Date: Thu, 18 Dec 2025 13:18:11 -0600 Subject: [PATCH] [USER32_WINETEST] Sync user32 winetest to wine-10.0 - [USER32_WINETEST] Sync to wine-10.0. - [USER32_WINETEST] Define out some function definitions we can't build yet. - [USER32_WINETEST] Skip parts of test that crash on ReactOS or Windows - [USER32_WINETEST] Pass behaviors from WS03-Win10 1607 --- .../rostests/winetests/user32/CMakeLists.txt | 19 +- .../winetests/user32/bmp1x1_32bpp.bmp | Bin 0 -> 58 bytes modules/rostests/winetests/user32/broadcast.c | 60 +- modules/rostests/winetests/user32/class.c | 450 +- modules/rostests/winetests/user32/clipboard.c | 915 ++- modules/rostests/winetests/user32/combo.c | 195 +- .../rostests/winetests/user32/cursoricon.c | 862 ++- modules/rostests/winetests/user32/dce.c | 134 +- modules/rostests/winetests/user32/dde.c | 899 ++- modules/rostests/winetests/user32/dialog.c | 689 +- modules/rostests/winetests/user32/edit.c | 522 +- modules/rostests/winetests/user32/generated.c | 12 +- modules/rostests/winetests/user32/input.c | 6876 ++++++++++++----- modules/rostests/winetests/user32/listbox.c | 373 +- modules/rostests/winetests/user32/menu.c | 399 +- modules/rostests/winetests/user32/monitor.c | 3677 ++++++++- modules/rostests/winetests/user32/msg.c | 6252 ++++++++++----- modules/rostests/winetests/user32/rawinput.c | 101 - modules/rostests/winetests/user32/resource.c | 122 +- modules/rostests/winetests/user32/resource.rc | 13 + modules/rostests/winetests/user32/scroll.c | 418 +- modules/rostests/winetests/user32/static.c | 275 +- modules/rostests/winetests/user32/sysparams.c | 1739 +++-- modules/rostests/winetests/user32/testdll.c | 32 + .../rostests/winetests/user32/testdll.spec | 1 + modules/rostests/winetests/user32/testlist.c | 37 +- modules/rostests/winetests/user32/text.c | 135 +- modules/rostests/winetests/user32/uitools.c | 4 +- modules/rostests/winetests/user32/win.c | 6846 ++++++++++++---- .../rostests/winetests/user32/winstation.c | 325 +- modules/rostests/winetests/user32/wsprintf.c | 147 +- 31 files changed, 24228 insertions(+), 8301 deletions(-) create mode 100644 modules/rostests/winetests/user32/bmp1x1_32bpp.bmp delete mode 100644 modules/rostests/winetests/user32/rawinput.c create mode 100644 modules/rostests/winetests/user32/testdll.c create mode 100644 modules/rostests/winetests/user32/testdll.spec diff --git a/modules/rostests/winetests/user32/CMakeLists.txt b/modules/rostests/winetests/user32/CMakeLists.txt index 51b8e272b7f..bd4db85695e 100644 --- a/modules/rostests/winetests/user32/CMakeLists.txt +++ b/modules/rostests/winetests/user32/CMakeLists.txt @@ -1,8 +1,6 @@ -add_definitions(-D__ROS_LONG64__) - remove_definitions(-DWINVER=0x502 -D_WIN32_WINNT=0x502) -add_definitions(-DWINVER=0x602 -D_WIN32_WINNT=0x602) +add_definitions(-DWINVER=0x0A00 -D_WIN32_WINNT=0x0A00 -DNTDDI_VERSION=0x0A000005) list(APPEND SOURCE broadcast.c @@ -20,7 +18,6 @@ list(APPEND SOURCE menu.c monitor.c msg.c - rawinput.c resource.c scroll.c static.c @@ -40,15 +37,21 @@ add_executable(user32_winetest resource.rc) if(MSVC) - # Disable warning C4477 (printf format warnings) + target_compile_options(user32_winetest PRIVATE "/wd4005") + target_compile_options(user32_winetest PRIVATE "/wd4024") + target_compile_options(user32_winetest PRIVATE "/wd4047") + target_compile_options(user32_winetest PRIVATE "/wd4098") remove_target_compile_option(user32_winetest "/we4477") endif() if(CMAKE_C_COMPILER_ID STREQUAL "GNU") - target_compile_options(user32_winetest PRIVATE -Wno-format-overflow) + target_compile_options(user32_winetest PRIVATE + -Wno-format + -Wno-int-conversion) endif() -add_pch(user32_winetest precomp.h "${PCH_SKIP_SOURCE}") +target_compile_definitions(user32_winetest PRIVATE wcsicmp=_wcsicmp) set_module_type(user32_winetest win32cui) -add_importlibs(user32_winetest user32 gdi32 advapi32 msvcrt kernel32) +add_importlibs(user32_winetest user32 gdi32 advapi32 imm32 hid msvcrt kernel32 ntdll) +add_pch(user32_winetest precomp.h "${PCH_SKIP_SOURCE}") add_rostests_file(TARGET user32_winetest) diff --git a/modules/rostests/winetests/user32/bmp1x1_32bpp.bmp b/modules/rostests/winetests/user32/bmp1x1_32bpp.bmp new file mode 100644 index 0000000000000000000000000000000000000000..3b565be8c2b1ca5b8d121df4e3b6f57822b72600 GIT binary patch literal 58 hcmZ?rwPJt(Ga#h_#EfvP0Aw*Ruz*QaLQu)r1pq_i0r>y` literal 0 HcmV?d00001 diff --git a/modules/rostests/winetests/user32/broadcast.c b/modules/rostests/winetests/user32/broadcast.c index f80d455cba3..a2de4f6bc23 100644 --- a/modules/rostests/winetests/user32/broadcast.c +++ b/modules/rostests/winetests/user32/broadcast.c @@ -37,13 +37,13 @@ static LRESULT WINAPI main_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPAR { if (msg == WM_NULL) { - trace("main_window_procA: Sleeping for %lu ms\n", wparam); + trace("main_window_procA: Sleeping for %Iu ms\n", wparam); if (wparam) { if (WaitForSingleObject(hevent, wparam) == WAIT_TIMEOUT) SetEvent(hevent); } - trace("main_window_procA: Returning WM_NULL with parameter %08lx\n", lparam); + trace("main_window_procA: Returning WM_NULL with parameter %08Ix\n", lparam); return lparam; } @@ -90,52 +90,52 @@ static void test_parameters(PBROADCAST broadcast, const char *functionname) win_skip("%s is not implemented\n", functionname); return; } - ok(!ret || broken(ret), "Returned: %d\n", ret); - if (!ret) ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError()); + ok(!ret || broken(ret), "Returned: %ld\n", ret); + if (!ret) ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08lx\n", GetLastError()); SetLastError(0xcafebabe); recips = BSM_APPLICATIONS; ret = broadcast( 0x80000000, &recips, WM_NULL, 0, 0 ); - ok(!ret || broken(ret), "Returned: %d\n", ret); - if (!ret) ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError()); + ok(!ret || broken(ret), "Returned: %ld\n", ret); + if (!ret) ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08lx\n", GetLastError()); if (0) /* TODO: Check the hang flags */ { SetLastError(0xcafebabe); recips = BSM_APPLICATIONS; ret = broadcast( BSF_QUERY|(BSF_NOHANG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0 ); - ok(0, "Last error: %08x\n", GetLastError()); - ok(0, "Returned: %d\n", ret); + ok(0, "Last error: %08lx\n", GetLastError()); + ok(0, "Returned: %ld\n", ret); SetLastError(0xcafebabe); recips = BSM_APPLICATIONS; ret = broadcast( BSF_QUERY|(BSF_NOHANG|BSF_NOTIMEOUTIFNOTHUNG), &recips, WM_NULL, 30000, 0 ); - ok(0, "Last error: %08x\n", GetLastError()); - ok(0, "Returned: %d\n", ret); + ok(0, "Last error: %08lx\n", GetLastError()); + ok(0, "Returned: %ld\n", ret); SetLastError(0xcafebabe); recips = BSM_APPLICATIONS; ret = broadcast( BSF_QUERY|(BSF_NOTIMEOUTIFNOTHUNG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0 ); - ok(0, "Last error: %08x\n", GetLastError()); - ok(0, "Returned: %d\n", ret); + ok(0, "Last error: %08lx\n", GetLastError()); + ok(0, "Returned: %ld\n", ret); SetLastError(0xcafebabe); recips = BSM_APPLICATIONS; ret = broadcast( BSF_POSTMESSAGE|(BSF_NOTIMEOUTIFNOTHUNG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0 ); - ok(0, "Last error: %08x\n", GetLastError()); - ok(0, "Returned: %d\n", ret); + ok(0, "Last error: %08lx\n", GetLastError()); + ok(0, "Returned: %ld\n", ret); } SetLastError( 0xdeadbeef ); recips = BSM_APPLICATIONS; ret = broadcast( BSF_POSTMESSAGE|BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, 0 ); - ok(ret==1, "Returned: %d\n", ret); + ok(ret==1, "Returned: %ld\n", ret); ok(WaitForSingleObject(hevent, 0) != WAIT_OBJECT_0, "Synchronous message sent instead\n"); PulseEvent(hevent); recips = BSM_APPLICATIONS; ret = broadcast( BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY ); - ok(ret==1, "Returned: %d\n", ret); + ok(ret==1, "Returned: %ld\n", ret); ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); PulseEvent(hevent); } @@ -152,51 +152,51 @@ static void test_parametersEx(PBROADCASTEX broadcastex) SetLastError(0xcafebabe); recips = BSM_APPLICATIONS; ret = broadcastex( 0x80000000, &recips, WM_NULL, 0, 0, NULL ); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError()); - ok(!ret, "Returned: %d\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08lx\n", GetLastError()); + ok(!ret, "Returned: %ld\n", ret); SetLastError(0xcafebabe); recips = BSM_APPLICATIONS; ret = broadcastex( 0x80000000, &recips, WM_NULL, 0, 0, NULL ); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError()); - ok(!ret, "Returned: %d\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08lx\n", GetLastError()); + ok(!ret, "Returned: %ld\n", ret); if (0) /* TODO: Check the hang flags */ { SetLastError(0xcafebabe); recips = BSM_APPLICATIONS; ret = broadcastex( BSF_QUERY|(BSF_NOHANG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0, NULL ); - ok(0, "Last error: %08x\n", GetLastError()); - ok(0, "Returned: %d\n", ret); + ok(0, "Last error: %08lx\n", GetLastError()); + ok(0, "Returned: %ld\n", ret); SetLastError(0xcafebabe); recips = BSM_APPLICATIONS; ret = broadcastex( BSF_QUERY|(BSF_NOHANG|BSF_NOTIMEOUTIFNOTHUNG), &recips, WM_NULL, 30000, 0, NULL ); - ok(0, "Last error: %08x\n", GetLastError()); - ok(0, "Returned: %d\n", ret); + ok(0, "Last error: %08lx\n", GetLastError()); + ok(0, "Returned: %ld\n", ret); SetLastError(0xcafebabe); recips = BSM_APPLICATIONS; ret = broadcastex( BSF_QUERY|(BSF_NOTIMEOUTIFNOTHUNG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0, NULL ); - ok(0, "Last error: %08x\n", GetLastError()); - ok(0, "Returned: %d\n", ret); + ok(0, "Last error: %08lx\n", GetLastError()); + ok(0, "Returned: %ld\n", ret); SetLastError(0xcafebabe); recips = BSM_APPLICATIONS; ret = broadcastex( BSF_POSTMESSAGE|(BSF_NOTIMEOUTIFNOTHUNG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0, NULL ); - ok(0, "Last error: %08x\n", GetLastError()); - ok(0, "Returned: %d\n", ret); + ok(0, "Last error: %08lx\n", GetLastError()); + ok(0, "Returned: %ld\n", ret); } recips = BSM_APPLICATIONS; ret = broadcastex( BSF_POSTMESSAGE|BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, 0, NULL ); - ok(ret==1, "Returned: %d\n", ret); + ok(ret==1, "Returned: %ld\n", ret); ok(WaitForSingleObject(hevent, 0) != WAIT_OBJECT_0, "Synchronous message sent instead\n"); PulseEvent(hevent); recips = BSM_APPLICATIONS; ret = broadcastex( BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY, NULL ); - ok(ret==1, "Returned: %d\n", ret); + ok(ret==1, "Returned: %ld\n", ret); ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); PulseEvent(hevent); } diff --git a/modules/rostests/winetests/user32/class.c b/modules/rostests/winetests/user32/class.c index 43c32162e08..fced53b76b0 100644 --- a/modules/rostests/winetests/user32/class.c +++ b/modules/rostests/winetests/user32/class.c @@ -22,6 +22,10 @@ #include #include +#ifdef __REACTOS__ +#define WIN32_NO_STATUS +#include +#endif #include "wine/test.h" #include "windef.h" #include "winbase.h" @@ -29,6 +33,9 @@ #include "winreg.h" #include "wingdi.h" #include "winuser.h" +#ifndef __REACTOS__ +#include "winternl.h" +#endif #include "commctrl.h" #define NUMCLASSWORDS 4 @@ -37,16 +44,18 @@ #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 +static const BOOL is_win64 = (sizeof(void *) > sizeof(int)); + static const char comctl32_manifest[] = "\n" "\n" @@ -90,11 +99,14 @@ static void ClassTest(HINSTANCE hInstance, BOOL global) WNDCLASSW cls, wc; static const WCHAR className[] = {'T','e','s','t','C','l','a','s','s',0}; static const WCHAR winName[] = {'W','i','n','C','l','a','s','s','T','e','s','t',0}; + WNDCLASSW info; ATOM test_atom; HWND hTestWnd; LONG i; WCHAR str[20]; ATOM classatom; + HINSTANCE hInstance2; + BOOL ret; cls.style = CS_HREDRAW | CS_VREDRAW | (global?CS_GLOBALCLASS:0); cls.lpfnWndProc = ClassTest_WndProc; @@ -118,6 +130,26 @@ static void ClassTest(HINSTANCE hInstance, BOOL global) "RegisterClass of the same class should fail for the second time\n"); /* Setup windows */ + hInstance2 = (HINSTANCE)(((ULONG_PTR)hInstance & ~0xffff) | 0xdead); + + hTestWnd = CreateWindowW (className, winName, + WS_OVERLAPPEDWINDOW + WS_HSCROLL + WS_VSCROLL, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0, + 0, hInstance2, 0); + ok(hTestWnd != 0, "Failed to create window for hInstance %p\n", hInstance2); + + ok((HINSTANCE)GetClassLongPtrA(hTestWnd, GCLP_HMODULE) == hInstance, + "Wrong GCL instance %p != %p\n", + (HINSTANCE)GetClassLongPtrA(hTestWnd, GCLP_HMODULE), hInstance); + ok((HINSTANCE)GetWindowLongPtrA(hTestWnd, GWLP_HINSTANCE) == hInstance2, + "Wrong GWL instance %p != %p\n", + (HINSTANCE)GetWindowLongPtrA(hTestWnd, GWLP_HINSTANCE), hInstance2); + + DestroyWindow(hTestWnd); + + ret = GetClassInfoW(hInstance2, className, &info); + ok(ret, "GetClassInfoW failed: %lu\n", GetLastError()); + hTestWnd = CreateWindowW (className, winName, WS_OVERLAPPEDWINDOW + WS_HSCROLL + WS_VSCROLL, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0, @@ -125,6 +157,14 @@ static void ClassTest(HINSTANCE hInstance, BOOL global) ok(hTestWnd!=0, "Failed to create window\n"); + ok((HINSTANCE)GetClassLongPtrA(hTestWnd, GCLP_HMODULE) == hInstance, + "Wrong GCL instance %p/%p\n", + (HINSTANCE)GetClassLongPtrA(hTestWnd, GCLP_HMODULE), hInstance); + ok((HINSTANCE)GetWindowLongPtrA(hTestWnd, GWLP_HINSTANCE) == hInstance, + "Wrong GWL instance %p/%p\n", + (HINSTANCE)GetWindowLongPtrA(hTestWnd, GWLP_HINSTANCE), hInstance); + + /* test initial values of valid classwords */ for(i=0; iA->W conversion */ WNDPROC pDefWindowProcA, pDefWindowProcW; - WNDPROC pNtdllDefWindowProcA, pNtdllDefWindowProcW; WNDPROC oldproc; WNDCLASSEXA cls; /* the memory layout of WNDCLASSEXA and WNDCLASSEXW is the same */ WCHAR buf[128]; @@ -660,57 +699,6 @@ static void test_builtinproc(void) pDefWindowProcA = (void *)GetProcAddress(GetModuleHandleA("user32.dll"), "DefWindowProcA"); pDefWindowProcW = (void *)GetProcAddress(GetModuleHandleA("user32.dll"), "DefWindowProcW"); - pNtdllDefWindowProcA = (void *)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtdllDefWindowProc_A"); - pNtdllDefWindowProcW = (void *)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtdllDefWindowProc_W"); - - /* On Vista+, the user32.dll export DefWindowProcA/W is forwarded to */ - /* ntdll.NtdllDefWindowProc_A/W. However, the wndproc returned by */ - /* GetClassLong/GetWindowLong points to an unexported user32 function */ - if (pDefWindowProcA == pNtdllDefWindowProcA && - pDefWindowProcW == pNtdllDefWindowProcW) - skip("user32.DefWindowProcX forwarded to ntdll.NtdllDefWindowProc_X\n"); - else - { - for (i = 0; i < 4; i++) - { - ZeroMemory(&cls, sizeof(cls)); - cls.cbSize = sizeof(cls); - cls.hInstance = GetModuleHandleA(NULL); - cls.hbrBackground = GetStockObject (WHITE_BRUSH); - if (i & 1) - cls.lpfnWndProc = pDefWindowProcA; - else - cls.lpfnWndProc = pDefWindowProcW; - - if (i & 2) - { - cls.lpszClassName = classA; - atom = RegisterClassExA(&cls); - } - else - { - cls.lpszClassName = (LPCSTR)classW; - atom = RegisterClassExW((WNDCLASSEXW *)&cls); - } - ok(atom != 0, "Couldn't register class, i=%d, %d\n", i, GetLastError()); - - hwnd = CreateWindowA(classA, NULL, 0, 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), NULL); - ok(hwnd != NULL, "Couldn't create window i=%d\n", i); - - ok(GetWindowLongPtrA(hwnd, GWLP_WNDPROC) == (LONG_PTR)pDefWindowProcA, "Wrong ANSI wndproc: %p vs %p\n", - (void *)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), pDefWindowProcA); - ok(GetClassLongPtrA(hwnd, GCLP_WNDPROC) == (ULONG_PTR)pDefWindowProcA, "Wrong ANSI wndproc: %p vs %p\n", - (void *)GetClassLongPtrA(hwnd, GCLP_WNDPROC), pDefWindowProcA); - - ok(GetWindowLongPtrW(hwnd, GWLP_WNDPROC) == (LONG_PTR)pDefWindowProcW, "Wrong Unicode wndproc: %p vs %p\n", - (void *)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), pDefWindowProcW); - ok(GetClassLongPtrW(hwnd, GCLP_WNDPROC) == (ULONG_PTR)pDefWindowProcW, "Wrong Unicode wndproc: %p vs %p\n", - (void *)GetClassLongPtrW(hwnd, GCLP_WNDPROC), pDefWindowProcW); - - DestroyWindow(hwnd); - UnregisterClassA((LPSTR)(DWORD_PTR)atom, GetModuleHandleA(NULL)); - } - } /* built-in winproc - window A/W type automatically detected */ ZeroMemory(&cls, sizeof(cls)); @@ -876,6 +864,163 @@ static void test_builtinproc(void) } +static void test_ntdll_wndprocs(void) +{ + static const char *classes[] = + { + "ScrollBar", + "Message", + "#32768", /* menu */ + "#32769", /* desktop */ + "DefWindowProc", /* not a real class */ + "#32772", /* icon title */ + "??", /* ?? */ + "Button", + "ComboBox", + "ComboLBox", + "#32770", /* dialog */ + "Edit", + "ListBox", + "MDIClient", + "Static", + "IME", + "Ghost", + }; + unsigned int i; + void *procsA[ARRAY_SIZE(classes)] = { NULL }; + void *procsW[ARRAY_SIZE(classes)] = { NULL }; + const UINT64 *ptr_A, *ptr_W, *ptr_workers; + NTSTATUS (WINAPI *pRtlRetrieveNtUserPfn)(const UINT64**,const UINT64**,const UINT64 **); + + pRtlRetrieveNtUserPfn = (void *)GetProcAddress( GetModuleHandleA("ntdll.dll"), "RtlRetrieveNtUserPfn" ); + if (!pRtlRetrieveNtUserPfn || pRtlRetrieveNtUserPfn( &ptr_A, &ptr_W, &ptr_workers )) + { + win_skip( "RtlRetrieveNtUserPfn not supported\n" ); + return; + } + + for (i = 0; i < ARRAY_SIZE(classes); i++) + { + WNDCLASSA wcA; + WNDCLASSW wcW; + WCHAR buffer[20]; + + MultiByteToWideChar( CP_ACP, 0, classes[i], -1, buffer, ARRAY_SIZE(buffer) ); + if (GetClassInfoA( 0, classes[i], &wcA )) procsA[i] = wcA.lpfnWndProc; + if (GetClassInfoW( 0, buffer, &wcW )) procsW[i] = wcW.lpfnWndProc; + } + procsA[4] = (void *)GetProcAddress(GetModuleHandleA("user32.dll"), "DefWindowProcA"); + procsW[4] = (void *)GetProcAddress(GetModuleHandleA("user32.dll"), "DefWindowProcW"); + + if (!is_win64 && ptr_A[0] >> 32) /* some older versions use 32-bit pointers */ + { + const void **ptr_A32 = (const void **)ptr_A, **ptr_W32 = (const void **)ptr_W; + for (i = 0; i < ARRAY_SIZE(procsA); i++) + { + ok( !procsA[i] || procsA[i] == ptr_A32[i], + "wrong ptr A %u %s: %p / %p\n", i, classes[i], procsA[i], ptr_A32[i] ); + ok( !procsW[i] || procsW[i] == ptr_W32[i] || + broken(i == 4), /* DefWindowProcW can be different on wow64 */ + "wrong ptr W %u %s: %p / %p\n", i, classes[i], procsW[i], ptr_W32[i] ); + } + } + else + { + for (i = 0; i < ARRAY_SIZE(procsA); i++) + { + ok( !procsA[i] || (ULONG_PTR)procsA[i] == ptr_A[i], + "wrong ptr A %u %s: %p / %I64x\n", i, classes[i], procsA[i], ptr_A[i] ); + ok( !procsW[i] || (ULONG_PTR)procsW[i] == ptr_W[i] || + broken( !is_win64 && i == 4 ), /* DefWindowProcW can be different on wow64 */ + "wrong ptr W %u %s: %p / %I64x\n", i, classes[i], procsW[i], ptr_W[i] ); + } + } +} + +static void test_wndproc_forwards(void) +{ + WCHAR path[MAX_PATH]; + HMODULE user32 = GetModuleHandleA( "user32.dll" ); + HANDLE map, file; + char *base; + ULONG i, size, *names, *functions; + WORD *ordinals; + IMAGE_EXPORT_DIRECTORY *exp; + + /* file on disk contains forwards */ + + GetModuleFileNameW( user32, path, ARRAY_SIZE(path) ); + file = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); + ok( file != INVALID_HANDLE_VALUE, "cannot open %s err %lu\n", debugstr_w(path), GetLastError() ); + map = CreateFileMappingW( file, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, 0 ); + ok( map != NULL, "failed to create mapping %lu\n", GetLastError() ); + base = MapViewOfFile( map, FILE_MAP_READ, 0, 0, 0 ); + ok( base != NULL, "failed to map file %lu\n", GetLastError() ); + exp = RtlImageDirectoryEntryToData( (HMODULE)base, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size ); + ok( exp != NULL, "no exports\n" ); + functions = (ULONG *)(base + exp->AddressOfFunctions); + names = (ULONG *)(base + exp->AddressOfNames); + ordinals = (WORD *)(base + exp->AddressOfNameOrdinals); + for (i = 0; i < exp->NumberOfNames; i++) + { + const char *name = base + names[i]; + const char *forward = base + functions[ordinals[i]]; + if (strcmp( name, "DefDlgProcA" ) && + strcmp( name, "DefDlgProcW" ) && + strcmp( name, "DefWindowProcA" ) && + strcmp( name, "DefWindowProcW" )) continue; + + if (!strcmp( name, "DefDlgProcA" ) && !(forward >= (char *)exp && forward < (char *)exp + size)) + { + win_skip( "Windows version too old, not using forwards\n" ); + UnmapViewOfFile( base ); + CloseHandle( file ); + CloseHandle( map ); + return; + } + ok( forward >= (char *)exp && forward < (char *)exp + size, + "not a forward %s %lx\n", name, functions[ordinals[i]] ); + ok( !strncmp( forward, "NTDLL.Ntdll", 11 ), "wrong forward %s -> %s\n", name, forward ); + } + UnmapViewOfFile( base ); + CloseHandle( file ); + CloseHandle( map ); + + /* loaded dll is patched to avoid forwards (on 32-bit) */ + + base = (char *)user32; + exp = RtlImageDirectoryEntryToData( (HMODULE)base, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size ); + ok( exp != NULL, "no exports\n" ); + functions = (ULONG *)(base + exp->AddressOfFunctions); + names = (ULONG *)(base + exp->AddressOfNames); + ordinals = (WORD *)(base + exp->AddressOfNameOrdinals); + for (i = 0; i < exp->NumberOfNames; i++) + { + const char *name = base + names[i]; + const char *forward = base + functions[ordinals[i]]; + if (strcmp( name, "DefDlgProcA" ) && + strcmp( name, "DefDlgProcW" ) && + strcmp( name, "DefWindowProcA" ) && + strcmp( name, "DefWindowProcW" )) continue; + if (is_win64) + { + ok( forward >= (char *)exp && forward < (char *)exp + size, + "not a forward %s %lx\n", name, functions[ordinals[i]] ); + ok( !strncmp( forward, "NTDLL.Ntdll", 11 ), "wrong forward %s -> %s\n", name, forward ); + } + else + { + void *expect = GetProcAddress( user32, name ); + ok( !(forward >= (char *)exp && forward < (char *)exp + size), + "%s %lx is a forward\n", name, functions[ordinals[i]] ); + ok( forward == expect || + broken( !strcmp( name, "DefWindowProcW" )), /* DefWindowProcW can be hooked on first run */ + "wrong function %s %p / %p\n", name, forward, expect ); + } + } +} + + static LRESULT WINAPI TestDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { return DefDlgProcA(hWnd, uMsg, wParam, lParam); @@ -926,15 +1071,11 @@ static const struct { const char name[9]; int value; - int badvalue; + int value64; /* 64-bit Windows use 64-bit size also for 32-bit applications */ } extra_values[] = { {"#32770",30,30}, /* Dialog */ -#ifdef _WIN64 - {"Edit",8,8}, -#else - {"Edit",6,8}, /* Windows XP 64-bit returns 8 also to 32-bit applications */ -#endif + {"Edit",6,8}, }; static void test_extra_values(void) @@ -947,7 +1088,7 @@ static void test_extra_values(void) ok( ret, "GetClassInfo (0) failed for global class %s\n", extra_values[i].name); if (!ret) continue; - ok(extra_values[i].value == wcx.cbWndExtra || broken(extra_values[i].badvalue == wcx.cbWndExtra), + ok(extra_values[i].value == wcx.cbWndExtra || extra_values[i].value64 == wcx.cbWndExtra, "expected %d, got %d\n", extra_values[i].value, wcx.cbWndExtra); } } @@ -961,29 +1102,29 @@ static void test_GetClassInfo(void) SetLastError(0xdeadbeef); ret = GetClassInfoA(0, "static", &wc); - ok(ret, "GetClassInfoA() error %d\n", GetLastError()); + ok(ret, "GetClassInfoA() error %ld\n", GetLastError()); if (0) { /* crashes under XP */ SetLastError(0xdeadbeef); ret = GetClassInfoA(0, "static", NULL); - ok(ret, "GetClassInfoA() error %d\n", GetLastError()); + ok(ret, "GetClassInfoA() error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = GetClassInfoW(0, staticW, NULL); - ok(ret, "GetClassInfoW() error %d\n", GetLastError()); + ok(ret, "GetClassInfoW() error %ld\n", GetLastError()); } wcx.cbSize = sizeof(wcx); SetLastError(0xdeadbeef); ret = GetClassInfoExA(0, "static", &wcx); - ok(ret, "GetClassInfoExA() error %d\n", GetLastError()); + ok(ret, "GetClassInfoExA() error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = GetClassInfoExA(0, "static", NULL); ok(!ret, "GetClassInfoExA() should fail\n"); ok(GetLastError() == ERROR_NOACCESS || broken(GetLastError() == 0xdeadbeef), /* win9x */ - "expected ERROR_NOACCESS, got %d\n", GetLastError()); + "expected ERROR_NOACCESS, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = GetClassInfoExW(0, staticW, NULL); @@ -991,14 +1132,14 @@ if (0) { /* crashes under XP */ ok(GetLastError() == ERROR_NOACCESS || broken(GetLastError() == 0xdeadbeef) /* NT4 */ || broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */ - "expected ERROR_NOACCESS, got %d\n", GetLastError()); + "expected ERROR_NOACCESS, got %ld\n", GetLastError()); wcx.cbSize = 0; wcx.lpfnWndProc = NULL; SetLastError(0xdeadbeef); ret = GetClassInfoExA(0, "static", &wcx); - ok(ret, "GetClassInfoExA() error %d\n", GetLastError()); - ok(GetLastError() == 0xdeadbeef, "Unexpected error code %d\n", GetLastError()); + ok(ret, "GetClassInfoExA() error %ld\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "Unexpected error code %ld\n", GetLastError()); ok(wcx.cbSize == 0, "expected 0, got %u\n", wcx.cbSize); ok(wcx.lpfnWndProc != NULL, "got null proc\n"); @@ -1006,7 +1147,7 @@ if (0) { /* crashes under XP */ wcx.lpfnWndProc = NULL; SetLastError(0xdeadbeef); ret = GetClassInfoExA(0, "static", &wcx); - ok(ret, "GetClassInfoExA() error %d\n", GetLastError()); + ok(ret, "GetClassInfoExA() error %ld\n", GetLastError()); ok(wcx.cbSize == sizeof(wcx) - 1, "expected sizeof(wcx)-1, got %u\n", wcx.cbSize); ok(wcx.lpfnWndProc != NULL, "got null proc\n"); @@ -1014,9 +1155,14 @@ if (0) { /* crashes under XP */ wcx.lpfnWndProc = NULL; SetLastError(0xdeadbeef); ret = GetClassInfoExA(0, "static", &wcx); - ok(ret, "GetClassInfoExA() error %d\n", GetLastError()); + ok(ret, "GetClassInfoExA() error %ld\n", GetLastError()); ok(wcx.cbSize == sizeof(wcx) + 1, "expected sizeof(wcx)+1, got %u\n", wcx.cbSize); ok(wcx.lpfnWndProc != NULL, "got null proc\n"); + + wcx.cbSize = sizeof(wcx); + ret = GetClassInfoExA(0, "stati", &wcx); + ok(!ret && GetLastError() == ERROR_CLASS_DOES_NOT_EXIST, + "GetClassInfoExA() returned %x %ld\n", ret, GetLastError()); } static void test_icons(void) @@ -1086,7 +1232,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); } @@ -1103,10 +1249,10 @@ static HANDLE create_test_actctx(const char *file) actctx.lpSource = path; handle = CreateActCtxW(&actctx); - ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %u\n", GetLastError()); + 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); @@ -1140,7 +1286,7 @@ static void test_comctl32_class( const char *name ) create_manifest_file(path, comctl32_manifest); context = create_test_actctx(path); ret = DeleteFileA(path); - ok(ret, "Failed to delete manifest file, error %d.\n", GetLastError()); + ok(ret, "Failed to delete manifest file, error %ld.\n", GetLastError()); module = GetModuleHandleA( "comctl32" ); ok( !module, "comctl32 already loaded\n" ); @@ -1251,7 +1397,7 @@ static void test_comctl32_classes(void) sprintf( path_name, "%s class %s", argv[0], classes[i] ); ok( CreateProcessA( NULL, path_name, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info ), "CreateProcess failed.\n" ); - winetest_wait_child_process( info.hProcess ); + wait_child_process( info.hProcess ); CloseHandle( info.hProcess ); CloseHandle( info.hThread ); } @@ -1277,10 +1423,10 @@ static void test_IME(void) ok(GetModuleHandleA("imm32") != 0, "imm32.dll is not loaded\n"); ret = GetClassInfoA(NULL, "IME", &wnd_class); - ok(ret, "GetClassInfo failed: %d\n", GetLastError()); + ok(ret, "GetClassInfo failed: %ld\n", GetLastError()); size = VirtualQuery(wnd_class.lpfnWndProc, &mbi, sizeof(mbi)); - ok(size == sizeof(mbi), "VirtualQuery returned %ld\n", size); + ok(size == sizeof(mbi), "VirtualQuery returned %Id\n", size); if (size == sizeof(mbi)) { size = GetModuleFileNameA(mbi.AllocationBase, module_name, sizeof(module_name)); ok(size, "GetModuleFileName failed\n"); @@ -1291,10 +1437,10 @@ static void test_IME(void) } ret = GetClassInfoW(NULL, ime_classW, &wnd_classw); - ok(ret, "GetClassInfo failed: %d\n", GetLastError()); + ok(ret, "GetClassInfo failed: %ld\n", GetLastError()); size = VirtualQuery(wnd_classw.lpfnWndProc, &mbi, sizeof(mbi)); - ok(size == sizeof(mbi), "VirtualQuery returned %ld\n", size); + ok(size == sizeof(mbi), "VirtualQuery returned %Id\n", size); size = GetModuleFileNameA(mbi.AllocationBase, module_name, sizeof(module_name)); ok(size, "GetModuleFileName failed\n"); for (ptr = module_name+size-1; ptr > module_name; ptr--) @@ -1329,7 +1475,7 @@ static void test_actctx_classes(void) create_manifest_file(path, main_manifest); context = create_test_actctx(path); ret = DeleteFileA(path); - ok(ret, "Failed to delete manifest file, error %d.\n", GetLastError()); + ok(ret, "Failed to delete manifest file, error %ld.\n", GetLastError()); ret = ActivateActCtx(context, &cookie); ok(ret, "Failed to activate context.\n"); @@ -1464,6 +1610,108 @@ static void test_actctx_classes(void) ReleaseActCtx(context); } +static void test_uxtheme(void) +{ + static const CHAR *class_name = "test_uxtheme_class"; + BOOL (WINAPI * pIsThemeActive)(void); + BOOL dll_loaded, is_theme_active; + WNDCLASSEXA class; + HMODULE uxtheme; + ATOM atom; + HWND hwnd; + + memset(&class, 0, sizeof(class)); + class.cbSize = sizeof(class); + class.lpfnWndProc = DefWindowProcA; + class.hInstance = GetModuleHandleA(NULL); + class.lpszClassName = class_name; + atom = RegisterClassExA(&class); + ok(atom, "RegisterClassExA failed, error %lu.\n", GetLastError()); + + dll_loaded = !!GetModuleHandleA("comctl32.dll"); + ok(!dll_loaded, "Expected comctl32.dll not loaded.\n"); + dll_loaded = !!GetModuleHandleA("uxtheme.dll"); + todo_wine_if(dll_loaded) + ok(!dll_loaded, "Expected uxtheme.dll not loaded.\n"); + + /* Creating a window triggers uxtheme load when theming is active */ + hwnd = CreateWindowA(class_name, "Test", WS_POPUP, 0, 0, 1, 1, NULL, NULL, + GetModuleHandleA(NULL), NULL); + ok(!!hwnd, "Failed to create a test window, error %lu.\n", GetLastError()); + + dll_loaded = !!GetModuleHandleA("comctl32.dll"); + ok(!dll_loaded, "Expected comctl32.dll not loaded.\n"); + + /* Uxtheme is loaded when theming is active */ + dll_loaded = !!GetModuleHandleA("uxtheme.dll"); + + uxtheme = LoadLibraryA("uxtheme.dll"); + ok(!!uxtheme, "Failed to load uxtheme.dll, error %lu.\n", GetLastError()); + pIsThemeActive = (void *)GetProcAddress(uxtheme, "IsThemeActive"); + ok(!!pIsThemeActive, "Failed to load IsThemeActive, error %lu.\n", GetLastError()); + is_theme_active = pIsThemeActive(); + FreeLibrary(uxtheme); + + ok(dll_loaded == is_theme_active, "Expected uxtheme %s when theming is %s.\n", + is_theme_active ? "loaded" : "not loaded", is_theme_active ? "active" : "inactive"); + + DestroyWindow(hwnd); + UnregisterClassA(class_name, GetModuleHandleA(NULL)); +} + +static void test_class_name(void) +{ + WCHAR class_name[] = L"ClassNameTest"; + HINSTANCE hinst = GetModuleHandleW(0); + WNDCLASSEXW wcex; + const WCHAR *nameW; + const char *nameA; + UINT_PTR res; + HWND hwnd; + +#ifdef __REACTOS__ + if (is_reactos()) { + ok(FALSE, "FIXME: ReactOS crashes on test_class_name()!\n"); + return; + } +#endif + memset(&wcex, 0, sizeof wcex); + wcex.cbSize = sizeof wcex; + wcex.lpfnWndProc = ClassTest_WndProc; + wcex.hIcon = LoadIconW(0, (LPCWSTR)IDI_APPLICATION); + wcex.hInstance = hinst; + wcex.lpszClassName = class_name; + wcex.lpszMenuName = L"menu name"; + ok(RegisterClassExW(&wcex), "RegisterClassExW returned 0\n"); + hwnd = CreateWindowExW(0, class_name, NULL, WS_OVERLAPPEDWINDOW, + 0, 0, 0, 0, NULL, NULL, hinst, 0); + ok(hwnd != NULL, "Window was not created\n"); + + nameA = (const char *)GetClassLongPtrA(hwnd, GCLP_MENUNAME); + ok(!strcmp(nameA, "menu name"), "unexpected class name %s\n", debugstr_a(nameA)); + nameW = (const WCHAR *)GetClassLongPtrW(hwnd, GCLP_MENUNAME); + ok(!wcscmp(nameW, L"menu name"), "unexpected class name %s\n", debugstr_w(nameW)); + + res = SetClassLongPtrA(hwnd, GCLP_MENUNAME, (LONG_PTR)"nameA"); + todo_wine + ok(res, "SetClassLongPtrA returned 0\n"); + nameA = (const char *)GetClassLongPtrA(hwnd, GCLP_MENUNAME); + ok(!strcmp(nameA, "nameA"), "unexpected class name %s\n", debugstr_a(nameA)); + nameW = (const WCHAR *)GetClassLongPtrW(hwnd, GCLP_MENUNAME); + ok(!wcscmp(nameW, L"nameA"), "unexpected class name %s\n", debugstr_w(nameW)); + + res = SetClassLongPtrW(hwnd, GCLP_MENUNAME, (LONG_PTR)L"nameW"); + todo_wine + ok(res, "SetClassLongPtrW returned 0\n"); + nameA = (const char *)GetClassLongPtrA(hwnd, GCLP_MENUNAME); + ok(!strcmp(nameA, "nameW"), "unexpected class name %s\n", debugstr_a(nameA)); + nameW = (const WCHAR *)GetClassLongPtrW(hwnd, GCLP_MENUNAME); + ok(!wcscmp(nameW, L"nameW"), "unexpected class name %s\n", debugstr_w(nameW)); + + DestroyWindow(hwnd); + UnregisterClassW(class_name, hinst); +} + START_TEST(class) { char **argv; @@ -1476,6 +1724,7 @@ START_TEST(class) return; } + test_uxtheme(); test_IME(); test_GetClassInfo(); test_extra_values(); @@ -1488,12 +1737,17 @@ START_TEST(class) ClassTest(hInstance,FALSE); ClassTest(hInstance,TRUE); + ClassTest((HANDLE)((ULONG_PTR)hInstance | 0x1234), FALSE); + ClassTest((HANDLE)((ULONG_PTR)hInstance | 0x1234), TRUE); CreateDialogParamTest(hInstance); test_styles(); test_builtinproc(); + test_ntdll_wndprocs(); + test_wndproc_forwards(); test_icons(); test_comctl32_classes(); test_actctx_classes(); + test_class_name(); /* this test unregisters the Button class so it should be executed at the end */ test_instances(); diff --git a/modules/rostests/winetests/user32/clipboard.c b/modules/rostests/winetests/user32/clipboard.c index eac3df7a4ec..8e473730031 100644 --- a/modules/rostests/winetests/user32/clipboard.c +++ b/modules/rostests/winetests/user32/clipboard.c @@ -29,14 +29,69 @@ static BOOL (WINAPI *pAddClipboardFormatListener)(HWND hwnd); static BOOL (WINAPI *pRemoveClipboardFormatListener)(HWND hwnd); static BOOL (WINAPI *pGetUpdatedClipboardFormats)( UINT *formats, UINT count, UINT *out_count ); +static HGLOBAL (WINAPI *pGlobalFree)(HGLOBAL); static int thread_from_line; static char *argv0; +#define open_clipboard(hwnd) open_clipboard_(__LINE__, hwnd) +static BOOL open_clipboard_(int line, HWND hwnd) +{ + DWORD start = GetTickCount(); + while (1) + { + BOOL ret = OpenClipboard(hwnd); + if (ret || GetLastError() != ERROR_ACCESS_DENIED) + return ret; + if (GetTickCount() - start > 100) + { + char classname[256]; + DWORD le = GetLastError(); + HWND clipwnd = GetOpenClipboardWindow(); + /* Provide a hint as to the source of interference: + * - The class name would typically be CLIPBRDWNDCLASS if the + * clipboard was opened by a Windows application using the + * ole32 API. + * - And it would be __wine_clipboard_manager if it was opened in + * response to a native application. + */ + GetClassNameA(clipwnd, classname, ARRAY_SIZE(classname)); + trace_(__FILE__, line)("%p (%s) opened the clipboard\n", clipwnd, classname); + SetLastError(le); + return ret; + } + Sleep(15); + } +} + +#define has_no_open_wnd() has_no_open_wnd_(__LINE__) +static BOOL has_no_open_wnd_(int line) +{ + DWORD start = GetTickCount(); + DWORD le = GetLastError(); + while (1) + { + HWND clipwnd = GetOpenClipboardWindow(); + if (!clipwnd) return TRUE; + if (GetTickCount() - start > 100) + { + char classname[256]; + le = GetLastError(); + /* See open_clipboard() */ + GetClassNameA(clipwnd, classname, ARRAY_SIZE(classname)); + trace_(__FILE__, line)("%p (%s) opened the clipboard\n", clipwnd, classname); + SetLastError(le); + return FALSE; + } + Sleep(15); + SetLastError(le); + } +} + static DWORD WINAPI open_clipboard_thread(LPVOID arg) { HWND hWnd = arg; - ok(OpenClipboard(hWnd), "%u: OpenClipboard failed\n", thread_from_line); + ok(open_clipboard(hWnd), "%u: OpenClipboard failed\n", thread_from_line); return 0; } @@ -44,7 +99,7 @@ static DWORD WINAPI empty_clipboard_thread(LPVOID arg) { SetLastError( 0xdeadbeef ); ok(!EmptyClipboard(), "%u: EmptyClipboard succeeded\n", thread_from_line ); - ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "%u: wrong error %u\n", + ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "%u: wrong error %lu\n", thread_from_line, GetLastError()); return 0; } @@ -52,7 +107,7 @@ static DWORD WINAPI empty_clipboard_thread(LPVOID arg) static DWORD WINAPI open_and_empty_clipboard_thread(LPVOID arg) { HWND hWnd = arg; - ok(OpenClipboard(hWnd), "%u: OpenClipboard failed\n", thread_from_line); + ok(open_clipboard(hWnd), "%u: OpenClipboard failed\n", thread_from_line); ok(EmptyClipboard(), "%u: EmptyClipboard failed\n", thread_from_line ); return 0; } @@ -60,7 +115,7 @@ static DWORD WINAPI open_and_empty_clipboard_thread(LPVOID arg) static DWORD WINAPI open_and_empty_clipboard_win_thread(LPVOID arg) { HWND hwnd = CreateWindowA( "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL ); - ok(OpenClipboard(hwnd), "%u: OpenClipboard failed\n", thread_from_line); + ok(open_clipboard(hwnd), "%u: OpenClipboard failed\n", thread_from_line); ok(EmptyClipboard(), "%u: EmptyClipboard failed\n", thread_from_line ); return 0; } @@ -76,22 +131,22 @@ static DWORD WINAPI set_clipboard_data_thread(LPVOID arg) SetClipboardData( CF_WAVE, 0 ); ok( IsClipboardFormatAvailable( CF_WAVE ), "%u: SetClipboardData failed\n", thread_from_line ); ret = SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_DDESHARE | GMEM_ZEROINIT, 100 )); - ok( ret != 0, "%u: SetClipboardData failed err %u\n", thread_from_line, GetLastError() ); + ok( ret != 0, "%u: SetClipboardData failed err %lu\n", thread_from_line, GetLastError() ); SetLastError( 0xdeadbeef ); ret = GetClipboardData( CF_WAVE ); ok( !ret, "%u: GetClipboardData succeeded\n", thread_from_line ); - ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "%u: wrong error %u\n", + ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "%u: wrong error %lu\n", thread_from_line, GetLastError()); } else { SetClipboardData( CF_WAVE, 0 ); - ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "%u: wrong error %u\n", + ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "%u: wrong error %lu\n", thread_from_line, GetLastError()); ok( !IsClipboardFormatAvailable( CF_WAVE ), "%u: SetClipboardData succeeded\n", thread_from_line ); ret = SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_DDESHARE | GMEM_ZEROINIT, 100 )); ok( !ret, "%u: SetClipboardData succeeded\n", thread_from_line ); - ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "%u: wrong error %u\n", + ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "%u: wrong error %lu\n", thread_from_line, GetLastError()); } return 0; @@ -101,24 +156,26 @@ static void set_clipboard_data_process( int arg ) { HANDLE ret; + winetest_push_context("process %u", arg); SetLastError( 0xdeadbeef ); if (arg) { - ok( IsClipboardFormatAvailable( CF_WAVE ), "process %u: CF_WAVE not available\n", arg ); + ok( IsClipboardFormatAvailable( CF_WAVE ), "CF_WAVE not available\n" ); ret = SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_DDESHARE | GMEM_ZEROINIT, 100 )); - ok( ret != 0, "process %u: SetClipboardData failed err %u\n", arg, GetLastError() ); + ok( ret != 0, "SetClipboardData failed err %lu\n", GetLastError() ); } else { SetClipboardData( CF_WAVE, 0 ); - ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "process %u: wrong error %u\n", - arg, GetLastError()); - ok( !IsClipboardFormatAvailable( CF_WAVE ), "process %u: SetClipboardData succeeded\n", arg ); + ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "wrong error %lu\n", + GetLastError()); + ok( !IsClipboardFormatAvailable( CF_WAVE ), "SetClipboardData succeeded\n" ); ret = SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_DDESHARE | GMEM_ZEROINIT, 100 )); - ok( !ret, "process %u: SetClipboardData succeeded\n", arg ); - ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "process %u: wrong error %u\n", - arg, GetLastError()); + ok( !ret, "SetClipboardData succeeded\n" ); + ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "wrong error %lu\n", + GetLastError()); } + winetest_pop_context(); } static void grab_clipboard_process( int arg ) @@ -126,14 +183,14 @@ static void grab_clipboard_process( int arg ) BOOL ret; SetLastError( 0xdeadbeef ); - ret = OpenClipboard( 0 ); + ret = open_clipboard( 0 ); ok( ret, "OpenClipboard failed\n" ); ret = EmptyClipboard(); ok( ret, "EmptyClipboard failed\n" ); if (arg) { HANDLE ret = SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_DDESHARE | GMEM_ZEROINIT, 100 )); - ok( ret != 0, "process %u: SetClipboardData failed err %u\n", arg, GetLastError() ); + ok( ret != 0, "process %u: SetClipboardData failed err %lu\n", arg, GetLastError() ); } } @@ -144,7 +201,7 @@ static void run_thread( LPTHREAD_START_ROUTINE func, void *arg, int line ) thread_from_line = line; thread = CreateThread(NULL, 0, func, arg, 0, NULL); - ok(thread != NULL, "%u: CreateThread failed with error %d\n", line, GetLastError()); + ok(thread != NULL, "%u: CreateThread failed with error %ld\n", line, GetLastError()); for (;;) { ret = MsgWaitForMultipleObjectsEx( 1, &thread, 1000, QS_ALLINPUT, 0 ); @@ -155,7 +212,7 @@ static void run_thread( LPTHREAD_START_ROUTINE func, void *arg, int line ) } else break; } - ok(ret == WAIT_OBJECT_0, "%u: expected WAIT_OBJECT_0, got %u\n", line, ret); + ok(ret == WAIT_OBJECT_0, "%u: expected WAIT_OBJECT_0, got %lu\n", line, ret); CloseHandle(thread); } @@ -171,7 +228,7 @@ static void run_process( const char *args ) ok( CreateProcessA( NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info ), "CreateProcess %s failed\n", cmd ); - winetest_wait_child_process( info.hProcess ); + wait_child_process( info.hProcess ); CloseHandle( info.hProcess ); CloseHandle( info.hThread ); } @@ -208,11 +265,11 @@ static LRESULT CALLBACK winproc_wrapper( HWND hwnd, UINT msg, WPARAM wp, LPARAM ok( wm_drawclipboard, "didn't receive WM_DRAWCLIPBOARD before WM_DESTROY\n" ); break; case WM_DRAWCLIPBOARD: - ok( msg_flags == ISMEX_NOSEND, "WM_DRAWCLIPBOARD wrong flags %x\n", msg_flags ); + ok( msg_flags == ISMEX_NOSEND, "WM_DRAWCLIPBOARD wrong flags %lx\n", msg_flags ); wm_drawclipboard++; break; case WM_RENDERALLFORMATS: - ok( msg_flags == ISMEX_NOSEND, "WM_RENDERALLFORMATS wrong flags %x\n", msg_flags ); + ok( msg_flags == ISMEX_NOSEND, "WM_RENDERALLFORMATS wrong flags %lx\n", msg_flags ); wm_renderallformats++; break; } @@ -230,27 +287,27 @@ static void test_ClipboardOwner(void) hWnd1 = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL); - ok(hWnd1 != 0, "CreateWindowExA error %d\n", GetLastError()); + ok(hWnd1 != 0, "CreateWindowExA error %ld\n", GetLastError()); trace("hWnd1 = %p\n", hWnd1); hWnd2 = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL); - ok(hWnd2 != 0, "CreateWindowExA error %d\n", GetLastError()); + ok(hWnd2 != 0, "CreateWindowExA error %ld\n", GetLastError()); trace("hWnd2 = %p\n", hWnd2); SetLastError(0xdeadbeef); ok(!CloseClipboard(), "CloseClipboard should fail if clipboard wasn't open\n"); ok(GetLastError() == ERROR_CLIPBOARD_NOT_OPEN || broken(GetLastError() == 0xdeadbeef), /* wow64 */ - "wrong error %u\n", GetLastError()); + "wrong error %lu\n", GetLastError()); - ok(OpenClipboard(0), "OpenClipboard failed\n"); + ok(open_clipboard(0), "OpenClipboard failed\n"); ok(!GetClipboardOwner(), "clipboard should still be not owned\n"); ok(!OpenClipboard(hWnd1), "OpenClipboard should fail since clipboard already opened\n"); - ok(OpenClipboard(0), "OpenClipboard again failed\n"); + ok(open_clipboard(0), "OpenClipboard again failed\n"); ret = CloseClipboard(); - ok( ret, "CloseClipboard error %d\n", GetLastError()); + ok( ret, "CloseClipboard error %ld\n", GetLastError()); - ok(OpenClipboard(hWnd1), "OpenClipboard failed\n"); + ok(open_clipboard(hWnd1), "OpenClipboard failed\n"); run_thread( open_clipboard_thread, hWnd1, __LINE__ ); run_thread( empty_clipboard_thread, 0, __LINE__ ); run_thread( set_clipboard_data_thread, hWnd1, __LINE__ ); @@ -258,17 +315,17 @@ static void test_ClipboardOwner(void) ok( !GetClipboardData( CF_WAVE ), "CF_WAVE data available\n" ); run_process( "set_clipboard_data 0" ); ok(!CloseClipboard(), "CloseClipboard should fail if clipboard wasn't open\n"); - ok(OpenClipboard(hWnd1), "OpenClipboard failed\n"); + ok(open_clipboard(hWnd1), "OpenClipboard failed\n"); SetLastError(0xdeadbeef); ret = OpenClipboard(hWnd2); ok(!ret && (GetLastError() == 0xdeadbeef || GetLastError() == ERROR_ACCESS_DENIED), - "OpenClipboard should fail without setting last error value, or with ERROR_ACCESS_DENIED, got error %d\n", GetLastError()); + "OpenClipboard should fail without setting last error value, or with ERROR_ACCESS_DENIED, got error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ok(!GetClipboardOwner() && GetLastError() == 0xdeadbeef, "clipboard should still be not owned\n"); ret = EmptyClipboard(); - ok( ret, "EmptyClipboard error %d\n", GetLastError()); + ok( ret, "EmptyClipboard error %ld\n", GetLastError()); ok(GetClipboardOwner() == hWnd1, "clipboard should be owned by %p, not by %p\n", hWnd1, GetClipboardOwner()); run_thread( empty_clipboard_thread, 0, __LINE__ ); run_thread( set_clipboard_data_thread, hWnd1, __LINE__ ); @@ -279,17 +336,17 @@ static void test_ClipboardOwner(void) SetLastError(0xdeadbeef); ret = OpenClipboard(hWnd2); ok(!ret && (GetLastError() == 0xdeadbeef || GetLastError() == ERROR_ACCESS_DENIED), - "OpenClipboard should fail without setting last error value, or with ERROR_ACCESS_DENIED, got error %d\n", GetLastError()); + "OpenClipboard should fail without setting last error value, or with ERROR_ACCESS_DENIED, got error %ld\n", GetLastError()); ret = CloseClipboard(); - ok( ret, "CloseClipboard error %d\n", GetLastError()); + ok( ret, "CloseClipboard error %ld\n", GetLastError()); ok(GetClipboardOwner() == hWnd1, "clipboard should still be owned\n"); /* any window will do, even from a different process */ - ret = OpenClipboard( GetDesktopWindow() ); - ok( ret, "OpenClipboard error %d\n", GetLastError()); + ret = open_clipboard( GetDesktopWindow() ); + ok( ret, "OpenClipboard error %ld\n", GetLastError()); ret = EmptyClipboard(); - ok( ret, "EmptyClipboard error %d\n", GetLastError()); + ok( ret, "EmptyClipboard error %ld\n", GetLastError()); ok( GetClipboardOwner() == GetDesktopWindow(), "wrong owner %p/%p\n", GetClipboardOwner(), GetDesktopWindow() ); run_thread( set_clipboard_data_thread, GetDesktopWindow(), __LINE__ ); @@ -297,12 +354,12 @@ static void test_ClipboardOwner(void) ok( GetClipboardData( CF_WAVE ) != 0, "CF_WAVE data not available\n" ); run_process( "set_clipboard_data 2" ); ret = CloseClipboard(); - ok( ret, "CloseClipboard error %d\n", GetLastError()); + ok( ret, "CloseClipboard error %ld\n", GetLastError()); - ret = OpenClipboard( hWnd1 ); - ok( ret, "OpenClipboard error %d\n", GetLastError()); + ret = open_clipboard( hWnd1 ); + ok( ret, "OpenClipboard error %ld\n", GetLastError()); ret = EmptyClipboard(); - ok( ret, "EmptyClipboard error %d\n", GetLastError()); + ok( ret, "EmptyClipboard error %ld\n", GetLastError()); SetClipboardData( CF_WAVE, 0 ); SetClipboardViewer( hWnd1 ); ok( GetClipboardOwner() == hWnd1, "wrong owner %p/%p\n", GetClipboardOwner(), hWnd1 ); @@ -312,57 +369,57 @@ static void test_ClipboardOwner(void) old_proc = (WNDPROC)SetWindowLongPtrA( hWnd1, GWLP_WNDPROC, (LONG_PTR)winproc_wrapper ); ret = DestroyWindow(hWnd1); - ok( ret, "DestroyWindow error %d\n", GetLastError()); + ok( ret, "DestroyWindow error %ld\n", GetLastError()); ret = DestroyWindow(hWnd2); - ok( ret, "DestroyWindow error %d\n", GetLastError()); + ok( ret, "DestroyWindow error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ok(!GetClipboardOwner() && GetLastError() == 0xdeadbeef, "clipboard should not be owned\n"); ok(!GetClipboardViewer() && GetLastError() == 0xdeadbeef, "viewer still exists\n"); - ok(!GetOpenClipboardWindow() && GetLastError() == 0xdeadbeef, "clipboard should not be open\n"); + ok( has_no_open_wnd() && GetLastError() == 0xdeadbeef, "clipboard should not be open\n"); ok( !IsClipboardFormatAvailable( CF_WAVE ), "CF_WAVE available\n" ); SetLastError( 0xdeadbeef ); ret = CloseClipboard(); ok( !ret, "CloseClipboard succeeded\n" ); - ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "wrong error %lu\n", GetLastError() ); - ret = OpenClipboard( 0 ); - ok( ret, "OpenClipboard error %d\n", GetLastError()); + ret = open_clipboard( 0 ); + ok( ret, "OpenClipboard error %ld\n", GetLastError()); run_thread( set_clipboard_data_thread, 0, __LINE__ ); ok( IsClipboardFormatAvailable( CF_WAVE ), "CF_WAVE not available\n" ); ok( GetClipboardData( CF_WAVE ) != 0, "CF_WAVE data not available\n" ); run_process( "set_clipboard_data 3" ); ret = CloseClipboard(); - ok( ret, "CloseClipboard error %d\n", GetLastError()); + ok( ret, "CloseClipboard error %ld\n", GetLastError()); run_thread( open_and_empty_clipboard_thread, 0, __LINE__ ); - ok( !GetOpenClipboardWindow(), "wrong open window %p\n", GetOpenClipboardWindow() ); + ok( has_no_open_wnd(), "wrong open window\n" ); ok( !GetClipboardOwner(), "wrong owner window %p\n", GetClipboardOwner() ); - ret = OpenClipboard( 0 ); - ok( ret, "OpenClipboard error %d\n", GetLastError()); + ret = open_clipboard( 0 ); + ok( ret, "OpenClipboard error %ld\n", GetLastError()); run_thread( set_clipboard_data_thread, 0, __LINE__ ); ok( IsClipboardFormatAvailable( CF_WAVE ), "CF_WAVE not available\n" ); ok( GetClipboardData( CF_WAVE ) != 0, "CF_WAVE data not available\n" ); run_process( "set_clipboard_data 4" ); ret = EmptyClipboard(); - ok( ret, "EmptyClipboard error %d\n", GetLastError()); + ok( ret, "EmptyClipboard error %ld\n", GetLastError()); ret = CloseClipboard(); - ok( ret, "CloseClipboard error %d\n", GetLastError()); + ok( ret, "CloseClipboard error %ld\n", GetLastError()); SetLastError( 0xdeadbeef ); ok( !SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_DDESHARE | GMEM_ZEROINIT, 100 )), "SetClipboardData succeeded\n" ); - ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "wrong error %lu\n", GetLastError() ); ok( !IsClipboardFormatAvailable( CF_WAVE ), "SetClipboardData succeeded\n" ); run_thread( open_and_empty_clipboard_thread, GetDesktopWindow(), __LINE__ ); - ok( !GetOpenClipboardWindow(), "wrong open window %p\n", GetOpenClipboardWindow() ); + ok( has_no_open_wnd(), "wrong open window\n" ); ok( GetClipboardOwner() == GetDesktopWindow(), "wrong owner window %p / %p\n", GetClipboardOwner(), GetDesktopWindow() ); run_thread( open_and_empty_clipboard_win_thread, 0, __LINE__ ); - ok( !GetOpenClipboardWindow(), "wrong open window %p\n", GetOpenClipboardWindow() ); + ok( has_no_open_wnd(), "wrong open window\n" ); ok( !GetClipboardOwner(), "wrong owner window %p\n", GetClipboardOwner() ); } @@ -381,7 +438,7 @@ static void test_RegisterClipboardFormatA(void) format_id2 = RegisterClipboardFormatA("MY_COOL_CLIPBOARD_FORMAT"); ok(format_id2 == format_id, "invalid clipboard format id %04x\n", format_id2); - len = GetClipboardFormatNameA(format_id, buf, 256); + len = GetClipboardFormatNameA(format_id, buf, ARRAY_SIZE(buf)); ok(len == lstrlenA("my_cool_clipboard_format"), "wrong format name length %d\n", len); ok(!lstrcmpA(buf, "my_cool_clipboard_format"), "wrong format name \"%s\"\n", buf); @@ -390,37 +447,38 @@ static void test_RegisterClipboardFormatA(void) lstrcpyA(buf, "foo"); SetLastError(0xdeadbeef); - len = GetAtomNameA((ATOM)format_id, buf, 256); - ok(len == 0, "GetAtomNameA should fail\n"); - ok(GetLastError() == ERROR_INVALID_HANDLE, "err %d\n", GetLastError()); + len = GetAtomNameA((ATOM)format_id, buf, ARRAY_SIZE(buf)); + ok(len == 0 || lstrcmpA(buf, "my_cool_clipboard_format") != 0, + "format_id should not be a valid local atom\n"); + ok(len != 0 || GetLastError() == ERROR_INVALID_HANDLE, + "err %ld\n", GetLastError()); -todo_wine -{ lstrcpyA(buf, "foo"); SetLastError(0xdeadbeef); - len = GlobalGetAtomNameA((ATOM)format_id, buf, 256); - ok(len == 0, "GlobalGetAtomNameA should fail\n"); - ok(GetLastError() == ERROR_INVALID_HANDLE, "err %d\n", GetLastError()); -} + len = GlobalGetAtomNameA((ATOM)format_id, buf, ARRAY_SIZE(buf)); + todo_wine ok(len == 0 || lstrcmpA(buf, "my_cool_clipboard_format") != 0, + "format_id should not be a valid global atom\n"); + ok(len != 0 || GetLastError() == ERROR_INVALID_HANDLE, + "err %ld\n", GetLastError()); SetLastError(0xdeadbeef); atom_id = FindAtomA("my_cool_clipboard_format"); - ok(atom_id == 0, "FindAtomA should fail\n"); - ok(GetLastError() == ERROR_FILE_NOT_FOUND, "err %d\n", GetLastError()); + ok(atom_id == 0, "FindAtomA should fail, but it returned %x (format_id=%x)\n", atom_id, format_id); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "err %ld\n", GetLastError()); - if (0) + todo_wine { /* this relies on the clipboard and global atom table being different */ SetLastError(0xdeadbeef); atom_id = GlobalFindAtomA("my_cool_clipboard_format"); - ok(atom_id == 0, "GlobalFindAtomA should fail\n"); - ok(GetLastError() == ERROR_FILE_NOT_FOUND, "err %d\n", GetLastError()); + ok(atom_id == 0, "GlobalFindAtomA should fail, but it returned %x (format_id=%x)\n", atom_id, format_id); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "err %ld\n", GetLastError()); } for (format_id = 0; format_id < 0x10fff; format_id++) { SetLastError(0xdeadbeef); - len = GetClipboardFormatNameA(format_id, buf, 256); + len = GetClipboardFormatNameA(format_id, buf, ARRAY_SIZE(buf)); if (format_id < 0xc000 || format_id > 0xffff) ok(!len, "GetClipboardFormatNameA should fail, but it returned %d (%s)\n", len, buf); @@ -428,20 +486,20 @@ todo_wine trace("%04x: %s\n", format_id, len ? buf : ""); } - ret = OpenClipboard(0); - ok( ret, "OpenClipboard error %d\n", GetLastError()); + ret = open_clipboard(0); + ok( ret, "OpenClipboard error %ld\n", GetLastError()); /* try some invalid/unregistered formats */ SetLastError( 0xdeadbeef ); handle = SetClipboardData( 0, GlobalAlloc( GMEM_DDESHARE | GMEM_MOVEABLE, 1 )); ok( !handle, "SetClipboardData succeeded\n" ); - ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "wrong error %u\n", GetLastError()); + ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "wrong error %lu\n", GetLastError()); handle = SetClipboardData( 0x1234, GlobalAlloc( GMEM_DDESHARE | GMEM_MOVEABLE, 1 )); - ok( handle != 0, "SetClipboardData failed err %d\n", GetLastError()); + ok( handle != 0, "SetClipboardData failed err %ld\n", GetLastError()); handle = SetClipboardData( 0x123456, GlobalAlloc( GMEM_DDESHARE | GMEM_MOVEABLE, 1 )); - ok( handle != 0, "SetClipboardData failed err %d\n", GetLastError()); + ok( handle != 0, "SetClipboardData failed err %ld\n", GetLastError()); handle = SetClipboardData( 0xffff8765, GlobalAlloc( GMEM_DDESHARE | GMEM_MOVEABLE, 1 )); - ok( handle != 0, "SetClipboardData failed err %d\n", GetLastError()); + ok( handle != 0, "SetClipboardData failed err %ld\n", GetLastError()); ok( IsClipboardFormatAvailable( 0x1234 ), "format missing\n" ); ok( IsClipboardFormatAvailable( 0x123456 ), "format missing\n" ); @@ -456,27 +514,27 @@ todo_wine while ((format_id = EnumClipboardFormats(format_id))) { ok(IsClipboardFormatAvailable(format_id), "format %04x was listed as available\n", format_id); - len = GetClipboardFormatNameA(format_id, buf, 256); + len = GetClipboardFormatNameA(format_id, buf, ARRAY_SIZE(buf)); trace("%04x: %s\n", format_id, len ? buf : ""); } ret = EmptyClipboard(); - ok( ret, "EmptyClipboard error %d\n", GetLastError()); + ok( ret, "EmptyClipboard error %ld\n", GetLastError()); ret =CloseClipboard(); - ok( ret, "CloseClipboard error %d\n", GetLastError()); + ok( ret, "CloseClipboard error %ld\n", GetLastError()); if (CountClipboardFormats()) { SetLastError(0xdeadbeef); ok(!EnumClipboardFormats(0), "EnumClipboardFormats should fail if clipboard wasn't open\n"); ok(GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, - "Last error should be set to ERROR_CLIPBOARD_NOT_OPEN, not %d\n", GetLastError()); + "Last error should be set to ERROR_CLIPBOARD_NOT_OPEN, not %ld\n", GetLastError()); } SetLastError(0xdeadbeef); ok(!EmptyClipboard(), "EmptyClipboard should fail if clipboard wasn't open\n"); ok(GetLastError() == ERROR_CLIPBOARD_NOT_OPEN || broken(GetLastError() == 0xdeadbeef), /* wow64 */ - "Wrong error %u\n", GetLastError()); + "Wrong error %lu\n", GetLastError()); format_id = RegisterClipboardFormatA("#1234"); ok(format_id == 1234, "invalid clipboard format id %04x\n", format_id); @@ -610,34 +668,34 @@ static void test_synthesized(void) htext = create_textA(); emf = create_emf(); - r = OpenClipboard(NULL); - ok(r, "gle %d\n", GetLastError()); + r = open_clipboard(NULL); + ok(r, "gle %ld\n", GetLastError()); r = EmptyClipboard(); - ok(r, "gle %d\n", GetLastError()); + ok(r, "gle %ld\n", GetLastError()); h = SetClipboardData(CF_TEXT, htext); ok(h == htext, "got %p\n", h); h = SetClipboardData(CF_ENHMETAFILE, emf); ok(h == emf, "got %p\n", h); r = CloseClipboard(); - ok(r, "gle %d\n", GetLastError()); + ok(r, "gle %ld\n", GetLastError()); count = CountClipboardFormats(); ok( count == 6, "count %u\n", count ); r = IsClipboardFormatAvailable( CF_TEXT ); - ok( r, "CF_TEXT not available err %d\n", GetLastError()); + ok( r, "CF_TEXT not available err %ld\n", GetLastError()); r = IsClipboardFormatAvailable( CF_LOCALE ); - ok( r, "CF_LOCALE not available err %d\n", GetLastError()); + ok( r, "CF_LOCALE not available err %ld\n", GetLastError()); r = IsClipboardFormatAvailable( CF_OEMTEXT ); - ok( r, "CF_OEMTEXT not available err %d\n", GetLastError()); + ok( r, "CF_OEMTEXT not available err %ld\n", GetLastError()); r = IsClipboardFormatAvailable( CF_UNICODETEXT ); - ok( r, "CF_UNICODETEXT not available err %d\n", GetLastError()); + ok( r, "CF_UNICODETEXT not available err %ld\n", GetLastError()); r = IsClipboardFormatAvailable( CF_ENHMETAFILE ); - ok( r, "CF_ENHMETAFILE not available err %d\n", GetLastError()); + ok( r, "CF_ENHMETAFILE not available err %ld\n", GetLastError()); r = IsClipboardFormatAvailable( CF_METAFILEPICT ); - ok( r, "CF_METAFILEPICT not available err %d\n", GetLastError()); + ok( r, "CF_METAFILEPICT not available err %ld\n", GetLastError()); - r = OpenClipboard(NULL); - ok(r, "gle %d\n", GetLastError()); + r = open_clipboard(NULL); + ok(r, "gle %ld\n", GetLastError()); cf = EnumClipboardFormats(0); ok(cf == CF_TEXT, "cf %08x\n", cf); data = GetClipboardData(cf); @@ -670,53 +728,54 @@ static void test_synthesized(void) ok(cf == 0, "cf %08x\n", cf); r = EmptyClipboard(); - ok(r, "gle %d\n", GetLastError()); + ok(r, "gle %ld\n", GetLastError()); SetClipboardData( CF_UNICODETEXT, create_textW() ); SetClipboardData( CF_TEXT, create_textA() ); SetClipboardData( CF_OEMTEXT, create_textA() ); r = CloseClipboard(); - ok(r, "gle %d\n", GetLastError()); + ok(r, "gle %ld\n", GetLastError()); - r = OpenClipboard( NULL ); - ok(r, "gle %d\n", GetLastError()); + r = open_clipboard( NULL ); + ok(r, "gle %ld\n", GetLastError()); SetLastError( 0xdeadbeef ); cf = EnumClipboardFormats(0); ok( cf == CF_UNICODETEXT, "cf %08x\n", cf ); - ok( GetLastError() == ERROR_SUCCESS, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_SUCCESS, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); cf = EnumClipboardFormats(cf); ok( cf == CF_TEXT, "cf %08x\n", cf ); - ok( GetLastError() == ERROR_SUCCESS, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_SUCCESS, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); cf = EnumClipboardFormats(cf); ok( cf == CF_OEMTEXT, "cf %08x\n", cf ); - ok( GetLastError() == ERROR_SUCCESS, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_SUCCESS, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); cf = EnumClipboardFormats(cf); ok( cf == CF_LOCALE, "cf %08x\n", cf ); - ok( GetLastError() == ERROR_SUCCESS, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_SUCCESS, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); cf = EnumClipboardFormats( cf ); ok( cf == 0, "cf %08x\n", cf ); - ok( GetLastError() == ERROR_SUCCESS, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_SUCCESS, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); cf = EnumClipboardFormats( 0xdead ); ok( cf == 0, "cf %08x\n", cf ); - ok( GetLastError() == ERROR_SUCCESS, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_SUCCESS, "wrong error %lu\n", GetLastError() ); r = EmptyClipboard(); - ok(r, "gle %d\n", GetLastError()); + ok(r, "gle %ld\n", GetLastError()); r = CloseClipboard(); - ok(r, "gle %d\n", GetLastError()); + ok(r, "gle %ld\n", GetLastError()); for (i = 0; i < ARRAY_SIZE(tests); i++) { - r = OpenClipboard(NULL); - ok(r, "%u: gle %d\n", i, GetLastError()); + winetest_push_context("%d", i); + r = open_clipboard(NULL); + ok(r, "gle %ld\n", GetLastError()); r = EmptyClipboard(); - ok(r, "%u: gle %d\n", i, GetLastError()); + ok(r, "gle %ld\n", GetLastError()); switch (tests[i].format) { @@ -743,146 +802,203 @@ static void test_synthesized(void) } count = CountClipboardFormats(); - ok( count == 1, "%u: count %u\n", i, count ); + ok( count == 1, "count %u\n", count ); r = CloseClipboard(); - ok(r, "%u: gle %d\n", i, GetLastError()); + ok(r, "gle %ld\n", GetLastError()); count = CountClipboardFormats(); for (j = 0; tests[i].expected[j]; j++) { r = IsClipboardFormatAvailable( tests[i].expected[j] ); - ok( r, "%u: %04x not available\n", i, tests[i].expected[j] ); + ok( r, "%04x not available\n", tests[i].expected[j] ); } - ok( count == j, "%u: count %u instead of %u\n", i, count, j ); + ok( count == j, "count %u instead of %u\n", count, j ); - r = OpenClipboard( hwnd ); - ok(r, "%u: gle %d\n", i, GetLastError()); + r = open_clipboard( hwnd ); + ok(r, "gle %ld\n", GetLastError()); cf = 0; for (j = 0; tests[i].expected[j]; j++) { + winetest_push_context("%d", j); cf = EnumClipboardFormats( cf ); - ok(cf == tests[i].expected[j], "%u.%u: got %04x instead of %04x\n", - i, j, cf, tests[i].expected[j] ); - if (cf != tests[i].expected[j]) break; + ok(cf == tests[i].expected[j], "got %04x instead of %04x\n", + cf, tests[i].expected[j] ); + if (cf != tests[i].expected[j]) + { + winetest_pop_context(); + break; + } old_seq = GetClipboardSequenceNumber(); data = GetClipboardData( cf ); ok(data != NULL || broken( tests[i].format == CF_DIBV5 && cf == CF_DIB ), /* >= Vista */ - "%u: couldn't get data, cf %04x err %d\n", i, cf, GetLastError()); + "couldn't get data, cf %04x err %ld\n", cf, GetLastError()); seq = GetClipboardSequenceNumber(); - ok(seq == old_seq, "sequence changed (test %d %d)\n", i, cf); + ok(seq == old_seq, "sequence changed (test %d)\n", cf); switch (cf) { case CF_LOCALE: { UINT *ptr = GlobalLock( data ); - ok( GlobalSize( data ) == sizeof(*ptr), "%u: size %lu\n", i, GlobalSize( data )); - ok( *ptr == GetUserDefaultLCID() || + DWORD layout = LOWORD( GetKeyboardLayout(0) ); + ok( GlobalSize( data ) == sizeof(*ptr), "size %Iu\n", GlobalSize( data )); + ok( *ptr == layout || broken( *ptr == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )), - "%u: CF_LOCALE %08x/%08x\n", i, *ptr, GetUserDefaultLCID() ); + "CF_LOCALE %04x/%04lx\n", *ptr, layout ); GlobalUnlock( data ); break; } case CF_TEXT: case CF_OEMTEXT: - ok( GlobalSize( data ) == 10, "wrong len %ld\n", GlobalSize( data )); + ok( GlobalSize( data ) == 10, "wrong len %Id\n", GlobalSize( data )); break; case CF_UNICODETEXT: - ok( GlobalSize( data ) == 10 * sizeof(WCHAR), "wrong len %ld\n", GlobalSize( data )); + ok( GlobalSize( data ) == 10 * sizeof(WCHAR), "wrong len %Id\n", GlobalSize( data )); break; } + winetest_pop_context(); } if (!tests[i].expected[j]) { cf = EnumClipboardFormats( cf ); - ok(cf == 0, "%u: cf %04x\n", i, cf); + ok(cf == 0, "cf %04x\n", cf); } /* now with delayed rendering */ r = EmptyClipboard(); - ok(r, "%u: gle %d\n", i, GetLastError()); + ok(r, "gle %ld\n", GetLastError()); rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); - ok( !rendered, "%u: formats %08x have been rendered\n", i, rendered ); + ok( !rendered, "formats %08x have been rendered\n", rendered ); SetClipboardData( tests[i].format, 0 ); rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); - ok( !rendered, "%u: formats %08x have been rendered\n", i, rendered ); + ok( !rendered, "formats %08x have been rendered\n", rendered ); count = CountClipboardFormats(); - ok( count == 1, "%u: count %u\n", i, count ); + ok( count == 1, "count %u\n", count ); r = CloseClipboard(); - ok(r, "%u: gle %d\n", i, GetLastError()); + ok(r, "gle %ld\n", GetLastError()); rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); - ok( !rendered, "%u: formats %08x have been rendered\n", i, rendered ); + ok( !rendered, "formats %08x have been rendered\n", rendered ); count = CountClipboardFormats(); for (j = 0; tests[i].expected[j]; j++) { r = IsClipboardFormatAvailable( tests[i].expected[j] ); - ok( r, "%u: %04x not available\n", i, tests[i].expected[j] ); + ok( r, "%04x not available\n", tests[i].expected[j] ); } - ok( count == j, "%u: count %u instead of %u\n", i, count, j ); + ok( count == j, "count %u instead of %u\n", count, j ); rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); - ok( !rendered, "%u: formats %08x have been rendered\n", i, rendered ); + ok( !rendered, "formats %08x have been rendered\n", rendered ); - r = OpenClipboard(NULL); - ok(r, "%u: gle %d\n", i, GetLastError()); + r = open_clipboard(NULL); + ok(r, "gle %ld\n", GetLastError()); cf = 0; for (j = 0; tests[i].expected[j]; j++) { + winetest_push_context("%d", j); cf = EnumClipboardFormats( cf ); - ok(cf == tests[i].expected[j], "%u.%u: got %04x instead of %04x\n", - i, j, cf, tests[i].expected[j] ); - if (cf != tests[i].expected[j]) break; + ok(cf == tests[i].expected[j], "got %04x instead of %04x\n", + cf, tests[i].expected[j] ); + if (cf != tests[i].expected[j]) + { + winetest_pop_context(); + break; + } rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); - ok( !rendered, "%u.%u: formats %08x have been rendered\n", i, j, rendered ); + ok( !rendered, "formats %08x have been rendered\n", rendered ); data = GetClipboardData( cf ); rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); if (cf == CF_LOCALE) { - ok(data != NULL, "%u: CF_LOCALE no data\n", i); - ok( !rendered, "%u.%u: formats %08x have been rendered\n", i, j, rendered ); + ok(data != NULL, "CF_LOCALE no data\n"); + ok( !rendered, "formats %08x have been rendered\n", rendered ); } else { - ok(!data, "%u: format %04x got data %p\n", i, cf, data); + ok(!data, "format %04x got data %p\n", cf, data); ok( rendered == (1 << tests[i].format), - "%u.%u: formats %08x have been rendered\n", i, j, rendered ); + "formats %08x have been rendered\n", rendered ); /* try to render a second time */ data = GetClipboardData( cf ); rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); ok( rendered == (1 << tests[i].format), - "%u.%u: formats %08x have been rendered\n", i, j, rendered ); + "formats %08x have been rendered\n", rendered ); } + winetest_pop_context(); } if (!tests[i].expected[j]) { cf = EnumClipboardFormats( cf ); - ok(cf == 0, "%u: cf %04x\n", i, cf); + ok(cf == 0, "cf %04x\n", cf); } r = CloseClipboard(); - ok(r, "%u: gle %d\n", i, GetLastError()); + ok(r, "gle %ld\n", GetLastError()); rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); - ok( !rendered, "%u: formats %08x have been rendered\n", i, rendered ); + ok( !rendered, "formats %08x have been rendered\n", rendered ); + winetest_pop_context(); } - r = OpenClipboard(NULL); - ok(r, "gle %d\n", GetLastError()); + r = open_clipboard(NULL); + ok(r, "gle %ld\n", GetLastError()); r = EmptyClipboard(); - ok(r, "gle %d\n", GetLastError()); + ok(r, "gle %ld\n", GetLastError()); r = CloseClipboard(); - ok(r, "gle %d\n", GetLastError()); + ok(r, "gle %ld\n", GetLastError()); DestroyWindow( hwnd ); + + /* Check what happens to the delayed rendering clipboard formats when the + * owner window is destroyed. + */ + hwnd = CreateWindowA( "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL ); + SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)renderer_winproc ); + + r = open_clipboard(hwnd); + ok(r, "gle %ld\n", GetLastError()); + r = EmptyClipboard(); + ok(r, "gle %ld\n", GetLastError()); + SetClipboardData( CF_UNICODETEXT, NULL ); + r = CloseClipboard(); + ok(r, "gle %ld\n", GetLastError()); + + r = open_clipboard(NULL); + ok(r, "gle %ld\n", GetLastError()); + count = CountClipboardFormats(); + ok(count == 4, "count %u\n", count ); + + DestroyWindow( hwnd ); + + /* CF_UNICODETEXT and derivatives, CF_TEXT + CF_OEMTEXT, should be gone */ + count = CountClipboardFormats(); + ok(count == 1, "count %u\n", count ); + cf = EnumClipboardFormats( 0 ); + ok(cf == CF_LOCALE, "unexpected clipboard format %u\n", cf); + + r = CloseClipboard(); + ok(r, "gle %ld\n", GetLastError()); + + r = open_clipboard(NULL); + ok(r, "gle %ld\n", GetLastError()); + + SetLastError(0xdeadbeef); + data = GetClipboardData( CF_TEXT ); + ok(GetLastError() == ERROR_NOT_FOUND /* win11 */ || + broken(GetLastError() == 0xdeadbeef), + "bad last error %ld\n", GetLastError()); + ok(!data, "GetClipboardData() should have returned NULL\n"); + + r = CloseClipboard(); + ok(r, "gle %ld\n", GetLastError()); } static DWORD WINAPI clipboard_render_data_thread(void *param) { HANDLE handle = SetClipboardData( CF_UNICODETEXT, create_textW() ); - ok( handle != 0, "SetClipboardData failed: %d\n", GetLastError() ); + ok( handle != 0, "SetClipboardData failed: %ld\n", GetLastError() ); return 0; } @@ -905,14 +1021,14 @@ static LRESULT CALLBACK clipboard_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARA switch(msg) { case WM_DRAWCLIPBOARD: ok( msg_flags == (cross_thread ? ISMEX_NOTIFY : ISMEX_NOSEND), - "WM_DRAWCLIPBOARD wrong flags %x\n", msg_flags ); + "WM_DRAWCLIPBOARD wrong flags %lx\n", msg_flags ); EnterCriticalSection(&clipboard_cs); wm_drawclipboard++; LeaveCriticalSection(&clipboard_cs); break; case WM_CHANGECBCHAIN: ok( msg_flags == (cross_thread ? ISMEX_SEND : ISMEX_NOSEND), - "WM_CHANGECBCHAIN wrong flags %x\n", msg_flags ); + "WM_CHANGECBCHAIN wrong flags %lx\n", msg_flags ); if (next_wnd == (HWND)wp) next_wnd = (HWND)lp; else if (next_wnd) @@ -920,13 +1036,13 @@ static LRESULT CALLBACK clipboard_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARA break; case WM_DESTROYCLIPBOARD: ok( msg_flags == (cross_thread ? ISMEX_SEND : ISMEX_NOSEND), - "WM_DESTROYCLIPBOARD wrong flags %x\n", msg_flags ); + "WM_DESTROYCLIPBOARD wrong flags %lx\n", msg_flags ); wm_destroyclipboard++; ok( GetClipboardOwner() == hwnd, "WM_DESTROYCLIPBOARD owner %p\n", GetClipboardOwner() ); nb_formats = CountClipboardFormats(); break; case WM_RENDERFORMAT: - ok( !wm_renderformat, "multiple WM_RENDERFORMAT %04x / %04lx\n", wm_renderformat, wp ); + ok( !wm_renderformat, "multiple WM_RENDERFORMAT %04x / %04Ix\n", wm_renderformat, wp ); wm_renderformat = wp; if (do_render_format) @@ -936,13 +1052,13 @@ static LRESULT CALLBACK clipboard_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARA old_seq = GetClipboardSequenceNumber(); handle = SetClipboardData( CF_TEXT, create_textA() ); - ok( handle != 0, "SetClipboardData failed: %d\n", GetLastError() ); + ok( handle != 0, "SetClipboardData failed: %ld\n", GetLastError() ); seq = GetClipboardSequenceNumber(); ok( seq == old_seq, "sequence changed\n" ); old_seq = seq; handle = CreateThread( NULL, 0, clipboard_render_data_thread, NULL, 0, NULL ); - ok( handle != NULL, "CreateThread failed: %d\n", GetLastError() ); + ok( handle != NULL, "CreateThread failed: %ld\n", GetLastError() ); ok( WaitForSingleObject(handle, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); CloseHandle( handle ); seq = GetClipboardSequenceNumber(); @@ -951,7 +1067,7 @@ static LRESULT CALLBACK clipboard_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARA break; case WM_CLIPBOARDUPDATE: - ok( msg_flags == ISMEX_NOSEND, "WM_CLIPBOARDUPDATE wrong flags %x\n", msg_flags ); + ok( msg_flags == ISMEX_NOSEND, "WM_CLIPBOARDUPDATE wrong flags %lx\n", msg_flags ); EnterCriticalSection(&clipboard_cs); wm_clipboardupdate++; SetEvent(update_event); @@ -989,12 +1105,12 @@ static void get_clipboard_data_process(void) HANDLE data; BOOL r; - r = OpenClipboard(0); - ok(r, "OpenClipboard failed: %d\n", GetLastError()); + r = open_clipboard(0); + ok(r, "OpenClipboard failed: %ld\n", GetLastError()); data = GetClipboardData( CF_UNICODETEXT ); - ok( data != NULL, "GetClipboardData failed: %d\n", GetLastError()); + ok( data != NULL, "GetClipboardData failed: %ld\n", GetLastError()); r = CloseClipboard(); - ok(r, "CloseClipboard failed: %d\n", GetLastError()); + ok(r, "CloseClipboard failed: %ld\n", GetLastError()); } static UINT old_seq; @@ -1044,38 +1160,38 @@ static DWORD WINAPI clipboard_thread(void *param) EnterCriticalSection(&clipboard_cs); SetLastError(0xdeadbeef); next_wnd = SetClipboardViewer(win); - ok(GetLastError() == 0xdeadbeef, "GetLastError = %d\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "GetLastError = %ld\n", GetLastError()); LeaveCriticalSection(&clipboard_cs); SetLastError( 0xdeadbeef ); ret = SetClipboardViewer( (HWND)0xdead ); ok( !ret, "SetClipboardViewer succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); r = ChangeClipboardChain( win, (HWND)0xdead ); ok( !r, "ChangeClipboardChain succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); r = ChangeClipboardChain( (HWND)0xdead, next_wnd ); ok( !r, "ChangeClipboardChain succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %lu\n", GetLastError() ); if (pAddClipboardFormatListener) { r = pAddClipboardFormatListener(win); - ok( r, "AddClipboardFormatListener failed err %d\n", GetLastError()); + ok( r, "AddClipboardFormatListener failed err %ld\n", GetLastError()); SetLastError( 0xdeadbeef ); r = pAddClipboardFormatListener( win ); ok( !r, "AddClipboardFormatListener succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); r = pAddClipboardFormatListener( (HWND)0xdead ); ok( !r, "AddClipboardFormatListener succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %lu\n", GetLastError() ); r = pAddClipboardFormatListener( GetDesktopWindow() ); - ok( r, "AddClipboardFormatListener failed err %d\n", GetLastError()); + ok( r, "AddClipboardFormatListener failed err %ld\n", GetLastError()); r = pRemoveClipboardFormatListener( GetDesktopWindow() ); - ok( r, "RemoveClipboardFormatListener failed err %d\n", GetLastError()); + ok( r, "RemoveClipboardFormatListener failed err %ld\n", GetLastError()); } check_messages(win, 0, 1, 0, 0, 0); @@ -1083,27 +1199,27 @@ static DWORD WINAPI clipboard_thread(void *param) SetLastError( 0xdeadbeef ); r = OpenClipboard( (HWND)0xdead ); ok( !r, "OpenClipboard succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %lu\n", GetLastError() ); - r = OpenClipboard(win); - ok(r, "OpenClipboard failed: %d\n", GetLastError()); + r = open_clipboard(win); + ok(r, "OpenClipboard failed: %ld\n", GetLastError()); check_messages(win, 0, 0, 0, 0, 0); r = EmptyClipboard(); - ok(r, "EmptyClipboard failed: %d\n", GetLastError()); + ok(r, "EmptyClipboard failed: %ld\n", GetLastError()); check_messages(win, 1, 0, 0, 0, 0); r = EmptyClipboard(); - ok(r, "EmptyClipboard failed: %d\n", GetLastError()); + ok(r, "EmptyClipboard failed: %ld\n", GetLastError()); /* sequence changes again, even though it was already empty */ check_messages(win, 1, 0, 0, 1, 0); count = SendMessageA( win, WM_USER+5, 0, 0 ); ok( !count, "wrong format count %u on WM_DESTROYCLIPBOARD\n", count ); handle = SetClipboardData( CF_TEXT, create_textA() ); - ok(handle != 0, "SetClipboardData failed: %d\n", GetLastError()); + ok(handle != 0, "SetClipboardData failed: %ld\n", GetLastError()); check_messages(win, 1, 0, 0, 0, 0); @@ -1121,13 +1237,13 @@ static DWORD WINAPI clipboard_thread(void *param) EnterCriticalSection(&clipboard_cs); r = CloseClipboard(); - ok(r, "CloseClipboard failed: %d\n", GetLastError()); + ok(r, "CloseClipboard failed: %ld\n", GetLastError()); LeaveCriticalSection(&clipboard_cs); check_messages(win, 2, 1, 1, 0, 0); - r = OpenClipboard(win); - ok(r, "OpenClipboard failed: %d\n", GetLastError()); + r = open_clipboard(win); + ok(r, "OpenClipboard failed: %ld\n", GetLastError()); check_messages(win, 0, 0, 0, 0, 0); @@ -1152,37 +1268,37 @@ static DWORD WINAPI clipboard_thread(void *param) check_messages(win, 1, 0, 0, 0, 0); r = CloseClipboard(); - ok(r, "CloseClipboard failed: %d\n", GetLastError()); + ok(r, "CloseClipboard failed: %ld\n", GetLastError()); /* no synthesized format, so CloseClipboard doesn't change the sequence */ check_messages(win, 0, 1, 1, 0, 0); - r = OpenClipboard(win); - ok(r, "OpenClipboard failed: %d\n", GetLastError()); + r = open_clipboard(win); + ok(r, "OpenClipboard failed: %ld\n", GetLastError()); r = CloseClipboard(); - ok(r, "CloseClipboard failed: %d\n", GetLastError()); + ok(r, "CloseClipboard failed: %ld\n", GetLastError()); /* nothing changed */ check_messages(win, 0, 0, 0, 0, 0); formats = CountClipboardFormats(); - r = OpenClipboard(0); - ok(r, "OpenClipboard failed: %d\n", GetLastError()); + r = open_clipboard(0); + ok(r, "OpenClipboard failed: %ld\n", GetLastError()); r = EmptyClipboard(); - ok(r, "EmptyClipboard failed: %d\n", GetLastError()); + ok(r, "EmptyClipboard failed: %ld\n", GetLastError()); r = CloseClipboard(); - ok(r, "CloseClipboard failed: %d\n", GetLastError()); + ok(r, "CloseClipboard failed: %ld\n", GetLastError()); check_messages(win, 1, 1, 1, 1, 0); count = SendMessageA( win, WM_USER+5, 0, 0 ); ok( count == formats, "wrong format count %u on WM_DESTROYCLIPBOARD\n", count ); - r = OpenClipboard(win); - ok(r, "OpenClipboard failed: %d\n", GetLastError()); + r = open_clipboard(win); + ok(r, "OpenClipboard failed: %ld\n", GetLastError()); SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_FIXED, 1 )); check_messages(win, 1, 0, 0, 0, 0); EnterCriticalSection(&clipboard_cs); r = CloseClipboard(); - ok(r, "CloseClipboard failed: %d\n", GetLastError()); + ok(r, "CloseClipboard failed: %ld\n", GetLastError()); LeaveCriticalSection(&clipboard_cs); check_messages(win, 0, 1, 1, 0, 0); @@ -1198,14 +1314,14 @@ static DWORD WINAPI clipboard_thread(void *param) } check_messages(win, 1, 1, 1, 0, 0); - r = OpenClipboard(0); - ok(r, "OpenClipboard failed: %d\n", GetLastError()); + r = open_clipboard(0); + ok(r, "OpenClipboard failed: %ld\n", GetLastError()); SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_FIXED, 1 )); check_messages(win, 1, 0, 0, 0, 0); EnterCriticalSection(&clipboard_cs); r = CloseClipboard(); - ok(r, "CloseClipboard failed: %d\n", GetLastError()); + ok(r, "CloseClipboard failed: %ld\n", GetLastError()); LeaveCriticalSection(&clipboard_cs); check_messages(win, 0, 1, 1, 0, 0); @@ -1221,27 +1337,27 @@ static DWORD WINAPI clipboard_thread(void *param) } check_messages(win, 2, 1, 1, 0, 0); - r = OpenClipboard(0); - ok(r, "OpenClipboard failed: %d\n", GetLastError()); + r = open_clipboard(0); + ok(r, "OpenClipboard failed: %ld\n", GetLastError()); SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_FIXED, 1 )); check_messages(win, 1, 0, 0, 0, 0); EnterCriticalSection(&clipboard_cs); r = CloseClipboard(); - ok(r, "CloseClipboard failed: %d\n", GetLastError()); + ok(r, "CloseClipboard failed: %ld\n", GetLastError()); LeaveCriticalSection(&clipboard_cs); check_messages(win, 0, 1, 1, 0, 0); if (cross_thread) { - r = OpenClipboard( win ); - ok(r, "OpenClipboard failed: %d\n", GetLastError()); + r = open_clipboard( win ); + ok(r, "OpenClipboard failed: %ld\n", GetLastError()); r = EmptyClipboard(); - ok(r, "EmptyClipboard failed: %d\n", GetLastError()); + ok(r, "EmptyClipboard failed: %ld\n", GetLastError()); SetClipboardData( CF_TEXT, 0 ); r = CloseClipboard(); - ok(r, "CloseClipboard failed: %d\n", GetLastError()); + ok(r, "CloseClipboard failed: %ld\n", GetLastError()); do_render_format = TRUE; old_seq = GetClipboardSequenceNumber(); @@ -1252,20 +1368,20 @@ static DWORD WINAPI clipboard_thread(void *param) } r = PostMessageA(win, WM_USER, 0, 0); - ok(r, "PostMessage failed: %d\n", GetLastError()); + ok(r, "PostMessage failed: %ld\n", GetLastError()); if (pRemoveClipboardFormatListener) { r = pRemoveClipboardFormatListener(win); - ok( r, "RemoveClipboardFormatListener failed err %d\n", GetLastError()); + ok( r, "RemoveClipboardFormatListener failed err %ld\n", GetLastError()); SetLastError( 0xdeadbeef ); r = pRemoveClipboardFormatListener(win); ok( !r, "RemoveClipboardFormatListener succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); r = pRemoveClipboardFormatListener( (HWND)0xdead ); ok( !r, "RemoveClipboardFormatListener succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %lu\n", GetLastError() ); } return 0; } @@ -1288,10 +1404,10 @@ static void test_messages(void) RegisterClassA(&cls); win = CreateWindowA("clipboard_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0); - ok(win != NULL, "CreateWindow failed: %d\n", GetLastError()); + ok(win != NULL, "CreateWindow failed: %ld\n", GetLastError()); thread = CreateThread(NULL, 0, clipboard_thread, (void*)win, 0, &tid); - ok(thread != NULL, "CreateThread failed: %d\n", GetLastError()); + ok(thread != NULL, "CreateThread failed: %ld\n", GetLastError()); while(GetMessageA(&msg, NULL, 0, 0)) { @@ -1308,7 +1424,7 @@ static void test_messages(void) /* same tests again but inside a single thread */ win = CreateWindowA( "clipboard_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0 ); - ok( win != NULL, "CreateWindow failed: %d\n", GetLastError() ); + ok( win != NULL, "CreateWindow failed: %ld\n", GetLastError() ); clipboard_thread( win ); DestroyWindow( win ); @@ -1366,11 +1482,11 @@ static void test_handles( HWND hwnd ) hfixed = GlobalAlloc( GMEM_FIXED, 17 ); hfixed2 = GlobalAlloc( GMEM_FIXED, 17 ); ok( is_fixed( hfixed ), "expected fixed mem %p\n", hfixed ); - ok( GlobalSize( hfixed ) == 17, "wrong size %lu\n", GlobalSize( hfixed )); + ok( GlobalSize( hfixed ) == 17, "wrong size %Iu\n", GlobalSize( hfixed )); hmoveable = GlobalAlloc( GMEM_MOVEABLE, 23 ); ok( is_moveable( hmoveable ), "expected moveable mem %p\n", hmoveable ); - ok( GlobalSize( hmoveable ) == 23, "wrong size %lu\n", GlobalSize( hmoveable )); + ok( GlobalSize( hmoveable ) == 23, "wrong size %Iu\n", GlobalSize( hmoveable )); empty_fixed = GlobalAlloc( GMEM_FIXED, 0 ); ok( is_fixed( empty_fixed ), "expected fixed mem %p\n", empty_fixed ); @@ -1379,10 +1495,10 @@ static void test_handles( HWND hwnd ) /* discarded handles can't be GlobalLock'ed */ ok( is_freed( empty_moveable ), "expected free mem %p\n", empty_moveable ); - r = OpenClipboard( hwnd ); - ok( r, "gle %d\n", GetLastError() ); + r = open_clipboard( hwnd ); + ok( r, "gle %ld\n", GetLastError() ); r = EmptyClipboard(); - ok( r, "gle %d\n", GetLastError() ); + ok( r, "gle %ld\n", GetLastError() ); h = SetClipboardData( CF_TEXT, htext ); ok( h == htext, "got %p\n", h ); @@ -1397,7 +1513,6 @@ static void test_handles( HWND hwnd ) h = SetClipboardData( CF_BITMAP, bitmap ); ok( h == bitmap, "got %p\n", h ); ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h ); - ok( !GetObjectType( bitmap_temp ), "expected free object %p\n", bitmap_temp ); h = SetClipboardData( CF_DSPBITMAP, bitmap2 ); ok( h == bitmap2, "got %p\n", h ); ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h ); @@ -1472,6 +1587,13 @@ static void test_handles( HWND hwnd ) data = GetClipboardData( 0xdeadfade ); ok( data == ptr, "wrong data %p\n", data ); + SetLastError( 0xdeadbeef ); + data = GetClipboardData( CF_RIFF ); + ok( GetLastError() == ERROR_NOT_FOUND /* win11 */ || + broken(GetLastError() == 0xdeadbeef), + "unexpected last error %ld\n", GetLastError() ); + ok( !data, "wrong data %p\n", data ); + h = SetClipboardData( CF_PRIVATEFIRST + 7, htext4 ); ok( h == htext4, "got %p\n", h ); ok( is_moveable( h ), "expected moveable mem %p\n", h ); @@ -1484,7 +1606,7 @@ static void test_handles( HWND hwnd ) ok( is_freed( hfixed2 ), "expected freed mem %p\n", hfixed2 ); r = CloseClipboard(); - ok( r, "gle %d\n", GetLastError() ); + ok( r, "gle %ld\n", GetLastError() ); /* data handles are still valid */ ok( is_moveable( htext ), "expected moveable mem %p\n", htext ); @@ -1498,8 +1620,8 @@ static void test_handles( HWND hwnd ) ok( is_moveable( hmoveable ), "expected moveable mem %p\n", hmoveable ); ok( is_fixed( empty_fixed ), "expected fixed mem %p\n", empty_fixed ); - r = OpenClipboard( hwnd ); - ok( r, "gle %d\n", GetLastError() ); + r = open_clipboard( hwnd ); + ok( r, "gle %ld\n", GetLastError() ); /* and now they are freed, unless we are the owner */ if (!is_owner) @@ -1524,19 +1646,19 @@ static void test_handles( HWND hwnd ) data = GetClipboardData( format_id2 ); ok( is_fixed( data ), "expected fixed mem %p\n", data ); - ok( GlobalSize( data ) == 1, "wrong size %lu\n", GlobalSize( data )); + ok( GlobalSize( data ) == 1, "wrong size %Iu\n", GlobalSize( data )); data = GetClipboardData( 0xdeadbeef ); ok( is_fixed( data ), "expected fixed mem %p\n", data ); - ok( GlobalSize( data ) == 17, "wrong size %lu\n", GlobalSize( data )); + ok( GlobalSize( data ) == 17, "wrong size %Iu\n", GlobalSize( data )); data = GetClipboardData( 0xdeadbabe ); ok( is_fixed( data ), "expected fixed mem %p\n", data ); - ok( GlobalSize( data ) == 23, "wrong size %lu\n", GlobalSize( data )); + ok( GlobalSize( data ) == 23, "wrong size %Iu\n", GlobalSize( data )); data = GetClipboardData( 0xdeadfade ); ok( is_fixed( data ) || !ptr, "expected fixed mem %p\n", data ); - if (ptr) ok( GlobalSize( data ) == 37, "wrong size %lu\n", GlobalSize( data )); + if (ptr) ok( GlobalSize( data ) == 37, "wrong size %Iu\n", GlobalSize( data )); } else { @@ -1595,7 +1717,7 @@ static void test_handles( HWND hwnd ) ok( is_fixed( empty_fixed ), "expected fixed mem %p\n", empty_fixed ); r = EmptyClipboard(); - ok( r, "gle %d\n", GetLastError() ); + ok( r, "gle %ld\n", GetLastError() ); /* w2003, w2008 don't seem to free the data here */ ok( is_freed( htext ) || broken( !is_freed( htext )), "expected freed mem %p\n", htext ); @@ -1605,12 +1727,9 @@ static void test_handles( HWND hwnd ) ok( is_freed( hmoveable ) || broken( !is_freed( hmoveable )), "expected freed mem %p\n", hmoveable ); ok( is_fixed( empty_fixed ), "expected fixed mem %p\n", empty_fixed ); ok( is_fixed( hfixed ), "expected fixed mem %p\n", hfixed ); - ok( !GetObjectType( bitmap ), "expected freed handle %p\n", bitmap ); - ok( !GetObjectType( bitmap2 ), "expected freed handle %p\n", bitmap2 ); - ok( !GetObjectType( palette ), "expected freed handle %p\n", palette ); r = CloseClipboard(); - ok( r, "gle %d\n", GetLastError() ); + ok( r, "gle %ld\n", GetLastError() ); } static DWORD WINAPI test_handles_thread( void *arg ) @@ -1626,8 +1745,8 @@ static DWORD WINAPI test_handles_thread2( void *arg ) HANDLE h; char *ptr; - r = OpenClipboard( 0 ); - ok( r, "gle %d\n", GetLastError() ); + r = open_clipboard( 0 ); + ok( r, "gle %ld\n", GetLastError() ); h = GetClipboardData( CF_TEXT ); ok( is_moveable( h ), "expected moveable mem %p\n", h ); ptr = GlobalLock( h ); @@ -1667,7 +1786,7 @@ static DWORD WINAPI test_handles_thread2( void *arg ) h = GetClipboardData( CF_DIBV5 ); ok( is_fixed( h ), "expected fixed mem %p\n", h ); r = CloseClipboard(); - ok( r, "gle %d\n", GetLastError() ); + ok( r, "gle %ld\n", GetLastError() ); return 0; } @@ -1681,8 +1800,8 @@ static void test_handles_process( const char *str ) BYTE buffer[1024]; format_id = RegisterClipboardFormatA( "my_cool_clipboard_format" ); - r = OpenClipboard( 0 ); - ok( r, "gle %d\n", GetLastError() ); + r = open_clipboard( 0 ); + ok( r, "gle %ld\n", GetLastError() ); h = GetClipboardData( CF_TEXT ); ok( is_fixed( h ), "expected fixed mem %p\n", h ); ptr = GlobalLock( h ); @@ -1721,17 +1840,11 @@ static void test_handles_process( const char *str ) trace( "palette %p\n", h ); h = GetClipboardData( CF_METAFILEPICT ); ok( is_fixed( h ), "expected fixed mem %p\n", h ); -#ifdef __REACTOS__ - if (h != NULL) -#endif ok( GetObjectType( ((METAFILEPICT *)h)->hMF ) == OBJ_METAFILE, "wrong object %p\n", ((METAFILEPICT *)h)->hMF ); trace( "metafile %p\n", h ); h = GetClipboardData( CF_DSPMETAFILEPICT ); ok( is_fixed( h ), "expected fixed mem %p\n", h ); -#ifdef __REACTOS__ - if (h != NULL) -#endif ok( GetObjectType( ((METAFILEPICT *)h)->hMF ) == OBJ_METAFILE, "wrong object %p\n", ((METAFILEPICT *)h)->hMF ); trace( "metafile2 %p\n", h ); @@ -1740,21 +1853,21 @@ static void test_handles_process( const char *str ) ok( GetEnhMetaFileBits( h, sizeof(buffer), buffer ) > sizeof(ENHMETAHEADER), "GetEnhMetaFileBits failed on %p\n", h ); ok( ((ENHMETAHEADER *)buffer)->nRecords == 3, - "wrong records %u\n", ((ENHMETAHEADER *)buffer)->nRecords ); + "wrong records %lu\n", ((ENHMETAHEADER *)buffer)->nRecords ); trace( "enhmetafile %p\n", h ); h = GetClipboardData( CF_DSPENHMETAFILE ); ok( GetObjectType( h ) == OBJ_ENHMETAFILE, "expected enhmetafile %p\n", h ); ok( GetEnhMetaFileBits( h, sizeof(buffer), buffer ) > sizeof(ENHMETAHEADER), "GetEnhMetaFileBits failed on %p\n", h ); ok( ((ENHMETAHEADER *)buffer)->nRecords == 3, - "wrong records %u\n", ((ENHMETAHEADER *)buffer)->nRecords ); + "wrong records %lu\n", ((ENHMETAHEADER *)buffer)->nRecords ); trace( "enhmetafile2 %p\n", h ); h = GetClipboardData( CF_DIB ); ok( is_fixed( h ), "expected fixed mem %p\n", h ); h = GetClipboardData( CF_DIBV5 ); ok( is_fixed( h ), "expected fixed mem %p\n", h ); r = CloseClipboard(); - ok( r, "gle %d\n", GetLastError() ); + ok( r, "gle %ld\n", GetLastError() ); } static void test_handles_process_open( const char *str ) @@ -1776,23 +1889,28 @@ static void test_handles_process_dib( const char *str ) BOOL r; HANDLE h; - r = OpenClipboard( 0 ); - ok( r, "gle %d\n", GetLastError() ); + r = open_clipboard( 0 ); + ok( r, "gle %ld\n", GetLastError() ); h = GetClipboardData( CF_BITMAP ); ok( !GetObjectType( h ), "expected invalid object %p\n", h ); trace( "dibsection %p\n", h ); r = CloseClipboard(); - ok( r, "gle %d\n", GetLastError() ); + ok( r, "gle %ld\n", GetLastError() ); } static void test_data_handles(void) { BOOL r; char *ptr; - HANDLE h, text; + HANDLE h, text, metafile; HWND hwnd = CreateWindowA( "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL ); BITMAPINFO bmi; void *bits; + PALETTEENTRY entry; + BYTE buffer[1024]; + HENHMETAFILE emf; + int result; + HDC hdc = GetDC( 0 ); ok( hwnd != 0, "window creation failed\n" ); format_id = RegisterClipboardFormatA( "my_cool_clipboard_format" ); @@ -1805,10 +1923,10 @@ static void test_data_handles(void) bitmap2 = CreateBitmap( 10, 10, 1, 1, NULL ); palette = CreatePalette( &logpalette ); - r = OpenClipboard( hwnd ); - ok( r, "gle %d\n", GetLastError() ); + r = open_clipboard( hwnd ); + ok( r, "gle %ld\n", GetLastError() ); r = EmptyClipboard(); - ok( r, "gle %d\n", GetLastError() ); + ok( r, "gle %ld\n", GetLastError() ); h = SetClipboardData( CF_TEXT, create_textA() ); ok( is_moveable( h ), "expected moveable mem %p\n", h ); h = SetClipboardData( format_id, create_textA() ); @@ -1836,13 +1954,13 @@ static void test_data_handles(void) h = SetClipboardData( CF_PRIVATEFIRST + 7, create_textA() ); ok( is_moveable( h ), "expected moveable mem %p\n", h ); r = CloseClipboard(); - ok( r, "gle %d\n", GetLastError() ); + ok( r, "gle %ld\n", GetLastError() ); run_thread( test_handles_thread2, 0, __LINE__ ); run_process( "handles test" ); - r = OpenClipboard( hwnd ); - ok( r, "gle %d\n", GetLastError() ); + r = open_clipboard( hwnd ); + ok( r, "gle %ld\n", GetLastError() ); h = GetClipboardData( CF_TEXT ); ok( is_moveable( h ), "expected moveable mem %p\n", h ); h = GetClipboardData( format_id ); @@ -1853,7 +1971,7 @@ static void test_data_handles(void) ok( is_moveable( h ), "expected moveable mem %p\n", h ); r = EmptyClipboard(); - ok( r, "gle %d\n", GetLastError() ); + ok( r, "gle %ld\n", GetLastError() ); text = create_textA(); h = SetClipboardData( CF_TEXT, text ); ok( is_moveable( h ), "expected moveable mem %p\n", h ); @@ -1865,16 +1983,16 @@ static void test_data_handles(void) ok( is_fixed( h ), "expected fixed mem %p\n", h ); ok( is_moveable( text ), "expected moveable mem %p\n", text ); ptr = GlobalLock( h ); - ok( !strcmp( ptr, "foobar" ), "wrong data '%.8s'\n", ptr ); + ok( ptr && !strcmp( ptr, "foobar" ), "wrong data %s\n", wine_dbgstr_a(ptr) ); GlobalUnlock( h ); r = EmptyClipboard(); - ok( r, "gle %d\n", GetLastError() ); + ok( r, "gle %ld\n", GetLastError() ); ok( is_fixed( h ), "expected free mem %p\n", h ); ok( is_freed( text ) || broken( is_moveable(text) ), /* w2003, w2008 */ "expected free mem %p\n", text ); r = CloseClipboard(); - ok( r, "gle %d\n", GetLastError() ); + ok( r, "gle %ld\n", GetLastError() ); /* test CF_BITMAP with a DIB section */ memset( &bmi, 0, sizeof(bmi) ); @@ -1885,27 +2003,100 @@ static void test_data_handles(void) bmi.bmiHeader.biBitCount = 32; bitmap = CreateDIBSection( 0, &bmi, DIB_RGB_COLORS, &bits, 0, 0 ); - r = OpenClipboard( hwnd ); - ok( r, "gle %d\n", GetLastError() ); + r = open_clipboard( hwnd ); + ok( r, "gle %ld\n", GetLastError() ); r = EmptyClipboard(); - ok( r, "gle %d\n", GetLastError() ); + ok( r, "gle %ld\n", GetLastError() ); h = SetClipboardData( CF_BITMAP, bitmap ); ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h ); trace( "dibsection %p\n", h ); r = CloseClipboard(); - ok( r, "gle %d\n", GetLastError() ); + ok( r, "gle %ld\n", GetLastError() ); run_process( "handles_dib dummy" ); - r = OpenClipboard( hwnd ); - ok( r, "gle %d\n", GetLastError() ); + r = open_clipboard( hwnd ); + ok( r, "gle %ld\n", GetLastError() ); ok( GetObjectType( bitmap ) == OBJ_BITMAP, "expected bitmap %p\n", bitmap ); r = EmptyClipboard(); - ok( r, "gle %d\n", GetLastError() ); - ok( !GetObjectType( bitmap ), "expected deleted %p\n", bitmap ); + ok( r, "gle %ld\n", GetLastError() ); r = CloseClipboard(); - ok( r, "gle %d\n", GetLastError() ); + ok( r, "gle %ld\n", GetLastError() ); + r = open_clipboard( hwnd ); + ok( r, "Open clipboard failed: %#lx.\n", GetLastError() ); + r = EmptyClipboard(); + ok( r, "EmptyClipboard failed: %#lx.\n", GetLastError() ); + + bitmap = CreateBitmap( 10, 10, 1, 1, NULL ); + h = SetClipboardData( CF_BITMAP, bitmap ); + ok( h == bitmap, "Expected bitmap %p, got %p.\n", bitmap, h ); + ok( !!DeleteObject( bitmap ), "DeleteObject failed.\n" ); + h = GetClipboardData( CF_BITMAP ); + ok( h == bitmap, "Expected bitmap %p, got %p.\n", bitmap, h ); + memset( &bmi, 0, sizeof(bmi) ); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + result = GetDIBits( hdc, h, 0, 0, NULL, &bmi, 0 ); + ok( !!result, "GetDIBits failed: %#lx.\n", GetLastError() ); + + bitmap = CreateBitmap( 10, 10, 1, 1, NULL ); + h = SetClipboardData( CF_DSPBITMAP, bitmap ); + ok( h == bitmap, "Expected bitmap %p, got %p.\n", bitmap, h ); + ok( !!DeleteObject( bitmap ), "DeleteObject failed.\n" ); + h = GetClipboardData( CF_DSPBITMAP ); + ok( h == bitmap, "Expected bitmap %p, got %p.\n", bitmap, h ); + memset( &bmi, 0, sizeof(bmi) ); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + ok( !GetDIBits( hdc, h, 0, 0, 0, &bmi, 0 ), "GetDIBits returned unexpected value.\n" ); + + palette = CreatePalette( &logpalette ); + h = SetClipboardData( CF_PALETTE, palette ); + ok( h == palette, "Expected palette %p, got %p.\n", palette, h ); + ok( !!DeleteObject( palette ), "DeleteObject failed.\n" ); + h = GetClipboardData( CF_PALETTE ); + ok( h == palette, "Expected palette %p, got %p.\n", palette, h ); + ok( !!GetPaletteEntries( h, 0, 1, &entry ), "GetPaletteEntries %p failed.\n", h ); + ok( entry.peRed == 0x12 && entry.peGreen == 0x34 && entry.peBlue == 0x56, + "Got wrong color (%02x, %02x, %02x).\n", entry.peRed, entry.peGreen, entry.peBlue ); + + emf = create_emf(); + h = SetClipboardData( CF_ENHMETAFILE, emf ); + ok( h == emf, "Expected enhmetafile %p, got %p.\n", palette, h ); + ok( !!DeleteEnhMetaFile( emf ), "DeleteEnhMetaFile failed.\n" ); + h = GetClipboardData( CF_ENHMETAFILE ); + ok( h == emf, "Expected enhmetafile %p, got %p.\n", palette, h ); + ok( !GetEnhMetaFileBits( h, sizeof(buffer), buffer ), "GetEnhMetaFileBits returned unexpected value.\n" ); + + emf = create_emf(); + h = SetClipboardData( CF_DSPENHMETAFILE, emf ); + ok( h == emf, "Expected enhmetafile %p, got %p.\n", emf, h ); + ok( !!DeleteEnhMetaFile( emf ), "DeleteEnhMetaFile failed.\n" ); + h = GetClipboardData( CF_DSPENHMETAFILE ); + ok( h == emf, "Expected enhmetafile %p, got %p.\n", emf, h ); + ok( !GetEnhMetaFileBits( h, sizeof(buffer), buffer ), "GetEnhMetaFileBits returned unexpected value.\n" ); + + metafile = create_metafile(); + h = SetClipboardData( CF_METAFILEPICT, metafile ); + ok( h == metafile, "Expected metafilepict %p, got %p.\n", metafile, h ); + ok( !pGlobalFree( metafile ), "GlobalFree failed.\n" ); + h = GetClipboardData( CF_METAFILEPICT ); + ok( h == metafile, "Expected metafile %p, got %p.\n", metafile, h ); + ok( is_freed( h ), "Expected freed mem %p.\n", h ); + + metafile = create_metafile(); + h = SetClipboardData( CF_DSPMETAFILEPICT, metafile ); + ok( h == metafile, "Expected metafilepict %p, got %p.\n", metafile, h ); + ok( !pGlobalFree( metafile ), "GlobalFree failed.\n" ); + h = GetClipboardData( CF_DSPMETAFILEPICT ); + ok( h == metafile, "Expected metafile %p, got %p.\n", metafile, h ); + ok( is_freed( h ), "Expected freed mem %p.\n", h ); + + r = EmptyClipboard(); + ok( r, "EmptyClipboard failed: %#lx.\n", GetLastError() ); + r = CloseClipboard(); + ok( r, "CloseClipboard failed: %#lx.\n", GetLastError() ); + + ReleaseDC( 0, hdc ); DestroyWindow( hwnd ); } @@ -1922,40 +2113,40 @@ static void test_GetUpdatedClipboardFormats(void) count = 0xdeadbeef; r = pGetUpdatedClipboardFormats( NULL, 0, &count ); - ok( r, "gle %d\n", GetLastError() ); + ok( r, "gle %ld\n", GetLastError() ); ok( !count, "wrong count %u\n", count ); count = 0xdeadbeef; r = pGetUpdatedClipboardFormats( NULL, 256, &count ); - ok( r, "gle %d\n", GetLastError() ); + ok( r, "gle %ld\n", GetLastError() ); ok( !count, "wrong count %u\n", count ); SetLastError( 0xdeadbeef ); - r = pGetUpdatedClipboardFormats( formats, 256, NULL ); + r = pGetUpdatedClipboardFormats( formats, ARRAY_SIZE(formats), NULL ); ok( !r, "succeeded\n" ); - ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_NOACCESS, "wrong error %lu\n", GetLastError() ); count = 0xdeadbeef; - r = pGetUpdatedClipboardFormats( formats, 256, &count ); - ok( r, "gle %d\n", GetLastError() ); + r = pGetUpdatedClipboardFormats( formats, ARRAY_SIZE(formats), &count ); + ok( r, "gle %ld\n", GetLastError() ); ok( !count, "wrong count %u\n", count ); - r = OpenClipboard( 0 ); - ok( r, "gle %d\n", GetLastError() ); + r = open_clipboard( 0 ); + ok( r, "gle %ld\n", GetLastError() ); r = EmptyClipboard(); - ok( r, "gle %d\n", GetLastError() ); + ok( r, "gle %ld\n", GetLastError() ); count = 0xdeadbeef; - r = pGetUpdatedClipboardFormats( formats, 256, &count ); - ok( r, "gle %d\n", GetLastError() ); + r = pGetUpdatedClipboardFormats( formats, ARRAY_SIZE(formats), &count ); + ok( r, "gle %ld\n", GetLastError() ); ok( !count, "wrong count %u\n", count ); SetClipboardData( CF_UNICODETEXT, 0 ); count = 0xdeadbeef; memset( formats, 0xcc, sizeof(formats) ); - r = pGetUpdatedClipboardFormats( formats, 256, &count ); - ok( r, "gle %d\n", GetLastError() ); + r = pGetUpdatedClipboardFormats( formats, ARRAY_SIZE(formats), &count ); + ok( r, "gle %ld\n", GetLastError() ); ok( count == 1, "wrong count %u\n", count ); ok( formats[0] == CF_UNICODETEXT, "wrong format %u\n", formats[0] ); ok( formats[1] == 0xcccccccc, "wrong format %u\n", formats[1] ); @@ -1963,8 +2154,8 @@ static void test_GetUpdatedClipboardFormats(void) SetClipboardData( CF_TEXT, 0 ); count = 0xdeadbeef; memset( formats, 0xcc, sizeof(formats) ); - r = pGetUpdatedClipboardFormats( formats, 256, &count ); - ok( r, "gle %d\n", GetLastError() ); + r = pGetUpdatedClipboardFormats( formats, ARRAY_SIZE(formats), &count ); + ok( r, "gle %ld\n", GetLastError() ); ok( count == 2, "wrong count %u\n", count ); ok( formats[0] == CF_UNICODETEXT, "wrong format %u\n", formats[0] ); ok( formats[1] == CF_TEXT, "wrong format %u\n", formats[1] ); @@ -1974,23 +2165,23 @@ static void test_GetUpdatedClipboardFormats(void) count = 0xdeadbeef; r = pGetUpdatedClipboardFormats( formats, 0, &count ); ok( !r, "succeeded\n" ); - ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "wrong error %lu\n", GetLastError() ); ok( count == 2, "wrong count %u\n", count ); SetLastError( 0xdeadbeef ); count = 0xdeadbeef; r = pGetUpdatedClipboardFormats( formats, 1, &count ); ok( !r, "succeeded\n" ); - ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "wrong error %lu\n", GetLastError() ); ok( count == 2, "wrong count %u\n", count ); r = CloseClipboard(); - ok( r, "gle %d\n", GetLastError() ); + ok( r, "gle %ld\n", GetLastError() ); count = 0xdeadbeef; memset( formats, 0xcc, sizeof(formats) ); - r = pGetUpdatedClipboardFormats( formats, 256, &count ); - ok( r, "gle %d\n", GetLastError() ); + r = pGetUpdatedClipboardFormats( formats, ARRAY_SIZE(formats), &count ); + ok( r, "gle %ld\n", GetLastError() ); ok( count == 4, "wrong count %u\n", count ); ok( formats[0] == CF_UNICODETEXT, "wrong format %u\n", formats[0] ); ok( formats[1] == CF_TEXT, "wrong format %u\n", formats[1] ); @@ -2001,21 +2192,21 @@ static void test_GetUpdatedClipboardFormats(void) count = 0xdeadbeef; memset( formats, 0xcc, sizeof(formats) ); r = pGetUpdatedClipboardFormats( formats, 2, &count ); - ok( !r, "gle %d\n", GetLastError() ); - ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "wrong error %u\n", GetLastError() ); + ok( !r, "gle %ld\n", GetLastError() ); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "wrong error %lu\n", GetLastError() ); ok( count == 4, "wrong count %u\n", count ); ok( formats[0] == 0xcccccccc, "wrong format %u\n", formats[0] ); count = 0xdeadbeef; r = pGetUpdatedClipboardFormats( NULL, 256, &count ); - ok( !r, "gle %d\n", GetLastError() ); - ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() ); + ok( !r, "gle %ld\n", GetLastError() ); + ok( GetLastError() == ERROR_NOACCESS, "wrong error %lu\n", GetLastError() ); ok( count == 4, "wrong count %u\n", count ); count = 0xdeadbeef; r = pGetUpdatedClipboardFormats( NULL, 256, &count ); - ok( !r, "gle %d\n", GetLastError() ); - ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() ); + ok( !r, "gle %ld\n", GetLastError() ); + ok( GetLastError() == ERROR_NOACCESS, "wrong error %lu\n", GetLastError() ); ok( count == 4, "wrong count %u\n", count ); } @@ -2026,40 +2217,53 @@ static const struct UINT len; } test_data[] = { - { "foo", {0}, 3 }, /* 0 */ +#if defined(__REACTOS__) && defined(_MSC_VER) && _MSVC_VER < 1930 + { "foo", {0}, 3 }, /* 0 */ { "foo", {0}, 4 }, { "foo\0bar", {0}, 7 }, { "foo\0bar", {0}, 8 }, - { "", {'f','o','o'}, 3 * sizeof(WCHAR) }, - { "", {'f','o','o',0}, 4 * sizeof(WCHAR) }, /* 5 */ + { "", {0}, 0 }, +#else + { "foo", {}, 3 }, /* 0 */ + { "foo", {}, 4 }, + { "foo\0bar", {}, 7 }, + { "foo\0bar", {}, 8 }, + { "", {}, 0 }, +#endif + { "", {'f'}, 1 }, /* 5 */ + { "", {'f'}, 2 }, + { "", {0x3b1,0x3b2,0x3b3}, 5 }, /* Alpha, beta, ... */ + { "", {0x3b1,0x3b2,0x3b3}, 6 }, + { "", {0x3b1,0x3b2,0x3b3,0}, 7 }, /* 10 */ + { "", {0x3b1,0x3b2,0x3b3,0}, 8 }, + { "", {0x3b1,0x3b2,0x3b3,0,0x3b4}, 9 }, { "", {'f','o','o',0,'b','a','r'}, 7 * sizeof(WCHAR) }, { "", {'f','o','o',0,'b','a','r',0}, 8 * sizeof(WCHAR) }, - { "", {'f','o','o'}, 1 }, - { "", {'f','o','o'}, 2 }, - { "", {'f','o','o'}, 5 }, /* 10 */ - { "", {'f','o','o',0}, 7 }, - { "", {'f','o','o',0}, 9 }, }; static void test_string_data(void) { UINT i; BOOL r; - HANDLE data; + HANDLE data, clip; char cmd[16]; char bufferA[12]; WCHAR bufferW[12]; for (i = 0; i < ARRAY_SIZE(test_data); i++) { - /* 1-byte Unicode strings crash on Win64 */ #ifdef _WIN64 - if (!test_data[i].strA[0] && test_data[i].len < sizeof(WCHAR)) continue; + /* Before Windows 11 1-byte Unicode strings crash on Win64 + * because it underflows when 'appending' a 2 bytes NUL character! + */ + if (!test_data[i].strA[0] && test_data[i].len < sizeof(WCHAR) && + strcmp(winetest_platform, "windows") == 0) continue; #endif - r = OpenClipboard( 0 ); - ok( r, "gle %d\n", GetLastError() ); + winetest_push_context("%d", i); + r = open_clipboard( 0 ); + ok( r, "gle %ld\n", GetLastError() ); r = EmptyClipboard(); - ok( r, "gle %d\n", GetLastError() ); + ok( r, "gle %ld\n", GetLastError() ); data = GlobalAlloc( GMEM_FIXED, test_data[i].len ); if (test_data[i].strA[0]) { @@ -2068,21 +2272,28 @@ static void test_string_data(void) memcpy( bufferA, test_data[i].strA, test_data[i].len ); bufferA[test_data[i].len - 1] = 0; ok( !memcmp( data, bufferA, test_data[i].len ), - "%u: wrong data %.*s\n", i, test_data[i].len, (char *)data ); + "wrong data %.*s\n", test_data[i].len, (char *)data ); } else { memcpy( data, test_data[i].strW, test_data[i].len ); - SetClipboardData( CF_UNICODETEXT, data ); - memcpy( bufferW, test_data[i].strW, test_data[i].len ); - bufferW[(test_data[i].len + 1) / sizeof(WCHAR) - 1] = 0; - ok( !memcmp( data, bufferW, test_data[i].len ), - "%u: wrong data %s\n", i, wine_dbgstr_wn( data, (test_data[i].len + 1) / sizeof(WCHAR) )); + clip = SetClipboardData( CF_UNICODETEXT, data ); + if (test_data[i].len >= sizeof(WCHAR)) + { + ok( clip == data, "SetClipboardData() returned %p != %p\n", clip, data ); + memcpy( bufferW, test_data[i].strW, test_data[i].len ); + *((WCHAR *)((char *)bufferW + test_data[i].len) - 1) = 0; + ok( !memcmp( data, bufferW, test_data[i].len ), + "wrong data %s\n", wine_dbgstr_an( data, test_data[i].len )); + } + else + ok( !clip || broken(clip != NULL), "expected SetClipboardData() to fail\n" ); } r = CloseClipboard(); - ok( r, "gle %d\n", GetLastError() ); + ok( r, "gle %ld\n", GetLastError() ); sprintf( cmd, "string_data %u", i ); run_process( cmd ); + winetest_pop_context(); } } @@ -2094,53 +2305,72 @@ static void test_string_data_process( int i ) char bufferA[12]; WCHAR bufferW[12]; - r = OpenClipboard( 0 ); - ok( r, "gle %d\n", GetLastError() ); + winetest_push_context("%d", i); + r = open_clipboard( 0 ); + ok( r, "gle %ld\n", GetLastError() ); if (test_data[i].strA[0]) { data = GetClipboardData( CF_TEXT ); - ok( data != 0, "%u: could not get data\n", i ); + ok( data != 0, "could not get data\n" ); len = GlobalSize( data ); - ok( len == test_data[i].len, "%u: wrong size %u / %u\n", i, len, test_data[i].len ); + ok( len == test_data[i].len, "wrong size %u / %u\n", len, test_data[i].len ); memcpy( bufferA, test_data[i].strA, test_data[i].len ); bufferA[test_data[i].len - 1] = 0; - ok( !memcmp( data, bufferA, len ), "%u: wrong data %.*s\n", i, len, (char *)data ); + ok( !memcmp( data, bufferA, len ), "wrong data %.*s\n", len, (char *)data ); data = GetClipboardData( CF_UNICODETEXT ); - ok( data != 0, "%u: could not get data\n", i ); + ok( data != 0, "could not get data\n" ); len = GlobalSize( data ); - len2 = MultiByteToWideChar( CP_ACP, 0, bufferA, test_data[i].len, bufferW, 12 ); - ok( len == len2 * sizeof(WCHAR), "%u: wrong size %u / %u\n", i, len, len2 ); - ok( !memcmp( data, bufferW, len ), "%u: wrong data %s\n", i, wine_dbgstr_wn( data, len2 )); + len2 = MultiByteToWideChar( CP_ACP, 0, bufferA, test_data[i].len, bufferW, ARRAY_SIZE(bufferW) ); + ok( len == len2 * sizeof(WCHAR), "wrong size %u / %u\n", len, len2 ); + ok( !memcmp( data, bufferW, len ), "wrong data %s\n", wine_dbgstr_wn( data, len2 )); } else { data = GetClipboardData( CF_UNICODETEXT ); - ok( data != 0, "%u: could not get data\n", i ); - len = GlobalSize( data ); - ok( len == test_data[i].len, "%u: wrong size %u / %u\n", i, len, test_data[i].len ); - memcpy( bufferW, test_data[i].strW, test_data[i].len ); - bufferW[(test_data[i].len + 1) / sizeof(WCHAR) - 1] = 0; - ok( !memcmp( data, bufferW, len ), - "%u: wrong data %s\n", i, wine_dbgstr_wn( data, (len + 1) / sizeof(WCHAR) )); - data = GetClipboardData( CF_TEXT ); - if (test_data[i].len >= sizeof(WCHAR)) + if (!data) { - ok( data != 0, "%u: could not get data\n", i ); + ok( test_data[i].len < sizeof(WCHAR), "got no data for len=%d\n", test_data[i].len ); + ok( !IsClipboardFormatAvailable( CF_UNICODETEXT ), "unicode available\n" ); + } + else if (test_data[i].len == 0) + { + /* 0-byte string handling is broken on Windows <= 10 */ len = GlobalSize( data ); - len2 = WideCharToMultiByte( CP_ACP, 0, bufferW, test_data[i].len / sizeof(WCHAR), - bufferA, 12, NULL, NULL ); - bufferA[len2 - 1] = 0; - ok( len == len2, "%u: wrong size %u / %u\n", i, len, len2 ); - ok( !memcmp( data, bufferA, len ), "%u: wrong data %.*s\n", i, len, (char *)data ); + ok( broken(len == 1), "wrong size %u / 0\n", len ); + ok( broken(*((char*)data) == 0), "wrong data %s\n", wine_dbgstr_an( data, len )); } else { - ok( !data, "%u: got data for empty string\n", i ); - ok( IsClipboardFormatAvailable( CF_TEXT ), "%u: text not available\n", i ); + len = GlobalSize( data ); + ok( len == test_data[i].len, "wrong size %u / %u\n", len, test_data[i].len ); + memcpy( bufferW, test_data[i].strW, test_data[i].len ); + *((WCHAR *)((char *)bufferW + test_data[i].len) - 1) = 0; + ok( !memcmp( data, bufferW, len ), "wrong data %s\n", wine_dbgstr_an( data, len )); + } + + data = GetClipboardData( CF_TEXT ); + if (test_data[i].len >= sizeof(WCHAR)) + { + ok( data != 0, "could not get data\n" ); + len = GlobalSize( data ); + len2 = WideCharToMultiByte( CP_ACP, 0, bufferW, test_data[i].len / sizeof(WCHAR), + bufferA, ARRAY_SIZE(bufferA), NULL, NULL ); + bufferA[len2 - 1] = 0; + ok( len == len2, "wrong size %u / %u\n", len, len2 ); + ok( !memcmp( data, bufferA, len ), "wrong data %s, expected %s\n", + wine_dbgstr_an( data, len ), wine_dbgstr_an( bufferA, len2 )); + } + else + { + BOOL available = IsClipboardFormatAvailable( CF_TEXT ); + ok( !available || broken(available /* win10 */), + "available text %d\n", available ); + ok( !data, "got data for empty string\n" ); } } r = CloseClipboard(); - ok( r, "gle %d\n", GetLastError() ); + ok( r, "gle %ld\n", GetLastError() ); + winetest_pop_context(); } START_TEST(clipboard) @@ -2153,6 +2383,7 @@ START_TEST(clipboard) pAddClipboardFormatListener = (void *)GetProcAddress( mod, "AddClipboardFormatListener" ); pRemoveClipboardFormatListener = (void *)GetProcAddress( mod, "RemoveClipboardFormatListener" ); pGetUpdatedClipboardFormats = (void *)GetProcAddress( mod, "GetUpdatedClipboardFormats" ); + pGlobalFree = (void *)GetProcAddress( GetModuleHandleA( "kernel32" ), "GlobalFree" ); if (argc == 4 && !strcmp( argv[2], "set_clipboard_data" )) { diff --git a/modules/rostests/winetests/user32/combo.c b/modules/rostests/winetests/user32/combo.c index 0d3b1b170f5..3ece418af64 100644 --- a/modules/rostests/winetests/user32/combo.c +++ b/modules/rostests/winetests/user32/combo.c @@ -24,6 +24,9 @@ #define STRICT #define WIN32_LEAN_AND_MEAN #include +#ifdef __REACTOS__ +#include +#endif #include "wine/test.h" @@ -43,7 +46,7 @@ static HWND build_combo(DWORD style) return CreateWindowA("ComboBox", "Combo", WS_VISIBLE|WS_CHILD|style, 5, 5, 100, 100, hMainWnd, (HMENU)COMBO_ID, NULL, 0); } -static int font_height(HFONT hFont) +static int get_font_height(HFONT hFont) { TEXTMETRICA tm; HFONT hFontOld; @@ -74,12 +77,13 @@ static BOOL is_font_installed(const char *name) static void test_setitemheight(DWORD style) { HWND hCombo = build_combo(style); + int i, font_height, height; + HFONT hFont; RECT r; - int i; - trace("Style %x\n", style); + trace("Style %lx\n", style); GetClientRect(hCombo, &r); - expect_rect(r, 0, 0, 100, font_height(GetStockObject(SYSTEM_FONT)) + 8); + expect_rect(r, 0, 0, 100, get_font_height(GetStockObject(SYSTEM_FONT)) + 8); SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r); MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); todo_wine expect_rect(r, 5, 5, 105, 105); @@ -92,6 +96,22 @@ static void test_setitemheight(DWORD style) } DestroyWindow(hCombo); + + /* Set item height below text height, force resize. */ + hCombo = build_combo(style); + + hFont = (HFONT)SendMessageA(hCombo, WM_GETFONT, 0, 0); + font_height = get_font_height(hFont); + SendMessageA(hCombo, CB_SETITEMHEIGHT, -1, font_height / 2); + height = SendMessageA(hCombo, CB_GETITEMHEIGHT, -1, 0); + todo_wine + ok(height == font_height / 2, "Unexpected item height %d, expected %d.\n", height, font_height / 2); + + SetWindowPos(hCombo, NULL, 10, 10, 150, 5 * font_height, SWP_SHOWWINDOW); + height = SendMessageA(hCombo, CB_GETITEMHEIGHT, -1, 0); + ok(height > font_height, "Unexpected item height %d, font height %d.\n", height, font_height); + + DestroyWindow(hCombo); } static void test_setfont(DWORD style) @@ -107,14 +127,14 @@ static void test_setfont(DWORD style) return; } - trace("Style %x\n", style); + trace("Style %lx\n", style); hCombo = build_combo(style); hFont1 = CreateFontA(10, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, SYMBOL_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett"); hFont2 = CreateFontA(8, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, SYMBOL_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett"); GetClientRect(hCombo, &r); - expect_rect(r, 0, 0, 100, font_height(GetStockObject(SYSTEM_FONT)) + 8); + expect_rect(r, 0, 0, 100, get_font_height(GetStockObject(SYSTEM_FONT)) + 8); SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r); MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); todo_wine expect_rect(r, 5, 5, 105, 105); @@ -123,39 +143,39 @@ static void test_setfont(DWORD style) of the window when it was created. The size of the calculated dropped area changes only by how much the selection area changes, not by how much the list area changes. */ - if (font_height(hFont1) == 10 && font_height(hFont2) == 8) + if (get_font_height(hFont1) == 10 && get_font_height(hFont2) == 8) { SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont1, FALSE); GetClientRect(hCombo, &r); expect_rect(r, 0, 0, 100, 18); SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r); MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); - todo_wine expect_rect(r, 5, 5, 105, 105 - (font_height(GetStockObject(SYSTEM_FONT)) - font_height(hFont1))); + todo_wine expect_rect(r, 5, 5, 105, 105 - (get_font_height(GetStockObject(SYSTEM_FONT)) - get_font_height(hFont1))); SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont2, FALSE); GetClientRect(hCombo, &r); expect_rect(r, 0, 0, 100, 16); SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r); MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); - todo_wine expect_rect(r, 5, 5, 105, 105 - (font_height(GetStockObject(SYSTEM_FONT)) - font_height(hFont2))); + todo_wine expect_rect(r, 5, 5, 105, 105 - (get_font_height(GetStockObject(SYSTEM_FONT)) - get_font_height(hFont2))); SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont1, FALSE); GetClientRect(hCombo, &r); expect_rect(r, 0, 0, 100, 18); SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r); MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); - todo_wine expect_rect(r, 5, 5, 105, 105 - (font_height(GetStockObject(SYSTEM_FONT)) - font_height(hFont1))); + todo_wine expect_rect(r, 5, 5, 105, 105 - (get_font_height(GetStockObject(SYSTEM_FONT)) - get_font_height(hFont1))); } else { ok(0, "Expected Marlett font heights 10/8, got %d/%d\n", - font_height(hFont1), font_height(hFont2)); + get_font_height(hFont1), get_font_height(hFont2)); } for (i = 1; i < 30; i++) { HFONT hFont = CreateFontA(i, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, SYMBOL_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett"); - int height = font_height(hFont); + int height = get_font_height(hFont); SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont, FALSE); GetClientRect(hCombo, &r); @@ -173,6 +193,8 @@ static LRESULT (CALLBACK *old_parent_proc)(HWND hwnd, UINT msg, WPARAM wparam, L static LPCSTR expected_edit_text; static LPCSTR expected_list_text; static BOOL selchange_fired; +static HWND lparam_for_WM_CTLCOLOR; +static HBRUSH brush_red; static LRESULT CALLBACK parent_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { @@ -204,6 +226,20 @@ static LRESULT CALLBACK parent_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPAR break; } break; + case WM_CTLCOLOR: + case WM_CTLCOLORMSGBOX: + case WM_CTLCOLOREDIT: + case WM_CTLCOLORLISTBOX: + case WM_CTLCOLORBTN: + case WM_CTLCOLORDLG: + case WM_CTLCOLORSCROLLBAR: + case WM_CTLCOLORSTATIC: + if (lparam_for_WM_CTLCOLOR) + { + ok(lparam_for_WM_CTLCOLOR == (HWND)lparam, "Expected %p, got %p\n", lparam_for_WM_CTLCOLOR, (HWND)lparam); + return (LRESULT) brush_red; + } + break; } return CallWindowProcA(old_parent_proc, hwnd, msg, wparam, lparam); @@ -301,7 +337,7 @@ static void test_WM_LBUTTONDOWN(void) cbInfo.cbSize = sizeof(COMBOBOXINFO); SetLastError(0xdeadbeef); ret = GetComboBoxInfo(hCombo, &cbInfo); - ok(ret, "Failed to get combobox info structure. LastError=%d\n", + ok(ret, "Failed to get combobox info structure. LastError=%ld\n", GetLastError()); hEdit = cbInfo.hwndItem; hList = cbInfo.hwndList; @@ -313,7 +349,7 @@ static void test_WM_LBUTTONDOWN(void) x = cbInfo.rcButton.left + (cbInfo.rcButton.right-cbInfo.rcButton.left)/2; y = cbInfo.rcButton.top + (cbInfo.rcButton.bottom-cbInfo.rcButton.top)/2; result = SendMessageA(hCombo, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y)); - ok(result, "WM_LBUTTONDOWN was not processed. LastError=%d\n", + ok(result, "WM_LBUTTONDOWN was not processed. LastError=%ld\n", GetLastError()); ok(SendMessageA(hCombo, CB_GETDROPPEDSTATE, 0, 0), "The dropdown list should have appeared after clicking the button.\n"); @@ -321,7 +357,7 @@ static void test_WM_LBUTTONDOWN(void) ok(GetFocus() == hEdit, "Focus not on ComboBox's Edit Control, instead on %p\n", GetFocus()); result = SendMessageA(hCombo, WM_LBUTTONUP, 0, MAKELPARAM(x, y)); - ok(result, "WM_LBUTTONUP was not processed. LastError=%d\n", + ok(result, "WM_LBUTTONUP was not processed. LastError=%ld\n", GetLastError()); ok(GetFocus() == hEdit, "Focus not on ComboBox's Edit Control, instead on %p\n", GetFocus()); @@ -332,13 +368,13 @@ static void test_WM_LBUTTONDOWN(void) x = rect.left + (rect.right-rect.left)/2; y = item_height/2 + item_height*4; result = SendMessageA(hList, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y)); - ok(!result, "WM_LBUTTONDOWN was not processed. LastError=%d\n", + ok(!result, "WM_LBUTTONDOWN was not processed. LastError=%ld\n", GetLastError()); ok(GetFocus() == hEdit, "Focus not on ComboBox's Edit Control, instead on %p\n", GetFocus()); result = SendMessageA(hList, WM_MOUSEMOVE, 0, MAKELPARAM(x, y)); - ok(!result, "WM_MOUSEMOVE was not processed. LastError=%d\n", + ok(!result, "WM_MOUSEMOVE was not processed. LastError=%ld\n", GetLastError()); ok(GetFocus() == hEdit, "Focus not on ComboBox's Edit Control, instead on %p\n", GetFocus()); @@ -346,7 +382,7 @@ static void test_WM_LBUTTONDOWN(void) "The dropdown list should still be visible.\n"); result = SendMessageA(hList, WM_LBUTTONUP, 0, MAKELPARAM(x, y)); - ok(!result, "WM_LBUTTONUP was not processed. LastError=%d\n", + ok(!result, "WM_LBUTTONUP was not processed. LastError=%ld\n", GetLastError()); ok(GetFocus() == hEdit, "Focus not on ComboBox's Edit Control, instead on %p\n", GetFocus()); @@ -374,29 +410,29 @@ static void test_changesize( DWORD style) /* first make it slightly smaller */ MoveWindow( hCombo, 10, 10, clwidth - 2, clheight - 2, TRUE); GetClientRect( hCombo, &rc); - ok( rc.right - rc.left == clwidth - 2, "clientrect width is %d vs %d\n", + ok( rc.right - rc.left == clwidth - 2, "clientrect width is %ld vs %d\n", rc.right - rc.left, clwidth - 2); - ok( rc.bottom - rc.top == clheight, "clientrect height is %d vs %d\n", + ok( rc.bottom - rc.top == clheight, "clientrect height is %ld vs %d\n", rc.bottom - rc.top, clheight); SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rc); - ok( rc.right - rc.left == clwidth - 2, "drop-down rect width is %d vs %d\n", + ok( rc.right - rc.left == clwidth - 2, "drop-down rect width is %ld vs %d\n", rc.right - rc.left, clwidth - 2); - ok( rc.bottom - rc.top == ddheight, "drop-down rect height is %d vs %d\n", + ok( rc.bottom - rc.top == ddheight, "drop-down rect height is %ld vs %d\n", rc.bottom - rc.top, ddheight); - ok( rc.right - rc.left == ddwidth -2, "drop-down rect width is %d vs %d\n", + ok( rc.right - rc.left == ddwidth -2, "drop-down rect width is %ld vs %d\n", rc.right - rc.left, ddwidth - 2); /* new cx, cy is slightly bigger than the initial values */ MoveWindow( hCombo, 10, 10, clwidth + 2, clheight + 2, TRUE); GetClientRect( hCombo, &rc); - ok( rc.right - rc.left == clwidth + 2, "clientrect width is %d vs %d\n", + ok( rc.right - rc.left == clwidth + 2, "clientrect width is %ld vs %d\n", rc.right - rc.left, clwidth + 2); - ok( rc.bottom - rc.top == clheight, "clientrect height is %d vs %d\n", + ok( rc.bottom - rc.top == clheight, "clientrect height is %ld vs %d\n", rc.bottom - rc.top, clheight); SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rc); - ok( rc.right - rc.left == clwidth + 2, "drop-down rect width is %d vs %d\n", + ok( rc.right - rc.left == clwidth + 2, "drop-down rect width is %ld vs %d\n", rc.right - rc.left, clwidth + 2); todo_wine { - ok( rc.bottom - rc.top == clheight + 2, "drop-down rect height is %d vs %d\n", + ok( rc.bottom - rc.top == clheight + 2, "drop-down rect height is %ld vs %d\n", rc.bottom - rc.top, clheight + 2); } @@ -448,7 +484,7 @@ static void test_editselection(void) cbInfo.cbSize = sizeof(COMBOBOXINFO); SetLastError(0xdeadbeef); ret = GetComboBoxInfo(hCombo, &cbInfo); - ok(ret, "Failed to get combobox info structure. LastError=%d\n", + ok(ret, "Failed to get combobox info structure. LastError=%ld\n", GetLastError()); hEdit = cbInfo.hwndItem; @@ -502,7 +538,7 @@ static void test_editselection(void) cbInfo.cbSize = sizeof(COMBOBOXINFO); SetLastError(0xdeadbeef); ret = GetComboBoxInfo(hCombo, &cbInfo); - ok(ret, "Failed to get combobox info structure. LastError=%d\n", + ok(ret, "Failed to get combobox info structure. LastError=%ld\n", GetLastError()); hEdit = cbInfo.hwndItem; @@ -581,7 +617,7 @@ static void test_editselection_focus(DWORD style) cbInfo.cbSize = sizeof(COMBOBOXINFO); SetLastError(0xdeadbeef); ret = GetComboBoxInfo(hCombo, &cbInfo); - ok(ret, "Failed to get COMBOBOXINFO structure; LastError: %u\n", GetLastError()); + ok(ret, "Failed to get COMBOBOXINFO structure; LastError: %lu\n", GetLastError()); hEdit = cbInfo.hwndItem; hButton = CreateWindowA("Button", "OK", WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON, @@ -652,8 +688,8 @@ static void test_listbox_styles(DWORD cb_style) style = GetWindowLongW( info.hwndList, GWL_STYLE ); exstyle = GetWindowLongW( info.hwndList, GWL_EXSTYLE ); - ok(style == expect_style, "%08x: got %08x\n", cb_style, style); - ok(exstyle == expect_exstyle, "%08x: got %08x\n", cb_style, exstyle); + ok(style == expect_style, "%08lx: got %08lx\n", cb_style, style); + ok(exstyle == expect_exstyle, "%08lx: got %08lx\n", cb_style, exstyle); if (cb_style != CBS_SIMPLE) expect_exstyle |= WS_EX_TOPMOST; @@ -661,14 +697,14 @@ static void test_listbox_styles(DWORD cb_style) SendMessageW(combo, CB_SHOWDROPDOWN, TRUE, 0 ); style = GetWindowLongW( info.hwndList, GWL_STYLE ); exstyle = GetWindowLongW( info.hwndList, GWL_EXSTYLE ); - ok(style == (expect_style | WS_VISIBLE), "%08x: got %08x\n", cb_style, style); - ok(exstyle == expect_exstyle, "%08x: got %08x\n", cb_style, exstyle); + ok(style == (expect_style | WS_VISIBLE), "%08lx: got %08lx\n", cb_style, style); + ok(exstyle == expect_exstyle, "%08lx: got %08lx\n", cb_style, exstyle); SendMessageW(combo, CB_SHOWDROPDOWN, FALSE, 0 ); style = GetWindowLongW( info.hwndList, GWL_STYLE ); exstyle = GetWindowLongW( info.hwndList, GWL_EXSTYLE ); - ok(style == expect_style, "%08x: got %08x\n", cb_style, style); - ok(exstyle == expect_exstyle, "%08x: got %08x\n", cb_style, exstyle); + ok(style == expect_style, "%08lx: got %08lx\n", cb_style, style); + ok(exstyle == expect_exstyle, "%08lx: got %08lx\n", cb_style, exstyle); DestroyWindow(combo); } @@ -726,7 +762,7 @@ static void test_listbox_size(DWORD style) cbInfo.cbSize = sizeof(COMBOBOXINFO); SetLastError(0xdeadbeef); ret = GetComboBoxInfo(hCombo, &cbInfo); - ok(ret, "Failed to get COMBOBOXINFO structure; LastError: %u\n", GetLastError()); + ok(ret, "Failed to get COMBOBOXINFO structure; LastError: %lu\n", GetLastError()); hList = cbInfo.hwndList; for (i = 0; i < info_test->num_items; i++) @@ -736,7 +772,7 @@ static void test_listbox_size(DWORD style) x = cbInfo.rcButton.left + (cbInfo.rcButton.right-cbInfo.rcButton.left)/2; y = cbInfo.rcButton.top + (cbInfo.rcButton.bottom-cbInfo.rcButton.top)/2; ret = SendMessageA(hCombo, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y)); - ok(ret, "WM_LBUTTONDOWN was not processed. LastError=%d\n", + ok(ret, "WM_LBUTTONDOWN was not processed. LastError=%ld\n", GetLastError()); ok(SendMessageA(hCombo, CB_GETDROPPEDSTATE, 0, 0), "The dropdown list should have appeared after clicking the button.\n"); @@ -782,7 +818,7 @@ static void test_WS_VSCROLL(void) SetLastError(0xdeadbeef); ret = GetComboBoxInfo(hCombo, &info); - ok(ret, "Failed to get COMBOBOXINFO structure; LastError: %u\n", GetLastError()); + ok(ret, "Failed to get COMBOBOXINFO structure; LastError: %lu\n", GetLastError()); hList = info.hwndList; for(i = 0; i < 3; i++) @@ -804,8 +840,87 @@ static void test_WS_VSCROLL(void) DestroyWindow(hCombo); } +static void test_combo_ctlcolor(void) +{ + static const int messages[] = + { + WM_CTLCOLOR, + WM_CTLCOLORMSGBOX, + WM_CTLCOLOREDIT, + WM_CTLCOLORLISTBOX, + WM_CTLCOLORBTN, + WM_CTLCOLORDLG, + WM_CTLCOLORSCROLLBAR, + WM_CTLCOLORSTATIC, + }; + + HBRUSH brush, global_brush; + unsigned int i, ret; + COMBOBOXINFO info; + HWND combo; + + combo = build_combo(CBS_DROPDOWN); + ok(!!combo, "Failed to create combo window.\n"); + + old_parent_proc = (void *)SetWindowLongPtrA(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)parent_wnd_proc); + + info.cbSize = sizeof(COMBOBOXINFO); + ret = GetComboBoxInfo(combo, &info); + ok(ret, "Failed to get combobox info structure.\n"); + + lparam_for_WM_CTLCOLOR = info.hwndItem; + + /* Parent returns valid brush handle. */ + for (i = 0; i < ARRAY_SIZE(messages); ++i) + { + brush = (HBRUSH)SendMessageA(combo, messages[i], 0, (LPARAM)info.hwndItem); + ok(brush == brush_red, "%u: unexpected brush %p, expected got %p.\n", i, brush, brush_red); + } + + /* Parent returns NULL brush. */ + global_brush = brush_red; + brush_red = NULL; + + for (i = 0; i < ARRAY_SIZE(messages); ++i) + { + brush = (HBRUSH)SendMessageA(combo, messages[i], 0, (LPARAM)info.hwndItem); + ok(!brush, "%u: unexpected brush %p.\n", i, brush); + } + + brush_red = global_brush; + + lparam_for_WM_CTLCOLOR = 0; + + /* Parent does default processing. */ + for (i = 0; i < ARRAY_SIZE(messages); ++i) + { + brush = (HBRUSH)SendMessageA(combo, messages[i], 0, (LPARAM)info.hwndItem); + ok(!!brush && brush != brush_red, "%u: unexpected brush %p.\n", i, brush); + } + + SetWindowLongPtrA(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)old_parent_proc); + DestroyWindow(combo); + + /* Combo without a parent. */ + combo = CreateWindowA("ComboBox", "Combo", CBS_DROPDOWN, 5, 5, 100, 100, NULL, NULL, NULL, 0); + ok(!!combo, "Failed to create combo window.\n"); + + info.cbSize = sizeof(COMBOBOXINFO); + ret = GetComboBoxInfo(combo, &info); + ok(ret, "Failed to get combobox info structure.\n"); + + for (i = 0; i < ARRAY_SIZE(messages); ++i) + { + brush = (HBRUSH)SendMessageA(combo, messages[i], 0, (LPARAM)info.hwndItem); + ok(!!brush && brush != brush_red, "%u: unexpected brush %p.\n", i, brush); + } + + DestroyWindow(combo); +} + START_TEST(combo) { + brush_red = CreateSolidBrush(RGB(255, 0, 0)); hMainWnd = CreateWindowA("static", "Test", WS_OVERLAPPEDWINDOW, 10, 10, 300, 300, NULL, NULL, NULL, 0); ShowWindow(hMainWnd, SW_SHOW); @@ -825,6 +940,8 @@ START_TEST(combo) test_listbox_styles(CBS_DROPDOWN); test_listbox_styles(CBS_DROPDOWNLIST); test_listbox_size(CBS_DROPDOWN); + test_combo_ctlcolor(); DestroyWindow(hMainWnd); + DeleteObject(brush_red); } diff --git a/modules/rostests/winetests/user32/cursoricon.c b/modules/rostests/winetests/user32/cursoricon.c index 8ce1eb163e1..23ebc7ee602 100644 --- a/modules/rostests/winetests/user32/cursoricon.c +++ b/modules/rostests/winetests/user32/cursoricon.c @@ -321,7 +321,7 @@ static LRESULT CALLBACK callback_child(HWND hwnd, UINT msg, WPARAM wParam, LPARA memset(&info, 0, sizeof(info)); ret = GetIconInfo(cursor, &info); - todo_wine ok(ret, "GetIconInfoEx failed with error %u\n", GetLastError()); + todo_wine ok(ret, "GetIconInfoEx failed with error %lu\n", GetLastError()); todo_wine ok(info.hbmColor != NULL, "info.hmbColor was not set\n"); todo_wine ok(info.hbmMask != NULL, "info.hmbColor was not set\n"); DeleteObject(info.hbmColor); @@ -330,10 +330,10 @@ static LRESULT CALLBACK callback_child(HWND hwnd, UINT msg, WPARAM wParam, LPARA SetLastError(0xdeadbeef); ret = DestroyCursor(cursor); error = GetLastError(); - ok(!ret || broken(ret) /* win9x */, "DestroyCursor on the active cursor succeeded.\n"); + ok(!ret, "DestroyCursor on the active cursor succeeded.\n"); ok(error == ERROR_DESTROY_OBJECT_OF_OTHER_THREAD || error == 0xdeadbeef, /* vista */ - "Last error: %u\n", error); + "Last error: %lu\n", error); return TRUE; } case WM_DESTROY: @@ -375,12 +375,12 @@ static void do_child(void) SetLastError(0xdeadbeef); ret = RegisterClassA(&class); - ok(ret, "Failed to register window class. Error: %u\n", GetLastError()); + ok(ret, "Failed to register window class. Error: %lu\n", GetLastError()); /* Create a window. */ child = CreateWindowA("cursor_child", "cursor_child", WS_POPUP | WS_VISIBLE, 0, 0, 200, 200, 0, 0, 0, NULL); - ok(child != 0, "CreateWindowA failed. Error: %u\n", GetLastError()); + ok(child != 0, "CreateWindowA failed. Error: %lu\n", GetLastError()); /* Let the parent know our HWND. */ PostMessageA(parent, PROC_INIT, (WPARAM) child, 0); @@ -388,7 +388,7 @@ static void do_child(void) /* Receive messages. */ while ((ret = GetMessageA(&msg, 0, 0, 0))) { - ok(ret != -1, "GetMessage failed. Error: %u\n", GetLastError()); + ok(ret != -1, "GetMessage failed. Error: %lu\n", GetLastError()); TranslateMessage(&msg); DispatchMessageA(&msg); } @@ -417,12 +417,12 @@ static void do_parent(void) SetLastError(0xdeadbeef); ret = RegisterClassA(&class); - ok(ret, "Failed to register window class. Error: %u\n", GetLastError()); + ok(ret, "Failed to register window class. Error: %lu\n", GetLastError()); /* Create a window. */ parent = CreateWindowA("cursor_parent", "cursor_parent", WS_POPUP | WS_VISIBLE, 0, 0, 200, 200, 0, 0, 0, NULL); - ok(parent != 0, "CreateWindowA failed. Error: %u\n", GetLastError()); + ok(parent != 0, "CreateWindowA failed. Error: %lu\n", GetLastError()); /* Start child process. */ memset(&startup, 0, sizeof(startup)); @@ -430,14 +430,14 @@ static void do_parent(void) startup.dwFlags = STARTF_USESHOWWINDOW; startup.wShowWindow = SW_SHOWNORMAL; - sprintf(path_name, "%s cursoricon %lx", test_argv[0], (INT_PTR)parent); + sprintf(path_name, "%s cursoricon %Ix", test_argv[0], (INT_PTR)parent); ok(CreateProcessA(NULL, path_name, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed.\n"); child_process = info.hProcess; /* Wait for child window handle. */ while ((child == 0) && (ret = GetMessageA(&msg, parent, 0, 0))) { - ok(ret != -1, "GetMessage failed. Error: %u\n", GetLastError()); + ok(ret != -1, "GetMessage failed. Error: %lu\n", GetLastError()); TranslateMessage(&msg); DispatchMessageA(&msg); } @@ -446,7 +446,7 @@ static void do_parent(void) static void finish_child_process(void) { SendMessageA(child, WM_CLOSE, 0, 0); - winetest_wait_child_process( child_process ); + wait_child_process( child_process ); CloseHandle(child_process); } @@ -486,22 +486,61 @@ static BOOL color_match(COLORREF a, COLORREF b) return (a & 0x00F8F8F8) == (b & 0x00F8F8F8); } -static void test_CopyImage_Check(HBITMAP bitmap, UINT flags, INT copyWidth, INT copyHeight, - INT expectedWidth, INT expectedHeight, WORD expectedDepth, BOOL dibExpected) +static void check_copy_image(HBITMAP bitmap, UINT type, UINT flags, INT copyWidth, INT copyHeight, + INT expectedWidth, INT expectedHeight, WORD expectedDepth, BOOL dibExpected) { HBITMAP copy; BITMAP origBitmap; BITMAP copyBitmap; - BOOL orig_is_dib; BOOL copy_is_dib; + BOOL ret; +#ifdef __REACTOS__ + UINT display_bpp; + HDC hdc; - copy = CopyImage(bitmap, IMAGE_BITMAP, copyWidth, copyHeight, flags); + hdc = GetDC(0); + display_bpp = GetDeviceCaps(hdc, BITSPIXEL); + ReleaseDC(0, hdc); +#endif + + GetObjectA(bitmap, sizeof(origBitmap), &origBitmap); + + winetest_push_context("%s, type %#x, flags %#x, size %ux%u", + origBitmap.bmBits ? "DIB" : "DDB", type, flags, copyWidth, copyHeight); + + if (type == IMAGE_BITMAP) + { + copy = CopyImage(bitmap, type, copyWidth, copyHeight, flags); + } + else + { + ICONINFO info = + { + .fIcon = (type == IMAGE_ICON), + .hbmColor = bitmap, + .hbmMask = bitmap, + }; + HICON icon = CreateIconIndirect(&info); + ok(!!icon, "Failed to create icon, error %lu\n", GetLastError()); + copy = CopyImage(icon, type, copyWidth, copyHeight, flags); + ret = DestroyIcon(icon); + ok(ret, "Failed to destroy icon, error %lu\n", GetLastError()); + } ok(copy != NULL, "CopyImage() failed\n"); if (copy != NULL) { - GetObjectA(bitmap, sizeof(origBitmap), &origBitmap); - GetObjectA(copy, sizeof(copyBitmap), ©Bitmap); - orig_is_dib = (origBitmap.bmBits != NULL); + if (type == IMAGE_BITMAP) + { + GetObjectA(copy, sizeof(copyBitmap), ©Bitmap); + } + else + { + ICONINFO info; + + ret = GetIconInfo((HICON)copy, &info); + ok(ret, "Failed to get icon info, error %lu\n", GetLastError()); + GetObjectA(info.hbmColor, sizeof(copyBitmap), ©Bitmap); + } copy_is_dib = (copyBitmap.bmBits != NULL); if (copy_is_dib && dibExpected @@ -525,21 +564,54 @@ static void test_CopyImage_Check(HBITMAP bitmap, UINT flags, INT copyWidth, INT expectedDepth = origBitmap.bmBitsPixel; } - ok((!(dibExpected ^ copy_is_dib) - && (copyBitmap.bmWidth == expectedWidth) - && (copyBitmap.bmHeight == expectedHeight) - && (copyBitmap.bmBitsPixel == expectedDepth)), - "CopyImage ((%s, %dx%d, %u bpp), %d, %d, %#x): Expected (%s, %dx%d, %u bpp), got (%s, %dx%d, %u bpp)\n", - orig_is_dib ? "DIB" : "DDB", origBitmap.bmWidth, origBitmap.bmHeight, origBitmap.bmBitsPixel, - copyWidth, copyHeight, flags, - dibExpected ? "DIB" : "DDB", expectedWidth, expectedHeight, expectedDepth, - copy_is_dib ? "DIB" : "DDB", copyBitmap.bmWidth, copyBitmap.bmHeight, copyBitmap.bmBitsPixel); + if (type != IMAGE_BITMAP) + { + dibExpected = FALSE; + expectedDepth = 32; + } - DeleteObject(copy); + ok(copy_is_dib == dibExpected, "Expected %s, got %s\n", + dibExpected ? "DIB" : "DDB", copy_is_dib ? "DIB" : "DDB"); + ok(copyBitmap.bmWidth == expectedWidth, "Expected width %u, got %u\n", + expectedWidth, copyBitmap.bmWidth); + ok(copyBitmap.bmHeight == expectedHeight, "Expected height %u, got %u\n", + expectedHeight, copyBitmap.bmHeight); +#ifdef __REACTOS__ + ok(copyBitmap.bmBitsPixel == expectedDepth || broken(copyBitmap.bmBitsPixel == display_bpp && expectedDepth == 32), "Expected depth %u, got %u\n", + expectedDepth, copyBitmap.bmBitsPixel); +#else + ok(copyBitmap.bmBitsPixel == expectedDepth, "Expected depth %u, got %u\n", + expectedDepth, copyBitmap.bmBitsPixel); +#endif + + if (type != IMAGE_BITMAP) + { + ICONINFO info; + + ret = GetIconInfo((HICON)copy, &info); + ok(ret, "Failed to get icon info, error %lu\n", GetLastError()); + GetObjectA(info.hbmMask, sizeof(copyBitmap), ©Bitmap); + + ok(!copyBitmap.bmBits, "Expected DDB\n"); + ok(copyBitmap.bmWidth == expectedWidth, "Expected mask width %u, got %u\n", + expectedWidth, copyBitmap.bmWidth); + ok(copyBitmap.bmHeight == expectedHeight, "Expected mask height %u, got %u\n", + expectedHeight, copyBitmap.bmHeight); + ok(copyBitmap.bmBitsPixel == 1, "Got mask depth %u\n", copyBitmap.bmBitsPixel); + } + + if (type == IMAGE_BITMAP) + DeleteObject(copy); + else if (type == IMAGE_ICON) + DestroyIcon((HICON)copy); + else + DestroyCursor((HCURSOR)copy); } + + winetest_pop_context(); } -static void test_CopyImage_Bitmap(int depth) +static void do_test_copy_image(UINT type, UINT depth) { HBITMAP ddb, dib; HDC screenDC; @@ -549,7 +621,7 @@ static void test_CopyImage_Bitmap(int depth) unsigned int i; /* Create a device-independent bitmap (DIB) */ - info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); + info = calloc(1, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); info->bmiHeader.biSize = sizeof(info->bmiHeader); info->bmiHeader.biWidth = 2; info->bmiHeader.biHeight = 2; @@ -582,53 +654,53 @@ static void test_CopyImage_Bitmap(int depth) if (ddb != NULL) { - test_CopyImage_Check(ddb, 0, 0, 0, 2, 2, depth == 1 ? 1 : screen_depth, FALSE); - test_CopyImage_Check(ddb, 0, 0, 5, 2, 5, depth == 1 ? 1 : screen_depth, FALSE); - test_CopyImage_Check(ddb, 0, 5, 0, 5, 2, depth == 1 ? 1 : screen_depth, FALSE); - test_CopyImage_Check(ddb, 0, 5, 5, 5, 5, depth == 1 ? 1 : screen_depth, FALSE); + check_copy_image(ddb, type, 0, 0, 0, 2, 2, depth == 1 ? 1 : screen_depth, FALSE); + check_copy_image(ddb, type, 0, 0, 5, 2, 5, depth == 1 ? 1 : screen_depth, FALSE); + check_copy_image(ddb, type, 0, 5, 0, 5, 2, depth == 1 ? 1 : screen_depth, FALSE); + check_copy_image(ddb, type, 0, 5, 5, 5, 5, depth == 1 ? 1 : screen_depth, FALSE); - test_CopyImage_Check(ddb, LR_MONOCHROME, 0, 0, 2, 2, 1, FALSE); - test_CopyImage_Check(ddb, LR_MONOCHROME, 5, 0, 5, 2, 1, FALSE); - test_CopyImage_Check(ddb, LR_MONOCHROME, 0, 5, 2, 5, 1, FALSE); - test_CopyImage_Check(ddb, LR_MONOCHROME, 5, 5, 5, 5, 1, FALSE); + check_copy_image(ddb, type, LR_MONOCHROME, 0, 0, 2, 2, 1, FALSE); + check_copy_image(ddb, type, LR_MONOCHROME, 5, 0, 5, 2, 1, FALSE); + check_copy_image(ddb, type, LR_MONOCHROME, 0, 5, 2, 5, 1, FALSE); + check_copy_image(ddb, type, LR_MONOCHROME, 5, 5, 5, 5, 1, FALSE); - test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE); - test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE); - test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE); - test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE); + check_copy_image(ddb, type, LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE); + check_copy_image(ddb, type, LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE); + check_copy_image(ddb, type, LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE); + check_copy_image(ddb, type, LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE); /* LR_MONOCHROME is ignored if LR_CREATEDIBSECTION is present */ - test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE); - test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE); - test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE); - test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE); + check_copy_image(ddb, type, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE); + check_copy_image(ddb, type, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE); + check_copy_image(ddb, type, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE); + check_copy_image(ddb, type, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE); DeleteObject(ddb); } if (depth != 1) { - test_CopyImage_Check(dib, 0, 0, 0, 2, 2, screen_depth, FALSE); - test_CopyImage_Check(dib, 0, 5, 0, 5, 2, screen_depth, FALSE); - test_CopyImage_Check(dib, 0, 0, 5, 2, 5, screen_depth, FALSE); - test_CopyImage_Check(dib, 0, 5, 5, 5, 5, screen_depth, FALSE); + check_copy_image(dib, type, 0, 0, 0, 2, 2, screen_depth, FALSE); + check_copy_image(dib, type, 0, 5, 0, 5, 2, screen_depth, FALSE); + check_copy_image(dib, type, 0, 0, 5, 2, 5, screen_depth, FALSE); + check_copy_image(dib, type, 0, 5, 5, 5, 5, screen_depth, FALSE); } - test_CopyImage_Check(dib, LR_MONOCHROME, 0, 0, 2, 2, 1, FALSE); - test_CopyImage_Check(dib, LR_MONOCHROME, 5, 0, 5, 2, 1, FALSE); - test_CopyImage_Check(dib, LR_MONOCHROME, 0, 5, 2, 5, 1, FALSE); - test_CopyImage_Check(dib, LR_MONOCHROME, 5, 5, 5, 5, 1, FALSE); + check_copy_image(dib, type, LR_MONOCHROME, 0, 0, 2, 2, 1, FALSE); + check_copy_image(dib, type, LR_MONOCHROME, 5, 0, 5, 2, 1, FALSE); + check_copy_image(dib, type, LR_MONOCHROME, 0, 5, 2, 5, 1, FALSE); + check_copy_image(dib, type, LR_MONOCHROME, 5, 5, 5, 5, 1, FALSE); - test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE); - test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE); - test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE); - test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE); + check_copy_image(dib, type, LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE); + check_copy_image(dib, type, LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE); + check_copy_image(dib, type, LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE); + check_copy_image(dib, type, LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE); /* LR_MONOCHROME is ignored if LR_CREATEDIBSECTION is present */ - test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE); - test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE); - test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE); - test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE); + check_copy_image(dib, type, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE); + check_copy_image(dib, type, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE); + check_copy_image(dib, type, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE); + check_copy_image(dib, type, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE); DeleteObject(dib); @@ -651,10 +723,10 @@ static void test_CopyImage_Bitmap(int depth) info->bmiColors[1].rgbBlue = 0; dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0); - test_CopyImage_Check(dib, 0, 0, 0, 2, 2, screen_depth, FALSE); - test_CopyImage_Check(dib, 0, 5, 0, 5, 2, screen_depth, FALSE); - test_CopyImage_Check(dib, 0, 0, 5, 2, 5, screen_depth, FALSE); - test_CopyImage_Check(dib, 0, 5, 5, 5, 5, screen_depth, FALSE); + check_copy_image(dib, type, 0, 0, 0, 2, 2, screen_depth, FALSE); + check_copy_image(dib, type, 0, 5, 0, 5, 2, screen_depth, FALSE); + check_copy_image(dib, type, 0, 0, 5, 2, 5, screen_depth, FALSE); + check_copy_image(dib, type, 0, 5, 5, 5, 5, screen_depth, FALSE); DeleteObject(dib); info->bmiHeader.biBitCount = 1; @@ -666,10 +738,10 @@ static void test_CopyImage_Bitmap(int depth) info->bmiColors[1].rgbBlue = 0xFF; dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0); - test_CopyImage_Check(dib, 0, 0, 0, 2, 2, 1, FALSE); - test_CopyImage_Check(dib, 0, 5, 0, 5, 2, 1, FALSE); - test_CopyImage_Check(dib, 0, 0, 5, 2, 5, 1, FALSE); - test_CopyImage_Check(dib, 0, 5, 5, 5, 5, 1, FALSE); + check_copy_image(dib, type, 0, 0, 0, 2, 2, 1, FALSE); + check_copy_image(dib, type, 0, 5, 0, 5, 2, 1, FALSE); + check_copy_image(dib, type, 0, 0, 5, 2, 5, 1, FALSE); + check_copy_image(dib, type, 0, 5, 5, 5, 5, 1, FALSE); DeleteObject(dib); info->bmiHeader.biBitCount = 1; @@ -681,15 +753,15 @@ static void test_CopyImage_Bitmap(int depth) info->bmiColors[1].rgbBlue = 0; dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0); - test_CopyImage_Check(dib, 0, 0, 0, 2, 2, 1, FALSE); - test_CopyImage_Check(dib, 0, 5, 0, 5, 2, 1, FALSE); - test_CopyImage_Check(dib, 0, 0, 5, 2, 5, 1, FALSE); - test_CopyImage_Check(dib, 0, 5, 5, 5, 5, 1, FALSE); + check_copy_image(dib, type, 0, 0, 0, 2, 2, 1, FALSE); + check_copy_image(dib, type, 0, 5, 0, 5, 2, 1, FALSE); + check_copy_image(dib, type, 0, 0, 5, 2, 5, 1, FALSE); + check_copy_image(dib, type, 0, 5, 5, 5, 5, 1, FALSE); DeleteObject(dib); } } - HeapFree(GetProcessHeap(), 0, info); + free(info); } static void test_initial_cursor(void) @@ -706,11 +778,13 @@ static void test_initial_cursor(void) ok(cursor == cursor2, "cursor (%p) is not IDC_WAIT (%p).\n", cursor, cursor2); } error = GetLastError(); - ok(error == 0xdeadbeef, "Last error: 0x%08x\n", error); + ok(error == 0xdeadbeef, "Last error: 0x%08lx\n", error); } -static void test_icon_info_dbg(HICON hIcon, UINT exp_cx, UINT exp_cy, UINT exp_mask_cy, UINT exp_bpp, int line) +static void test_icon_info_(HICON hIcon, UINT exp_cx, UINT exp_cy, + UINT exp_mask_cy, UINT exp_bpp, const BYTE *mask_bits, UINT has_color, int line) { + BYTE ret_bits[1024]; ICONINFO info; DWORD ret; BITMAP bmMask, bmColor; @@ -719,15 +793,23 @@ static void test_icon_info_dbg(HICON hIcon, UINT exp_cx, UINT exp_cy, UINT exp_m ok_(__FILE__, line)(ret, "GetIconInfo failed\n"); /* CreateIcon under XP causes info.fIcon to be 0 */ - ok_(__FILE__, line)(info.xHotspot == exp_cx/2, "info.xHotspot = %u\n", info.xHotspot); - ok_(__FILE__, line)(info.yHotspot == exp_cy/2, "info.yHotspot = %u\n", info.yHotspot); + ok_(__FILE__, line)(info.xHotspot == exp_cx/2, "info.xHotspot = %lu\n", info.xHotspot); + ok_(__FILE__, line)(info.yHotspot == exp_cy/2, "info.yHotspot = %lu\n", info.yHotspot); ok_(__FILE__, line)(info.hbmMask != 0, "info.hbmMask is NULL\n"); - ret = GetObjectA(info.hbmMask, sizeof(bmMask), &bmMask); - ok_(__FILE__, line)(ret == sizeof(bmMask), "GetObject(info.hbmMask) failed, ret %u\n", ret); + if (mask_bits) + { + unsigned int exp_stride = (exp_cx + 7) / 8; + exp_stride = (exp_stride + 1) & ~1; + ret = GetBitmapBits(info.hbmMask, sizeof(ret_bits), ret_bits); + ok_(__FILE__, line)(ret == exp_stride * exp_mask_cy, "GetBitmapBits returned %lu\n", ret); + ok_(__FILE__, line)(!memcmp(ret_bits, mask_bits, ret), "mask bitmap didn't match\n"); + } - if (exp_bpp == 1) - ok_(__FILE__, line)(info.hbmColor == 0, "info.hbmColor should be NULL\n"); + ret = GetObjectA(info.hbmMask, sizeof(bmMask), &bmMask); + ok_(__FILE__, line)(ret == sizeof(bmMask), "GetObject(info.hbmMask) failed, ret %lu\n", ret); + + ok_(__FILE__, line)(!!info.hbmColor == has_color, "got hbmColor %p\n", info.hbmColor); if (info.hbmColor) { @@ -739,11 +821,15 @@ static void test_icon_info_dbg(HICON hIcon, UINT exp_cx, UINT exp_cy, UINT exp_m ReleaseDC(0, hdc); ret = GetObjectA(info.hbmColor, sizeof(bmColor), &bmColor); - ok_(__FILE__, line)(ret == sizeof(bmColor), "GetObject(info.hbmColor) failed, ret %u\n", ret); + ok_(__FILE__, line)(ret == sizeof(bmColor), "GetObject(info.hbmColor) failed, ret %lu\n", ret); - ok_(__FILE__, line)(bmColor.bmBitsPixel == display_bpp /* XP */ || - bmColor.bmBitsPixel == exp_bpp /* Win98 */, +#ifdef __REACTOS__ + ok_(__FILE__, line)(bmColor.bmBitsPixel == display_bpp || broken(!bmColor.bmBits && bmColor.bmBitsPixel == 32) /* Happens with PrivateExtractIcons test */, "bmColor.bmBitsPixel = %d\n", bmColor.bmBitsPixel); +#else + ok_(__FILE__, line)(bmColor.bmBitsPixel == display_bpp, + "bmColor.bmBitsPixel = %d\n", bmColor.bmBitsPixel); +#endif ok_(__FILE__, line)(bmColor.bmWidth == exp_cx, "bmColor.bmWidth = %d\n", bmColor.bmWidth); ok_(__FILE__, line)(bmColor.bmHeight == exp_cy, "bmColor.bmHeight = %d\n", bmColor.bmHeight); @@ -766,35 +852,35 @@ static void test_icon_info_dbg(HICON hIcon, UINT exp_cx, UINT exp_cy, UINT exp_m infoex.cbSize = sizeof(infoex) - 1; ret = pGetIconInfoExA( hIcon, &infoex ); ok_(__FILE__, line)(!ret, "GetIconInfoEx succeeded\n"); - ok_(__FILE__, line)(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %d\n", GetLastError()); + ok_(__FILE__, line)(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %ld\n", GetLastError()); SetLastError( 0xdeadbeef ); infoex.cbSize = sizeof(infoex) + 1; ret = pGetIconInfoExA( hIcon, &infoex ); ok_(__FILE__, line)(!ret, "GetIconInfoEx succeeded\n"); - ok_(__FILE__, line)(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %d\n", GetLastError()); + ok_(__FILE__, line)(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %ld\n", GetLastError()); SetLastError( 0xdeadbeef ); infoex.cbSize = sizeof(infoex); ret = pGetIconInfoExA( (HICON)0xdeadbabe, &infoex ); ok_(__FILE__, line)(!ret, "GetIconInfoEx succeeded\n"); ok_(__FILE__, line)(GetLastError() == ERROR_INVALID_CURSOR_HANDLE, - "wrong error %d\n", GetLastError()); + "wrong error %ld\n", GetLastError()); infoex.cbSize = sizeof(infoex); ret = pGetIconInfoExA( hIcon, &infoex ); - ok_(__FILE__, line)(ret, "GetIconInfoEx failed err %d\n", GetLastError()); + ok_(__FILE__, line)(ret, "GetIconInfoEx failed err %ld\n", GetLastError()); ok_(__FILE__, line)(infoex.wResID == 0, "GetIconInfoEx wrong resid %x\n", infoex.wResID); ok_(__FILE__, line)(infoex.szModName[0] == 0, "GetIconInfoEx wrong module %s\n", infoex.szModName); ok_(__FILE__, line)(infoex.szResName[0] == 0, "GetIconInfoEx wrong name %s\n", infoex.szResName); } } -#define test_icon_info(a,b,c,d,e) test_icon_info_dbg((a),(b),(c),(d),(e),__LINE__) +#define test_icon_info(a,b,c,d,e,f,g) test_icon_info_(a,b,c,d,e,f,g,__LINE__) static void test_CreateIcon(void) { - static const BYTE bmp_bits[1024]; + BYTE bmp_bits[1024]; HICON hIcon; HBITMAP hbmMask, hbmColor; BITMAPINFO *bmpinfo; @@ -804,6 +890,9 @@ static void test_CreateIcon(void) UINT display_bpp; int i; + for (i = 0; i < sizeof(bmp_bits); ++i) + bmp_bits[i] = 111 * i; + hdc = GetDC(0); display_bpp = GetDeviceCaps(hdc, BITSPIXEL); @@ -812,14 +901,19 @@ static void test_CreateIcon(void) hIcon = CreateIcon(0, 16, 16, 1, 1, NULL, bmp_bits); */ - hIcon = CreateIcon(0, 16, 16, 1, 1, bmp_bits, bmp_bits); + hIcon = CreateIcon(0, 16, 16, 1, 1, bmp_bits, &bmp_bits[16 * 16 / 8]); ok(hIcon != 0, "CreateIcon failed\n"); - test_icon_info(hIcon, 16, 16, 32, 1); + test_icon_info(hIcon, 16, 16, 32, 1, bmp_bits, FALSE); DestroyIcon(hIcon); + hIcon = CreateCursor(0, 8, 8, 16, 16, bmp_bits, &bmp_bits[16 * 16 / 8]); + ok(hIcon != 0, "CreateCursor failed\n"); + test_icon_info(hIcon, 16, 16, 32, 1, bmp_bits, FALSE); + DestroyCursor(hIcon); + hIcon = CreateIcon(0, 16, 16, 1, display_bpp, bmp_bits, bmp_bits); ok(hIcon != 0, "CreateIcon failed\n"); - test_icon_info(hIcon, 16, 16, 16, display_bpp); + test_icon_info(hIcon, 16, 16, 16, display_bpp, bmp_bits, TRUE); DestroyIcon(hIcon); hbmMask = CreateBitmap(16, 16, 1, 1, bmp_bits); @@ -835,7 +929,7 @@ static void test_CreateIcon(void) SetLastError(0xdeadbeaf); hIcon = CreateIconIndirect(&info); ok(!hIcon, "CreateIconIndirect should fail\n"); - ok(GetLastError() == 0xdeadbeaf, "wrong error %u\n", GetLastError()); + ok(GetLastError() == 0xdeadbeaf, "wrong error %lu\n", GetLastError()); info.fIcon = TRUE; info.xHotspot = 8; @@ -845,7 +939,7 @@ static void test_CreateIcon(void) SetLastError(0xdeadbeaf); hIcon = CreateIconIndirect(&info); ok(!hIcon, "CreateIconIndirect should fail\n"); - ok(GetLastError() == 0xdeadbeaf, "wrong error %u\n", GetLastError()); + ok(GetLastError() == 0xdeadbeaf, "wrong error %lu\n", GetLastError()); info.fIcon = TRUE; info.xHotspot = 8; @@ -854,7 +948,7 @@ static void test_CreateIcon(void) info.hbmColor = hbmColor; hIcon = CreateIconIndirect(&info); ok(hIcon != 0, "CreateIconIndirect failed\n"); - test_icon_info(hIcon, 16, 16, 16, display_bpp); + test_icon_info(hIcon, 16, 16, 16, display_bpp, bmp_bits, TRUE); DestroyIcon(hIcon); DeleteObject(hbmMask); @@ -871,8 +965,17 @@ static void test_CreateIcon(void) SetLastError(0xdeadbeaf); hIcon = CreateIconIndirect(&info); ok(hIcon != 0, "CreateIconIndirect failed\n"); - test_icon_info(hIcon, 16, 16, 32, 1); + test_icon_info(hIcon, 16, 16, 32, 1, bmp_bits, FALSE); DestroyIcon(hIcon); + + info.hbmMask = hbmMask; + info.hbmColor = hbmMask; + SetLastError(0xdeadbeaf); + hIcon = CreateIconIndirect(&info); + ok(hIcon != 0, "CreateIconIndirect failed\n"); + test_icon_info(hIcon, 16, 32, 32, 1, bmp_bits, TRUE); + DestroyIcon(hIcon); + DeleteObject(hbmMask); for (i = 0; i <= 4; i++) @@ -888,14 +991,27 @@ static void test_CreateIcon(void) SetLastError(0xdeadbeaf); hIcon = CreateIconIndirect(&info); ok(hIcon != 0, "CreateIconIndirect failed\n"); - test_icon_info(hIcon, 1, i / 2, max(i,1), 1); + test_icon_info(hIcon, 1, i / 2, max(i,1), 1, NULL, FALSE); DestroyIcon(hIcon); DeleteObject(hbmMask); } + hbmMask = CreateBitmap(16, 32, 1, 16, bmp_bits); + ok(hbmMask != 0, "CreateBitmap failed\n"); + + info.hbmMask = hbmMask; + info.hbmColor = 0; + SetLastError(0xdeadbeaf); + hIcon = CreateIconIndirect(&info); + ok(hIcon != 0, "CreateIconIndirect failed\n"); + test_icon_info(hIcon, 16, 16, 32, 1, NULL, FALSE); + DestroyIcon(hIcon); + + DeleteObject(hbmMask); + /* test creating an icon from a DIB section */ - bmpinfo = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, FIELD_OFFSET(BITMAPINFO,bmiColors[256])); + bmpinfo = calloc( 1, FIELD_OFFSET(BITMAPINFO,bmiColors[256]) ); bmpinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmpinfo->bmiHeader.biWidth = 32; bmpinfo->bmiHeader.biHeight = 32; @@ -920,7 +1036,7 @@ static void test_CreateIcon(void) SetLastError(0xdeadbeaf); hIcon = CreateIconIndirect(&info); ok(hIcon != 0, "CreateIconIndirect failed\n"); - test_icon_info(hIcon, 32, 32, 32, 8); + test_icon_info(hIcon, 32, 32, 32, 8, NULL, TRUE); DestroyIcon(hIcon); DeleteObject(hbmColor); @@ -938,7 +1054,7 @@ static void test_CreateIcon(void) SetLastError(0xdeadbeaf); hIcon = CreateIconIndirect(&info); ok(hIcon != 0, "CreateIconIndirect failed\n"); - test_icon_info(hIcon, 32, 32, 32, 8); + test_icon_info(hIcon, 32, 32, 32, 8, NULL, TRUE); DestroyIcon(hIcon); DeleteObject(hbmColor); @@ -956,12 +1072,12 @@ static void test_CreateIcon(void) SetLastError(0xdeadbeaf); hIcon = CreateIconIndirect(&info); ok(hIcon != 0, "CreateIconIndirect failed\n"); - test_icon_info(hIcon, 32, 32, 32, 8); + test_icon_info(hIcon, 32, 32, 32, 8, NULL, TRUE); DestroyIcon(hIcon); DeleteObject(hbmMask); DeleteObject(hbmColor); - HeapFree( GetProcessHeap(), 0, bmpinfo ); + free(bmpinfo); ReleaseDC(0, hdc); } @@ -1017,11 +1133,10 @@ static unsigned char bmpimage[70] = { 0xFF,0xFF,0x00,0x00,0x00,0x00 }; -/* 1x1 pixel bmp using BITMAPCOREHEADER */ +/* 1x1 pixel bmp using BITMAPCOREHEADER with 24 bits colors (1 bit color fails to load) */ static const unsigned char bmpcoreimage[38] = { -0x42,0x4d,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x0c,0x00, -0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xff,0xff,0xff,0x00,0x55,0x55, -0x55,0x00,0x00,0x00,0x00,0x00 +0x42,0x4d,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x0c,0x00, +0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x18,0x00,0xff,0xff,0xff,0x00 }; /* 2x2 pixel gif */ @@ -1053,7 +1168,7 @@ static const DWORD biSize_tests[] = { 0xffffffff }; -static void test_LoadImageBitmap(const char * test_desc, HBITMAP hbm) +static void test_LoadImageBitmap(HBITMAP hbm) { BITMAP bm; BITMAPINFO bmi; @@ -1061,7 +1176,7 @@ static void test_LoadImageBitmap(const char * test_desc, HBITMAP hbm) HDC hdc = GetDC(NULL); ret = GetObjectA(hbm, sizeof(bm), &bm); - ok(ret == sizeof(bm), "GetObject returned %d\n", ret); + ok(ret == sizeof(bm), "GetObject returned %ld\n", ret); memset(&bmi, 0, sizeof(bmi)); bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); @@ -1071,9 +1186,9 @@ static void test_LoadImageBitmap(const char * test_desc, HBITMAP hbm) bmi.bmiHeader.biBitCount= 24; bmi.bmiHeader.biCompression= BI_RGB; ret = GetDIBits(hdc, hbm, 0, bm.bmHeight, &pixel, &bmi, DIB_RGB_COLORS); - ok(ret == bm.bmHeight, "%s: %d lines were converted, not %d\n", test_desc, ret, bm.bmHeight); + ok(ret == bm.bmHeight, "%ld lines were converted, not %d\n", ret, bm.bmHeight); - ok(color_match(pixel, 0x00ffffff), "%s: Pixel is 0x%08x\n", test_desc, pixel); + ok(color_match(pixel, 0x00ffffff), "Pixel is 0x%08lx\n", pixel); ReleaseDC(NULL, hdc); } @@ -1086,13 +1201,14 @@ static void test_LoadImageFile(const char * test_desc, const unsigned char * ima DWORD error, bytes_written; char filename[64]; + winetest_push_context("%s", test_desc); strcpy(filename, "test."); strcat(filename, ext); /* Create the test image. */ handle = CreateFileA(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); - ok(handle != INVALID_HANDLE_VALUE, "CreateFileA failed. %u\n", GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "CreateFileA failed. %lu\n", GetLastError()); ret = WriteFile(handle, image_data, image_size, &bytes_written, NULL); ok(ret && bytes_written == image_size, "test file created improperly.\n"); CloseHandle(handle); @@ -1100,41 +1216,35 @@ static void test_LoadImageFile(const char * test_desc, const unsigned char * ima /* Load as cursor. For all tested formats, this should fail */ SetLastError(0xdeadbeef); handle = LoadImageA(NULL, filename, IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE); - ok(handle == NULL, "%s: IMAGE_CURSOR succeeded incorrectly.\n", test_desc); + ok(handle == NULL, "IMAGE_CURSOR succeeded incorrectly\n"); error = GetLastError(); - ok(error == 0 || - broken(error == 0xdeadbeef) || /* Win9x */ - broken(error == ERROR_BAD_PATHNAME), /* Win98, WinMe */ - "Last error: %u\n", error); + ok(error == 0, "Last error: %lu\n", error); if (handle != NULL) DestroyCursor(handle); /* Load as icon. For all tested formats, this should fail */ SetLastError(0xdeadbeef); handle = LoadImageA(NULL, filename, IMAGE_ICON, 0, 0, LR_LOADFROMFILE); - ok(handle == NULL, "%s: IMAGE_ICON succeeded incorrectly.\n", test_desc); + ok(handle == NULL, "IMAGE_ICON succeeded incorrectly\n"); error = GetLastError(); - ok(error == 0 || - broken(error == 0xdeadbeef) || /* Win9x */ - broken(error == ERROR_BAD_PATHNAME), /* Win98, WinMe */ - "Last error: %u\n", error); + ok(error == 0, "Last error: %lu\n", error); if (handle != NULL) DestroyIcon(handle); /* Load as bitmap. Should succeed for correct bmp, fail for everything else */ SetLastError(0xdeadbeef); handle = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); error = GetLastError(); - ok(error == 0 || - error == 0xdeadbeef, /* Win9x, WinMe */ - "Last error: %u\n", error); + ok(error == 0, "Last error: %lu\n", error); if (expect_success) { - ok(handle != NULL, "%s: IMAGE_BITMAP failed.\n", test_desc); - if (handle != NULL) test_LoadImageBitmap(test_desc, handle); + ok(handle != NULL || broken(image_data == bmpcoreimage) /* pre-security update */, + "IMAGE_BITMAP failed\n"); + if (handle != NULL) test_LoadImageBitmap(handle); } - else ok(handle == NULL, "%s: IMAGE_BITMAP succeeded incorrectly.\n", test_desc); + else ok(handle == NULL, "IMAGE_BITMAP succeeded incorrectly\n"); if (handle != NULL) DeleteObject(handle); DeleteFileA(filename); + winetest_pop_context(); } typedef struct { @@ -1161,7 +1271,7 @@ static void create_ico_file(const char *filename, const test_icon_entries_t *tes for(i=0; iidReserved = 0; @@ -1195,12 +1305,12 @@ static void create_ico_file(const char *filename, const test_icon_entries_t *tes /* Create the icon. */ file = CreateFileA(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); - ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed. %u\n", GetLastError()); + ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed. %lu\n", GetLastError()); ret = WriteFile(file, buf, icon_size, &bytes_written, NULL); ok(ret && bytes_written == icon_size, "icon.ico created improperly.\n"); CloseHandle(file); - HeapFree(GetProcessHeap(), 0, buf); + free(buf); } static void create_bitmap_file(const char *filename, const BITMAPINFO *bmi, const unsigned char *bits) @@ -1224,15 +1334,15 @@ static void create_bitmap_file(const char *filename, const BITMAPINFO *bmi, cons hdr.bfReserved2 = 0; file = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); - ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed, result %u.\n", GetLastError()); + ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed, result %lu.\n", GetLastError()); ret = WriteFile(file, &hdr, sizeof(hdr), &bytes_written, NULL); - ok(ret && bytes_written == sizeof(hdr), "Unexpected WriteFile() result, ret %#x, bytes_written %u.\n", + ok(ret && bytes_written == sizeof(hdr), "Unexpected WriteFile() result, ret %#x, bytes_written %lu.\n", ret, bytes_written); ret = WriteFile(file, bmi, bmi_size, &bytes_written, NULL); - ok(ret && bytes_written == bmi_size, "Unexpected WriteFile() result, ret %#x, bytes_written %u.\n", + ok(ret && bytes_written == bmi_size, "Unexpected WriteFile() result, ret %#x, bytes_written %lu.\n", ret, bytes_written); ret = WriteFile(file, bits, bits_size, &bytes_written, NULL); - ok(ret && bytes_written == bits_size, "Unexpected WriteFile() result, ret %#x, bytes_written %u.\n", + ok(ret && bytes_written == bits_size, "Unexpected WriteFile() result, ret %#x, bytes_written %lu.\n", ret, bytes_written); CloseHandle(file); } @@ -1253,7 +1363,7 @@ static void test_LoadImage_working_directory_run(char *path) create_ico_file(path_icon, &icon_desc, 1); handle = CreateFileA(path_image, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); - ok(handle != INVALID_HANDLE_VALUE, "run %s: CreateFileA failed. %u\n", path, GetLastError()); + ok(handle != INVALID_HANDLE_VALUE, "run %s: CreateFileA failed. %lu\n", path, GetLastError()); ret = WriteFile(handle, bmpimage, sizeof(bmpimage), &bytes_written, NULL); ok(ret && bytes_written == sizeof(bmpimage), "run %s: Test file created improperly.\n", path); CloseHandle(handle); @@ -1263,20 +1373,20 @@ static void test_LoadImage_working_directory_run(char *path) ok(handle != NULL, "run %s: LoadImage() failed.\n", path); ret = DestroyIcon(handle); - ok(ret, "run %s: DestroyIcon failed: %d\n", path, GetLastError()); + ok(ret, "run %s: DestroyIcon failed: %ld\n", path, GetLastError()); /* Test image */ handle = LoadImageA(NULL, "test.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); ok(handle != NULL, "run %s: LoadImageA failed.\n", path); ret = DeleteObject(handle); - ok(ret, "run %s: DeleteObject failed: %d\n", path, GetLastError()); + ok(ret, "run %s: DeleteObject failed: %ld\n", path, GetLastError()); /* Cleanup */ ret = DeleteFileA(path_image); - ok(ret, "run %s: DeleteFileA failed: %d\n", path, GetLastError()); + ok(ret, "run %s: DeleteFileA failed: %ld\n", path, GetLastError()); ret = DeleteFileA(path_icon); - ok(ret, "run %s: DeleteFileA failed: %d\n", path, GetLastError()); + ok(ret, "run %s: DeleteFileA failed: %ld\n", path, GetLastError()); } static void test_LoadImage_working_directory(void) @@ -1287,7 +1397,7 @@ static void test_LoadImage_working_directory(void) char executable_path[MAX_PATH]; int pos_slash; char old_PATH[10000]; - char new_PATH[10000]; + char new_PATH[10000 + MAX_PATH]; BOOL ret; GetCurrentDirectoryA(ARRAY_SIZE(old_working_dir), old_working_dir); @@ -1318,9 +1428,9 @@ static void test_LoadImage_working_directory(void) SetEnvironmentVariableA("PATH", old_PATH); ret = RemoveDirectoryA(temp_dir_current); - ok(ret, "RemoveDirectoryA failed: %d\n", GetLastError()); + ok(ret, "RemoveDirectoryA failed: %ld\n", GetLastError()); ret = RemoveDirectoryA(temp_dir_PATH); - ok(ret, "RemoveDirectoryA failed: %d\n", GetLastError()); + ok(ret, "RemoveDirectoryA failed: %ld\n", GetLastError()); } static void test_LoadImage(void) @@ -1349,25 +1459,21 @@ static void test_LoadImage(void) handle = LoadImageA(NULL, "icon.ico", IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE); ok(handle != NULL, "LoadImage() failed.\n"); error = GetLastError(); - ok(error == 0 || - broken(error == 0xdeadbeef) || /* Win9x */ - broken(error == ERROR_BAD_PATHNAME), /* Win98, WinMe */ - "Last error: %u\n", error); + ok(error == 0, "Last error: %lu\n", error); /* Test the icon information. */ SetLastError(0xdeadbeef); ret = GetIconInfo(handle, &icon_info); ok(ret, "GetIconInfo() failed.\n"); error = GetLastError(); - ok(error == 0xdeadbeef, "Last error: %u\n", error); + ok(error == 0xdeadbeef, "Last error: %lu\n", error); if (ret) { ok(icon_info.fIcon == FALSE, "fIcon != FALSE.\n"); - ok(icon_info.xHotspot == 1, "xHotspot is %u.\n", icon_info.xHotspot); - ok(icon_info.yHotspot == 1, "yHotspot is %u.\n", icon_info.yHotspot); - ok(icon_info.hbmColor != NULL || broken(!icon_info.hbmColor) /* no color cursor support */, - "No hbmColor!\n"); + ok(icon_info.xHotspot == 1, "xHotspot is %lu.\n", icon_info.xHotspot); + ok(icon_info.yHotspot == 1, "yHotspot is %lu.\n", icon_info.yHotspot); + ok(icon_info.hbmColor != NULL, "No hbmColor!\n"); ok(icon_info.hbmMask != NULL, "No hbmMask!\n"); } @@ -1376,7 +1482,7 @@ static void test_LoadImage(void) ICONINFOEXA infoex; infoex.cbSize = sizeof(infoex); ret = pGetIconInfoExA( handle, &infoex ); - ok( ret, "GetIconInfoEx failed err %d\n", GetLastError() ); + ok( ret, "GetIconInfoEx failed err %ld\n", GetLastError() ); ok( infoex.wResID == 0, "GetIconInfoEx wrong resid %x\n", infoex.wResID ); ok( infoex.szModName[0] == 0, "GetIconInfoEx wrong module %s\n", infoex.szModName ); ok( infoex.szResName[0] == 0, "GetIconInfoEx wrong name %s\n", infoex.szResName ); @@ -1388,7 +1494,7 @@ static void test_LoadImage(void) ret = DestroyCursor(handle); ok(ret, "DestroyCursor() failed.\n"); error = GetLastError(); - ok(error == 0xdeadbeef, "Last error: %u\n", error); + ok(error == 0xdeadbeef, "Last error: %lu\n", error); DeleteFileA("icon.ico"); @@ -1401,7 +1507,7 @@ static void test_LoadImage(void) ICONINFOEXW infoexW; infoexA.cbSize = sizeof(infoexA); ret = pGetIconInfoExA( handle, &infoexA ); - ok( ret, "GetIconInfoEx failed err %d\n", GetLastError() ); + ok( ret, "GetIconInfoEx failed err %ld\n", GetLastError() ); ok( infoexA.wResID == (UINT_PTR)IDI_HAND, "GetIconInfoEx wrong resid %x\n", infoexA.wResID ); /* the A version is broken on 64-bit, it truncates the string after the first char */ if (is_win64 && infoexA.szModName[0] && infoexA.szModName[1] == 0) @@ -1412,7 +1518,7 @@ static void test_LoadImage(void) ok( infoexA.szResName[0] == 0, "GetIconInfoEx wrong name %s\n", infoexA.szResName ); infoexW.cbSize = sizeof(infoexW); ret = pGetIconInfoExW( handle, &infoexW ); - ok( ret, "GetIconInfoEx failed err %d\n", GetLastError() ); + ok( ret, "GetIconInfoEx failed err %ld\n", GetLastError() ); ok( infoexW.wResID == (UINT_PTR)IDI_HAND, "GetIconInfoEx wrong resid %x\n", infoexW.wResID ); ok( GetModuleHandleW(infoexW.szModName) == GetModuleHandleA("user32.dll"), "GetIconInfoEx wrong module %s\n", wine_dbgstr_w(infoexW.szModName) ); @@ -1451,14 +1557,28 @@ static void test_LoadImage(void) test_LoadImage_working_directory(); } +static BOOL CALLBACK find_res_proc(HMODULE module, LPCSTR type, LPSTR name, LONG_PTR param) +{ + char **res_name = (char **)param; + *res_name = name; + return FALSE; +} + static void test_CreateIconFromResource(void) { - HANDLE handle; + HANDLE handle, old_handle; BOOL ret; DWORD error; BITMAPINFOHEADER *icon_header; INT16 *hotspot; ICONINFO icon_info; + HMODULE user32; + char *res_name; + HRSRC rsrc; + HGLOBAL res; + BYTE *bits; + UINT size; + #define ICON_RES_WIDTH 32 #define ICON_RES_HEIGHT 32 @@ -1469,7 +1589,7 @@ static void test_CreateIconFromResource(void) #define CRSR_RES_SIZE (2*sizeof(INT16) + ICON_RES_SIZE) /* Set icon data. */ - hotspot = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, CRSR_RES_SIZE); + hotspot = calloc(1, CRSR_RES_SIZE); /* Cursor resources have an extra hotspot, icon resources not. */ hotspot[0] = 3; @@ -1487,21 +1607,22 @@ static void test_CreateIconFromResource(void) SetLastError(0xdeadbeef); handle = CreateIconFromResource((PBYTE) hotspot, CRSR_RES_SIZE, FALSE, 0x00030000); ok(handle != NULL, "Create cursor failed.\n"); + ret = DestroyCursor(handle); + ok(ret, "Destroy cursor failed, error %lu.\n", GetLastError()); /* Test the icon information. */ SetLastError(0xdeadbeef); ret = GetIconInfo(handle, &icon_info); ok(ret, "GetIconInfo() failed.\n"); error = GetLastError(); - ok(error == 0xdeadbeef, "Last error: %u\n", error); + ok(error == 0xdeadbeef, "Last error: %lu\n", error); if (ret) { ok(icon_info.fIcon == FALSE, "fIcon != FALSE.\n"); - ok(icon_info.xHotspot == 3, "xHotspot is %u.\n", icon_info.xHotspot); - ok(icon_info.yHotspot == 3, "yHotspot is %u.\n", icon_info.yHotspot); - ok(icon_info.hbmColor != NULL || broken(!icon_info.hbmColor) /* no color cursor support */, - "No hbmColor!\n"); + ok(icon_info.xHotspot == 3, "xHotspot is %lu.\n", icon_info.xHotspot); + ok(icon_info.yHotspot == 3, "yHotspot is %lu.\n", icon_info.yHotspot); + ok(icon_info.hbmColor != NULL, "No hbmColor!\n"); ok(icon_info.hbmMask != NULL, "No hbmMask!\n"); } @@ -1510,55 +1631,42 @@ static void test_CreateIconFromResource(void) ICONINFOEXA infoex; infoex.cbSize = sizeof(infoex); ret = pGetIconInfoExA( handle, &infoex ); - ok( ret, "GetIconInfoEx failed err %d\n", GetLastError() ); + ok( ret, "GetIconInfoEx failed err %ld\n", GetLastError() ); ok( infoex.wResID == 0, "GetIconInfoEx wrong resid %x\n", infoex.wResID ); ok( infoex.szModName[0] == 0, "GetIconInfoEx wrong module %s\n", infoex.szModName ); ok( infoex.szResName[0] == 0, "GetIconInfoEx wrong name %s\n", infoex.szResName ); } - /* Clean up. */ - SetLastError(0xdeadbeef); - ret = DestroyCursor(handle); - ok(ret, "DestroyCursor() failed.\n"); - error = GetLastError(); - ok(error == 0xdeadbeef, "Last error: %u\n", error); - /* Test creating an icon. */ SetLastError(0xdeadbeef); handle = CreateIconFromResource((PBYTE) icon_header, ICON_RES_SIZE, TRUE, 0x00030000); ok(handle != NULL, "Create icon failed.\n"); + ret = DestroyIcon(handle); + ok(ret, "Destroy icon failed, error %lu.\n", GetLastError()); /* Test the icon information. */ SetLastError(0xdeadbeef); ret = GetIconInfo(handle, &icon_info); ok(ret, "GetIconInfo() failed.\n"); error = GetLastError(); - ok(error == 0xdeadbeef, "Last error: %u\n", error); + ok(error == 0xdeadbeef, "Last error: %lu\n", error); if (ret) { ok(icon_info.fIcon == TRUE, "fIcon != TRUE.\n"); /* Icons always have hotspot in the middle */ - ok(icon_info.xHotspot == ICON_WIDTH/2, "xHotspot is %u.\n", icon_info.xHotspot); - ok(icon_info.yHotspot == ICON_HEIGHT/2, "yHotspot is %u.\n", icon_info.yHotspot); + ok(icon_info.xHotspot == ICON_WIDTH/2, "xHotspot is %lu.\n", icon_info.xHotspot); + ok(icon_info.yHotspot == ICON_HEIGHT/2, "yHotspot is %lu.\n", icon_info.yHotspot); ok(icon_info.hbmColor != NULL, "No hbmColor!\n"); ok(icon_info.hbmMask != NULL, "No hbmMask!\n"); } - /* Clean up. */ - SetLastError(0xdeadbeef); - ret = DestroyCursor(handle); - ok(ret, "DestroyCursor() failed.\n"); - error = GetLastError(); - ok(error == 0xdeadbeef, "Last error: %u\n", error); - /* Rejection of NULL pointer crashes at least on WNT4WSSP6, W2KPROSP4, WXPPROSP3 * * handle = CreateIconFromResource(NULL, ICON_RES_SIZE, TRUE, 0x00030000); * ok(handle == NULL, "Invalid pointer accepted (%p)\n", handle); */ - HeapFree(GetProcessHeap(), 0, hotspot); /* Test creating an animated cursor. */ empty_anicursor.frames[0].data.icon_info.idType = 2; /* type: cursor */ @@ -1566,30 +1674,88 @@ static void test_CreateIconFromResource(void) empty_anicursor.frames[0].data.icon_info.idEntries[0].yHotspot = 3; handle = CreateIconFromResource((PBYTE) &empty_anicursor, sizeof(empty_anicursor), FALSE, 0x00030000); ok(handle != NULL, "Create cursor failed.\n"); + ret = DestroyCursor(handle); + ok(ret, "Destroy cursor failed, error %lu.\n", GetLastError()); /* Test the animated cursor's information. */ SetLastError(0xdeadbeef); ret = GetIconInfo(handle, &icon_info); + todo_wine ok(ret, "GetIconInfo() failed.\n"); error = GetLastError(); - ok(error == 0xdeadbeef, "Last error: %u\n", error); + todo_wine + ok(error == 0xdeadbeef, "Last error: %lu\n", error); if (ret) { ok(icon_info.fIcon == FALSE, "fIcon != FALSE.\n"); - ok(icon_info.xHotspot == 3, "xHotspot is %u.\n", icon_info.xHotspot); - ok(icon_info.yHotspot == 3, "yHotspot is %u.\n", icon_info.yHotspot); - ok(icon_info.hbmColor != NULL || broken(!icon_info.hbmColor) /* no color cursor support */, - "No hbmColor!\n"); + ok(icon_info.xHotspot == 3, "xHotspot is %lu.\n", icon_info.xHotspot); + ok(icon_info.yHotspot == 3, "yHotspot is %lu.\n", icon_info.yHotspot); + ok(icon_info.hbmColor != NULL, "No hbmColor!\n"); ok(icon_info.hbmMask != NULL, "No hbmMask!\n"); } - /* Clean up. */ - SetLastError(0xdeadbeef); - ret = DestroyCursor(handle); - ok(ret, "DestroyCursor() failed.\n"); - error = GetLastError(); - ok(error == 0xdeadbeef, "Last error: %u\n", error); + /* Test creating and destroying a non-shared icon. */ + handle = CreateIconFromResourceEx((BYTE *)icon_header, ICON_RES_SIZE, TRUE, 0x00030000, + 0, 0, LR_DEFAULTSIZE); + ok(handle != NULL, "Create icon failed, error %lu.\n", GetLastError()); + ret = DestroyIcon(handle); + ok(ret, "Destroy icon failed, error %lu.\n", GetLastError()); + ret = GetIconInfo(handle, &icon_info); + ok(!ret, "Get info succeeded.\n"); + ok(GetLastError() == ERROR_INVALID_CURSOR_HANDLE, "Got unexpected error %lu.\n", error); + + /* Test creating and destroying a shared icon from heap bits. */ + handle = CreateIconFromResourceEx((BYTE *)icon_header, ICON_RES_SIZE, TRUE, 0x00030000, + 0, 0, LR_DEFAULTSIZE | LR_SHARED); + ok(handle != NULL, "Create icon failed, error %lu.\n", GetLastError()); + ret = DestroyIcon(handle); + ok(ret, "Destroy icon failed, error %lu.\n", GetLastError()); + ret = GetIconInfo(handle, &icon_info); + ok(ret, "Get info failed, error %lu.\n", GetLastError()); + + /* Test creating a shared icon from heap bits that has been created before. */ + old_handle = handle; + handle = CreateIconFromResourceEx((BYTE *)icon_header, ICON_RES_SIZE, TRUE, 0x00030000, + 0, 0, LR_DEFAULTSIZE | LR_SHARED); + ok(handle != NULL, "Create icon failed, error %lu.\n", GetLastError()); + ok(handle != old_handle, "Expect a different handle.\n"); + + free(hotspot); + + /* Get icon resource bits */ + user32 = GetModuleHandleA("user32.dll"); + EnumResourceNamesA(user32, (const char *)RT_GROUP_ICON, find_res_proc, (LONG_PTR)&res_name); + rsrc = FindResourceA(user32, res_name, (const char *)RT_GROUP_ICON); + ok(rsrc != NULL, "Find resource failed, error %lu.\n", GetLastError()); + res = LoadResource(user32, rsrc); + ok(res != NULL, "Load resource failed, error %lu.\n", GetLastError()); + bits = LockResource(res); + ok(bits != NULL, "Lock resource failed, error %lu.\n", GetLastError()); + + res_name = MAKEINTRESOURCEA(LookupIconIdFromDirectory(bits, TRUE)); + rsrc = FindResourceA(user32, res_name, (const char *)RT_ICON); + ok(rsrc != NULL, "Find resource failed, error %lu.\n", GetLastError()); + size = SizeofResource(user32, rsrc); + ok(size != 0, "Get resource size failed, error %lu.\n", GetLastError()); + res = LoadResource(user32, rsrc); + ok(res != NULL, "Load resource failed, error %lu.\n", GetLastError()); + bits = LockResource(res); + ok(bits != NULL, "Lock resource failed, error %lu.\n", GetLastError()); + + /* Test creating and destroying a shared icon from resource bits. */ + handle = CreateIconFromResourceEx(bits, size, TRUE, 0x00030000, 0, 0, LR_DEFAULTSIZE | LR_SHARED); + ok(handle != NULL, "Create icon failed, error %lu\n", GetLastError()); + ret = DestroyIcon(handle); + ok(ret, "Destroy icon failed, error %lu.\n", GetLastError()); + ret = GetIconInfo(handle, &icon_info); + ok(ret, "Get info failed, error %lu.\n", GetLastError()); + + /* Test creating a shared icon from resource bits that has been created before. */ + old_handle = handle; + handle = CreateIconFromResourceEx(bits, size, TRUE, 0x00030000, 0, 0, LR_DEFAULTSIZE | LR_SHARED); + ok(handle != NULL, "Create icon failed, error %lu.\n", GetLastError()); + ok(handle != old_handle, "Expect a different handle.\n"); } static int check_cursor_data( HDC hdc, HCURSOR hCursor, void *data, int length) @@ -1604,8 +1770,8 @@ static int check_cursor_data( HDC hdc, HCURSOR hCursor, void *data, int length) ok(ret, "GetIconInfo() failed\n"); if (!ret) return 0; ret = 0; - info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )); - ok(info != NULL, "HeapAlloc() failed\n"); + info = malloc( FIELD_OFFSET( BITMAPINFO, bmiColors[256] )); + ok(info != NULL, "malloc() failed\n"); if (!info) return 0; info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); @@ -1619,19 +1785,19 @@ static int check_cursor_data( HDC hdc, HCURSOR hCursor, void *data, int length) info->bmiHeader.biYPelsPerMeter = 0; info->bmiHeader.biClrUsed = 0; info->bmiHeader.biClrImportant = 0; - image = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage ); - ok(image != NULL, "HeapAlloc() failed\n"); + image = malloc( info->bmiHeader.biSizeImage ); + ok(image != NULL, "malloc() failed\n"); if (!image) goto cleanup; ret = GetDIBits( hdc, iinfo.hbmColor, 0, 32, image, info, DIB_RGB_COLORS ); ok(ret, "GetDIBits() failed\n"); for (i = 0; ret && i < length / sizeof(COLORREF); i++) { ret = color_match( ((COLORREF *)data)[i], ((COLORREF *)image)[i] ); - ok(ret, "%04x: Expected 0x%x, actually 0x%x\n", i, ((COLORREF *)data)[i], ((COLORREF *)image)[i] ); + ok(ret, "%04x: Expected 0x%lx, actually 0x%lx\n", i, ((COLORREF *)data)[i], ((COLORREF *)image)[i] ); } cleanup: - HeapFree( GetProcessHeap(), 0, image ); - HeapFree( GetProcessHeap(), 0, info ); + free( image ); + free( info ); return ret; } @@ -1684,7 +1850,7 @@ static void test_GetCursorFrameInfo(void) #define CRSR_RES_SIZE (2*sizeof(INT16) + ICON_RES_SIZE) /* Set icon data. */ - hotspot = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, CRSR_RES_SIZE); + hotspot = calloc(1, CRSR_RES_SIZE); /* Cursor resources have an extra hotspot, icon resources not. */ hotspot[0] = 3; @@ -1701,19 +1867,19 @@ static void test_GetCursorFrameInfo(void) /* Creating a static cursor. */ SetLastError(0xdeadbeef); h1 = CreateIconFromResource((PBYTE) hotspot, CRSR_RES_SIZE, FALSE, 0x00030000); - ok(h1 != NULL, "Create cursor failed (error = %d).\n", GetLastError()); + ok(h1 != NULL, "Create cursor failed (error = %ld).\n", GetLastError()); /* Check GetCursorFrameInfo behavior on a static cursor */ rate = steps = 0xdead; h2 = pGetCursorFrameInfo(h1, 0xdead, 0xdead, &rate, &steps); ok(h1 == h2, "GetCursorFrameInfo() failed: (%p != %p).\n", h1, h2); - ok(rate == 0, "GetCursorFrameInfo() unexpected param 4 value (0x%x != 0x0).\n", rate); - ok(steps == 1, "GetCursorFrameInfo() unexpected param 5 value (%d != 1).\n", steps); + ok(rate == 0, "GetCursorFrameInfo() unexpected param 4 value (0x%lx != 0x0).\n", rate); + ok(steps == 1, "GetCursorFrameInfo() unexpected param 5 value (%ld != 1).\n", steps); /* Clean up static cursor. */ SetLastError(0xdeadbeef); ret = DestroyCursor(h1); - ok(ret, "DestroyCursor() failed (error = %d).\n", GetLastError()); + ok(ret, "DestroyCursor() failed (error = %ld).\n", GetLastError()); /* Creating a single-frame animated cursor. */ empty_anicursor.frames[0].data.icon_info.idType = 2; /* type: cursor */ @@ -1722,7 +1888,7 @@ static void test_GetCursorFrameInfo(void) memcpy( &empty_anicursor.frames[0].data.bmi_data.data[0], &frame_identifier[0], sizeof(DWORD) ); SetLastError(0xdeadbeef); h1 = CreateIconFromResource((PBYTE) &empty_anicursor, sizeof(empty_anicursor), FALSE, 0x00030000); - ok(h1 != NULL, "Create cursor failed (error = %d).\n", GetLastError()); + ok(h1 != NULL, "Create cursor failed (error = %ld).\n", GetLastError()); /* Check GetCursorFrameInfo behavior on a single-frame animated cursor */ rate = steps = 0xdead; @@ -1730,14 +1896,14 @@ static void test_GetCursorFrameInfo(void) ok(h1 == h2, "GetCursorFrameInfo() failed: (%p != %p).\n", h1, h2); ret = check_cursor_data( hdc, h2, &frame_identifier[0], sizeof(DWORD) ); ok(ret, "GetCursorFrameInfo() returned wrong cursor data for frame 0.\n"); - ok(rate == 0x0, "GetCursorFrameInfo() unexpected param 4 value (0x%x != 0x0).\n", rate); + ok(rate == 0x0, "GetCursorFrameInfo() unexpected param 4 value (0x%lx != 0x0).\n", rate); ok(steps == empty_anicursor.header.header.num_steps, - "GetCursorFrameInfo() unexpected param 5 value (%d != 1).\n", steps); + "GetCursorFrameInfo() unexpected param 5 value (%ld != 1).\n", steps); /* Clean up single-frame animated cursor. */ SetLastError(0xdeadbeef); ret = DestroyCursor(h1); - ok(ret, "DestroyCursor() failed (error = %d).\n", GetLastError()); + ok(ret, "DestroyCursor() failed (error = %ld).\n", GetLastError()); /* Creating a multi-frame animated cursor. */ for (i=0; ibmiHeader.biHeight, result_bits, bmi, DIB_RGB_COLORS); - ok(ret == bmi->bmiHeader.biHeight, "Unexpected GetDIBits result %d, GetLastError() %u.\n", + ok(ret == bmi->bmiHeader.biHeight, "Unexpected GetDIBits result %d, GetLastError() %lu.\n", ret, GetLastError()); for (row = 0; row < bmi->bmiHeader.biHeight; ++row) for (column = 0; column < bmi->bmiHeader.biWidth; ++column) @@ -2832,12 +2970,13 @@ static void compare_bitmap_bits_(unsigned int line, HDC hdc, HBITMAP bitmap, BIT result = get_color_from_bits(result_bits, bmi, row, column); expected = get_color_from_bits(expected_bits, bmi, row, column); - todo_wine_if(todo) - ok_(__FILE__, line)(result == expected, "Colors do not match, " - "got 0x%06x, expected 0x%06x, test_index %u, row %u, column %u.\n", + todo_wine_if(allow_todo && result != expected) + ok_(__FILE__, line)(result == expected || broken(expected_broken_bits + && result == get_color_from_bits(expected_broken_bits, bmi, row, column)), + "Colors do not match, got 0x%06lx, expected 0x%06lx, test_index %u, row %u, column %u.\n", result, expected, test_index, row, column); } - HeapFree(GetProcessHeap(), 0, result_bits); + free(result_bits); } static void test_Image_StretchMode(void) @@ -2849,11 +2988,16 @@ static void test_Image_StretchMode(void) 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, }; - static const unsigned char expected_bits_24[] = + static const unsigned char expected_broken_bits_24[] = { 0x3f, 0xff, 0x00, 0x3f, 0xff, 0x3f, 0x00, 0x00, 0x3f, 0xff, 0x7f, 0x00, 0xff, 0x3f, 0x00, 0x00, }; + static const unsigned char expected_bits_24[] = + { + 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, + }; #define rgb16(r, g, b) ((WORD)(((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3))) static const WORD test_bits_16[] = { @@ -2907,20 +3051,22 @@ static void test_Image_StretchMode(void) size_t test_bits_size, result_bits_size; const RGBQUAD *bmi_colors; size_t bmi_colors_size; - BOOL todo; + BOOL allow_todo; + const unsigned char *expected_broken_bits; } tests[] = { {4, 4, 2, 2, 24, test_bits_24, expected_bits_24, - sizeof(test_bits_24), sizeof(expected_bits_24), NULL, 0, TRUE}, + sizeof(test_bits_24), sizeof(expected_bits_24), NULL, 0, TRUE, + /* Broken on Windows before Win10 1607+ */ expected_broken_bits_24}, {4, 4, 2, 2, 1, test_bits_1, expected_bits_1, sizeof(test_bits_1), sizeof(expected_bits_1), colors_bits_1, - sizeof(colors_bits_1), FALSE}, + sizeof(colors_bits_1)}, {4, 4, 2, 2, 8, test_bits_8, expected_bits_8, sizeof(test_bits_8), sizeof(expected_bits_8), colors_bits_8, - sizeof(colors_bits_8), FALSE}, + sizeof(colors_bits_8), TRUE}, {4, 4, 2, 2, 16, (const unsigned char *)test_bits_16, (const unsigned char *)expected_bits_16, - sizeof(test_bits_16), sizeof(expected_bits_16), NULL, 0, FALSE}, + sizeof(test_bits_16), sizeof(expected_bits_16), NULL, 0, TRUE}, }; static const char filename[] = "test.bmp"; BITMAPINFO *bmi, *bmi_output; @@ -2932,8 +3078,8 @@ static void test_Image_StretchMode(void) HDC hdc; bmi_size = sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD); - bmi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bmi_size); - bmi_output = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bmi_size); + bmi = calloc(1, bmi_size); + bmi_output = calloc(1, bmi_size); bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi->bmiHeader.biPlanes = 1; bmi->bmiHeader.biCompression = BI_RGB; @@ -2958,30 +3104,45 @@ static void test_Image_StretchMode(void) bmi_output->bmiHeader.biHeight = tests[test_index].output_height; bitmap = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, (void **)&bits, NULL, 0); - ok(bitmap && bits, "CreateDIBSection() failed, result %u.\n", GetLastError()); + ok(bitmap && bits, "CreateDIBSection() failed, result %lu.\n", GetLastError()); memcpy(bits, tests[test_index].test_bits, tests[test_index].test_bits_size); bitmap_copy = CopyImage(bitmap, IMAGE_BITMAP, tests[test_index].output_width, tests[test_index].output_height, LR_CREATEDIBSECTION); - ok(!!bitmap_copy, "CopyImage() failed, result %u.\n", GetLastError()); + ok(!!bitmap_copy, "CopyImage() failed, result %lu.\n", GetLastError()); compare_bitmap_bits(hdc, bitmap_copy, bmi_output, tests[test_index].result_bits_size, - tests[test_index].expected_bits, test_index, tests[test_index].todo); + tests[test_index].expected_bits, test_index, tests[test_index].allow_todo, + tests[test_index].expected_broken_bits); DeleteObject(bitmap); DeleteObject(bitmap_copy); create_bitmap_file(filename, bmi, tests[test_index].test_bits); bitmap = LoadImageA(NULL, filename, IMAGE_BITMAP, tests[test_index].output_width, tests[test_index].output_height, LR_CREATEDIBSECTION | LR_LOADFROMFILE); - ok(!!bitmap, "LoadImageA() failed, result %u.\n", GetLastError()); + ok(!!bitmap, "LoadImageA() failed, result %lu.\n", GetLastError()); DeleteFileA(filename); compare_bitmap_bits(hdc, bitmap, bmi_output, tests[test_index].result_bits_size, - tests[test_index].expected_bits, test_index, tests[test_index].todo); + tests[test_index].expected_bits, test_index, tests[test_index].allow_todo, + tests[test_index].expected_broken_bits); DeleteObject(bitmap); } ReleaseDC(0, hdc); - HeapFree(GetProcessHeap(), 0, bmi_output); - HeapFree(GetProcessHeap(), 0, bmi); + free(bmi_output); + free(bmi); +} + +static void test_copy_image(void) +{ + static const UINT types[] = {IMAGE_BITMAP, IMAGE_ICON, IMAGE_CURSOR}; + static const UINT depths[] = {1, 4, 8, 16, 24, 32}; + unsigned int i, j; + + for (i = 0; i < ARRAY_SIZE(types); ++i) + { + for (j = 0; j < ARRAY_SIZE(depths); ++j) + do_test_copy_image(types[i], depths[j]); + } } START_TEST(cursoricon) @@ -3005,12 +3166,7 @@ START_TEST(cursoricon) return; } - test_CopyImage_Bitmap(1); - test_CopyImage_Bitmap(4); - test_CopyImage_Bitmap(8); - test_CopyImage_Bitmap(16); - test_CopyImage_Bitmap(24); - test_CopyImage_Bitmap(32); + test_copy_image(); test_Image_StretchMode(); test_initial_cursor(); test_CreateIcon(); diff --git a/modules/rostests/winetests/user32/dce.c b/modules/rostests/winetests/user32/dce.c index 18ded3357de..18f31e3708c 100644 --- a/modules/rostests/winetests/user32/dce.c +++ b/modules/rostests/winetests/user32/dce.c @@ -54,7 +54,7 @@ static void test_dc_attributes(void) ok( WindowFromDC( hdc ) == hwnd_cache, "wrong window\n" ); ReleaseDC( hwnd_cache, hdc ); - ok( WindowFromDC( hdc ) == 0, "wrong window\n" ); + ok( WindowFromDC( hdc ) != hwnd_cache, "wrong window\n" ); hdc = GetDC( hwnd_cache ); rop = GetROP2( hdc ); ok( rop == def_rop, "wrong ROP2 %d after release\n", rop ); @@ -124,7 +124,7 @@ static void test_dc_attributes(void) ok( caps == 0, "got %d\n", caps ); caps = GetDeviceCaps( old_hdc, NUMCOLORS ); ok( caps == 0, "got %d\n", caps ); - ok( WindowFromDC( old_hdc ) == 0, "wrong window\n" ); + ok( WindowFromDC( old_hdc ) != hwnd_cache, "wrong window\n" ); hdc = GetDC(0); caps = GetDeviceCaps( hdc, HORZRES ); @@ -369,6 +369,7 @@ static void test_dc_visrgn(void) /* parent DC */ hdc = GetDC( hwnd_parentdc ); GetClipBox( hdc, &rect ); + MapWindowPoints(hwnd_parentdc, hwnd_parent, (POINT *)&rect, 2); ReleaseDC( hwnd_parentdc, hdc ); hdc = GetDC( hwnd_parent ); @@ -384,7 +385,7 @@ static void test_dc_visrgn(void) static void test_begin_paint(void) { HDC old_hdc, hdc; - RECT rect, parent_rect; + RECT rect, parent_rect, client_rect; PAINTSTRUCT ps; COLORREF cr; @@ -401,6 +402,33 @@ static void test_begin_paint(void) "invalid clip box %s\n", wine_dbgstr_rect( &rect )); EndPaint( hwnd_cache, &ps ); + SetWindowPos( hwnd_cache, 0, 0, 0, 100, 100, SWP_NOZORDER|SWP_NOMOVE|SWP_NOACTIVATE ); + RedrawWindow( hwnd_cache, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE ); + SetRect( &rect, 0, 0, 150, 150 ); + RedrawWindow( hwnd_cache, &rect, 0, RDW_INVALIDATE|RDW_NOFRAME|RDW_NOERASE ); + hdc = BeginPaint( hwnd_cache, &ps ); + GetClipBox( hdc, &rect ); + GetClientRect( hwnd_cache, &client_rect ); + ok( EqualRect( &rect, &client_rect ), "clip box = %s, expected %s\n", + wine_dbgstr_rect( &rect ), wine_dbgstr_rect( &client_rect )); + SetWindowPos( hwnd_cache, 0, 0, 0, 200, 200, SWP_NOZORDER|SWP_NOMOVE|SWP_NOACTIVATE ); + GetClipBox( hdc, &rect ); + GetClientRect( hwnd_cache, &client_rect ); + todo_wine ok( (!rect.left && !rect.top && rect.right == 150 && rect.bottom == 150) || + broken( EqualRect( &rect, &client_rect )), + "clip box = %s\n", wine_dbgstr_rect( &rect )); + EndPaint( hwnd_cache, &ps ); + + SetWindowPos( hwnd_cache, 0, 0, 0, 100, 100, SWP_NOZORDER|SWP_NOMOVE|SWP_NOACTIVATE ); + RedrawWindow( hwnd_cache, NULL, 0, RDW_INVALIDATE|RDW_NOFRAME|RDW_NOERASE ); + hdc = BeginPaint( hwnd_cache, &ps ); + SetWindowPos( hwnd_cache, 0, 0, 0, 200, 200, SWP_NOZORDER|SWP_NOMOVE|SWP_NOACTIVATE ); + GetClipBox( hdc, &rect ); + GetClientRect( hwnd_cache, &client_rect ); + todo_wine ok( EqualRect( &rect, &client_rect ), "clip box = %s, expected %s\n", + wine_dbgstr_rect( &rect ), wine_dbgstr_rect( &client_rect )); + EndPaint( hwnd_cache, &ps ); + /* window DC */ RedrawWindow( hwnd_owndc, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE ); @@ -440,6 +468,21 @@ static void test_begin_paint(void) ok( !(rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20), "clip box should still be the whole window %s\n", wine_dbgstr_rect( &rect )); + SetWindowPos( hwnd_owndc, 0, 0, 0, 100, 100, SWP_NOZORDER|SWP_NOMOVE|SWP_NOACTIVATE ); + RedrawWindow( hwnd_owndc, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE ); + SetRect( &rect, 0, 0, 50, 50 ); + RedrawWindow( hwnd_owndc, &rect, 0, RDW_INVALIDATE|RDW_ERASE ); + hdc = BeginPaint( hwnd_owndc, &ps ); + GetClipBox( hdc, &rect ); + ok( !rect.left && !rect.top && rect.right == 50 && rect.bottom == 50, + "clip box = %s\n", wine_dbgstr_rect( &rect )); + SetWindowPos( hwnd_owndc, 0, 0, 0, 200, 200, SWP_NOZORDER|SWP_NOMOVE|SWP_NOACTIVATE ); + GetClipBox( hdc, &rect ); + GetClientRect( hwnd_owndc, &client_rect ); + ok( EqualRect( &rect, &client_rect ), "clip box = %s, expected %s\n", + wine_dbgstr_rect( &rect ), wine_dbgstr_rect( &client_rect )); + EndPaint( hwnd_owndc, &ps ); + /* class DC */ RedrawWindow( hwnd_classdc, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE ); @@ -466,18 +509,19 @@ static void test_begin_paint(void) RedrawWindow( hwnd_parentdc, NULL, 0, RDW_INVALIDATE ); hdc = BeginPaint( hwnd_parentdc, &ps ); GetClipBox( hdc, &rect ); + MapWindowPoints(hwnd_parentdc, hwnd_parent, (POINT *)&rect, 2); cr = SetPixel( hdc, 10, 10, RGB(255, 0, 0) ); ok( cr != -1, "error drawing outside of window client area\n" ); EndPaint( hwnd_parentdc, &ps ); GetClientRect( hwnd_parent, &parent_rect ); - ok( rect.left == parent_rect.left, "rect.left = %d, expected %d\n", rect.left, parent_rect.left ); - ok( rect.top == parent_rect.top, "rect.top = %d, expected %d\n", rect.top, parent_rect.top ); - todo_wine ok( rect.right == parent_rect.right, "rect.right = %d, expected %d\n", rect.right, parent_rect.right ); - todo_wine ok( rect.bottom == parent_rect.bottom, "rect.bottom = %d, expected %d\n", rect.bottom, parent_rect.bottom ); + todo_wine ok( rect.left == parent_rect.left, "rect.left = %ld, expected %ld\n", rect.left, parent_rect.left ); + todo_wine ok( rect.top == parent_rect.top, "rect.top = %ld, expected %ld\n", rect.top, parent_rect.top ); + todo_wine ok( rect.right == parent_rect.right, "rect.right = %ld, expected %ld\n", rect.right, parent_rect.right ); + todo_wine ok( rect.bottom == parent_rect.bottom, "rect.bottom = %ld, expected %ld\n", rect.bottom, parent_rect.bottom ); hdc = GetDC( hwnd_parent ); - todo_wine ok( GetPixel( hdc, 10, 10 ) == cr, "error drawing outside of window client area\n" ); + todo_wine ok( GetPixel( hdc, 60, 60 ) == cr, "error drawing outside of window client area\n" ); ReleaseDC( hwnd_parent, hdc ); } @@ -550,24 +594,13 @@ static void test_invisible_create(void) static void test_dc_layout(void) { - DWORD (WINAPI *pSetLayout)(HDC hdc, DWORD layout); - DWORD (WINAPI *pGetLayout)(HDC hdc); HWND hwnd_cache_rtl, hwnd_owndc_rtl, hwnd_classdc_rtl, hwnd_classdc2_rtl; HDC hdc; DWORD layout; - HMODULE mod = GetModuleHandleA("gdi32.dll"); - - pGetLayout = (void *)GetProcAddress( mod, "GetLayout" ); - pSetLayout = (void *)GetProcAddress( mod, "SetLayout" ); - if (!pGetLayout || !pSetLayout) - { - win_skip( "Don't have SetLayout\n" ); - return; - } hdc = GetDC( hwnd_cache ); - pSetLayout( hdc, LAYOUT_RTL ); - layout = pGetLayout( hdc ); + SetLayout( hdc, LAYOUT_RTL ); + layout = GetLayout( hdc ); ReleaseDC( hwnd_cache, hdc ); if (!layout) { @@ -584,43 +617,43 @@ static void test_dc_layout(void) hwnd_classdc2_rtl = CreateWindowExA(WS_EX_LAYOUTRTL, "classdc_class", NULL, WS_OVERLAPPED | WS_VISIBLE, 200, 200, 100, 100, 0, 0, GetModuleHandleA(0), NULL ); hdc = GetDC( hwnd_cache_rtl ); - layout = pGetLayout( hdc ); + layout = GetLayout( hdc ); - ok( layout == LAYOUT_RTL, "wrong layout %x\n", layout ); - pSetLayout( hdc, 0 ); + ok( layout == LAYOUT_RTL, "wrong layout %lx\n", layout ); + SetLayout( hdc, 0 ); ReleaseDC( hwnd_cache_rtl, hdc ); hdc = GetDC( hwnd_owndc_rtl ); - layout = pGetLayout( hdc ); - ok( layout == LAYOUT_RTL, "wrong layout %x\n", layout ); + layout = GetLayout( hdc ); + ok( layout == LAYOUT_RTL, "wrong layout %lx\n", layout ); ReleaseDC( hwnd_cache_rtl, hdc ); hdc = GetDC( hwnd_cache ); - layout = pGetLayout( hdc ); - ok( layout == 0, "wrong layout %x\n", layout ); + layout = GetLayout( hdc ); + ok( layout == 0, "wrong layout %lx\n", layout ); ReleaseDC( hwnd_cache, hdc ); hdc = GetDC( hwnd_owndc_rtl ); - layout = pGetLayout( hdc ); - ok( layout == LAYOUT_RTL, "wrong layout %x\n", layout ); - pSetLayout( hdc, 0 ); + layout = GetLayout( hdc ); + ok( layout == LAYOUT_RTL, "wrong layout %lx\n", layout ); + SetLayout( hdc, 0 ); ReleaseDC( hwnd_owndc_rtl, hdc ); hdc = GetDC( hwnd_owndc_rtl ); - layout = pGetLayout( hdc ); - ok( layout == LAYOUT_RTL, "wrong layout %x\n", layout ); + layout = GetLayout( hdc ); + ok( layout == LAYOUT_RTL, "wrong layout %lx\n", layout ); ReleaseDC( hwnd_owndc_rtl, hdc ); hdc = GetDC( hwnd_classdc_rtl ); - layout = pGetLayout( hdc ); - ok( layout == LAYOUT_RTL, "wrong layout %x\n", layout ); - pSetLayout( hdc, 0 ); + layout = GetLayout( hdc ); + ok( layout == LAYOUT_RTL, "wrong layout %lx\n", layout ); + SetLayout( hdc, 0 ); ReleaseDC( hwnd_classdc_rtl, hdc ); hdc = GetDC( hwnd_classdc2_rtl ); - layout = pGetLayout( hdc ); - ok( layout == LAYOUT_RTL, "wrong layout %x\n", layout ); + layout = GetLayout( hdc ); + ok( layout == LAYOUT_RTL, "wrong layout %lx\n", layout ); ReleaseDC( hwnd_classdc2_rtl, hdc ); hdc = GetDC( hwnd_classdc ); - layout = pGetLayout( hdc ); - ok( layout == LAYOUT_RTL, "wrong layout %x\n", layout ); + layout = GetLayout( hdc ); + ok( layout == LAYOUT_RTL, "wrong layout %lx\n", layout ); ReleaseDC( hwnd_classdc_rtl, hdc ); DestroyWindow(hwnd_classdc2_rtl); @@ -632,8 +665,7 @@ static void test_dc_layout(void) static void test_destroyed_window(void) { HDC dc, old_dc; - HDC hdcs[30]; - int i, rop; + int rop; dc = GetDC( hwnd_cache ); SetROP2( dc, R2_WHITE ); @@ -645,19 +677,11 @@ static void test_destroyed_window(void) DestroyWindow( hwnd_cache ); rop = GetROP2( dc ); ok( rop == 0, "wrong ROP2 %d\n", rop ); - ok( WindowFromDC( dc ) == 0, "wrong window\n" ); + ok( WindowFromDC( dc ) != hwnd_cache, "wrong window\n" ); ok( !ReleaseDC( hwnd_cache, dc ), "ReleaseDC succeeded\n" ); dc = GetDC( hwnd_cache ); ok( !dc, "Got a non-NULL DC (%p) for a destroyed window\n", dc ); - for (i = 0; i < 30; i++) - { - dc = hdcs[i] = GetDCEx( hwnd_parent, 0, DCX_CACHE | DCX_USESTYLE ); - if (dc == old_dc) break; - } - ok( i < 30, "DC for destroyed window not reused\n" ); - while (i > 0) ReleaseDC( hwnd_parent, hdcs[--i] ); - dc = GetDC( hwnd_classdc ); SetROP2( dc, R2_WHITE ); rop = GetROP2( dc ); @@ -674,7 +698,7 @@ static void test_destroyed_window(void) rop = GetROP2( dc ); ok( rop == R2_WHITE, "wrong ROP2 %d\n", rop ); - ok( WindowFromDC( dc ) == 0, "wrong window\n" ); + ok( WindowFromDC( dc ) != hwnd_classdc2, "wrong window\n" ); ok( !ReleaseDC( hwnd_classdc2, dc ), "ReleaseDC succeeded\n" ); dc = GetDC( hwnd_classdc2 ); ok( !dc, "Got a non-NULL DC (%p) for a destroyed window\n", dc ); @@ -688,7 +712,7 @@ static void test_destroyed_window(void) rop = GetROP2( dc ); ok( rop == R2_WHITE, "wrong ROP2 %d\n", rop ); - ok( WindowFromDC( dc ) == 0, "wrong window\n" ); + ok( WindowFromDC( dc ) != hwnd_classdc, "wrong window\n" ); ok( !ReleaseDC( hwnd_classdc, dc ), "ReleaseDC succeeded\n" ); dc = GetDC( hwnd_classdc ); ok( !dc, "Got a non-NULL DC (%p) for a destroyed window\n", dc ); @@ -702,7 +726,7 @@ static void test_destroyed_window(void) rop = GetROP2( dc ); ok( rop == 0, "wrong ROP2 %d\n", rop ); - ok( WindowFromDC( dc ) == 0, "wrong window\n" ); + ok( WindowFromDC( dc ) != hwnd_owndc, "wrong window\n" ); ok( !ReleaseDC( hwnd_owndc, dc ), "ReleaseDC succeeded\n" ); dc = GetDC( hwnd_owndc ); ok( !dc, "Got a non-NULL DC (%p) for a destroyed window\n", dc ); @@ -750,7 +774,7 @@ START_TEST(dce) hwnd_parent = CreateWindowA("static", NULL, WS_OVERLAPPED | WS_VISIBLE, 400, 0, 100, 100, 0, 0, 0, NULL ); hwnd_parentdc = CreateWindowA("parentdc_class", NULL, WS_CHILD | WS_VISIBLE, - 0, 0, 1, 1, hwnd_parent, 0, 0, NULL ); + 50, 50, 1, 1, hwnd_parent, 0, 0, NULL ); test_dc_attributes(); test_parameters(); diff --git a/modules/rostests/winetests/user32/dde.c b/modules/rostests/winetests/user32/dde.c index eed2ac437e1..4f7d61ddb72 100644 --- a/modules/rostests/winetests/user32/dde.c +++ b/modules/rostests/winetests/user32/dde.c @@ -43,6 +43,22 @@ static WNDPROC old_dde_client_wndproc; static const DWORD default_timeout = 200; +static HANDLE create_process(const char *arg) +{ + STARTUPINFOA si = {.cb = sizeof(si)}; + PROCESS_INFORMATION pi; + char cmdline[200]; + char **argv; + BOOL ret; + + winetest_get_mainargs(&argv); + sprintf(cmdline, "\"%s\" %s %s", argv[0], argv[1], arg); + ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + ok(ret, "CreateProcess failed: %lu\n", GetLastError()); + CloseHandle(pi.hThread); + return pi.hProcess; +} + static BOOL is_cjk(void) { int lang_id = PRIMARYLANGID(GetUserDefaultLangID()); @@ -133,7 +149,7 @@ static LRESULT WINAPI dde_server_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPA ok((msg_index >= 2 && msg_index <= 4) || (msg_index >= 7 && msg_index <= 8), "Expected 2, 3, 4, 7 or 8, got %d\n", msg_index); - ok(wparam == (WPARAM)client, "Expected client hwnd, got %08lx\n", wparam); + ok(wparam == (WPARAM)client, "Expected client hwnd, got %08Ix\n", wparam); ok(LOWORD(lparam) == CF_TEXT, "Expected CF_TEXT, got %d\n", LOWORD(lparam)); GlobalGetAtomNameA(HIWORD(lparam), str, MAX_PATH); @@ -182,7 +198,7 @@ static LRESULT WINAPI dde_server_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPA case WM_DDE_POKE: { ok(msg_index == 5 || msg_index == 6, "Expected 5 or 6, got %d\n", msg_index); - ok(wparam == (WPARAM)client, "Expected client hwnd, got %08lx\n", wparam); + ok(wparam == (WPARAM)client, "Expected client hwnd, got %08Ix\n", wparam); UnpackDDElParam(WM_DDE_POKE, lparam, &lo, &hi); @@ -199,7 +215,7 @@ static LRESULT WINAPI dde_server_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPA if (msg_index == 5) { size = GlobalSize((HGLOBAL)lo); - ok(size == 4 || broken(size == 32), /* sizes are rounded up on win9x */ "got %d\n", size); + ok(size == 4, "got %ld\n", size); } else ok(!lstrcmpA((LPSTR)poke->Value, "poke data\r\n"), @@ -216,7 +232,7 @@ static LRESULT WINAPI dde_server_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPA case WM_DDE_EXECUTE: { ok(msg_index == 7, "Expected 7, got %d\n", msg_index); - ok(wparam == (WPARAM)client, "Expected client hwnd, got %08lx\n", wparam); + ok(wparam == (WPARAM)client, "Expected client hwnd, got %08Ix\n", wparam); ptr = GlobalLock((HGLOBAL)lparam); ok(!lstrcmpA(ptr, "[Command(Var)]"), "Expected [Command(Var)], got %s\n", ptr); @@ -233,19 +249,14 @@ static LRESULT WINAPI dde_server_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPA case WM_DDE_TERMINATE: { ok(msg_index == 9, "Expected 9, got %d\n", msg_index); - ok(wparam == (WPARAM)client, "Expected client hwnd, got %08lx\n", wparam); - ok(lparam == 0, "Expected 0, got %08lx\n", lparam); + ok(wparam == (WPARAM)client, "Expected client hwnd, got %08Ix\n", wparam); + ok(lparam == 0, "Expected 0, got %08Ix\n", lparam); PostMessageA(client, WM_DDE_TERMINATE, (WPARAM)hwnd, 0); break; } - case WM_DDE_ACK: /* happens on win9x when fAckReq is TRUE, ignore it */ - ok(msg_index == 4, "Expected 4, got %d\n", msg_index); - msg_index--; - break; - default: ok(FALSE, "Unhandled msg: %08x\n", msg); } @@ -253,23 +264,25 @@ static LRESULT WINAPI dde_server_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPA return DefWindowProcA(hwnd, msg, wparam, lparam); } -static void test_msg_server(HANDLE hproc, HANDLE hthread) +static void test_msg_server(void) { + HANDLE client; MSG msg; HWND hwnd; DWORD res; create_dde_window(&hwnd, "dde_server", dde_server_wndproc); - ResumeThread( hthread ); + client = create_process("ddeml"); - while (MsgWaitForMultipleObjects( 1, &hproc, FALSE, INFINITE, QS_ALLINPUT ) != 0) + while (MsgWaitForMultipleObjects(1, &client, FALSE, INFINITE, QS_ALLINPUT) != 0) { while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); } destroy_dde_window(&hwnd, "dde_server"); - GetExitCodeProcess( hproc, &res ); - ok( !res, "client failed with %u error(s)\n", res ); + GetExitCodeProcess(client, &res); + ok( !res, "client failed with %lu error(s)\n", res ); + CloseHandle(client); } static HDDEDATA CALLBACK client_ddeml_callback(UINT uType, UINT uFmt, HCONV hconv, @@ -302,7 +315,12 @@ static void test_ddeml_client(void) DdeGetLastError(client_pid); conversation = DdeConnect(client_pid, server, topic, NULL); - ok(conversation != NULL, "Expected non-NULL conversation\n"); + if (broken(!conversation)) /* Windows 10 version 1607 */ + { + win_skip("Failed to connect; error %#x.\n", DdeGetLastError(client_pid)); + DdeUninitialize(client_pid); + return; + } ret = DdeGetLastError(client_pid); ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret); @@ -316,14 +334,13 @@ static void test_ddeml_client(void) hdata = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_REQUEST, default_timeout, &res); ret = DdeGetLastError(client_pid); ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret); - ok(res == DDE_FNOTPROCESSED || broken(res == 0xdeadbeef), /* win9x */ - "Expected DDE_FNOTPROCESSED, got %08x\n", res); + ok(res == DDE_FNOTPROCESSED, "Expected DDE_FNOTPROCESSED, got %08lx\n", res); ok( hdata != NULL, "hdata is NULL\n" ); if (hdata) { str = (LPSTR)DdeAccessData(hdata, &size); ok(!lstrcmpA(str, "requested data\r\n"), "Expected 'requested data\\r\\n', got %s\n", str); - ok(size == 17, "Expected 17, got %d\n", size); + ok(size == 17, "Expected 17, got %ld\n", size); ret = DdeUnaccessData(hdata); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); @@ -334,17 +351,15 @@ static void test_ddeml_client(void) DdeGetLastError(client_pid); hdata = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_REQUEST, default_timeout, &res); ret = DdeGetLastError(client_pid); - ok(res == DDE_FNOTPROCESSED || broken(res == 0xdeadbeef), /* win9x */ - "Expected DDE_FNOTPROCESSED, got %x\n", res); -todo_wine - ok(ret == DMLERR_MEMORY_ERROR || broken(ret == 0), /* win9x */ - "Expected DMLERR_MEMORY_ERROR, got %d\n", ret); + ok(res == DDE_FNOTPROCESSED, "Expected DDE_FNOTPROCESSED, got %lx\n", res); + todo_wine + ok(ret == DMLERR_MEMORY_ERROR, "Expected DMLERR_MEMORY_ERROR, got %d\n", ret); ok( hdata != NULL, "hdata is NULL\n" ); if (hdata) { str = (LPSTR)DdeAccessData(hdata, &size); ok(!lstrcmpA(str, "requested data\r\n"), "Expected 'requested data\\r\\n', got %s\n", str); - ok(size == 17, "Expected 17, got %d\n", size); + ok(size == 17, "Expected 17, got %ld\n", size); ret = DdeUnaccessData(hdata); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); @@ -356,15 +371,14 @@ todo_wine hdata = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_REQUEST, default_timeout, &res); ret = DdeGetLastError(client_pid); ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret); - ok(res == DDE_FNOTPROCESSED || broken(res == 0xdeadbeef), /* win9x */ - "Expected DDE_FNOTPROCESSED, got %x\n", res); + ok(res == DDE_FNOTPROCESSED, "Expected DDE_FNOTPROCESSED, got %lx\n", res); if (hdata == NULL) ok(FALSE, "hdata is NULL\n"); else { str = (LPSTR)DdeAccessData(hdata, &size); ok(!lstrcmpA(str, "requested data\r\n"), "Expected 'requested data\\r\\n', got %s\n", str); - ok(size == 17, "Expected 17, got %d\n", size); + ok(size == 17, "Expected 17, got %ld\n", size); ret = DdeUnaccessData(hdata); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); @@ -376,7 +390,7 @@ todo_wine hdata = DdeClientTransaction(NULL, 0, conversation, 0, CF_TEXT, XTYP_REQUEST, default_timeout, &res); ret = DdeGetLastError(client_pid); ok(hdata == NULL, "Expected NULL hdata, got %p\n", hdata); - ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %08x\n", res); + ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %08lx\n", res); ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret); DdeFreeStringHandle(client_pid, item); @@ -394,7 +408,7 @@ todo_wine op = DdeClientTransaction((LPBYTE)hdata, -1, conversation, 0, CF_TEXT, XTYP_POKE, default_timeout, &res); ret = DdeGetLastError(client_pid); ok(op == NULL, "Expected NULL, got %p\n", op); - ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res); + ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", res); ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret); /* XTYP_POKE, no data */ @@ -403,7 +417,7 @@ todo_wine op = DdeClientTransaction(NULL, 0, conversation, 0, CF_TEXT, XTYP_POKE, default_timeout, &res); ret = DdeGetLastError(client_pid); ok(op == NULL, "Expected NULL, got %p\n", op); - ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res); + ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", res); ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret); /* XTYP_POKE, wrong size */ @@ -412,8 +426,7 @@ todo_wine op = DdeClientTransaction((LPBYTE)hdata, 0, conversation, item, CF_TEXT, XTYP_POKE, default_timeout, &res); ret = DdeGetLastError(client_pid); ok(op == (HDDEDATA)TRUE, "Expected TRUE, got %p\n", op); - ok(res == DDE_FACK || broken(res == (0xdead0000 | DDE_FACK)), /* win9x */ - "Expected DDE_FACK, got %x\n", res); + ok(res == DDE_FACK, "Expected DDE_FACK, got %lx\n", res); ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret); /* XTYP_POKE, correct params */ @@ -422,8 +435,7 @@ todo_wine op = DdeClientTransaction((LPBYTE)hdata, -1, conversation, item, CF_TEXT, XTYP_POKE, default_timeout, &res); ret = DdeGetLastError(client_pid); ok(op == (HDDEDATA)TRUE, "Expected TRUE, got %p\n", op); - ok(res == DDE_FACK || broken(res == (0xdead0000 | DDE_FACK)), /* win9x */ - "Expected DDE_FACK, got %x\n", res); + ok(res == DDE_FACK, "Expected DDE_FACK, got %lx\n", res); ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret); DdeFreeDataHandle(hdata); @@ -440,25 +452,16 @@ todo_wine ret = DdeGetLastError(client_pid); ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret); ok(op == (HDDEDATA)TRUE, "Expected TRUE, got %p\n", op); - ok(res == DDE_FACK || broken(res == (0xdead0000 | DDE_FACK)), /* win9x */ - "Expected DDE_FACK, got %x\n", res); + ok(res == DDE_FACK, "Expected DDE_FACK, got %lx\n", res); /* XTYP_EXECUTE, no data */ res = 0xdeadbeef; DdeGetLastError(client_pid); op = DdeClientTransaction(NULL, 0, conversation, NULL, 0, XTYP_EXECUTE, default_timeout, &res); ret = DdeGetLastError(client_pid); - ok(op == NULL || broken(op == (HDDEDATA)TRUE), /* win9x */ "Expected NULL, got %p\n", op); - if (!op) - { - ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res); - ok(ret == DMLERR_MEMORY_ERROR, "Expected DMLERR_MEMORY_ERROR, got %d\n", ret); - } - else /* win9x */ - { - ok(res == (0xdead0000 | DDE_FACK), "Expected DDE_FACK, got %x\n", res); - ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret); - } + ok(op == NULL, "Expected NULL, got %p\n", op); + ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", res); + ok(ret == DMLERR_MEMORY_ERROR, "Expected DMLERR_MEMORY_ERROR, got %d\n", ret); /* XTYP_EXECUTE, no data, -1 size */ res = 0xdeadbeef; @@ -466,9 +469,8 @@ todo_wine op = DdeClientTransaction(NULL, -1, conversation, NULL, 0, XTYP_EXECUTE, default_timeout, &res); ret = DdeGetLastError(client_pid); ok(op == NULL, "Expected NULL, got %p\n", op); - ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res); - ok(ret == DMLERR_INVALIDPARAMETER || broken(ret == DMLERR_NO_ERROR), /* win9x */ - "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret); + ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", res); + ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret); DdeFreeStringHandle(client_pid, topic); DdeFreeDataHandle(hdata); @@ -481,19 +483,13 @@ todo_wine hdata = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_REQUEST, default_timeout, &res); ret = DdeGetLastError(client_pid); ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret); - ok(res == DDE_FNOTPROCESSED || broken(res == (0xdead0000 | DDE_FNOTPROCESSED)), /* win9x */ - "Expected DDE_FNOTPROCESSED, got %d\n", res); - if (hdata == NULL) - ok(FALSE, "hdata is NULL\n"); - else - { - str = (LPSTR)DdeAccessData(hdata, &size); - ok(!lstrcmpA(str, "command executed\r\n"), "Expected 'command executed\\r\\n', got %s\n", str); - ok(size == 19, "Expected 19, got %d\n", size); + ok(res == DDE_FNOTPROCESSED, "Expected DDE_FNOTPROCESSED, got %ld\n", res); + str = (LPSTR)DdeAccessData(hdata, &size); + ok(!strcmp(str, "command executed\r\n"), "Expected 'command executed\\r\\n', got %s\n", str); + ok(size == 19, "Expected 19, got %ld\n", size); - ret = DdeUnaccessData(hdata); - ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - } + ret = DdeUnaccessData(hdata); + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); /* invalid transactions */ res = 0xdeadbeef; @@ -501,7 +497,7 @@ todo_wine op = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_ADVREQ, default_timeout, &res); ret = DdeGetLastError(client_pid); ok(op == NULL, "Expected NULL, got %p\n", op); - ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res); + ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", res); ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret); res = 0xdeadbeef; @@ -509,7 +505,7 @@ todo_wine op = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_CONNECT, default_timeout, &res); ret = DdeGetLastError(client_pid); ok(op == NULL, "Expected NULL, got %p\n", op); - ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res); + ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", res); ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret); res = 0xdeadbeef; @@ -517,7 +513,7 @@ todo_wine op = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_CONNECT_CONFIRM, default_timeout, &res); ret = DdeGetLastError(client_pid); ok(op == NULL, "Expected NULL, got %p\n", op); - ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res); + ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", res); ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret); res = 0xdeadbeef; @@ -525,7 +521,7 @@ todo_wine op = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_DISCONNECT, default_timeout, &res); ret = DdeGetLastError(client_pid); ok(op == NULL, "Expected NULL, got %p\n", op); - ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res); + ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", res); ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret); res = 0xdeadbeef; @@ -533,7 +529,7 @@ todo_wine op = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_ERROR, default_timeout, &res); ret = DdeGetLastError(client_pid); ok(op == NULL, "Expected NULL, got %p\n", op); - ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res); + ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", res); ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret); res = 0xdeadbeef; @@ -541,7 +537,7 @@ todo_wine op = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_MONITOR, default_timeout, &res); ret = DdeGetLastError(client_pid); ok(op == NULL, "Expected NULL, got %p\n", op); - ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res); + ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", res); ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret); res = 0xdeadbeef; @@ -549,7 +545,7 @@ todo_wine op = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_REGISTER, default_timeout, &res); ret = DdeGetLastError(client_pid); ok(op == NULL, "Expected NULL, got %p\n", op); - ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res); + ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", res); ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret); res = 0xdeadbeef; @@ -557,7 +553,7 @@ todo_wine op = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_UNREGISTER, default_timeout, &res); ret = DdeGetLastError(client_pid); ok(op == NULL, "Expected NULL, got %p\n", op); - ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res); + ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", res); ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret); res = 0xdeadbeef; @@ -565,7 +561,7 @@ todo_wine op = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_WILDCONNECT, default_timeout, &res); ret = DdeGetLastError(client_pid); ok(op == NULL, "Expected NULL, got %p\n", op); - ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res); + ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", res); ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret); res = 0xdeadbeef; @@ -573,7 +569,7 @@ todo_wine op = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_XACT_COMPLETE, default_timeout, &res); ret = DdeGetLastError(client_pid); ok(op == NULL, "Expected NULL, got %p\n", op); - ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res); + ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", res); ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret); DdeFreeStringHandle(client_pid, item); @@ -608,24 +604,17 @@ static HDDEDATA CALLBACK server_ddeml_callback(UINT uType, UINT uFmt, HCONV hcon ok(uFmt == 0, "Expected 0, got %d\n", uFmt); ok(hconv == 0, "Expected 0, got %p\n", hconv); ok(hdata == 0, "Expected 0, got %p\n", hdata); - ok(dwData1 == 0, "Expected 0, got %08lx\n", dwData1); - ok(dwData2 == 0, "Expected 0, got %08lx\n", dwData2); + ok(dwData1 == 0, "Expected 0, got %08Ix\n", dwData1); + ok(dwData2 == 0, "Expected 0, got %08Ix\n", dwData2); size = DdeQueryStringA(server_pid, hsz1, str, MAX_PATH, CP_WINANSI); ok(!lstrcmpA(str, "TestDDEServer"), "Expected TestDDEServer, got %s\n", str); - ok(size == 13, "Expected 13, got %d\n", size); + ok(size == 13, "Expected 13, got %ld\n", size); size = DdeQueryStringA(server_pid, hsz2, str, MAX_PATH, CP_WINANSI); - if (!strncmp( str, "TestDDEServer:(", 15 )) /* win9x style */ - { - ok(size == 16 + 2*sizeof(WORD), "Got size %d for %s\n", size, str); - } - else - { - ok(!strncmp(str, "TestDDEServer(", 14), "Expected TestDDEServer(, got %s\n", str); - ok(size == 17 + 2*sizeof(ULONG_PTR), "Got size %d for %s\n", size, str); - } - ok(str[size - 1] == ')', "Expected ')', got %c\n", str[size - 1]); + ok(!strncmp(str, "TestDDEServer(", 14), "Expected TestDDEServer(, got %s\n", str); + ok(size == 17 + 2*sizeof(ULONG_PTR), "Got size %ld for %s\n", size, str); + ok(str[size - 1] == ')', "Expected ')', got %c\n", str[size - 1]); return (HDDEDATA)TRUE; } @@ -636,16 +625,16 @@ static HDDEDATA CALLBACK server_ddeml_callback(UINT uType, UINT uFmt, HCONV hcon ok(uFmt == 0, "Expected 0, got %d\n", uFmt); ok(hconv == 0, "Expected 0, got %p\n", hconv); ok(hdata == 0, "Expected 0, got %p\n", hdata); - ok(dwData1 == 0, "Expected 0, got %08lx\n", dwData1); - ok(dwData2 == FALSE, "Expected FALSE, got %08lx\n", dwData2); + ok(dwData1 == 0, "Expected 0, got %08Ix\n", dwData1); + ok(dwData2 == FALSE, "Expected FALSE, got %08Ix\n", dwData2); size = DdeQueryStringA(server_pid, hsz1, str, MAX_PATH, CP_WINANSI); ok(!lstrcmpA(str, "TestDDETopic"), "Expected TestDDETopic, got %s\n", str); - ok(size == 12, "Expected 12, got %d\n", size); + ok(size == 12, "Expected 12, got %ld\n", size); size = DdeQueryStringA(server_pid, hsz2, str, MAX_PATH, CP_WINANSI); ok(!lstrcmpA(str, "TestDDEServer"), "Expected TestDDEServer, got %s\n", str); - ok(size == 13, "Expected 13, got %d\n", size); + ok(size == 13, "Expected 13, got %ld\n", size); return (HDDEDATA)TRUE; } @@ -658,16 +647,16 @@ static HDDEDATA CALLBACK server_ddeml_callback(UINT uType, UINT uFmt, HCONV hcon ok(uFmt == 0, "Expected 0, got %d\n", uFmt); ok(hconv != NULL, "Expected non-NULL hconv\n"); ok(hdata == 0, "Expected 0, got %p\n", hdata); - ok(dwData1 == 0, "Expected 0, got %08lx\n", dwData1); - ok(dwData2 == FALSE, "Expected FALSE, got %08lx\n", dwData2); + ok(dwData1 == 0, "Expected 0, got %08Ix\n", dwData1); + ok(dwData2 == FALSE, "Expected FALSE, got %08Ix\n", dwData2); size = DdeQueryStringA(server_pid, hsz1, str, MAX_PATH, CP_WINANSI); ok(!lstrcmpA(str, "TestDDETopic"), "Expected TestDDETopic, got %s\n", str); - ok(size == 12, "Expected 12, got %d\n", size); + ok(size == 12, "Expected 12, got %ld\n", size); size = DdeQueryStringA(server_pid, hsz2, str, MAX_PATH, CP_WINANSI); ok(!lstrcmpA(str, "TestDDEServer"), "Expected TestDDEServer, got %s\n", str); - ok(size == 13, "Expected 13, got %d\n", size); + ok(size == 13, "Expected 13, got %ld\n", size); return (HDDEDATA)TRUE; } @@ -678,8 +667,8 @@ static HDDEDATA CALLBACK server_ddeml_callback(UINT uType, UINT uFmt, HCONV hcon "Expected 4, 5 or 6, got %d\n", msg_index); ok(hconv == conversation, "Expected conversation handle, got %p\n", hconv); ok(hdata == 0, "Expected 0, got %p\n", hdata); - ok(dwData1 == 0, "Expected 0, got %08lx\n", dwData1); - ok(dwData2 == 0, "Expected 0, got %08lx\n", dwData2); + ok(dwData1 == 0, "Expected 0, got %08Ix\n", dwData1); + ok(dwData2 == 0, "Expected 0, got %08Ix\n", dwData2); if (msg_index == 4) ok(uFmt == 0xbeef, "Expected 0xbeef, got %08x\n", uFmt); @@ -688,7 +677,7 @@ static HDDEDATA CALLBACK server_ddeml_callback(UINT uType, UINT uFmt, HCONV hcon size = DdeQueryStringA(server_pid, hsz1, str, MAX_PATH, CP_WINANSI); ok(!lstrcmpA(str, "TestDDETopic"), "Expected TestDDETopic, got %s\n", str); - ok(size == 12, "Expected 12, got %d\n", size); + ok(size == 12, "Expected 12, got %ld\n", size); size = DdeQueryStringA(server_pid, hsz2, str, MAX_PATH, CP_WINANSI); @@ -696,13 +685,13 @@ static HDDEDATA CALLBACK server_ddeml_callback(UINT uType, UINT uFmt, HCONV hcon { { ok(!lstrcmpA(str, ""), "Expected empty string, got %s\n", str); - ok(size == 1, "Expected 1, got %d\n", size); + ok(size == 1, "Expected 1, got %ld\n", size); } } else if (msg_index == 6) { ok(!lstrcmpA(str, "request"), "Expected request, got %s\n", str); - ok(size == 7, "Expected 7, got %d\n", size); + ok(size == 7, "Expected 7, got %ld\n", size); } if (msg_index == 6) @@ -720,17 +709,16 @@ static HDDEDATA CALLBACK server_ddeml_callback(UINT uType, UINT uFmt, HCONV hcon ok(msg_index == 7 || msg_index == 8, "Expected 7 or 8, got %d\n", msg_index); ok(uFmt == CF_TEXT, "Expected CF_TEXT, got %d\n", uFmt); ok(hconv == conversation, "Expected conversation handle, got %p\n", hconv); - ok(dwData1 == 0, "Expected 0, got %08lx\n", dwData1); - ok(dwData2 == 0, "Expected 0, got %08lx\n", dwData2); + ok(dwData1 == 0, "Expected 0, got %08Ix\n", dwData1); + ok(dwData2 == 0, "Expected 0, got %08Ix\n", dwData2); size = DdeQueryStringA(server_pid, hsz1, str, MAX_PATH, CP_WINANSI); ok(!lstrcmpA(str, "TestDDETopic"), "Expected TestDDETopic, got %s\n", str); - ok(size == 12, "Expected 12, got %d\n", size); + ok(size == 12, "Expected 12, got %ld\n", size); ptr = (LPSTR)DdeAccessData(hdata, &size); ok(!lstrcmpA(ptr, "poke data\r\n"), "Expected 'poke data\\r\\n', got %s\n", ptr); - ok(size == 12 || broken(size == 28), /* sizes are rounded up on win9x */ - "Expected 12, got %d\n", size); + ok(size == 12, "Expected 12, got %ld\n", size); DdeUnaccessData(hdata); size = DdeQueryStringA(server_pid, hsz2, str, MAX_PATH, CP_WINANSI); @@ -738,13 +726,13 @@ static HDDEDATA CALLBACK server_ddeml_callback(UINT uType, UINT uFmt, HCONV hcon { { ok(!lstrcmpA(str, ""), "Expected empty string, got %s\n", str); - ok(size == 1, "Expected 1, got %d\n", size); + ok(size == 1, "Expected 1, got %ld\n", size); } } else { ok(!lstrcmpA(str, "poke"), "Expected poke, got %s\n", str); - ok(size == 4, "Expected 4, got %d\n", size); + ok(size == 4, "Expected 4, got %ld\n", size); } return (HDDEDATA)DDE_FACK; @@ -755,13 +743,13 @@ static HDDEDATA CALLBACK server_ddeml_callback(UINT uType, UINT uFmt, HCONV hcon ok(msg_index >= 9 && msg_index <= 11, "Expected 9 or 11, got %d\n", msg_index); ok(uFmt == 0, "Expected 0, got %d\n", uFmt); ok(hconv == conversation, "Expected conversation handle, got %p\n", hconv); - ok(dwData1 == 0, "Expected 0, got %08lx\n", dwData1); - ok(dwData2 == 0, "Expected 0, got %08lx\n", dwData2); + ok(dwData1 == 0, "Expected 0, got %08Ix\n", dwData1); + ok(dwData2 == 0, "Expected 0, got %08Ix\n", dwData2); ok(hsz2 == 0, "Expected 0, got %p\n", hsz2); size = DdeQueryStringA(server_pid, hsz1, str, MAX_PATH, CP_WINANSI); ok(!lstrcmpA(str, "TestDDETopic"), "Expected TestDDETopic, got %s\n", str); - ok(size == 12, "Expected 12, got %d\n", size); + ok(size == 12, "Expected 12, got %ld\n", size); if (msg_index == 9 || msg_index == 11) { @@ -770,13 +758,13 @@ static HDDEDATA CALLBACK server_ddeml_callback(UINT uType, UINT uFmt, HCONV hcon if (msg_index == 9) { ok(!lstrcmpA(ptr, "[Command(Var)]"), "Expected '[Command(Var)]', got %s\n", ptr); - ok(size == 15, "Expected 15, got %d\n", size); + ok(size == 15, "Expected 15, got %ld\n", size); ret = (HDDEDATA)DDE_FACK; } else { ok(!lstrcmpA(ptr, "[BadCommand(Var)]"), "Expected '[BadCommand(Var)]', got %s\n", ptr); - ok(size == 18, "Expected 18, got %d\n", size); + ok(size == 18, "Expected 18, got %ld\n", size); ret = DDE_FNOTPROCESSED; } @@ -787,17 +775,17 @@ static HDDEDATA CALLBACK server_ddeml_callback(UINT uType, UINT uFmt, HCONV hcon DWORD rsize = 0; size = DdeGetData(hdata, NULL, 0, 0); - ok(size == 17, "DdeGetData should have returned 17 not %d\n", size); - ptr = HeapAlloc(GetProcessHeap(), 0, size); - ok(ptr != NULL,"HeapAlloc should have returned ptr not NULL\n"); + ok(size == 17, "DdeGetData should have returned 17 not %ld\n", size); + ptr = malloc(size); + ok(ptr != NULL, "malloc should have returned ptr not NULL\n"); rsize = DdeGetData(hdata, (LPBYTE)ptr, size, 0); - ok(rsize == size, "DdeGetData did not return %d bytes but %d\n", size, rsize); + ok(rsize == size, "DdeGetData did not return %ld bytes but %ld\n", size, rsize); ok(!lstrcmpA(ptr, "[Command-2(Var)]"), "Expected '[Command-2(Var)]' got %s\n", ptr); - ok(size == 17, "Expected 17, got %d\n", size); + ok(size == 17, "Expected 17, got %ld\n", size); ret = (HDDEDATA)DDE_FACK; - HeapFree(GetProcessHeap(), 0, ptr); + free(ptr); } return ret; @@ -808,8 +796,8 @@ static HDDEDATA CALLBACK server_ddeml_callback(UINT uType, UINT uFmt, HCONV hcon ok(msg_index == 12, "Expected 12, got %d\n", msg_index); ok(uFmt == 0, "Expected 0, got %d\n", uFmt); ok(hconv == conversation, "Expected conversation handle, got %p\n", hconv); - ok(dwData1 == 0, "Expected 0, got %08lx\n", dwData1); - ok(dwData2 == 0, "Expected 0, got %08lx\n", dwData2); + ok(dwData1 == 0, "Expected 0, got %08Ix\n", dwData1); + ok(dwData2 == 0, "Expected 0, got %08Ix\n", dwData2); ok(hsz1 == 0, "Expected 0, got %p\n", hsz2); ok(hsz2 == 0, "Expected 0, got %p\n", hsz2); @@ -823,14 +811,18 @@ static HDDEDATA CALLBACK server_ddeml_callback(UINT uType, UINT uFmt, HCONV hcon return 0; } -static void test_ddeml_server(HANDLE hproc) +static void test_ddeml_server(void) { + HANDLE client; MSG msg; UINT res; + DWORD exit_code; BOOL ret; HSZ server; HDDEDATA hdata; + client = create_process("msg"); + /* set up DDE server */ server_pid = 0; res = DdeInitializeA(&server_pid, server_ddeml_callback, APPCLASS_STANDARD, 0); @@ -842,14 +834,15 @@ static void test_ddeml_server(HANDLE hproc) hdata = DdeNameService(server_pid, server, 0, DNS_REGISTER); ok(hdata == (HDDEDATA)TRUE, "Expected TRUE, got %p\n", hdata); - while (MsgWaitForMultipleObjects( 1, &hproc, FALSE, INFINITE, QS_ALLINPUT ) != 0) + while (MsgWaitForMultipleObjects(1, &client, FALSE, INFINITE, QS_ALLINPUT) != 0) { while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); } ret = DdeUninitialize(server_pid); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - GetExitCodeProcess( hproc, &res ); - ok( !res, "client failed with %u error(s)\n", res ); + GetExitCodeProcess(client, &exit_code); + ok( !res, "client failed with %lu error(s)\n", exit_code ); + CloseHandle(client); } static HWND client_hwnd, server_hwnd; @@ -877,17 +870,17 @@ static LRESULT WINAPI dde_msg_client_wndproc(HWND hwnd, UINT msg, WPARAM wparam, case WM_DDE_INITIATE: { ok(msg_index == 1, "Expected 1, got %d\n", msg_index); - ok(wparam == (WPARAM)client_hwnd, "Expected client hwnd, got %08lx\n", wparam); + ok(wparam == (WPARAM)client_hwnd, "Expected client hwnd, got %08Ix\n", wparam); size = GlobalGetAtomNameA(LOWORD(lparam), str, MAX_PATH); ok(LOWORD(lparam) == server, "Expected server atom, got %08x\n", LOWORD(lparam)); ok(!lstrcmpA(str, "TestDDEServer"), "Expected TestDDEServer, got %s\n", str); - ok(size == 13, "Expected 13, got %d\n", size); + ok(size == 13, "Expected 13, got %ld\n", size); size = GlobalGetAtomNameA(HIWORD(lparam), str, MAX_PATH); ok(HIWORD(lparam) == topic, "Expected topic atom, got %08x\n", HIWORD(lparam)); ok(!lstrcmpA(str, "TestDDETopic"), "Expected TestDDETopic, got %s\n", str); - ok(size == 12, "Expected 12, got %d\n", size); + ok(size == 12, "Expected 12, got %ld\n", size); break; } @@ -900,21 +893,21 @@ static LRESULT WINAPI dde_msg_client_wndproc(HWND hwnd, UINT msg, WPARAM wparam, if (msg_index == 2) { server_hwnd = (HWND)wparam; - ok(wparam != 0, "Expected non-NULL wparam, got %08lx\n", wparam); + ok(wparam != 0, "Expected non-NULL wparam, got %08Ix\n", wparam); size = GlobalGetAtomNameA(LOWORD(lparam), str, MAX_PATH); ok(LOWORD(lparam) == server, "Expected server atom, got %08x\n", LOWORD(lparam)); ok(!lstrcmpA(str, "TestDDEServer"), "Expected TestDDEServer, got %s\n", str); - ok(size == 13, "Expected 13, got %d\n", size); + ok(size == 13, "Expected 13, got %ld\n", size); size = GlobalGetAtomNameA(HIWORD(lparam), str, MAX_PATH); ok(HIWORD(lparam) == topic, "Expected topic atom, got %08x\n", HIWORD(lparam)); ok(!lstrcmpA(str, "TestDDETopic"), "Expected TestDDETopic, got %s\n", str); - ok(size == 12, "Expected 12, got %d\n", size); + ok(size == 12, "Expected 12, got %ld\n", size); } else if (msg_index >= 9 && msg_index <= 11) { - ok(wparam == (WPARAM)server_hwnd, "Expected server hwnd, got %08lx\n", wparam); + ok(wparam == (WPARAM)server_hwnd, "Expected server hwnd, got %08Ix\n", wparam); UnpackDDElParam(WM_DDE_ACK, lparam, &lo, &hi); @@ -923,7 +916,7 @@ static LRESULT WINAPI dde_msg_client_wndproc(HWND hwnd, UINT msg, WPARAM wparam, ok(ack->reserved == 0, "Expected 0, got %d\n", ack->reserved); ok(ack->fBusy == FALSE, "Expected FALSE, got %d\n", ack->fBusy); - ok(hi == (UINT_PTR)execute_hglobal, "Expected execute hglobal, got %08lx\n", hi); + ok(hi == (UINT_PTR)execute_hglobal, "Expected execute hglobal, got %08Ix\n", hi); ptr = GlobalLock((HGLOBAL)hi); if (msg_index == 9) @@ -945,7 +938,7 @@ static LRESULT WINAPI dde_msg_client_wndproc(HWND hwnd, UINT msg, WPARAM wparam, } else { - ok(wparam == (WPARAM)server_hwnd, "Expected server hwnd, got %08lx\n", wparam); + ok(wparam == (WPARAM)server_hwnd, "Expected server hwnd, got %08Ix\n", wparam); UnpackDDElParam(WM_DDE_ACK, lparam, &lo, &hi); @@ -965,22 +958,22 @@ static LRESULT WINAPI dde_msg_client_wndproc(HWND hwnd, UINT msg, WPARAM wparam, size = GlobalGetAtomNameA(hi, str, MAX_PATH); if (msg_index == 3) { - ok(hi == item, "Expected item atom, got %08lx\n", hi); + ok(hi == item, "Expected item atom, got %08Ix\n", hi); ok(!lstrcmpA(str, "request"), "Expected request, got %s\n", str); - ok(size == 7, "Expected 7, got %d\n", size); + ok(size == 7, "Expected 7, got %ld\n", size); } else if (msg_index == 4 || msg_index == 7) { - ok(hi == 0, "Expected 0, got %08lx\n", hi); - ok(size == 0, "Expected empty string, got %d\n", size); + ok(hi == 0, "Expected 0, got %08Ix\n", hi); + ok(size == 0, "Expected empty string, got %ld\n", size); } else { - ok(hi == item, "Expected item atom, got %08lx\n", hi); + ok(hi == item, "Expected item atom, got %08Ix\n", hi); if (msg_index == 6) todo_wine { ok(!lstrcmpA(str, "poke"), "Expected poke, got %s\n", str); - ok(size == 4, "Expected 4, got %d\n", size); + ok(size == 4, "Expected 4, got %ld\n", size); } } } @@ -991,7 +984,7 @@ static LRESULT WINAPI dde_msg_client_wndproc(HWND hwnd, UINT msg, WPARAM wparam, case WM_DDE_DATA: { ok(msg_index == 5, "Expected 5, got %d\n", msg_index); - ok(wparam == (WPARAM)server_hwnd, "Expected server hwnd, got %08lx\n", wparam); + ok(wparam == (WPARAM)server_hwnd, "Expected server hwnd, got %08Ix\n", wparam); UnpackDDElParam(WM_DDE_DATA, lparam, &lo, &hi); @@ -1011,7 +1004,7 @@ static LRESULT WINAPI dde_msg_client_wndproc(HWND hwnd, UINT msg, WPARAM wparam, size = GlobalGetAtomNameA(hi, str, MAX_PATH); ok(hi == item, "Expected item atom, got %08x\n", HIWORD(lparam)); ok(!lstrcmpA(str, "request"), "Expected request, got %s\n", str); - ok(size == 7, "Expected 7, got %d\n", size); + ok(size == 7, "Expected 7, got %ld\n", size); GlobalFree((HGLOBAL)lo); GlobalDeleteAtom(hi); @@ -1117,14 +1110,8 @@ static void test_msg_client(void) /* WM_DDE_POKE, no ddepoke */ lparam = PackDDElParam(WM_DDE_POKE, 0, item); - /* win9x returns 0 here and crashes in PostMessageA */ - if (lparam) { - PostMessageA(server_hwnd, WM_DDE_POKE, (WPARAM)client_hwnd, lparam); - flush_events(); - } - else - win_skip("no lparam for WM_DDE_POKE\n"); - + PostMessageA(server_hwnd, WM_DDE_POKE, (WPARAM)client_hwnd, lparam); + flush_events(); /* WM_DDE_POKE, no item */ lparam = PackDDElParam(WM_DDE_POKE, (UINT_PTR)hglobal, 0); @@ -1196,13 +1183,13 @@ static LRESULT WINAPI hook_dde_client_wndprocA(HWND hwnd, UINT msg, WPARAM wpara { UINT_PTR lo, hi; - trace("hook_dde_client_wndprocA: %p %04x %08lx %08lx\n", hwnd, msg, wparam, lparam); + if (winetest_debug > 1) trace("hook_dde_client_wndprocA: %p %04x %08Ix %08Ix\n", hwnd, msg, wparam, lparam); switch (msg) { case WM_DDE_ACK: UnpackDDElParam(WM_DDE_ACK, lparam, &lo, &hi); - trace("WM_DDE_ACK: status %04lx hglobal %p\n", lo, (HGLOBAL)hi); + if (winetest_debug > 1) trace("WM_DDE_ACK: status %04Ix hglobal %p\n", lo, (HGLOBAL)hi); break; default: @@ -1215,13 +1202,13 @@ static LRESULT WINAPI hook_dde_client_wndprocW(HWND hwnd, UINT msg, WPARAM wpara { UINT_PTR lo, hi; - trace("hook_dde_client_wndprocW: %p %04x %08lx %08lx\n", hwnd, msg, wparam, lparam); + if (winetest_debug > 1) trace("hook_dde_client_wndprocW: %p %04x %08Ix %08Ix\n", hwnd, msg, wparam, lparam); switch (msg) { case WM_DDE_ACK: UnpackDDElParam(WM_DDE_ACK, lparam, &lo, &hi); - trace("WM_DDE_ACK: status %04lx hglobal %p\n", lo, (HGLOBAL)hi); + if (winetest_debug > 1) trace("WM_DDE_ACK: status %04Ix hglobal %p\n", lo, (HGLOBAL)hi); break; default: @@ -1241,7 +1228,7 @@ static LRESULT WINAPI dde_server_wndprocA(HWND hwnd, UINT msg, WPARAM wparam, LP { ATOM aService = GlobalAddAtomW(TEST_DDE_SERVICE); - trace("server A: got WM_DDE_INITIATE from %p (%s) with %08lx\n", + if (winetest_debug > 1) trace("server A: got WM_DDE_INITIATE from %p (%s) with %08Ix\n", (HWND)wparam, client_unicode ? "Unicode" : "ANSI", lparam); if (LOWORD(lparam) == aService) @@ -1256,7 +1243,6 @@ static LRESULT WINAPI dde_server_wndprocA(HWND hwnd, UINT msg, WPARAM wparam, LP else old_dde_client_wndproc = (WNDPROC)SetWindowLongPtrA((HWND)wparam, GWLP_WNDPROC, (ULONG_PTR)hook_dde_client_wndprocA); - trace("server: sending WM_DDE_ACK to %p\n", (HWND)wparam); SendMessageW((HWND)wparam, WM_DDE_ACK, (WPARAM)hwnd, PackDDElParam(WM_DDE_ACK, aService, 0)); } else @@ -1271,10 +1257,10 @@ static LRESULT WINAPI dde_server_wndprocA(HWND hwnd, UINT msg, WPARAM wparam, LP LPCSTR cmd; UINT_PTR lo, hi; - trace("server A: got WM_DDE_EXECUTE from %p with %08lx\n", (HWND)wparam, lparam); + if (winetest_debug > 1) trace("server A: got WM_DDE_EXECUTE from %p with %08Ix\n", (HWND)wparam, lparam); UnpackDDElParam(WM_DDE_EXECUTE, lparam, &lo, &hi); - trace("%08lx => lo %04lx hi %04lx\n", lparam, lo, hi); + if (winetest_debug > 1) trace("%08Ix => lo %04Ix hi %04Ix\n", lparam, lo, hi); ack.bAppReturnCode = 0; ack.reserved = 0; @@ -1293,7 +1279,6 @@ static LRESULT WINAPI dde_server_wndprocA(HWND hwnd, UINT msg, WPARAM wparam, LP switch (step % 5) { case 0: /* bad command */ - trace( "server A got unhandled command\n" ); break; case 1: /* ANSI command */ @@ -1326,10 +1311,9 @@ static LRESULT WINAPI dde_server_wndprocA(HWND hwnd, UINT msg, WPARAM wparam, LP } GlobalUnlock((HGLOBAL)hi); } - else ok( 0, "bad command data %lx\n", hi ); + else ok( 0, "bad command data %Ix\n", hi ); step++; - trace("server A: posting %s WM_DDE_ACK to %p\n", ack.fAck ? "POSITIVE" : "NEGATIVE", (HWND)wparam); status = *((WORD *)&ack); lparam = ReuseDDElParam(lparam, WM_DDE_EXECUTE, WM_DDE_ACK, status, hi); @@ -1343,15 +1327,13 @@ static LRESULT WINAPI dde_server_wndprocA(HWND hwnd, UINT msg, WPARAM wparam, LP DDEACK ack; WORD status; - trace("server A: got WM_DDE_TERMINATE from %p with %08lx\n", (HWND)wparam, lparam); + if (winetest_debug > 1) trace("server A: got WM_DDE_TERMINATE from %#Ix with %08Ix\n", wparam, lparam); ack.bAppReturnCode = 0; ack.reserved = 0; ack.fBusy = 0; ack.fAck = 1; - trace("server A: posting %s WM_DDE_ACK to %p\n", ack.fAck ? "POSITIVE" : "NEGATIVE", (HWND)wparam); - status = *((WORD *)&ack); lparam = PackDDElParam(WM_DDE_ACK, status, 0); @@ -1389,14 +1371,14 @@ static LRESULT WINAPI dde_server_wndprocW(HWND hwnd, UINT msg, WPARAM wparam, LP else old_dde_client_wndproc = (WNDPROC)SetWindowLongPtrA((HWND)wparam, GWLP_WNDPROC, (ULONG_PTR)hook_dde_client_wndprocA); - trace("server W: sending WM_DDE_ACK to %p\n", (HWND)wparam); SendMessageW((HWND)wparam, WM_DDE_ACK, (WPARAM)hwnd, PackDDElParam(WM_DDE_ACK, aService, 0)); } else GlobalDeleteAtom(aService); - trace("server W: got WM_DDE_INITIATE from %p with %08lx (client %s conv %s)\n", (HWND)wparam, - lparam, client_unicode ? "Unicode" : "ANSI", conv_unicode ? "Unicode" : "ANSI" ); + if (winetest_debug > 1) + trace("server W: got WM_DDE_INITIATE from %p with %08Ix (client %s conv %s)\n", (HWND)wparam, + lparam, client_unicode ? "Unicode" : "ANSI", conv_unicode ? "Unicode" : "ANSI" ); return 0; } @@ -1408,10 +1390,10 @@ static LRESULT WINAPI dde_server_wndprocW(HWND hwnd, UINT msg, WPARAM wparam, LP LPCSTR cmd; UINT_PTR lo, hi; - trace("server W: got WM_DDE_EXECUTE from %p with %08lx\n", (HWND)wparam, lparam); + if (winetest_debug > 1) trace("server W: got WM_DDE_EXECUTE from %#Ix with %08Ix\n", wparam, lparam); UnpackDDElParam(WM_DDE_EXECUTE, lparam, &lo, &hi); - trace("%08lx => lo %04lx hi %04lx\n", lparam, lo, hi); + if (winetest_debug > 1) trace("%08Ix => lo %04Ix hi %04Ix\n", lparam, lo, hi); ack.bAppReturnCode = 0; ack.reserved = 0; @@ -1430,7 +1412,6 @@ static LRESULT WINAPI dde_server_wndprocW(HWND hwnd, UINT msg, WPARAM wparam, LP switch (step % 5) { case 0: /* bad command */ - trace( "server W got unhandled command\n" ); break; case 1: /* ANSI command */ @@ -1471,10 +1452,9 @@ static LRESULT WINAPI dde_server_wndprocW(HWND hwnd, UINT msg, WPARAM wparam, LP } GlobalUnlock((HGLOBAL)hi); } - else ok( 0, "bad command data %lx\n", hi ); + else ok( 0, "bad command data %Ix\n", hi ); step++; - trace("server W: posting %s WM_DDE_ACK to %p\n", ack.fAck ? "POSITIVE" : "NEGATIVE", (HWND)wparam); status = *((WORD *)&ack); lparam = ReuseDDElParam(lparam, WM_DDE_EXECUTE, WM_DDE_ACK, status, hi); @@ -1488,15 +1468,13 @@ static LRESULT WINAPI dde_server_wndprocW(HWND hwnd, UINT msg, WPARAM wparam, LP DDEACK ack; WORD status; - trace("server W: got WM_DDE_TERMINATE from %p with %08lx\n", (HWND)wparam, lparam); + if (winetest_debug > 1) trace("server W: got WM_DDE_TERMINATE from %#Ix with %08Ix\n", wparam, lparam); ack.bAppReturnCode = 0; ack.reserved = 0; ack.fBusy = 0; ack.fAck = 1; - trace("server W: posting %s WM_DDE_ACK to %p\n", ack.fAck ? "POSITIVE" : "NEGATIVE", (HWND)wparam); - status = *((WORD *)&ack); lparam = PackDDElParam(WM_DDE_ACK, status, 0); @@ -1562,8 +1540,9 @@ static HDDEDATA CALLBACK client_dde_callback(UINT uType, UINT uFmt, HCONV hconv, type = (uType & XTYP_MASK) >> XTYP_SHIFT; cmd_name = (type <= 14) ? cmd_type[type] : "unknown"; - trace("client_dde_callback: %04x (%s) %d %p %p %p %p %08lx %08lx\n", - uType, cmd_name, uFmt, hconv, hsz1, hsz2, hdata, dwData1, dwData2); + if (winetest_debug > 1) + trace("client_dde_callback: %04x (%s) %d %p %p %p %p %08Ix %08Ix\n", + uType, cmd_name, uFmt, hconv, hsz1, hsz2, hdata, dwData1, dwData2); return 0; } @@ -1586,19 +1565,25 @@ static void test_dde_aw_transaction( BOOL client_unicode, BOOL server_unicode ) ret = DdeInitializeW(&dde_inst, client_dde_callback, APPCMD_CLIENTONLY, 0); else ret = DdeInitializeA(&dde_inst, client_dde_callback, APPCMD_CLIENTONLY, 0); - ok(ret == DMLERR_NO_ERROR, "DdeInitializeA failed with error %04x (%x)\n", + ok(ret == DMLERR_NO_ERROR, "DdeInitializeA failed with error %04lx (%x)\n", ret, DdeGetLastError(dde_inst)); hsz_server = DdeCreateStringHandleW(dde_inst, TEST_DDE_SERVICE, CP_WINUNICODE); hconv = DdeConnect(dde_inst, hsz_server, 0, NULL); - ok(hconv != 0, "DdeConnect error %x\n", DdeGetLastError(dde_inst)); + if (broken(!hconv)) /* Windows 10 version 1607 */ + { + win_skip("Failed to connect; error %#x.\n", DdeGetLastError(dde_inst)); + DdeUninitialize(dde_inst); + return; + } err = DdeGetLastError(dde_inst); - ok(err == DMLERR_NO_ERROR, "wrong dde error %x\n", err); + ok(err == DMLERR_NO_ERROR, "wrong dde error %lx\n", err); info.cb = sizeof(info); ret = DdeQueryConvInfo(hconv, QID_SYNC, &info); - ok(ret, "wrong info size %d, DdeQueryConvInfo error %x\n", ret, DdeGetLastError(dde_inst)); + ok(ret, "wrong info size %ld, DdeQueryConvInfo error %x\n", ret, DdeGetLastError(dde_inst)); +#if !defined(__REACTOS__) || !defined(_WIN64) ok(info.ConvCtxt.iCodePage == (client_unicode ? CP_WINUNICODE : CP_WINANSI), "wrong iCodePage %d\n", info.ConvCtxt.iCodePage); ok(!info.hConvPartner, "unexpected info.hConvPartner: %p\n", info.hConvPartner); @@ -1607,112 +1592,141 @@ todo_wine { } ok((info.wStatus & (ST_CONNECTED | ST_CLIENT)) == (ST_CONNECTED | ST_CLIENT), "unexpected info.wStatus: %04x\n", info.wStatus); ok(info.wConvst == XST_CONNECTED, "unexpected info.wConvst: %04x\n", info.wConvst); +#endif ok(info.wType == 0, "unexpected info.wType: %04x\n", info.wType); client_unicode = IsWindowUnicode( info.hwnd ); - trace("hwnd %p, hwndPartner %p, unicode %u\n", info.hwnd, info.hwndPartner, client_unicode); - trace("sending test client transaction command\n"); ret = 0xdeadbeef; hdata = DdeClientTransaction((LPBYTE)test_cmd, strlen(test_cmd) + 1, hconv, (HSZ)0xdead, 0xbeef, XTYP_EXECUTE, 1000, &ret); ok(!hdata, "DdeClientTransaction succeeded\n"); - ok(ret == DDE_FNOTPROCESSED || broken(ret == (0xdead0000 | DDE_FNOTPROCESSED)), /* win9x */ - "wrong status code %04x\n", ret); + ok(ret == DDE_FNOTPROCESSED, "wrong status code %04lx\n", ret); err = DdeGetLastError(dde_inst); - ok(err == DMLERR_NOTPROCESSED, "wrong dde error %x\n", err); + ok(err == DMLERR_NOTPROCESSED, "wrong dde error %lx\n", err); - trace("sending ANSI client transaction command\n"); ret = 0xdeadbeef; hdata = DdeClientTransaction((LPBYTE)exec_cmdA, lstrlenA(exec_cmdA) + 1, hconv, 0, 0, XTYP_EXECUTE, 1000, &ret); err = DdeGetLastError(dde_inst); if (conv_unicode && (!client_unicode || !server_unicode)) /* W->A mapping -> garbage */ { - ok(!hdata, "DdeClientTransaction returned %p, error %x\n", hdata, err); - ok(ret == DDE_FNOTPROCESSED, "wrong status code %04x\n", ret); - ok(err == DMLERR_NOTPROCESSED, "DdeClientTransaction returned error %x\n", err); +#ifdef __REACTOS__ + ok(!hdata || broken(hdata != 0) /* WS03 */, "DdeClientTransaction returned %p, error %lx\n", hdata, err); + ok(ret == DDE_FNOTPROCESSED || broken(ret == DDE_FACKREQ) /* WS03 */, "wrong status code %04lx\n", ret); + ok(err == DMLERR_NOTPROCESSED || broken(err == DMLERR_NO_ERROR) /* WS03 */, "DdeClientTransaction returned error %lx\n", err); +#else + ok(!hdata, "DdeClientTransaction returned %p, error %lx\n", hdata, err); + ok(ret == DDE_FNOTPROCESSED, "wrong status code %04lx\n", ret); + ok(err == DMLERR_NOTPROCESSED, "DdeClientTransaction returned error %lx\n", err); +#endif } else if (!conv_unicode && client_unicode && server_unicode) /* A->W mapping -> wrong cmd */ { - ok(!hdata, "DdeClientTransaction returned %p, error %x\n", hdata, err); - ok(ret == DDE_FNOTPROCESSED, "wrong status code %04x\n", ret); - ok(err == DMLERR_NOTPROCESSED, "DdeClientTransaction returned error %x\n", err); + ok(!hdata, "DdeClientTransaction returned %p, error %lx\n", hdata, err); + ok(ret == DDE_FNOTPROCESSED, "wrong status code %04lx\n", ret); + ok(err == DMLERR_NOTPROCESSED, "DdeClientTransaction returned error %lx\n", err); } else /* no mapping */ { - ok(hdata != 0, "DdeClientTransaction returned %p, error %x\n", hdata, err); - ok(ret == DDE_FACK, "wrong status code %04x\n", ret); - ok(err == DMLERR_NO_ERROR, "wrong dde error %x\n", err); +#ifdef __REACTOS__ + ok(hdata != 0 || broken(!hdata) /* WS03 */, "DdeClientTransaction returned %p, error %lx\n", hdata, err); + ok(ret == DDE_FACK || broken(ret == DDE_FNOTPROCESSED) /* WS03 */, "wrong status code %04lx\n", ret); + ok(err == DMLERR_NO_ERROR || broken(err == DMLERR_NOTPROCESSED) /* WS03 */, "wrong dde error %lx\n", err); +#else + ok(hdata != 0, "DdeClientTransaction returned %p, error %lx\n", hdata, err); + ok(ret == DDE_FACK, "wrong status code %04lx\n", ret); + ok(err == DMLERR_NO_ERROR, "wrong dde error %lx\n", err); +#endif } - trace("sending ANSI-as-Unicode client transaction command\n"); ret = 0xdeadbeef; hdata = DdeClientTransaction((LPBYTE)exec_cmdAW, (lstrlenW(exec_cmdAW) + 1) * sizeof(WCHAR), hconv, 0, 0, XTYP_EXECUTE, 1000, &ret); err = DdeGetLastError(dde_inst); if (conv_unicode && (!client_unicode || !server_unicode)) /* W->A mapping */ { - ok(hdata != 0, "DdeClientTransaction returned %p, error %x\n", hdata, err); - ok(ret == DDE_FACK, "wrong status code %04x\n", ret); - ok(err == DMLERR_NO_ERROR, "wrong dde error %x\n", err); +#ifdef __REACTOS__ + ok(hdata != 0 || broken(!hdata) /* WS03 */, "DdeClientTransaction returned %p, error %lx\n", hdata, err); + ok(ret == DDE_FACK || broken(ret == DDE_FNOTPROCESSED) /* WS03 */, "wrong status code %04lx\n", ret); + ok(err == DMLERR_NO_ERROR || broken(err == DMLERR_NOTPROCESSED) /* WS03 */, "wrong dde error %lx\n", err); +#else + ok(hdata != 0, "DdeClientTransaction returned %p, error %lx\n", hdata, err); + ok(ret == DDE_FACK, "wrong status code %04lx\n", ret); + ok(err == DMLERR_NO_ERROR, "wrong dde error %lx\n", err); +#endif } else if (!conv_unicode && client_unicode && server_unicode) /* A->W mapping -> garbage */ { - ok(!hdata, "DdeClientTransaction returned %p, error %x\n", hdata, err); - ok(ret == DDE_FNOTPROCESSED, "wrong status code %04x\n", ret); - ok(err == DMLERR_NOTPROCESSED, "DdeClientTransaction returned error %x\n", err); + ok(!hdata, "DdeClientTransaction returned %p, error %lx\n", hdata, err); + ok(ret == DDE_FNOTPROCESSED, "wrong status code %04lx\n", ret); + ok(err == DMLERR_NOTPROCESSED, "DdeClientTransaction returned error %lx\n", err); } else /* no mapping */ { - ok(!hdata, "DdeClientTransaction returned %p, error %x\n", hdata, err); - ok(ret == DDE_FNOTPROCESSED || broken(ret == (0xdead0000 | DDE_FNOTPROCESSED)), /* win9x */ - "wrong status code %04x\n", ret); - ok(err == DMLERR_NOTPROCESSED, "DdeClientTransaction returned error %x\n", err); + ok(!hdata, "DdeClientTransaction returned %p, error %lx\n", hdata, err); + ok(ret == DDE_FNOTPROCESSED, "wrong status code %04lx\n", ret); + ok(err == DMLERR_NOTPROCESSED, "DdeClientTransaction returned error %lx\n", err); } - trace("sending unicode client transaction command\n"); ret = 0xdeadbeef; hdata = DdeClientTransaction((LPBYTE)exec_cmdW, (lstrlenW(exec_cmdW) + 1) * sizeof(WCHAR), hconv, 0, 0, XTYP_EXECUTE, 1000, &ret); err = DdeGetLastError(dde_inst); if (conv_unicode && (!client_unicode || !server_unicode)) /* W->A mapping -> wrong cmd */ { - ok(!hdata, "DdeClientTransaction returned %p, error %x\n", hdata, err); - ok(ret == DDE_FNOTPROCESSED, "wrong status code %04x\n", ret); - ok(err == DMLERR_NOTPROCESSED, "DdeClientTransaction returned error %x\n", err); +#ifdef __REACTOS__ + ok(!hdata || broken(hdata) /* WS03 */, "DdeClientTransaction returned %p, error %lx\n", hdata, err); + ok(ret == DDE_FNOTPROCESSED || broken(ret == DDE_FACKREQ) /* WS03 */, "wrong status code %04lx\n", ret); + ok(err == DMLERR_NOTPROCESSED || broken(err == DMLERR_NO_ERROR) /* WS03 */, "DdeClientTransaction returned error %lx\n", err); +#else + ok(!hdata, "DdeClientTransaction returned %p, error %lx\n", hdata, err); + ok(ret == DDE_FNOTPROCESSED, "wrong status code %04lx\n", ret); + ok(err == DMLERR_NOTPROCESSED, "DdeClientTransaction returned error %lx\n", err); +#endif } else if (!conv_unicode && client_unicode && server_unicode) /* A->W mapping -> garbage */ { - ok(!hdata, "DdeClientTransaction returned %p, error %x\n", hdata, err); - ok(ret == DDE_FNOTPROCESSED, "wrong status code %04x\n", ret); - ok(err == DMLERR_NOTPROCESSED, "DdeClientTransaction returned error %x\n", err); + ok(!hdata, "DdeClientTransaction returned %p, error %lx\n", hdata, err); + ok(ret == DDE_FNOTPROCESSED, "wrong status code %04lx\n", ret); + ok(err == DMLERR_NOTPROCESSED, "DdeClientTransaction returned error %lx\n", err); } else /* no mapping */ { - ok(hdata != 0, "DdeClientTransaction returned %p, error %x\n", hdata, err); - ok(ret == DDE_FACK, "wrong status code %04x\n", ret); - ok(err == DMLERR_NO_ERROR, "wrong dde error %x\n", err); +#ifdef __REACTOS__ + ok(hdata != 0 || broken(!hdata) /* WS03 */, "DdeClientTransaction returned %p, error %lx\n", hdata, err); + ok(ret == DDE_FACK || broken(ret == DDE_FNOTPROCESSED) /* WS03 */, "wrong status code %04lx\n", ret); + ok(err == DMLERR_NO_ERROR || broken(err == DMLERR_NOTPROCESSED) /* WS03 */, "wrong dde error %lx\n", err); +#else + ok(hdata != 0, "DdeClientTransaction returned %p, error %lx\n", hdata, err); + ok(ret == DDE_FACK, "wrong status code %04lx\n", ret); + ok(err == DMLERR_NO_ERROR, "wrong dde error %lx\n", err); +#endif } - trace("sending Unicode-as-ANSI client transaction command\n"); ret = 0xdeadbeef; hdata = DdeClientTransaction((LPBYTE)exec_cmdWA, lstrlenA(exec_cmdWA) + 1, hconv, 0, 0, XTYP_EXECUTE, 1000, &ret); err = DdeGetLastError(dde_inst); if (conv_unicode && (!client_unicode || !server_unicode)) /* W->A mapping -> garbage */ { - ok(!hdata, "DdeClientTransaction returned %p, error %x\n", hdata, err); - ok(ret == DDE_FNOTPROCESSED, "wrong status code %04x\n", ret); - ok(err == DMLERR_NOTPROCESSED, "DdeClientTransaction returned error %x\n", err); + ok(!hdata, "DdeClientTransaction returned %p, error %lx\n", hdata, err); + ok(ret == DDE_FNOTPROCESSED, "wrong status code %04lx\n", ret); + ok(err == DMLERR_NOTPROCESSED, "DdeClientTransaction returned error %lx\n", err); } else if (!conv_unicode && client_unicode && server_unicode) /* A->W mapping */ { - ok(hdata != 0, "DdeClientTransaction returned %p, error %x\n", hdata, err); - ok(ret == DDE_FACK, "wrong status code %04x\n", ret); - ok(err == DMLERR_NO_ERROR, "wrong dde error %x\n", err); + ok(hdata != 0, "DdeClientTransaction returned %p, error %lx\n", hdata, err); + ok(ret == DDE_FACK, "wrong status code %04lx\n", ret); + ok(err == DMLERR_NO_ERROR, "wrong dde error %lx\n", err); } else /* no mapping */ { - ok(!hdata, "DdeClientTransaction returned %p, error %x\n", hdata, err); - ok(ret == DDE_FNOTPROCESSED, "wrong status code %04x\n", ret); - ok(err == DMLERR_NOTPROCESSED, "DdeClientTransaction returned error %x\n", err); +#ifdef __REACTOS__ + ok(!hdata || broken(hdata) /* WS03 */, "DdeClientTransaction returned %p, error %lx\n", hdata, err); + ok(ret == DDE_FNOTPROCESSED || broken(ret == DDE_FACKREQ) /* WS03 */, "wrong status code %04lx\n", ret); + ok(err == DMLERR_NOTPROCESSED || broken(err == DMLERR_NO_ERROR) /* WS03 */, "DdeClientTransaction returned error %lx\n", err); +#else + ok(!hdata, "DdeClientTransaction returned %p, error %lx\n", hdata, err); + ok(ret == DDE_FNOTPROCESSED, "wrong status code %04lx\n", ret); + ok(err == DMLERR_NOTPROCESSED, "DdeClientTransaction returned error %lx\n", err); +#endif } got = DdeDisconnect(hconv); @@ -1723,7 +1737,7 @@ todo_wine { ok(!ret, "DdeQueryConvInfo should fail\n"); err = DdeGetLastError(dde_inst); todo_wine { - ok(err == DMLERR_INVALIDPARAMETER, "wrong dde error %x\n", err); + ok(err == DMLERR_INVALIDPARAMETER, "wrong dde error %lx\n", err); } got = DdeFreeStringHandle(dde_inst, hsz_server); @@ -1771,9 +1785,9 @@ static void test_initialisation(void) hdata = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_REQUEST, default_timeout, &res); ok(hdata == NULL, "Expected NULL, got %p\n", hdata); ret = DdeGetLastError(client_pid); -todo_wine + todo_wine ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret); - ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %08x\n", res); + ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %08lx\n", res); DdeFreeStringHandle(client_pid, server); ret = DdeDisconnect(conversation); @@ -1847,7 +1861,7 @@ static void test_DdeCreateStringHandleW(DWORD dde_inst, int codepage) atom = GlobalFindAtomA((LPSTR)dde_string); ok(atom == 0, "Expected 0, got %d\n", atom); ok(GetLastError() == ERROR_FILE_NOT_FOUND, - "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError()); } else { @@ -1858,7 +1872,7 @@ static void test_DdeCreateStringHandleW(DWORD dde_inst, int codepage) atom = GlobalFindAtomW(dde_string); ok(atom == 0, "Expected 0, got %d\n", atom); ok(GetLastError() == ERROR_FILE_NOT_FOUND, - "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError()); } ok(DdeFreeStringHandle(dde_inst, str_handle), "DdeFreeStringHandle failed\n"); @@ -1907,10 +1921,7 @@ static void test_DdeCreateDataHandle(void) item = DdeCreateStringHandleA(dde_inst2, "item", CP_WINANSI); ok(item != NULL, "Expected non-NULL hsz\n"); - if (0) { - /* do not test with an invalid instance id: that crashes on win9x */ - hdata = DdeCreateDataHandle(0xdeadbeef, (LPBYTE)"data", MAX_PATH, 0, item, CF_TEXT, 0); - } + hdata = DdeCreateDataHandle(0xdeadbeef, (LPBYTE)"data", MAX_PATH, 0, item, CF_TEXT, 0); /* 0 instance id * This block tests an invalid instance Id. The correct behaviour is that if the instance Id @@ -1940,7 +1951,7 @@ static void test_DdeCreateDataHandle(void) ptr = DdeAccessData(hdata, &size); ok(ptr != NULL, "Expected non-NULL ptr\n"); - ok(size == 260, "Expected 260, got %d\n", size); + ok(size == 260, "Expected 260, got %ld\n", size); ret = DdeUnaccessData(hdata); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); @@ -1957,7 +1968,7 @@ static void test_DdeCreateDataHandle(void) ptr = DdeAccessData(hdata, &size); ok(ptr != NULL, "Expected non-NULL ptr\n"); - ok(size == 0, "Expected 0, got %d\n", size); + ok(size == 0, "Expected 0, got %ld\n", size); ret = DdeUnaccessData(hdata); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); @@ -1974,10 +1985,10 @@ static void test_DdeCreateDataHandle(void) ptr = DdeAccessData(hdata, &size); ok(ptr != NULL, "Expected non-NULL ptr\n"); - ok(size == 262, "Expected 262, got %d\n", size); + ok(size == 262, "Expected 262, got %ld\n", size); todo_wine { - ok(lstrlenA((LPSTR)ptr) == 0, "Expected 0, got %d\n", lstrlenA((LPSTR)ptr)); + ok(ptr && !*ptr, "Expected 0, got %d\n", lstrlenA((LPSTR)ptr)); } ret = DdeUnaccessData(hdata); @@ -1996,7 +2007,7 @@ static void test_DdeCreateDataHandle(void) ptr = DdeAccessData(hdata, &size); ok(ptr != NULL, "Expected non-NULL ptr\n"); ok(!lstrcmpA((LPSTR)ptr, "data"), "Expected data, got %s\n", ptr); - ok(size == 260, "Expected 260, got %d\n", size); + ok(size == 260, "Expected 260, got %ld\n", size); ret = DdeUnaccessData(hdata); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); @@ -2014,7 +2025,7 @@ static void test_DdeCreateDataHandle(void) ptr = DdeAccessData(hdata, &size); ok(ptr != NULL, "Expected non-NULL ptr\n"); ok(!lstrcmpA((LPSTR)ptr, "data"), "Expected data, got %s\n", ptr); - ok(size == 260, "Expected 260, got %d\n", size); + ok(size == 260, "Expected 260, got %ld\n", size); ret = DdeUnaccessData(hdata); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); @@ -2032,7 +2043,7 @@ static void test_DdeCreateDataHandle(void) ptr = DdeAccessData(hdata, &size); ok(ptr != NULL, "Expected non-NULL ptr\n"); ok(!lstrcmpA((LPSTR)ptr, "data"), "Expected data, got %s\n", ptr); - ok(size == 260, "Expected 260, got %d\n", size); + ok(size == 260, "Expected 260, got %ld\n", size); ret = DdeUnaccessData(hdata); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); @@ -2051,12 +2062,12 @@ static void test_DdeCreateStringHandle(void) dde_inst = 0xdeadbeef; SetLastError(0xdeadbeef); ret = DdeInitializeW(&dde_inst, client_ddeml_callback, APPCMD_CLIENTONLY, 0); - ok(ret == DMLERR_INVALIDPARAMETER, "DdeInitializeW should fail, but got %04x instead\n", ret); + ok(ret == DMLERR_INVALIDPARAMETER, "DdeInitializeW should fail, but got %04lx instead\n", ret); ok(DdeGetLastError(dde_inst) == DMLERR_INVALIDPARAMETER, "expected DMLERR_INVALIDPARAMETER\n"); dde_inst = 0; ret = DdeInitializeW(&dde_inst, client_ddeml_callback, APPCMD_CLIENTONLY, 0); - ok(ret == DMLERR_NO_ERROR, "DdeInitializeW failed with error %04x (%08x)\n", + ok(ret == DMLERR_NO_ERROR, "DdeInitializeW failed with error %04lx (%08x)\n", ret, DdeGetLastError(dde_inst)); test_DdeCreateStringHandleW(dde_inst, 0); @@ -2123,153 +2134,133 @@ static void test_PackDDElParam(void) lparam = PackDDElParam(WM_DDE_INITIATE, 0xcafe, 0xbeef); /* value gets sign-extended despite being an LPARAM */ - ok(lparam == (int)0xbeefcafe, "Expected 0xbeefcafe, got %08lx\n", lparam); + ok(lparam == (int)0xbeefcafe, "Expected 0xbeefcafe, got %08Ix\n", lparam); lo = hi = 0; ret = UnpackDDElParam(WM_DDE_INITIATE, lparam, &lo, &hi); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo); - ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi); + ok(lo == 0xcafe, "Expected 0xcafe, got %08Ix\n", lo); + ok(hi == 0xbeef, "Expected 0xbeef, got %08Ix\n", hi); ret = FreeDDElParam(WM_DDE_INITIATE, lparam); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); lparam = PackDDElParam(WM_DDE_TERMINATE, 0xcafe, 0xbeef); - ok(lparam == (int)0xbeefcafe, "Expected 0xbeefcafe, got %08lx\n", lparam); + ok(lparam == (int)0xbeefcafe, "Expected 0xbeefcafe, got %08Ix\n", lparam); lo = hi = 0; ret = UnpackDDElParam(WM_DDE_TERMINATE, lparam, &lo, &hi); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo); - ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi); + ok(lo == 0xcafe, "Expected 0xcafe, got %08Ix\n", lo); + ok(hi == 0xbeef, "Expected 0xbeef, got %08Ix\n", hi); ret = FreeDDElParam(WM_DDE_TERMINATE, lparam); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); lparam = PackDDElParam(WM_DDE_ADVISE, 0xcafe, 0xbeef); - /* win9x returns 0 here */ - if (lparam) { - ptr = GlobalLock((HGLOBAL)lparam); - ok(ptr != NULL, "Expected non-NULL ptr\n"); - ok(ptr[0] == 0xcafe, "Expected 0xcafe, got %08lx\n", ptr[0]); - ok(ptr[1] == 0xbeef, "Expected 0xbeef, got %08lx\n", ptr[1]); + ptr = GlobalLock((HGLOBAL)lparam); + ok(ptr != NULL, "Expected non-NULL ptr\n"); + ok(ptr[0] == 0xcafe, "Expected 0xcafe, got %08Ix\n", ptr[0]); + ok(ptr[1] == 0xbeef, "Expected 0xbeef, got %08Ix\n", ptr[1]); - ret = GlobalUnlock((HGLOBAL)lparam); - ok(ret == 1, "Expected 1, got %d\n", ret); + ret = GlobalUnlock((HGLOBAL)lparam); + ok(ret == 1, "Expected 1, got %d\n", ret); - lo = hi = 0; - ret = UnpackDDElParam(WM_DDE_ADVISE, lparam, &lo, &hi); - ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo); - ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi); - } - else - win_skip("no lparam for WM_DDE_ADVISE\n"); + lo = hi = 0; + ret = UnpackDDElParam(WM_DDE_ADVISE, lparam, &lo, &hi); + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); + ok(lo == 0xcafe, "Expected 0xcafe, got %08Ix\n", lo); + ok(hi == 0xbeef, "Expected 0xbeef, got %08Ix\n", hi); ret = FreeDDElParam(WM_DDE_ADVISE, lparam); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); lparam = PackDDElParam(WM_DDE_UNADVISE, 0xcafe, 0xbeef); - ok(lparam == (int)0xbeefcafe, "Expected 0xbeefcafe, got %08lx\n", lparam); + ok(lparam == (int)0xbeefcafe, "Expected 0xbeefcafe, got %08Ix\n", lparam); lo = hi = 0; ret = UnpackDDElParam(WM_DDE_UNADVISE, lparam, &lo, &hi); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo); - ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi); + ok(lo == 0xcafe, "Expected 0xcafe, got %08Ix\n", lo); + ok(hi == 0xbeef, "Expected 0xbeef, got %08Ix\n", hi); ret = FreeDDElParam(WM_DDE_UNADVISE, lparam); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); lparam = PackDDElParam(WM_DDE_ACK, 0xcafe, 0xbeef); - /* win9x returns the input (0xbeef<<16 | 0xcafe) here */ - if (lparam != (int)0xbeefcafe) { - ptr = GlobalLock((HGLOBAL)lparam); - ok(ptr != NULL, "Expected non-NULL ptr\n"); - ok(ptr[0] == 0xcafe, "Expected 0xcafe, got %08lx\n", ptr[0]); - ok(ptr[1] == 0xbeef, "Expected 0xbeef, got %08lx\n", ptr[1]); + ptr = GlobalLock((HGLOBAL)lparam); + ok(ptr != NULL, "Expected non-NULL ptr\n"); + ok(ptr[0] == 0xcafe, "Expected 0xcafe, got %08Ix\n", ptr[0]); + ok(ptr[1] == 0xbeef, "Expected 0xbeef, got %08Ix\n", ptr[1]); - ret = GlobalUnlock((HGLOBAL)lparam); - ok(ret == 1, "Expected 1, got %d\n", ret); + ret = GlobalUnlock((HGLOBAL)lparam); + ok(ret == 1, "Expected 1, got %d\n", ret); - lo = hi = 0; - ret = UnpackDDElParam(WM_DDE_ACK, lparam, &lo, &hi); - ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo); - ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi); + lo = hi = 0; + ret = UnpackDDElParam(WM_DDE_ACK, lparam, &lo, &hi); + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); + ok(lo == 0xcafe, "Expected 0xcafe, got %08Ix\n", lo); + ok(hi == 0xbeef, "Expected 0xbeef, got %08Ix\n", hi); - ret = FreeDDElParam(WM_DDE_ACK, lparam); - ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - } - else - win_skip("got lparam 0x%lx for WM_DDE_ACK\n", lparam); + ret = FreeDDElParam(WM_DDE_ACK, lparam); + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); lparam = PackDDElParam(WM_DDE_DATA, 0xcafe, 0xbeef); - /* win9x returns 0 here */ - if (lparam) { - ptr = GlobalLock((HGLOBAL)lparam); - ok(ptr != NULL, "Expected non-NULL ptr\n"); - ok(ptr[0] == 0xcafe, "Expected 0xcafe, got %08lx\n", ptr[0]); - ok(ptr[1] == 0xbeef, "Expected 0xbeef, got %08lx\n", ptr[1]); + ptr = GlobalLock((HGLOBAL)lparam); + ok(ptr != NULL, "Expected non-NULL ptr\n"); + ok(ptr[0] == 0xcafe, "Expected 0xcafe, got %08Ix\n", ptr[0]); + ok(ptr[1] == 0xbeef, "Expected 0xbeef, got %08Ix\n", ptr[1]); - ret = GlobalUnlock((HGLOBAL)lparam); - ok(ret == 1, "Expected 1, got %d\n", ret); + ret = GlobalUnlock((HGLOBAL)lparam); + ok(ret == 1, "Expected 1, got %d\n", ret); - lo = hi = 0; - ret = UnpackDDElParam(WM_DDE_DATA, lparam, &lo, &hi); - ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo); - ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi); - } - else - win_skip("no lparam for WM_DDE_DATA\n"); + lo = hi = 0; + ret = UnpackDDElParam(WM_DDE_DATA, lparam, &lo, &hi); + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); + ok(lo == 0xcafe, "Expected 0xcafe, got %08Ix\n", lo); + ok(hi == 0xbeef, "Expected 0xbeef, got %08Ix\n", hi); ret = FreeDDElParam(WM_DDE_DATA, lparam); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); lparam = PackDDElParam(WM_DDE_REQUEST, 0xcafe, 0xbeef); - ok(lparam == (int)0xbeefcafe, "Expected 0xbeefcafe, got %08lx\n", lparam); + ok(lparam == (int)0xbeefcafe, "Expected 0xbeefcafe, got %08Ix\n", lparam); lo = hi = 0; ret = UnpackDDElParam(WM_DDE_REQUEST, lparam, &lo, &hi); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo); - ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi); + ok(lo == 0xcafe, "Expected 0xcafe, got %08Ix\n", lo); + ok(hi == 0xbeef, "Expected 0xbeef, got %08Ix\n", hi); ret = FreeDDElParam(WM_DDE_REQUEST, lparam); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); lparam = PackDDElParam(WM_DDE_POKE, 0xcafe, 0xbeef); - /* win9x returns 0 here */ - if (lparam) { - ptr = GlobalLock((HGLOBAL)lparam); - ok(ptr != NULL, "Expected non-NULL ptr\n"); - ok(ptr[0] == 0xcafe, "Expected 0xcafe, got %08lx\n", ptr[0]); - ok(ptr[1] == 0xbeef, "Expected 0xbeef, got %08lx\n", ptr[1]); + ptr = GlobalLock((HGLOBAL)lparam); + ok(ptr != NULL, "Expected non-NULL ptr\n"); + ok(ptr[0] == 0xcafe, "Expected 0xcafe, got %08Ix\n", ptr[0]); + ok(ptr[1] == 0xbeef, "Expected 0xbeef, got %08Ix\n", ptr[1]); - ret = GlobalUnlock((HGLOBAL)lparam); - ok(ret == 1, "Expected 1, got %d\n", ret); + ret = GlobalUnlock((HGLOBAL)lparam); + ok(ret == 1, "Expected 1, got %d\n", ret); - lo = hi = 0; - ret = UnpackDDElParam(WM_DDE_POKE, lparam, &lo, &hi); - ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo); - ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi); - } - else - win_skip("no lparam for WM_DDE_POKE\n"); + lo = hi = 0; + ret = UnpackDDElParam(WM_DDE_POKE, lparam, &lo, &hi); + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); + ok(lo == 0xcafe, "Expected 0xcafe, got %08Ix\n", lo); + ok(hi == 0xbeef, "Expected 0xbeef, got %08Ix\n", hi); ret = FreeDDElParam(WM_DDE_POKE, lparam); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); lparam = PackDDElParam(WM_DDE_EXECUTE, 0xcafe, 0xbeef); - ok(lparam == 0xbeef, "Expected 0xbeef, got %08lx\n", lparam); + ok(lparam == 0xbeef, "Expected 0xbeef, got %08Ix\n", lparam); lo = hi = 0; ret = UnpackDDElParam(WM_DDE_EXECUTE, lparam, &lo, &hi); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - ok(lo == 0, "Expected 0, got %08lx\n", lo); - ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi); + ok(lo == 0, "Expected 0, got %08Ix\n", lo); + ok(hi == 0xbeef, "Expected 0xbeef, got %08Ix\n", hi); ret = FreeDDElParam(WM_DDE_EXECUTE, lparam); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); @@ -2286,38 +2277,38 @@ static void test_UnpackDDElParam(void) hi = 0xbeef; ret = UnpackDDElParam(WM_DDE_INITIATE, 0, &lo, &hi); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - ok(lo == 0, "Expected 0, got %08lx\n", lo); - ok(hi == 0, "Expected 0, got %08lx\n", hi); + ok(lo == 0, "Expected 0, got %08Ix\n", lo); + ok(hi == 0, "Expected 0, got %08Ix\n", hi); /* NULL lo */ lo = 0xdead; hi = 0xbeef; ret = UnpackDDElParam(WM_DDE_INITIATE, 0xcafebabe, NULL, &hi); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - ok(lo == 0xdead, "Expected 0xdead, got %08lx\n", lo); - ok(hi == 0xcafe, "Expected 0xcafe, got %08lx\n", hi); + ok(lo == 0xdead, "Expected 0xdead, got %08Ix\n", lo); + ok(hi == 0xcafe, "Expected 0xcafe, got %08Ix\n", hi); /* NULL hi */ lo = 0xdead; hi = 0xbeef; ret = UnpackDDElParam(WM_DDE_INITIATE, 0xcafebabe, &lo, NULL); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - ok(lo == 0xbabe, "Expected 0xbabe, got %08lx\n", lo); - ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi); + ok(lo == 0xbabe, "Expected 0xbabe, got %08Ix\n", lo); + ok(hi == 0xbeef, "Expected 0xbeef, got %08Ix\n", hi); lo = 0xdead; hi = 0xbeef; ret = UnpackDDElParam(WM_DDE_INITIATE, 0xcafebabe, &lo, &hi); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - ok(lo == 0xbabe, "Expected 0xbabe, got %08lx\n", lo); - ok(hi == 0xcafe, "Expected 0xcafe, got %08lx\n", hi); + ok(lo == 0xbabe, "Expected 0xbabe, got %08Ix\n", lo); + ok(hi == 0xcafe, "Expected 0xcafe, got %08Ix\n", hi); lo = 0xdead; hi = 0xbeef; ret = UnpackDDElParam(WM_DDE_TERMINATE, 0xcafebabe, &lo, &hi); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - ok(lo == 0xbabe, "Expected 0xbabe, got %08lx\n", lo); - ok(hi == 0xcafe, "Expected 0xcafe, got %08lx\n", hi); + ok(lo == 0xbabe, "Expected 0xbabe, got %08Ix\n", lo); + ok(hi == 0xcafe, "Expected 0xcafe, got %08Ix\n", hi); lo = 0xdead; hi = 0xbeef; @@ -2325,10 +2316,10 @@ static void test_UnpackDDElParam(void) ok(ret == FALSE, "Expected FALSE, got %d\n", ret); ok(lo == 0 || broken(lo == 0xdead), /* win2k */ - "Expected 0, got %08lx\n", lo); + "Expected 0, got %08Ix\n", lo); ok(hi == 0 || broken(hi == 0xbeef), /* win2k */ - "Expected 0, got %08lx\n", hi); + "Expected 0, got %08Ix\n", hi); hglobal = GlobalAlloc(GMEM_DDESHARE, 2 * sizeof(*ptr)); ptr = GlobalLock(hglobal); @@ -2340,50 +2331,50 @@ static void test_UnpackDDElParam(void) hi = 0xbeef; ret = UnpackDDElParam(WM_DDE_ADVISE, (LPARAM)hglobal, &lo, &hi); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - ok(lo == 0xcafebabe, "Expected 0xcafebabe, got %08lx\n", lo); - ok(hi == 0xdeadbeef, "Expected 0xdeadbeef, got %08lx\n", hi); + ok(lo == 0xcafebabe, "Expected 0xcafebabe, got %08Ix\n", lo); + ok(hi == 0xdeadbeef, "Expected 0xdeadbeef, got %08Ix\n", hi); lo = 0xdead; hi = 0xbeef; ret = UnpackDDElParam(WM_DDE_UNADVISE, 0xcafebabe, &lo, &hi); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - ok(lo == 0xbabe, "Expected 0xbabe, got %08lx\n", lo); - ok(hi == 0xcafe, "Expected 0xcafe, got %08lx\n", hi); + ok(lo == 0xbabe, "Expected 0xbabe, got %08Ix\n", lo); + ok(hi == 0xcafe, "Expected 0xcafe, got %08Ix\n", hi); lo = 0xdead; hi = 0xbeef; ret = UnpackDDElParam(WM_DDE_ACK, (LPARAM)hglobal, &lo, &hi); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - ok(lo == 0xcafebabe, "Expected 0xcafebabe, got %08lx\n", lo); - ok(hi == 0xdeadbeef, "Expected 0xdeadbeef, got %08lx\n", hi); + ok(lo == 0xcafebabe, "Expected 0xcafebabe, got %08Ix\n", lo); + ok(hi == 0xdeadbeef, "Expected 0xdeadbeef, got %08Ix\n", hi); lo = 0xdead; hi = 0xbeef; ret = UnpackDDElParam(WM_DDE_DATA, (LPARAM)hglobal, &lo, &hi); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - ok(lo == 0xcafebabe, "Expected 0xcafebabe, got %08lx\n", lo); - ok(hi == 0xdeadbeef, "Expected 0xdeadbeef, got %08lx\n", hi); + ok(lo == 0xcafebabe, "Expected 0xcafebabe, got %08Ix\n", lo); + ok(hi == 0xdeadbeef, "Expected 0xdeadbeef, got %08Ix\n", hi); lo = 0xdead; hi = 0xbeef; ret = UnpackDDElParam(WM_DDE_REQUEST, 0xcafebabe, &lo, &hi); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - ok(lo == 0xbabe, "Expected 0xbabe, got %08lx\n", lo); - ok(hi == 0xcafe, "Expected 0xcafe, got %08lx\n", hi); + ok(lo == 0xbabe, "Expected 0xbabe, got %08Ix\n", lo); + ok(hi == 0xcafe, "Expected 0xcafe, got %08Ix\n", hi); lo = 0xdead; hi = 0xbeef; ret = UnpackDDElParam(WM_DDE_POKE, (LPARAM)hglobal, &lo, &hi); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - ok(lo == 0xcafebabe, "Expected 0xcafebabe, got %08lx\n", lo); - ok(hi == 0xdeadbeef, "Expected 0xdeadbeef, got %08lx\n", hi); + ok(lo == 0xcafebabe, "Expected 0xcafebabe, got %08Ix\n", lo); + ok(hi == 0xdeadbeef, "Expected 0xdeadbeef, got %08Ix\n", hi); lo = 0xdead; hi = 0xbeef; ret = UnpackDDElParam(WM_DDE_EXECUTE, 0xcafebabe, &lo, &hi); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - ok(lo == 0, "Expected 0, got %08lx\n", lo); - ok(hi == 0xcafebabe, "Expected 0xcafebabe, got %08lx\n", hi); + ok(lo == 0, "Expected 0, got %08Ix\n", lo); + ok(hi == 0xcafebabe, "Expected 0xcafebabe, got %08Ix\n", hi); GlobalFree(hglobal); } @@ -2396,7 +2387,8 @@ static WCHAR test_cmd_w_to_w[][32] = { { 0x4efa, 0x4efc, 0x0061, 0x4efe, 0 }, /* some Chinese chars */ { 0x0061, 0x0062, 0x0063, 0x9152, 0 }, /* Chinese with latin characters begin */ }; -static const int nb_callbacks = 5 + ARRAY_SIZE(test_cmd_w_to_w); +static int msg_index; +static BOOL unicode_server, unicode_client; static HDDEDATA CALLBACK server_end_to_end_callback(UINT uType, UINT uFmt, HCONV hconv, HSZ hsz1, HSZ hsz2, HDDEDATA hdata, @@ -2404,45 +2396,47 @@ static HDDEDATA CALLBACK server_end_to_end_callback(UINT uType, UINT uFmt, HCONV { DWORD size, rsize; char str[MAX_PATH]; - static int msg_index = 0; static HCONV conversation = 0; static const char test_service [] = "TestDDEService"; static const char test_topic [] = "TestDDETopic"; + if (winetest_debug > 1) trace("type %#x, fmt %#x\n", uType, uFmt); + + ok(msg_index < 5 + ARRAY_SIZE(test_cmd_w_to_w), "Got unexpected message type %#x.\n", uType); msg_index++; switch (uType) { case XTYP_REGISTER: { - ok(msg_index % nb_callbacks == 1, "Expected 1 modulo %u, got %d\n", nb_callbacks, msg_index); + ok(msg_index == 1, "Expected 1, got %d\n", msg_index); return (HDDEDATA)TRUE; } case XTYP_CONNECT: { - ok(msg_index % nb_callbacks == 2, "Expected 2 modulo %u, got %d\n", nb_callbacks, msg_index); + ok(msg_index == 2, "Expected 2, got %d\n", msg_index); ok(uFmt == 0, "Expected 0, got %d, msg_index=%d\n", uFmt, msg_index); ok(hconv == 0, "Expected 0, got %p, msg_index=%d\n", hconv, msg_index); ok(hdata == 0, "Expected 0, got %p, msg_index=%d\n", hdata, msg_index); - ok(dwData1 != 0, "Expected not 0, got %08lx, msg_index=%d\n", dwData1, msg_index); - ok(dwData2 == FALSE, "Expected FALSE, got %08lx, msg_index=%d\n", dwData2, msg_index); + ok(dwData1 != 0, "Expected not 0, got %08Ix, msg_index=%d\n", dwData1, msg_index); + ok(dwData2 == FALSE, "Expected FALSE, got %08Ix, msg_index=%d\n", dwData2, msg_index); size = DdeQueryStringA(server_pid, hsz1, str, MAX_PATH, CP_WINANSI); ok(!lstrcmpA(str, test_topic), "Expected %s, got %s, msg_index=%d\n", test_topic, str, msg_index); - ok(size == 12, "Expected 12, got %d, msg_index=%d\n", size, msg_index); + ok(size == 12, "Expected 12, got %ld, msg_index=%d\n", size, msg_index); size = DdeQueryStringA(server_pid, hsz2, str, MAX_PATH, CP_WINANSI); ok(!lstrcmpA(str, test_service), "Expected %s, got %s, msg_index=%d\n", test_service, str, msg_index); - ok(size == 14, "Expected 14, got %d, msg_index=%d\n", size, msg_index); + ok(size == 14, "Expected 14, got %ld, msg_index=%d\n", size, msg_index); return (HDDEDATA) TRUE; } case XTYP_CONNECT_CONFIRM: { - ok(msg_index % nb_callbacks == 3, "Expected 3 modulo %u, got %d\n", nb_callbacks, msg_index); + ok(msg_index == 3, "Expected 3, got %d\n", msg_index); conversation = hconv; return (HDDEDATA) TRUE; } @@ -2453,29 +2447,27 @@ static HDDEDATA CALLBACK server_end_to_end_callback(UINT uType, UINT uFmt, HCONV char test_cmd_w_to_a[64]; WCHAR test_cmd_a_to_w[64]; DWORD size_a, size_w, size_w_to_a, size_a_to_w; - BOOL unicode_server, unicode_client, str_index; + BOOL str_index; ok(uFmt == 0, "Expected 0, got %d\n", uFmt); ok(hconv == conversation, "Expected conversation handle, got %p, msg_index=%d\n", hconv, msg_index); - ok(dwData1 == 0, "Expected 0, got %08lx, msg_index=%d\n", dwData1, msg_index); - ok(dwData2 == 0, "Expected 0, got %08lx, msg_index=%d\n", dwData2, msg_index); + ok(dwData1 == 0, "Expected 0, got %08Ix, msg_index=%d\n", dwData1, msg_index); + ok(dwData2 == 0, "Expected 0, got %08Ix, msg_index=%d\n", dwData2, msg_index); ok(hsz2 == 0, "Expected 0, got %p, msg_index=%d\n", hsz2, msg_index); size = DdeQueryStringA(server_pid, hsz1, str, MAX_PATH, CP_WINANSI); ok(!lstrcmpA(str, test_topic), "Expected %s, got %s, msg_index=%d\n", test_topic, str, msg_index); - ok(size == 12, "Expected 12, got %d, msg_index=%d\n", size, msg_index); + ok(size == 12, "Expected 12, got %ld, msg_index=%d\n", size, msg_index); size = DdeGetData(hdata, NULL, 0, 0); - ok((buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size)) != NULL, "should not be null\n"); + ok((buffer = calloc(1, size)) != NULL, "should not be null\n"); rsize = DdeGetData(hdata, buffer, size, 0); - ok(rsize == size, "Incorrect size returned, expected %d got %d, msg_index=%d\n", + ok(rsize == size, "Incorrect size returned, expected %ld got %ld, msg_index=%d\n", size, rsize, msg_index); - trace("msg %u strA \"%s\" strW %s\n", msg_index, buffer, wine_dbgstr_w((WCHAR*)buffer)); + if (winetest_debug > 1) trace("msg %u strA \"%s\" strW %s\n", msg_index, buffer, wine_dbgstr_w((WCHAR*)buffer)); - unicode_server = (msg_index / nb_callbacks == 1 || msg_index / nb_callbacks == 2); - unicode_client = (msg_index / nb_callbacks == 1 || msg_index / nb_callbacks == 3); - str_index = msg_index % nb_callbacks - 4; + str_index = msg_index - 4; cmd_w = test_cmd_w_to_w[str_index - 1]; size_a = strlen(test_cmd_a_to_a) + 1; size_w = (lstrlenW(cmd_w) + 1) * sizeof(WCHAR); @@ -2485,20 +2477,20 @@ static HDDEDATA CALLBACK server_end_to_end_callback(UINT uType, UINT uFmt, HCONV test_cmd_w_to_a, sizeof(test_cmd_w_to_a), NULL, NULL ); switch (str_index) { - case 0: /* ASCII string */ + case 0: /* ANSI string */ if (unicode_server) { - ok(size == size_a_to_w, "Wrong size %d/%d, msg_index=%d\n", size, size_a_to_w, msg_index); + ok(size == size_a_to_w, "Wrong size %ld/%ld, msg_index=%d\n", size, size_a_to_w, msg_index); ok(!lstrcmpW((WCHAR*)buffer, test_cmd_a_to_w), "Expected %s, msg_index=%d\n", wine_dbgstr_w(test_cmd_a_to_w), msg_index); } else if (unicode_client) { - /* ASCII string mapped W->A -> garbage */ + /* ANSI string mapped W->A -> garbage */ } else { - ok(size == size_a, "Wrong size %d/%d, msg_index=%d\n", size, size_a, msg_index); + ok(size == size_a, "Wrong size %ld/%ld, msg_index=%d\n", size, size_a, msg_index); ok(!lstrcmpA((CHAR*)buffer, test_cmd_a_to_a), "Expected %s, got %s, msg_index=%d\n", test_cmd_a_to_a, buffer, msg_index); } @@ -2507,13 +2499,13 @@ static HDDEDATA CALLBACK server_end_to_end_callback(UINT uType, UINT uFmt, HCONV case 1: /* Unicode string with only 8-bit chars */ if (unicode_server) { - ok(size == size_w, "Wrong size %d/%d, msg_index=%d\n", size, size_w, msg_index); + ok(size == size_w, "Wrong size %ld/%ld, msg_index=%d\n", size, size_w, msg_index); ok(!lstrcmpW((WCHAR*)buffer, cmd_w), "Expected %s, msg_index=%d\n", wine_dbgstr_w(cmd_w), msg_index); } else { - ok(size == size_w_to_a, "Wrong size %d/%d, msg_index=%d\n", + ok(size == size_w_to_a, "Wrong size %ld/%ld, msg_index=%d\n", size, size_w_to_a, msg_index); ok(!lstrcmpA((CHAR*)buffer, test_cmd_w_to_a), "Expected %s, got %s, msg_index=%d\n", test_cmd_w_to_a, buffer, msg_index); @@ -2532,19 +2524,19 @@ static HDDEDATA CALLBACK server_end_to_end_callback(UINT uType, UINT uFmt, HCONV DWORD xp_size = MultiByteToWideChar( CP_ACP, 0, (char *)cmd_w, -1, NULL, 0 ) * sizeof(WCHAR); ok(size == xp_size || broken(size == nt_size) || broken(str_index == 4 && IsDBCSLeadByte(cmd_w[0])) /* East Asian */, - "Wrong size %d/%d, msg_index=%d\n", size, size_a_to_w, msg_index); + "Wrong size %ld/%ld, msg_index=%d\n", size, size_a_to_w, msg_index); ok(!lstrcmpW((WCHAR*)buffer, test_cmd_a_to_w), "Expected %s, msg_index=%d\n", wine_dbgstr_w(test_cmd_a_to_w), msg_index); } else if (unicode_client) { - ok(size == size_w_to_a, "Wrong size %d/%d, msg_index=%d\n", size, size_w_to_a, msg_index); + ok(size == size_w_to_a, "Wrong size %ld/%ld, msg_index=%d\n", size, size_w_to_a, msg_index); ok(!lstrcmpA((CHAR*)buffer, test_cmd_w_to_a), "Expected %s, got %s, msg_index=%d\n", test_cmd_w_to_a, buffer, msg_index); } else { - ok(size == size_w, "Wrong size %d/%d, msg_index=%d\n", size, size_w, msg_index); + ok(size == size_w, "Wrong size %ld/%ld, msg_index=%d\n", size, size_w, msg_index); ok(!lstrcmpW((WCHAR*)buffer, cmd_w), "Expected %s, msg_index=%d\n", wine_dbgstr_w(cmd_w), msg_index); } @@ -2552,7 +2544,7 @@ static HDDEDATA CALLBACK server_end_to_end_callback(UINT uType, UINT uFmt, HCONV case 5: /* Chinese with latin characters begin */ if (unicode_server && unicode_client) { - todo_wine ok(size == size_w, "Wrong size %d expected %d, msg_index=%d\n", size, size_w, msg_index); + todo_wine ok(size == size_w, "Wrong size %ld expected %ld, msg_index=%d\n", size, size_w, msg_index); MultiByteToWideChar(CP_ACP, 0, test_cmd_w_to_a, size_w, test_cmd_a_to_w, ARRAY_SIZE(test_cmd_a_to_w)); todo_wine ok(!lstrcmpW((WCHAR*)buffer, cmd_w), @@ -2560,7 +2552,7 @@ static HDDEDATA CALLBACK server_end_to_end_callback(UINT uType, UINT uFmt, HCONV } else if (unicode_server) { - todo_wine ok(size == size_w, "Wrong size %d expected %d, msg_index=%d\n", size, size_w, msg_index); + todo_wine ok(size == size_w, "Wrong size %ld expected %ld, msg_index=%d\n", size, size_w, msg_index); MultiByteToWideChar(CP_ACP, 0, test_cmd_w_to_a, size_w, test_cmd_a_to_w, ARRAY_SIZE(test_cmd_a_to_w)); if (!is_cjk()) @@ -2572,13 +2564,13 @@ static HDDEDATA CALLBACK server_end_to_end_callback(UINT uType, UINT uFmt, HCONV } else if (unicode_client) { - ok(size == size_w_to_a, "Wrong size %d expected %d, msg_index=%d\n", size, size_w_to_a, msg_index); + ok(size == size_w_to_a, "Wrong size %ld expected %ld, msg_index=%d\n", size, size_w_to_a, msg_index); ok(!lstrcmpA((CHAR*)buffer, test_cmd_w_to_a), "Expected %s, got %s, msg_index=%d\n", test_cmd_w_to_a, buffer, msg_index); } else { - todo_wine ok(size == size_w_to_a || size == (size_w_to_a - 1), "Wrong size %d expected %d or %d, msg_index=%d\n", + todo_wine ok(size == size_w_to_a || size == (size_w_to_a - 1), "Wrong size %ld expected %ld or %ld, msg_index=%d\n", size, size_w_to_a, size_w_to_a - 1, msg_index); todo_wine ok(!lstrcmpA((CHAR*)buffer, test_cmd_w_to_a), "Expected %s, got %s, msg_index=%d\n", test_cmd_w_to_a, buffer, msg_index); @@ -2589,7 +2581,7 @@ static HDDEDATA CALLBACK server_end_to_end_callback(UINT uType, UINT uFmt, HCONV ok( 0, "Invalid message %u\n", msg_index ); break; } - HeapFree(GetProcessHeap(), 0, buffer); + free(buffer); return (HDDEDATA) DDE_FACK; } case XTYP_DISCONNECT: @@ -2630,13 +2622,11 @@ static void test_end_to_end_client(BOOL type_a) static const char test_topic[] = "TestDDETopic"; static const WCHAR test_topic_w[] = {'T','e','s','t','D','D','E','T','o','p','i','c',0}; - trace("Start end to end client %s\n", type_a ? "ASCII" : "UNICODE"); - if (type_a) ret = DdeInitializeA(&client_pid, client_end_to_end_callback, APPCMD_CLIENTONLY, 0); else ret = DdeInitializeW(&client_pid, client_end_to_end_callback, APPCMD_CLIENTONLY, 0); - ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %x\n", ret); + ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %lx\n", ret); if (type_a) { @@ -2650,18 +2640,23 @@ static void test_end_to_end_client(BOOL type_a) DdeGetLastError(client_pid); hconv = DdeConnect(client_pid, server, topic, NULL); - ok(hconv != NULL, "Expected non-NULL conversation\n"); + if (broken(!hconv)) /* Windows 10 version 1607 */ + { + win_skip("Failed to connect; error %#x.\n", DdeGetLastError(client_pid)); + DdeUninitialize(client_pid); + return; + } ret = DdeGetLastError(client_pid); - ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %x\n", ret); + ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %lx\n", ret); DdeFreeStringHandle(client_pid, server); /* Test both A and W data being passed to DdeClientTransaction */ hdata = DdeClientTransaction((LPBYTE)test_cmd_a_to_a, sizeof(test_cmd_a_to_a), hconv, (HSZ)0xdead, 0xbeef, XTYP_EXECUTE, 1000, &ret); ok(hdata != NULL, "DdeClientTransaction failed\n"); - ok(ret == DDE_FACK, "wrong status code %x\n", ret); + ok(ret == DDE_FACK, "wrong status code %lx\n", ret); err = DdeGetLastError(client_pid); - ok(err == DMLERR_NO_ERROR, "wrong dde error %x\n", err); + ok(err == DMLERR_NO_ERROR, "wrong dde error %lx\n", err); for (i = 0; i < ARRAY_SIZE(test_cmd_w_to_w); i++) { @@ -2669,22 +2664,23 @@ static void test_end_to_end_client(BOOL type_a) (lstrlenW(test_cmd_w_to_w[i]) + 1) * sizeof(WCHAR), hconv, (HSZ)0xdead, 0xbeef, XTYP_EXECUTE, 1000, &ret); ok(hdata != NULL, "DdeClientTransaction failed\n"); - ok(ret == DDE_FACK, "wrong status code %x\n", ret); + ok(ret == DDE_FACK, "wrong status code %lx\n", ret); err = DdeGetLastError(client_pid); - ok(err == DMLERR_NO_ERROR, "wrong dde error %x\n", err); + ok(err == DMLERR_NO_ERROR, "wrong dde error %lx\n", err); } DdeFreeStringHandle(client_pid, topic); ret = DdeDisconnect(hconv); - ok(ret == TRUE, "Expected TRUE, got %x\n", ret); + ok(ret == TRUE, "Expected TRUE, got %lx\n", ret); ret = DdeUninitialize(client_pid); - ok(ret == TRUE, "Expected TRUE, got %x\n", ret); + ok(ret == TRUE, "Expected TRUE, got %lx\n", ret); } -static void test_end_to_end_server(HANDLE hproc, HANDLE hthread, BOOL type_a) +static void test_end_to_end_server(void) { + HANDLE client; MSG msg; HSZ server; BOOL ret; @@ -2692,41 +2688,41 @@ static void test_end_to_end_server(HANDLE hproc, HANDLE hthread, BOOL type_a) HDDEDATA hdata; static const char test_service[] = "TestDDEService"; - trace("start end to end server %s\n", type_a ? "ASCII" : "UNICODE"); + trace("client %s, server %s\n", unicode_client ? "unicode" : "ansi", + unicode_server ? "unicode" : "ansi"); server_pid = 0; + msg_index = 0; - if (type_a) - res = DdeInitializeA(&server_pid, server_end_to_end_callback, APPCLASS_STANDARD, 0); - else + if (unicode_server) res = DdeInitializeW(&server_pid, server_end_to_end_callback, APPCLASS_STANDARD, 0); - ok(res == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", res); + else + res = DdeInitializeA(&server_pid, server_end_to_end_callback, APPCLASS_STANDARD, 0); + ok(res == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %ld\n", res); server = DdeCreateStringHandleA(server_pid, test_service, CP_WINANSI); ok(server != NULL, "Expected non-NULL string handle\n"); hdata = DdeNameService(server_pid, server, 0, DNS_REGISTER); ok(hdata == (HDDEDATA)TRUE, "Expected TRUE, got %p\n", hdata); - ResumeThread( hthread ); + client = create_process(unicode_client ? "endw" : "enda"); - while (MsgWaitForMultipleObjects( 1, &hproc, FALSE, INFINITE, QS_ALLINPUT ) != 0) + while (MsgWaitForMultipleObjects(1, &client, FALSE, INFINITE, QS_ALLINPUT) != 0) { while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); } ret = DdeUninitialize(server_pid); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - GetExitCodeProcess( hproc, &res ); - ok( !res, "client failed with %u error(s)\n", res ); + GetExitCodeProcess(client, &res); + ok( !res, "client failed with %lu error(s)\n", res ); + CloseHandle(client); } START_TEST(dde) { int argc; char **argv; - char buffer[MAX_PATH]; - STARTUPINFOA startup; - PROCESS_INFORMATION proc; DWORD dde_inst = 0xdeadbeef; argc = winetest_get_mainargs(&argv); @@ -2746,75 +2742,40 @@ START_TEST(dde) test_initialisation(); - SetLastError(0xdeadbeef); DdeInitializeW(&dde_inst, client_ddeml_callback, APPCMD_CLIENTONLY, 0); - if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) - { - win_skip("Skipping tests on win9x because of brokenness\n"); - return; - } - ZeroMemory(&startup, sizeof(STARTUPINFOA)); - sprintf(buffer, "%s dde ddeml", argv[0]); - startup.cb = sizeof(startup); - startup.dwFlags = STARTF_USESHOWWINDOW; - startup.wShowWindow = SW_SHOWNORMAL; - - CreateProcessA(NULL, buffer, NULL, NULL, FALSE, - CREATE_SUSPENDED, NULL, NULL, &startup, &proc); - - test_msg_server(proc.hProcess, proc.hThread); - - sprintf(buffer, "%s dde msg", argv[0]); - CreateProcessA(NULL, buffer, NULL, NULL, FALSE, - 0, NULL, NULL, &startup, &proc); - - test_ddeml_server(proc.hProcess); + test_msg_server(); + test_ddeml_server(); /* Test the combinations of A and W interfaces with A and W data end to end to ensure that data conversions are accurate */ - sprintf(buffer, "%s dde enda", argv[0]); - CreateProcessA(NULL, buffer, NULL, NULL, FALSE, - CREATE_SUSPENDED, NULL, NULL, &startup, &proc); + unicode_client = unicode_server = FALSE; + test_end_to_end_server(); + unicode_client = unicode_server = TRUE; + test_end_to_end_server(); + unicode_client = FALSE; + unicode_server = TRUE; + test_end_to_end_server(); + unicode_client = TRUE; + unicode_server = FALSE; + test_end_to_end_server(); - test_end_to_end_server(proc.hProcess, proc.hThread, TRUE); + test_dde_aw_transaction( FALSE, TRUE ); + test_dde_aw_transaction( TRUE, FALSE ); + test_dde_aw_transaction( TRUE, TRUE ); + test_dde_aw_transaction( FALSE, FALSE ); - /* Don't bother testing W interfaces on Win9x/WinMe */ - SetLastError(0xdeadbeef); - lstrcmpW(NULL, NULL); - if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) - { - win_skip("Skipping W-interface tests\n"); - } - else - { - sprintf(buffer, "%s dde endw", argv[0]); - CreateProcessA(NULL, buffer, NULL, NULL, FALSE, - CREATE_SUSPENDED, NULL, NULL, &startup, &proc); - - test_end_to_end_server(proc.hProcess, proc.hThread, FALSE); - - sprintf(buffer, "%s dde enda", argv[0]); - CreateProcessA(NULL, buffer, NULL, NULL, FALSE, - CREATE_SUSPENDED, NULL, NULL, &startup, &proc); - - test_end_to_end_server(proc.hProcess, proc.hThread, FALSE); - - sprintf(buffer, "%s dde endw", argv[0]); - CreateProcessA(NULL, buffer, NULL, NULL, FALSE, - CREATE_SUSPENDED, NULL, NULL, &startup, &proc); - - test_end_to_end_server(proc.hProcess, proc.hThread, TRUE); - - test_dde_aw_transaction( FALSE, TRUE ); - test_dde_aw_transaction( TRUE, FALSE ); - test_dde_aw_transaction( TRUE, TRUE ); - test_dde_aw_transaction( FALSE, FALSE ); - - test_dde_aw_transaction( FALSE, TRUE ); - test_dde_aw_transaction( TRUE, FALSE ); - test_dde_aw_transaction( TRUE, TRUE ); +#if defined(__REACTOS__) && defined(__GNUC__) + if (is_reactos()) { + ok(FALSE, "FIXME: Running these test_dde_aw_transaction() tests again crashes GCC ReactOS but not MSVC ReactOS!\n"); + } else { +#endif + test_dde_aw_transaction( FALSE, TRUE ); + test_dde_aw_transaction( TRUE, FALSE ); +#if defined(__REACTOS__) && defined(__GNUC__) } +#endif + test_dde_aw_transaction( TRUE, TRUE ); test_dde_aw_transaction( FALSE, FALSE ); test_DdeCreateDataHandle(); diff --git a/modules/rostests/winetests/user32/dialog.c b/modules/rostests/winetests/user32/dialog.c index 812cbfaa5c6..4d5919d017f 100644 --- a/modules/rostests/winetests/user32/dialog.c +++ b/modules/rostests/winetests/user32/dialog.c @@ -168,7 +168,7 @@ static BOOL CreateWindows (HINSTANCE hinst) { if (p->id >= ARRAY_SIZE(hwnd)) { - trace ("Control %ld is out of range\n", p->id); + trace ("Control %Id is out of range\n", p->id); return FALSE; } else @@ -176,21 +176,21 @@ static BOOL CreateWindows (HINSTANCE hinst) } if (p->id <= 0) { - trace ("Control %ld is out of range\n", p->id); + trace ("Control %Id is out of range\n", p->id); return FALSE; } if (hwnd[p->id] != 0) { - trace ("Control %ld is used more than once\n", p->id); + trace ("Control %Id is used more than once\n", p->id); return FALSE; } /* Create the control */ - sprintf (ctrlname, "ctrl%4.4ld", p->id); + sprintf (ctrlname, "ctrl%4.4Id", p->id); hwnd[p->id] = CreateWindowExA(p->exstyle, p->parent ? "static" : "GetNextDlgItemWindowClass", ctrlname, p->style, 10, 10, 10, 10, hwnd[p->parent], p->parent ? (HMENU) (2000 + p->id) : 0, hinst, 0); if (!hwnd[p->id]) { - trace ("Failed to create control %ld\n", p->id); + trace ("Failed to create control %Id\n", p->id); return FALSE; } @@ -204,7 +204,7 @@ static BOOL CreateWindows (HINSTANCE hinst) exstyle = GetWindowLongA(hwnd[p->id], GWL_EXSTYLE); if (style != p->style || exstyle != p->exstyle) { - trace ("Style mismatch at %ld: %8.8x %8.8x cf %8.8x %8.8x\n", p->id, style, exstyle, p->style, p->exstyle); + trace ("Style mismatch at %Id: %8.8lx %8.8lx cf %8.8lx %8.8lx\n", p->id, style, exstyle, p->style, p->exstyle); } } p++; @@ -489,7 +489,7 @@ static LRESULT CALLBACK main_window_procA (HWND hwnd, UINT uiMsg, WPARAM wParam, return DefWindowProcA (hwnd, uiMsg, wParam, lParam); } -static LRESULT CALLBACK disabled_test_proc (HWND hwnd, UINT uiMsg, +static INT_PTR CALLBACK disabled_test_proc (HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) { switch (uiMsg) @@ -568,8 +568,46 @@ static LRESULT CALLBACK test_control_procA(HWND hwnd, UINT msg, WPARAM wparam, L return DefWindowProcA(hwnd, msg, wparam, lparam); } +static int wm_char_count; + +static BOOL is_cjk(void) +{ + int lang_id = PRIMARYLANGID(GetUserDefaultLangID()); + + if (lang_id == LANG_CHINESE || lang_id == LANG_JAPANESE || lang_id == LANG_KOREAN) + return TRUE; + return FALSE; +} + +static LRESULT CALLBACK test_IsDialogMessageA_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch (msg) + { + case WM_CHAR: + if (is_cjk()) + ok(wparam == 0x5b57, "Got unexpected wparam %#Ix.\n", wparam); + else if (PRIMARYLANGID(GetUserDefaultLangID()) == LANG_HINDI && GetACP() == CP_UTF8) + ok(wparam == 0xfffd, "Got unexpected wparam %#Ix.\n", wparam); + else + ok(wparam == 0x3f, "Got unexpected wparam %#Ix.\n", wparam); + wm_char_count++; + return 0; + case WM_CLOSE: + DestroyWindow(hwnd); + return 0; + case WM_DESTROY: + PostQuitMessage(0); + return 0; + case WM_GETDLGCODE: + return DLGC_WANTCHARS; + default: + return DefWindowProcW(hwnd, msg, wparam, lparam); + } +} + static BOOL RegisterWindowClasses (void) { + WNDCLASSW cls_w; WNDCLASSA cls; cls.style = 0; @@ -598,6 +636,11 @@ static BOOL RegisterWindowClasses (void) cls.lpszClassName = "WM_NEXTDLGCTLWndClass"; if (!RegisterClassA (&cls)) return FALSE; + memset (&cls_w, 0, sizeof(cls_w)); + cls_w.lpfnWndProc = test_IsDialogMessageA_proc; + cls_w.hInstance = g_hinst; + cls_w.lpszClassName = L"TestIsDialogMessageAClass"; + if (!RegisterClassW (&cls_w)) return FALSE; return TRUE; } @@ -653,8 +696,8 @@ static void test_WM_NEXTDLGCTL(void) * Check whether the style of the button which got the focus, changed to BS_DEFPUSHBUTTON and * the style of default button changed to BS_PUSHBUTTON. */ - ok(get_button_style(g_hwndTestDlgBut1) == BS_DEFPUSHBUTTON, "Button1's style not set to BS_DEFPUSHBUTTON"); - ok(get_button_style(g_hwndTestDlgBut2) == BS_PUSHBUTTON, "Button2's style not set to BS_PUSHBUTTON"); + ok(get_button_style(g_hwndTestDlgBut1) == BS_DEFPUSHBUTTON, "Button1's style not set to BS_DEFPUSHBUTTON\n"); + ok(get_button_style(g_hwndTestDlgBut2) == BS_PUSHBUTTON, "Button2's style not set to BS_PUSHBUTTON\n"); /* Move focus to Button2 using "WM_NEXTDLGCTL" */ DefDlgProcA(g_hwndTestDlg, WM_NEXTDLGCTL, 0, 0); @@ -668,8 +711,8 @@ static void test_WM_NEXTDLGCTL(void) * Check whether the style of the button which got the focus, changed to BS_DEFPUSHBUTTON and * the style of button which lost the focus changed to BS_PUSHBUTTON. */ - ok(get_button_style(g_hwndTestDlgBut1) == BS_PUSHBUTTON, "Button1's style not set to BS_PUSHBUTTON"); - ok(get_button_style(g_hwndTestDlgBut2) == BS_DEFPUSHBUTTON, "Button2's style not set to BS_DEFPUSHBUTTON"); + ok(get_button_style(g_hwndTestDlgBut1) == BS_PUSHBUTTON, "Button1's style not set to BS_PUSHBUTTON\n"); + ok(get_button_style(g_hwndTestDlgBut2) == BS_DEFPUSHBUTTON, "Button2's style not set to BS_DEFPUSHBUTTON\n"); /* Move focus to Edit control using "WM_NEXTDLGCTL" */ DefDlgProcA(g_hwndTestDlg, WM_NEXTDLGCTL, 0, 0); @@ -694,11 +737,11 @@ static void test_WM_NEXTDLGCTL(void) DefDlgProcA( g_hwndTestDlg, DM_SETDEFID, 200, 0); dwVal = DefDlgProcA( g_hwndTestDlg, DM_GETDEFID, 0, 0); - ok(LOWORD(dwVal) == 200, "expected 200, got %x\n", dwVal); + ok(LOWORD(dwVal) == 200, "expected 200, got %lx\n", dwVal); DefDlgProcA( g_hwndTestDlg, DM_SETDEFID, 300, 0); dwVal = DefDlgProcA( g_hwndTestDlg, DM_GETDEFID, 0, 0); - ok(LOWORD(dwVal) == 300, "expected 300, got %x\n", dwVal); + ok(LOWORD(dwVal) == 300, "expected 300, got %lx\n", dwVal); ok(SendMessageW( child3, WM_GETDLGCODE, 0, 0) != DLGC_DEFPUSHBUTTON, "expected child3 not to be marked as DLGC_DEFPUSHBUTTON\n"); @@ -730,6 +773,8 @@ static LRESULT CALLBACK hook_proc2(INT code, WPARAM wParam, LPARAM lParam) static void test_IsDialogMessage(void) { HHOOK hook; + HWND child; + BOOL ret; MSG msg; g_hwndMain = CreateWindowA("IsDialogMessageWindowClass", "IsDialogMessageWindowClass", @@ -817,6 +862,35 @@ static void test_IsDialogMessage(void) ok(IsDialogMessageA(g_hwndMain, &msg), "Did not handle the ENTER\n"); ok(g_button1Clicked, "Did not receive button 1 click notification\n"); + /* Test IsDialogMessageA converting a WM_CHAR wparam in ASCII to Unicode */ + child = CreateWindowW(L"TestIsDialogMessageAClass", L"test", WS_CHILD | WS_VISIBLE, 0, 0, 10, + 10, g_hwndMain, 0, g_hinst, 0); + ok(!!child, "Failed to create a window, error %#lx.\n", GetLastError()); + + /* \u5b57 is a 'å­—' in Chinese */ + PostMessageW(child, WM_CHAR, 0x5b57, 0x1); + PostMessageW(child, WM_CLOSE, 0, 0); + + while (GetMessageA(&msg, child, 0, 0) > 0) + { + if (msg.message == WM_CHAR) + { + if (is_cjk()) + ok(msg.wParam != 0x3f && msg.wParam != 0x5b57, "Got unexpected wparam %#Ix.\n", msg.wParam); + else if (PRIMARYLANGID(GetUserDefaultLangID()) == LANG_HINDI && GetACP() == CP_UTF8) + ok(msg.wParam == 0x97ade5, "Got unexpected wparam %#Ix.\n", msg.wParam); + else + ok(msg.wParam == 0x3f, "Got unexpected wparam %#Ix.\n", msg.wParam); + ret = IsDialogMessageA(g_hwndMain, &msg); + ok(ret, "IsDialogMessageA failed.\n"); + } + else + { + TranslateMessage(&msg); + DispatchMessageA(&msg); + } + } + ok(wm_char_count == 1, "Got unexpected WM_CHAR count %d.\n", wm_char_count); DestroyWindow(g_hwndMain); } @@ -1043,13 +1117,13 @@ static void test_focus(void) SendMessageA(hDlg, WM_SETFOCUS, 0, 0); SendMessageA(hTextbox, EM_GETSEL, (WPARAM)&selectionStart, (LPARAM)&selectionEnd); - ok(selectionStart == 0 && selectionEnd == 11, "Text selection after WM_SETFOCUS is [%i, %i) expected [0, 11)\n", selectionStart, selectionEnd); + ok(selectionStart == 0 && selectionEnd == 11, "Text selection after WM_SETFOCUS is [%li, %li) expected [0, 11)\n", selectionStart, selectionEnd); /* but WM_ACTIVATE does not */ SendMessageA(hTextbox, EM_SETSEL, 0, 0); SendMessageA(hDlg, WM_ACTIVATE, WA_ACTIVE, 0); SendMessageA(hTextbox, EM_GETSEL, (WPARAM)&selectionStart, (LPARAM)&selectionEnd); - ok(selectionStart == 0 && selectionEnd == 0, "Text selection after WM_ACTIVATE is [%i, %i) expected [0, 0)\n", selectionStart, selectionEnd); + ok(selectionStart == 0 && selectionEnd == 0, "Text selection after WM_ACTIVATE is [%li, %li) expected [0, 0)\n", selectionStart, selectionEnd); DestroyWindow(hDlg); } @@ -1113,7 +1187,7 @@ static void test_focus(void) GetFocus(), hDlg, edit); SendMessageA(edit, EM_GETSEL, (WPARAM)&selectionStart, (LPARAM)&selectionEnd); ok(selectionStart == 0 && selectionEnd == 11, - "Text selection after WM_SETFOCUS is [%i, %i) expected [0, 11)\n", + "Text selection after WM_SETFOCUS is [%li, %li) expected [0, 11)\n", selectionStart, selectionEnd); DestroyWindow(hDlg); @@ -1176,7 +1250,7 @@ static INT_PTR CALLBACK getdlgitem_test_dialog_proc(HWND hdlg, UINT msg, WPARAM ok(val == -1, "Unexpected id.\n"); val = GetWindowLongPtrA(hwnd, GWLP_ID); - ok(val == -1, "Unexpected id %ld.\n", val); + ok(val == -1, "Unexpected id %Id.\n", val); hwnd = GetDlgItem(hdlg, -2); ok(hwnd != NULL, "Expected dialog item.\n"); @@ -1185,7 +1259,7 @@ static INT_PTR CALLBACK getdlgitem_test_dialog_proc(HWND hdlg, UINT msg, WPARAM ok(val == -2, "Unexpected id.\n"); val = GetWindowLongPtrA(hwnd, GWLP_ID); - ok(val == -2, "Unexpected id %ld.\n", val); + ok(val == -2, "Unexpected id %Id.\n", val); EndDialog(hdlg, 0xdead); } @@ -1358,9 +1432,9 @@ static INT_PTR CALLBACK TestControlStyleDlgProc(HWND hdlg, UINT msg, control = GetDlgItem(hdlg, 7); ok(control != 0, "dialog control with id 7 not found\n"); style = GetWindowLongA(control, GWL_STYLE); - ok(style == (WS_CHILD|WS_VISIBLE), "expected WS_CHILD|WS_VISIBLE, got %#x\n", style); + ok(style == (WS_CHILD|WS_VISIBLE), "expected WS_CHILD|WS_VISIBLE, got %#lx\n", style); exstyle = GetWindowLongA(control, GWL_EXSTYLE); - ok(exstyle == (WS_EX_NOPARENTNOTIFY|WS_EX_TRANSPARENT|WS_EX_CLIENTEDGE), "expected WS_EX_NOPARENTNOTIFY|WS_EX_TRANSPARENT|WS_EX_CLIENTEDGE, got %#x\n", exstyle); + ok(exstyle == (WS_EX_NOPARENTNOTIFY|WS_EX_TRANSPARENT|WS_EX_CLIENTEDGE), "expected WS_EX_NOPARENTNOTIFY|WS_EX_TRANSPARENT|WS_EX_CLIENTEDGE, got %#lx\n", exstyle); buf[0] = 0; GetWindowTextA(control, buf, sizeof(buf)); ok(strcmp(buf, "bump7") == 0, "expected bump7, got %s\n", buf); @@ -1368,9 +1442,9 @@ static INT_PTR CALLBACK TestControlStyleDlgProc(HWND hdlg, UINT msg, control = GetDlgItem(hdlg, 8); ok(control != 0, "dialog control with id 8 not found\n"); style = GetWindowLongA(control, GWL_STYLE); - ok(style == (WS_CHILD|WS_VISIBLE), "expected WS_CHILD|WS_VISIBLE, got %#x\n", style); + ok(style == (WS_CHILD|WS_VISIBLE), "expected WS_CHILD|WS_VISIBLE, got %#lx\n", style); exstyle = GetWindowLongA(control, GWL_EXSTYLE); - ok(exstyle == (WS_EX_NOPARENTNOTIFY|WS_EX_TRANSPARENT), "expected WS_EX_NOPARENTNOTIFY|WS_EX_TRANSPARENT, got %#x\n", exstyle); + ok(exstyle == (WS_EX_NOPARENTNOTIFY|WS_EX_TRANSPARENT), "expected WS_EX_NOPARENTNOTIFY|WS_EX_TRANSPARENT, got %#lx\n", exstyle); buf[0] = 0; GetWindowTextA(control, buf, sizeof(buf)); ok(strcmp(buf, "bump8") == 0, "expected bump8, got %s\n", buf); @@ -1540,28 +1614,28 @@ static INT_PTR CALLBACK test_aw_conversion_dlgproc(HWND hdlg, UINT msg, WPARAM w /* WM_SETTEXT/WM_GETTEXT */ originalproc = GetWindowLongPtrW(hdlg, DWLP_DLGPROC); - ok(originalproc == (ULONG_PTR)test_aw_conversion_dlgproc, "Unexpected dlg proc %#lx.\n", originalproc); + ok(originalproc == (ULONG_PTR)test_aw_conversion_dlgproc, "Unexpected dlg proc %#Ix.\n", originalproc); dlgproc = GetWindowLongPtrA(hdlg, DWLP_DLGPROC); - ok(dlgproc != (ULONG_PTR)test_aw_conversion_dlgproc, "Unexpected dlg proc %#lx.\n", dlgproc); + ok(dlgproc != (ULONG_PTR)test_aw_conversion_dlgproc, "Unexpected dlg proc %#Ix.\n", dlgproc); dlgproc = SetWindowLongPtrA(hdlg, DWLP_DLGPROC, (UINT_PTR)test_aw_conversion_dlgprocA); ok(IsWindowUnicode(hdlg), "Expected unicode window.\n"); dlgproc = GetWindowLongPtrW(hdlg, DWLP_DLGPROC); - ok(dlgproc != (ULONG_PTR)test_aw_conversion_dlgprocA, "Unexpected dlg proc %#lx.\n", dlgproc); + ok(dlgproc != (ULONG_PTR)test_aw_conversion_dlgprocA, "Unexpected dlg proc %#Ix.\n", dlgproc); dlgproc = GetWindowLongPtrA(hdlg, DWLP_DLGPROC); - ok(dlgproc == (ULONG_PTR)test_aw_conversion_dlgprocA, "Unexpected dlg proc %#lx.\n", dlgproc); + ok(dlgproc == (ULONG_PTR)test_aw_conversion_dlgprocA, "Unexpected dlg proc %#Ix.\n", dlgproc); SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SETTEXTA)); ret = SetWindowTextA(hdlg, testtext); - todo_wine + todo_wine ok(ret, "Failed to set window text.\n"); SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SETTEXTW)); ret = SetWindowTextW(hdlg, testtextW); - todo_wine + todo_wine ok(ret, "Failed to set window text.\n"); memset(buff, 'A', sizeof(buff)); @@ -1585,19 +1659,19 @@ static INT_PTR CALLBACK test_aw_conversion_dlgproc(HWND hdlg, UINT msg, WPARAM w ok(IsWindowUnicode(hdlg), "Expected unicode window.\n"); dlgproc = GetWindowLongPtrW(hdlg, DWLP_DLGPROC); - ok(dlgproc == (ULONG_PTR)test_aw_conversion_dlgprocW, "Unexpected dlg proc %#lx.\n", dlgproc); + ok(dlgproc == (ULONG_PTR)test_aw_conversion_dlgprocW, "Unexpected dlg proc %#Ix.\n", dlgproc); dlgproc = GetWindowLongPtrA(hdlg, DWLP_DLGPROC); - ok(dlgproc != (ULONG_PTR)test_aw_conversion_dlgprocW, "Unexpected dlg proc %#lx.\n", dlgproc); + ok(dlgproc != (ULONG_PTR)test_aw_conversion_dlgprocW, "Unexpected dlg proc %#Ix.\n", dlgproc); SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SETTEXTA)); ret = SetWindowTextA(hdlg, testtext); - todo_wine + todo_wine ok(ret, "Failed to set window text.\n"); SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SETTEXTW)); ret = SetWindowTextW(hdlg, testtextW); - todo_wine + todo_wine ok(ret, "Failed to set window text.\n"); memset(buff, 'A', sizeof(buff)); @@ -1647,28 +1721,28 @@ static INT_PTR CALLBACK test_aw_conversion_dlgproc2(HWND hdlg, UINT msg, WPARAM dlg_test_aw_message(hdlg, WM_SETTEXT); originalproc = GetWindowLongPtrW(hdlg, DWLP_DLGPROC); - ok(originalproc != (ULONG_PTR)test_aw_conversion_dlgproc2, "Unexpected dlg proc %#lx.\n", originalproc); + ok(originalproc != (ULONG_PTR)test_aw_conversion_dlgproc2, "Unexpected dlg proc %#Ix.\n", originalproc); dlgproc = GetWindowLongPtrA(hdlg, DWLP_DLGPROC); - ok(dlgproc == (ULONG_PTR)test_aw_conversion_dlgproc2, "Unexpected dlg proc %#lx.\n", dlgproc); + ok(dlgproc == (ULONG_PTR)test_aw_conversion_dlgproc2, "Unexpected dlg proc %#Ix.\n", dlgproc); dlgproc = SetWindowLongPtrA(hdlg, DWLP_DLGPROC, (UINT_PTR)test_aw_conversion_dlgprocW); ok(!IsWindowUnicode(hdlg), "Unexpected unicode window.\n"); dlgproc = GetWindowLongPtrW(hdlg, DWLP_DLGPROC); - ok(dlgproc != (ULONG_PTR)test_aw_conversion_dlgprocW, "Unexpected dlg proc %#lx.\n", dlgproc); + ok(dlgproc != (ULONG_PTR)test_aw_conversion_dlgprocW, "Unexpected dlg proc %#Ix.\n", dlgproc); dlgproc = GetWindowLongPtrA(hdlg, DWLP_DLGPROC); - ok(dlgproc == (ULONG_PTR)test_aw_conversion_dlgprocW, "Unexpected dlg proc %#lx.\n", dlgproc); + ok(dlgproc == (ULONG_PTR)test_aw_conversion_dlgprocW, "Unexpected dlg proc %#Ix.\n", dlgproc); SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SETTEXTA)); ret = SetWindowTextA(hdlg, testtext); - todo_wine + todo_wine ok(ret, "Failed to set window text.\n"); SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SETTEXTW)); ret = SetWindowTextW(hdlg, testtextW); - todo_wine + todo_wine ok(ret, "Failed to set window text.\n"); memset(buff, 'A', sizeof(buff)); @@ -1692,19 +1766,19 @@ static INT_PTR CALLBACK test_aw_conversion_dlgproc2(HWND hdlg, UINT msg, WPARAM ok(!IsWindowUnicode(hdlg), "Unexpected unicode window.\n"); dlgproc = GetWindowLongPtrW(hdlg, DWLP_DLGPROC); - ok(dlgproc == (ULONG_PTR)test_aw_conversion_dlgprocA, "Unexpected dlg proc %#lx.\n", dlgproc); + ok(dlgproc == (ULONG_PTR)test_aw_conversion_dlgprocA, "Unexpected dlg proc %#Ix.\n", dlgproc); dlgproc = GetWindowLongPtrA(hdlg, DWLP_DLGPROC); - ok(dlgproc != (ULONG_PTR)test_aw_conversion_dlgprocA, "Unexpected dlg proc %#lx.\n", dlgproc); + ok(dlgproc != (ULONG_PTR)test_aw_conversion_dlgprocA, "Unexpected dlg proc %#Ix.\n", dlgproc); SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SETTEXTA)); ret = SetWindowTextA(hdlg, testtext); - todo_wine + todo_wine ok(ret, "Failed to set window text.\n"); SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SETTEXTW)); ret = SetWindowTextW(hdlg, testtextW); - todo_wine + todo_wine ok(ret, "Failed to set window text.\n"); memset(buff, 'A', sizeof(buff)); @@ -1820,46 +1894,49 @@ static void test_DialogBoxParam(void) HWND hwnd_invalid = (HWND)0x4444; ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_DLG_CHILD_POPUP", 0, TestControlStyleDlgProc, 0); - ok(ret == -7, "expected -7, got %ld\n", ret); + ok(ret == -7, "expected -7, got %Id\n", ret); SetLastError(0xdeadbeef); ret = DialogBoxParamA(GetModuleHandleA(NULL), "IDD_DIALOG" , hwnd_invalid, 0 , 0); - ok(0 == ret || broken(ret == -1), "DialogBoxParamA returned %ld, expected 0\n", ret); + ok(0 == ret || broken(ret == -1), "DialogBoxParamA returned %Id, expected 0\n", ret); ok(ERROR_INVALID_WINDOW_HANDLE == GetLastError() || broken(GetLastError() == 0xdeadbeef), - "got %d, expected ERROR_INVALID_WINDOW_HANDLE\n",GetLastError()); + "got %ld, expected ERROR_INVALID_WINDOW_HANDLE\n",GetLastError()); /* Test a dialog which destroys itself on WM_INITDIALOG. */ SetLastError(0xdeadbeef); ret = DialogBoxParamA(GetModuleHandleA(NULL), "IDD_DIALOG", 0, DestroyDlgWinProc, 0); - ok(-1 == ret, "DialogBoxParamA returned %ld, expected -1\n", ret); + ok(-1 == ret, "DialogBoxParamA returned %Id, expected -1\n", ret); ok(ERROR_INVALID_WINDOW_HANDLE == GetLastError() || GetLastError() == ERROR_SUCCESS || broken(GetLastError() == 0xdeadbeef), - "got %d, expected ERROR_INVALID_WINDOW_HANDLE\n",GetLastError()); + "got %ld, expected ERROR_INVALID_WINDOW_HANDLE\n",GetLastError()); /* Test a dialog which destroys itself on WM_CLOSE. */ ret = DialogBoxParamA(GetModuleHandleA(NULL), "IDD_DIALOG", 0, DestroyOnCloseDlgWinProc, 0); - ok(0 == ret, "DialogBoxParamA returned %ld, expected 0\n", ret); + ok(0 == ret, "DialogBoxParamA returned %Id, expected 0\n", ret); SetLastError(0xdeadbeef); ret = DialogBoxParamA(GetModuleHandleA(NULL), "RESOURCE_INVALID" , 0, 0, 0); - ok(-1 == ret, "DialogBoxParamA returned %ld, expected -1\n", ret); + ok(-1 == ret, "DialogBoxParamA returned %Id, expected -1\n", ret); ok(ERROR_RESOURCE_NAME_NOT_FOUND == GetLastError() || broken(GetLastError() == 0xdeadbeef), - "got %d, expected ERROR_RESOURCE_NAME_NOT_FOUND\n",GetLastError()); + "got %ld, expected ERROR_RESOURCE_NAME_NOT_FOUND\n",GetLastError()); SetLastError(0xdeadbeef); ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_DIALOG_INVALID_CLASS", 0, DestroyDlgWinProc, 0); - ok(ret == -1, "DialogBoxParamA returned %ld, expected -1\n", ret); - ok(GetLastError() == 0, "got %d\n", GetLastError()); + ok(ret == -1, "DialogBoxParamA returned %Id, expected -1\n", ret); + todo_wine + ok(GetLastError() == ERROR_CANNOT_FIND_WND_CLASS || + broken(GetLastError() == ERROR_SUCCESS) /* < win10 21H1 */, + "got %lu, expected ERROR_CANNOT_FIND_WND_CLASS\n", GetLastError()); SetLastError(0xdeadbeef); ret = DefDlgProcA(0, WM_ERASEBKGND, 0, 0); - ok(ret == 0, "DefDlgProcA returned %ld, expected 0\n", ret); + ok(ret == 0, "DefDlgProcA returned %Id, expected 0\n", ret); ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef), - "got %d, expected ERROR_INVALID_WINDOW_HANDLE\n", GetLastError()); + "got %ld, expected ERROR_INVALID_WINDOW_HANDLE\n", GetLastError()); ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, TestInitDialogHandleProc, 0); ok(ret == IDOK, "Expected IDOK\n"); @@ -1868,20 +1945,20 @@ static void test_DialogBoxParam(void) ok(ret == IDOK, "Expected IDOK\n"); ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, TestReturnKeyDlgProc, 0); - ok(ret == 0, "Unexpected ret value %ld.\n", ret); + ok(ret == 0, "Unexpected ret value %Id.\n", ret); /* WM_SETTEXT handling in case of A/W dialog procedures vs A/W dialog window. */ ret = DialogBoxParamW(GetModuleHandleA(NULL), nameW, 0, test_aw_conversion_dlgproc, 0); - ok(ret == -123, "Unexpected ret value %ld.\n", ret); + ok(ret == -123, "Unexpected ret value %Id.\n", ret); ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, test_aw_conversion_dlgproc2, 0); - ok(ret == -123, "Unexpected ret value %ld.\n", ret); + ok(ret == -123, "Unexpected ret value %Id.\n", ret); ret = DialogBoxParamW(GetModuleHandleA(NULL), nameW, 0, test_aw_conversion_dlgproc3, 1); - ok(ret == -123, "Unexpected ret value %ld.\n", ret); + ok(ret == -123, "Unexpected ret value %Id.\n", ret); ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, test_aw_conversion_dlgproc3, 0); - ok(ret == -123, "Unexpected ret value %ld.\n", ret); + ok(ret == -123, "Unexpected ret value %Id.\n", ret); } static void test_DisabledDialogTest(void) @@ -1983,193 +2060,14 @@ static void test_MessageBoxFontTest(void) ncMetrics.cbSize = FIELD_OFFSET(NONCLIENTMETRICSW, iPaddedBorderWidth); SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 0, &ncMetrics, 0); + /* The height doesn't match on Windows 10 1709+. */ + ncMetrics.lfMessageFont.lfHeight = lfStaticFont.lfHeight; ok( !memcmp(&lfStaticFont, &ncMetrics.lfMessageFont, FIELD_OFFSET(LOGFONTW, lfFaceName)) && !lstrcmpW(lfStaticFont.lfFaceName, ncMetrics.lfMessageFont.lfFaceName), "dialog doesn't use message box font\n"); DestroyWindow(hDlg); } -static const char msgbox_title[] = "%5!z9ZXw*ia;57n/FGl.bCH,Su\"mfKN;foCqAU\'j6AmoJgAc_D:Z0A\'E6PF_O/w"; -static WCHAR expectedOK[] = -{ -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', -'%','5','!','z','9','Z','X','w','*','i','a',';','5','7','n','/','F','G','l','.','b','C','H',',','S','u','"','m','f', -'K','N',';','f','o','C','q','A','U','\'','j','6','A','m','o','J','g','A','c','_','D',':','Z','0','A','\'','E','6','P', -'F','_','O','/','w','\r','\n', -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', -'M','e','s','s','a','g','e','\r','\n', -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', -'O','K',' ',' ',' ','\r','\n', -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', 0 -}; -static WCHAR expectedOkCancel[] = -{ -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', -'%','5','!','z','9','Z','X','w','*','i','a',';','5','7','n','/','F','G','l','.','b','C','H',',','S','u','"','m','f', -'K','N',';','f','o','C','q','A','U','\'','j','6','A','m','o','J','g','A','c','_','D',':','Z','0','A','\'','E','6','P', -'F','_','O','/','w','\r','\n', -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', -'M','e','s','s','a','g','e','\r','\n', -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', -'O','K',' ',' ',' ','C','a','n','c','e','l',' ',' ',' ','\r','\n', -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', 0 -}; -static WCHAR expectedAbortRetryIgnore[] = -{ -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', -'%','5','!','z','9','Z','X','w','*','i','a',';','5','7','n','/','F','G','l','.','b','C','H',',','S','u','"','m','f', -'K','N',';','f','o','C','q','A','U','\'','j','6','A','m','o','J','g','A','c','_','D',':','Z','0','A','\'','E','6','P', -'F','_','O','/','w','\r','\n', -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', -'M','e','s','s','a','g','e','\r','\n', -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', -'A','b','o','r','t',' ',' ',' ','R','e','t','r','y',' ',' ',' ','I','g','n','o','r','e',' ',' ',' ','\r','\n', -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', 0 -}; - -static WCHAR expectedYesNo[] = -{ -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', -'%','5','!','z','9','Z','X','w','*','i','a',';','5','7','n','/','F','G','l','.','b','C','H',',','S','u','"','m','f', -'K','N',';','f','o','C','q','A','U','\'','j','6','A','m','o','J','g','A','c','_','D',':','Z','0','A','\'','E','6','P', -'F','_','O','/','w','\r','\n', -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', -'M','e','s','s','a','g','e','\r','\n', -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', -'Y','e','s',' ',' ',' ','N','o',' ',' ',' ','\r','\n', -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', 0 -}; -static WCHAR expectedYesNoCancel[] = -{ -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', -'%','5','!','z','9','Z','X','w','*','i','a',';','5','7','n','/','F','G','l','.','b','C','H',',','S','u','"','m','f', -'K','N',';','f','o','C','q','A','U','\'','j','6','A','m','o','J','g','A','c','_','D',':','Z','0','A','\'','E','6','P', -'F','_','O','/','w','\r','\n', -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', -'M','e','s','s','a','g','e','\r','\n', -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', -'Y','e','s',' ',' ',' ','N','o',' ',' ',' ','C','a','n','c','e','l',' ',' ',' ','\r','\n', -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', 0 -}; -static WCHAR expectedRetryCancel[] = -{ -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', -'%','5','!','z','9','Z','X','w','*','i','a',';','5','7','n','/','F','G','l','.','b','C','H',',','S','u','"','m','f', -'K','N',';','f','o','C','q','A','U','\'','j','6','A','m','o','J','g','A','c','_','D',':','Z','0','A','\'','E','6','P', -'F','_','O','/','w','\r','\n', -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', -'M','e','s','s','a','g','e','\r','\n', -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', -'R','e','t','r','y',' ',' ',' ','C','a','n','c','e','l',' ',' ',' ','\r','\n', -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', 0 -}; -static WCHAR expectedCancelTryContinue[] = -{ -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', -'%','5','!','z','9','Z','X','w','*','i','a',';','5','7','n','/','F','G','l','.','b','C','H',',','S','u','"','m','f', -'K','N',';','f','o','C','q','A','U','\'','j','6','A','m','o','J','g','A','c','_','D',':','Z','0','A','\'','E','6','P', -'F','_','O','/','w','\r','\n', -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', -'M','e','s','s','a','g','e','\r','\n', -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', -'C','a','n','c','e','l',' ',' ',' ','T','r','y',' ','A','g','a','i','n',' ',' ',' ','C','o','n','t','i','n','u','e',' ',' ',' ','\r','\n', -'-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', 0 -}; - -BOOL non_english = FALSE; - -DWORD WINAPI WorkerThread(void *param) -{ - WCHAR *expected = param; - char windowTitle[sizeof(msgbox_title)]; - HWND hwndMbox; - BOOL succeeded = FALSE; - - Sleep(200); - - hwndMbox = GetForegroundWindow(); - - /* Find the Window, if it doesn't have focus */ - if (!(IsWindow(hwndMbox) && - GetWindowTextA(hwndMbox, windowTitle, sizeof(msgbox_title)) && - lstrcmpA(msgbox_title, windowTitle) == 0)) - { - hwndMbox = FindWindowA(NULL, msgbox_title); - - if (!IsWindow(hwndMbox)) - goto cleanup; - } - - SendMessageA(hwndMbox, WM_COPY, 0, 0); - - if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL)) - { - HANDLE textHandle = GetClipboardData(CF_UNICODETEXT); - WCHAR *text = GlobalLock(textHandle); - - if (text != NULL) - { - if(non_english) - ok(lstrlenW(text) > 0, "Empty string on clipboard\n"); - else - { - succeeded = lstrcmpW(expected, text) == 0; - if(!succeeded) - { - ok(0, "%s\n", wine_dbgstr_w(text)); - ok(0, "%s\n", wine_dbgstr_w(expected)); - } - } - - GlobalUnlock(textHandle); - } - else - ok(0, "No text on clipboard.\n"); - - CloseClipboard(); - - } - else - trace("Clipboard error\n"); - - PostMessageA(hwndMbox, WM_COMMAND, IDIGNORE, 0); /* For MB_ABORTRETRYIGNORE dialog. */ - PostMessageA(hwndMbox, WM_CLOSE, 0, 0); - -cleanup: - ok(succeeded || non_english, "Failed to get string.\n"); - - return 0; -} - -static void test_MessageBox_WM_COPY_Test(void) -{ - DWORD tid = 0; - - non_english = (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH); - trace("non_english %d\n", non_english); - - CreateThread(NULL, 0, WorkerThread, &expectedOK, 0, &tid); - MessageBoxA(NULL, "Message", msgbox_title, MB_OK); - - CreateThread(NULL, 0, WorkerThread, &expectedOkCancel, 0, &tid); - MessageBoxA(NULL, "Message", msgbox_title, MB_OKCANCEL); - - CreateThread(NULL, 0, WorkerThread, &expectedAbortRetryIgnore, 0, &tid); - MessageBoxA(NULL, "Message", msgbox_title, MB_ABORTRETRYIGNORE); - - CreateThread(NULL, 0, WorkerThread, &expectedYesNo, 0, &tid); - MessageBoxA(NULL, "Message", msgbox_title, MB_YESNO); - - CreateThread(NULL, 0, WorkerThread, &expectedYesNoCancel, 0, &tid); - MessageBoxA(NULL, "Message", msgbox_title, MB_YESNOCANCEL); - - CreateThread(NULL, 0, WorkerThread, &expectedRetryCancel, 0, &tid); - MessageBoxA(NULL, "Message", msgbox_title, MB_RETRYCANCEL); - - CreateThread(NULL, 0, WorkerThread, &expectedCancelTryContinue, 0, &tid); - MessageBoxA(NULL, "Message", msgbox_title, MB_CANCELTRYCONTINUE); -} - static void test_SaveRestoreFocus(void) { HWND hDlg; @@ -2188,12 +2086,12 @@ static void test_SaveRestoreFocus(void) ok (hDlg != 0, "Failed to create test dialog.\n"); foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID); - ok (foundId == 1000, "First edit box should have gained focus on dialog creation. Expected: %d, Found: %ld\n", 1000, foundId); + ok (foundId == 1000, "First edit box should have gained focus on dialog creation. Expected: %d, Found: %Id\n", 1000, foundId); SetFocus(GetNextDlgTabItem(hDlg, GetFocus(), FALSE)); SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_ACTIVE, 0), 0); foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID); - ok (foundId == 1001, "First edit box should have regained focus after dialog reactivation. Expected: %d, Found: %ld\n", 1001, foundId); + ok (foundId == 1001, "First edit box should have regained focus after dialog reactivation. Expected: %d, Found: %Id\n", 1001, foundId); SetFocus(GetNextDlgTabItem(hDlg, NULL, FALSE)); /* de- then reactivate the dialog */ @@ -2201,38 +2099,38 @@ static void test_SaveRestoreFocus(void) SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_ACTIVE, 0), 0); foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID); - ok (foundId == 1000, "First edit box should have regained focus after dialog reactivation. Expected: %d, Found: %ld\n", 1000, foundId); + ok (foundId == 1000, "First edit box should have regained focus after dialog reactivation. Expected: %d, Found: %Id\n", 1000, foundId); /* select the next tabbable item */ SetFocus(GetNextDlgTabItem(hDlg, GetFocus(), FALSE)); foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID); - ok (foundId == 1001, "Second edit box should have gained focus. Expected: %d, Found: %ld\n", 1001, foundId); + ok (foundId == 1001, "Second edit box should have gained focus. Expected: %d, Found: %Id\n", 1001, foundId); /* de- then reactivate the dialog */ SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_INACTIVE, 0), 0); SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_ACTIVE, 0), 0); foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID); - ok (foundId == 1001, "Second edit box should have gained focus after dialog reactivation. Expected: %d, Found: %ld\n", 1001, foundId); + ok (foundId == 1001, "Second edit box should have gained focus after dialog reactivation. Expected: %d, Found: %Id\n", 1001, foundId); /* set focus to the dialog */ SetFocus(hDlg); foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID); - ok (foundId == 1000, "First edit box should have gained focus on dialog focus. Expected: %d, Found: %ld\n", 1000, foundId); + ok (foundId == 1000, "First edit box should have gained focus on dialog focus. Expected: %d, Found: %Id\n", 1000, foundId); /* select second tabbable item */ SetFocus(GetNextDlgTabItem(hDlg, GetNextDlgTabItem(hDlg, NULL, FALSE), FALSE)); foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID); - ok (foundId == 1001, "Second edit box should have gained focus. Expected: %d, Found: %ld\n", 1001, foundId); + ok (foundId == 1001, "Second edit box should have gained focus. Expected: %d, Found: %Id\n", 1001, foundId); /* send WM_ACTIVATE message to already active dialog */ SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_ACTIVE, 0), 0); foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID); - ok (foundId == 1001, "Second edit box should have gained focus. Expected: %d, Found: %ld\n", 1001, foundId); + ok (foundId == 1001, "Second edit box should have gained focus. Expected: %d, Found: %Id\n", 1001, foundId); /* disable the 2nd box */ EnableWindow(GetFocus(), FALSE); @@ -2300,15 +2198,39 @@ static void test_timer_message(void) DialogBoxA(g_hinst, "RADIO_TEST_DIALOG", NULL, timer_message_dlg_proc); } +static unsigned int msgbox_hook_proc_called; +static UINT msgbox_type; + static LRESULT CALLBACK msgbox_hook_proc(INT code, WPARAM wParam, LPARAM lParam) { + static const LONG considered_ex_styles = WS_EX_CONTROLPARENT | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME | WS_EX_TOPMOST; + if (code == HCBT_ACTIVATE) { HWND msgbox = (HWND)wParam, msghwnd; + LONG exstyles, expected_exstyles; + BOOL system_modal; char text[64]; if (msgbox) { + exstyles = GetWindowLongA(msgbox, GWL_EXSTYLE) & considered_ex_styles; + + ++msgbox_hook_proc_called; + system_modal = msgbox_type & MB_SYSTEMMODAL && !(msgbox_type & MB_TASKMODAL); + expected_exstyles = WS_EX_CONTROLPARENT | WS_EX_WINDOWEDGE; + if ((msgbox_type & MB_TOPMOST) || system_modal) + expected_exstyles |= WS_EX_TOPMOST; + if (!system_modal) + expected_exstyles |= WS_EX_DLGMODALFRAME; + + todo_wine_if(system_modal && exstyles == (expected_exstyles | WS_EX_DLGMODALFRAME)) +#ifdef __REACTOS__ + ok(exstyles == expected_exstyles || broken(exstyles == (expected_exstyles & ~WS_EX_TOPMOST)) /* Vista */, "got %#lx, expected %#lx\n", exstyles, expected_exstyles); +#else + ok(exstyles == expected_exstyles, "got %#lx, expected %#lx\n", exstyles, expected_exstyles); +#endif + text[0] = 0; GetWindowTextA(msgbox, text, sizeof(text)); ok(!strcmp(text, "MSGBOX caption"), "Unexpected window text \"%s\"\n", text); @@ -2318,6 +2240,8 @@ static LRESULT CALLBACK msgbox_hook_proc(INT code, WPARAM wParam, LPARAM lParam) text[0] = 0; GetWindowTextA(msghwnd, text, sizeof(text)); + + todo_wine_if(msgbox_type != MB_OKCANCEL && !*text) ok(!strcmp(text, "Text"), "Unexpected window text \"%s\"\n", text); SendDlgItemMessageA(msgbox, IDCANCEL, WM_LBUTTONDOWN, 0, 0); @@ -2328,123 +2252,36 @@ static LRESULT CALLBACK msgbox_hook_proc(INT code, WPARAM wParam, LPARAM lParam) return CallNextHookEx(NULL, code, wParam, lParam); } -struct create_window_params -{ - BOOL owner; - char caption[64]; - DWORD style; -}; - -static DWORD WINAPI create_window_thread(void *param) -{ - struct create_window_params *p = param; - HWND owner = 0; - - if (p->owner) - { - owner = CreateWindowExA(0, "Static", NULL, WS_POPUP, 10, 10, 10, 10, 0, 0, 0, NULL); - ok(owner != 0, "failed to create owner window\n"); - } - - MessageBoxA(owner, NULL, p->caption, p->style); - - if (owner) DestroyWindow(owner); - - return 0; -} - -static HWND wait_for_window(const char *caption) -{ - HWND hwnd; - DWORD timeout = 0; - - for (;;) - { - hwnd = FindWindowA(NULL, caption); - if (hwnd) break; - - Sleep(50); - timeout += 50; - if (timeout > 3000) - { - ok(0, "failed to wait for a window %s\n", caption); - break; - } - } - - Sleep(50); - return hwnd; -} - static void test_MessageBox(void) { - static const struct + static const UINT tests[] = { - DWORD mb_style; - DWORD ex_style; - } test[] = - { - { MB_OK, 0 }, - { MB_OK | MB_TASKMODAL, 0 }, - { MB_OK | MB_SYSTEMMODAL, WS_EX_TOPMOST }, + MB_OKCANCEL, + MB_OKCANCEL | MB_SYSTEMMODAL, + MB_OKCANCEL | MB_TASKMODAL | MB_SYSTEMMODAL, + MB_OKCANCEL | MB_TOPMOST, + MB_OKCANCEL | MB_TOPMOST | MB_SYSTEMMODAL, + MB_OKCANCEL | MB_TASKMODAL | MB_TOPMOST, + MB_OKCANCEL | MB_TASKMODAL | MB_SYSTEMMODAL | MB_TOPMOST, }; - struct create_window_params params; - HANDLE thread; - DWORD tid, i; + unsigned int i; HHOOK hook; int ret; hook = SetWindowsHookExA(WH_CBT, msgbox_hook_proc, NULL, GetCurrentThreadId()); - ret = MessageBoxA(NULL, "Text", "MSGBOX caption", MB_OKCANCEL); - ok(ret == IDCANCEL, "got %d\n", ret); + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + msgbox_type = tests[i]; + winetest_push_context("type %#x", msgbox_type); + msgbox_hook_proc_called = 0; + ret = MessageBoxA(NULL, "Text", "MSGBOX caption", msgbox_type); + ok(ret == IDCANCEL, "got %d\n", ret); + ok(msgbox_hook_proc_called, "got %u.\n", msgbox_hook_proc_called); + winetest_pop_context(); + } UnhookWindowsHookEx(hook); - - sprintf(params.caption, "pid %08x, tid %08x, time %08x", - GetCurrentProcessId(), GetCurrentThreadId(), GetCurrentTime()); - - params.owner = FALSE; - - for (i = 0; i < sizeof(test)/sizeof(test[0]); i++) - { - HWND hwnd; - DWORD ex_style; - - params.style = test[i].mb_style; - - thread = CreateThread(NULL, 0, create_window_thread, ¶ms, 0, &tid); - - hwnd = wait_for_window(params.caption); - ex_style = GetWindowLongA(hwnd, GWL_EXSTYLE); - ok((ex_style & WS_EX_TOPMOST) == test[i].ex_style, "%d: got window ex_style %#x\n", i, ex_style); - - PostMessageA(hwnd, WM_COMMAND, IDCANCEL, 0); - - ok(WaitForSingleObject(thread, 5000) != WAIT_TIMEOUT, "thread failed to terminate\n"); - CloseHandle(thread); - } - - params.owner = TRUE; - - for (i = 0; i < sizeof(test)/sizeof(test[0]); i++) - { - HWND hwnd; - DWORD ex_style; - - params.style = test[i].mb_style; - - thread = CreateThread(NULL, 0, create_window_thread, ¶ms, 0, &tid); - - hwnd = wait_for_window(params.caption); - ex_style = GetWindowLongA(hwnd, GWL_EXSTYLE); - ok((ex_style & WS_EX_TOPMOST) == test[i].ex_style, "%d: got window ex_style %#x\n", i, ex_style); - - PostMessageA(hwnd, WM_COMMAND, IDCANCEL, 0); - - ok(WaitForSingleObject(thread, 5000) != WAIT_TIMEOUT, "thread failed to terminate\n"); - CloseHandle(thread); - } } static INT_PTR CALLBACK custom_test_dialog_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam) @@ -2460,6 +2297,147 @@ static void test_dialog_custom_data(void) DialogBoxA(g_hinst, "CUSTOM_TEST_DIALOG", NULL, custom_test_dialog_proc); } +static INT_PTR CALLBACK capture_release_proc(HWND dialog, UINT message, WPARAM wparam, LPARAM lparam) +{ + if (message == WM_INITDIALOG) + { + HWND child = (HWND)lparam; + DWORD style; + + ok(GetCapture() == child, "got capture %p\n", GetCapture()); + style = GetWindowLongA(child, GWL_STYLE); + ok(!(style & WS_DISABLED), "child should not be disabled\n"); + + PostMessageA(dialog, WM_USER, 0, (LPARAM)child); + } + else if (message == WM_USER) + { + HWND child = (HWND)lparam; + DWORD style; + + ok(!GetCapture(), "got capture %p\n", GetCapture()); + style = GetWindowLongA(child, GWL_STYLE); + ok(!(style & WS_DISABLED), "child should not be disabled\n"); + + EndDialog(dialog, 1); + } + return FALSE; +} + +static INT_PTR CALLBACK capture_release_modeless_proc(HWND dialog, UINT message, WPARAM wparam, LPARAM lparam) +{ + if (message == WM_INITDIALOG) + { + HWND child = (HWND)lparam; + DWORD style; + + ok(GetCapture() == child, "got capture %p\n", GetCapture()); + style = GetWindowLongA(child, GWL_STYLE); + ok(!(style & WS_DISABLED), "child should not be disabled\n"); + + PostMessageA(dialog, WM_QUIT, 0, 0); + } + return FALSE; +} + +static void test_capture_release(void) +{ + HWND window, child, dialog; + INT_PTR ret; + MSG msg; + + /* Set the capture to a child window. The main window will receive + * WM_CANCELMODE when being disabled, but the child window will retain + * capture. */ + + window = CreateWindowA("static", "parent", 0, 100, 200, 300, 400, NULL, NULL, NULL, NULL); + child = CreateWindowA("static", "child", WS_CHILD, 10, 20, 100, 100, window, NULL, NULL, NULL); + + SetCapture(child); + ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", NULL, capture_release_proc, (LPARAM)child); + ok(ret == 1, "got %#Ix\n", ret); + ok(!GetCapture(), "got capture %p\n", GetCapture()); + + SetCapture(child); + ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", window, capture_release_proc, (LPARAM)child); + ok(ret == 1, "got %#Ix\n", ret); + ok(!GetCapture(), "got capture %p\n", GetCapture()); + + SetCapture(child); + dialog = CreateDialogParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", + window, capture_release_modeless_proc, (LPARAM)child); + ok(!!dialog, "failed to create dialog\n"); + ok(GetCapture() == child, "got capture %p\n", GetCapture()); + ShowWindow(dialog, SW_SHOWNORMAL); + ok(GetCapture() == child, "got capture %p\n", GetCapture()); + while (GetMessageA(&msg, NULL, 0, 0)) + DispatchMessageA(&msg); + ok(GetCapture() == child, "got capture %p\n", GetCapture()); + + DestroyWindow(dialog); + + DestroyWindow(child); + DestroyWindow(window); +} + +static WNDPROC orig_static_proc; +static WCHAR cs_name_paramW[3]; +static char cs_name_paramA[4]; + +static LRESULT WINAPI test_static_create_procW(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if (msg == WM_NCCREATE) + { + CREATESTRUCTW *cs = (CREATESTRUCTW *)lparam; + memcpy( cs_name_paramW, cs->lpszName, sizeof(cs_name_paramW) ); + } + + return orig_static_proc(hwnd, msg, wparam, lparam); +} + +static LRESULT WINAPI test_static_create_procA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if (msg == WM_NCCREATE) + { + CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam; + memcpy( cs_name_paramA, cs->lpszName, sizeof(cs_name_paramA) ); + } + + return orig_static_proc(hwnd, msg, wparam, lparam); +} + +static void test_create_controls(void) +{ + HWND control; + INT_PTR ret; + + control = CreateWindowA("static", "", 0, 100, 200, 300, 400, NULL, NULL, NULL, NULL); + ok(control != 0, "failed to create control window\n"); + + orig_static_proc = (WNDPROC)SetClassLongPtrA(control, GCLP_WNDPROC, (ULONG_PTR)test_static_create_procA); + + cs_name_paramW[0] = 0; + ret = DialogBoxParamA(GetModuleHandleA(NULL), "IDD_SS_ICON_DIALOG", 0, DestroyOnCloseDlgWinProc, 0); + ok(0 == ret, "DialogBoxParamA returned %Id, expected 0\n", ret); + ok(!memcmp(cs_name_paramA, "\xff\0\x61", 3), "name param = %s\n", debugstr_an(cs_name_paramA, 3)); + + SetClassLongPtrA(control, GCLP_WNDPROC, (ULONG_PTR)orig_static_proc); + DestroyWindow(control); + + control = CreateWindowW(L"static", L"", 0, 100, 200, 300, 400, NULL, NULL, NULL, NULL); + ok(control != 0, "failed to create control window\n"); + + orig_static_proc = (WNDPROC)SetClassLongPtrW(control, GCLP_WNDPROC, (ULONG_PTR)test_static_create_procW); + + ret = DialogBoxParamW(GetModuleHandleW(NULL), L"IDD_SS_ICON_DIALOG", 0, DestroyOnCloseDlgWinProc, 0); + ok(0 == ret, "DialogBoxParamW returned %Id, expected 0\n", ret); + ok(!memcmp(cs_name_paramW, L"\xffff\x6100", 2 * sizeof(WCHAR)), + "name param = %s\n", debugstr_wn(cs_name_paramW, 2)); + + SetClassLongPtrW(control, GCLP_WNDPROC, (ULONG_PTR)orig_static_proc); + DestroyWindow(control); +} + START_TEST(dialog) { g_hinst = GetModuleHandleA (0); @@ -2473,11 +2451,12 @@ START_TEST(dialog) test_focus(); test_GetDlgItem(); test_GetDlgItemText(); + test_create_controls(); test_DialogBoxParam(); test_DisabledDialogTest(); test_MessageBoxFontTest(); test_SaveRestoreFocus(); test_timer_message(); test_MessageBox(); - test_MessageBox_WM_COPY_Test(); + test_capture_release(); } diff --git a/modules/rostests/winetests/user32/edit.c b/modules/rostests/winetests/user32/edit.c index d0374c02a35..c236a6b07d2 100644 --- a/modules/rostests/winetests/user32/edit.c +++ b/modules/rostests/winetests/user32/edit.c @@ -32,6 +32,35 @@ #define ID_EDITTEST2 99 #define MAXLEN 200 +static BOOL open_clipboard(HWND hwnd) +{ + DWORD start = GetTickCount(); + while (1) + { + BOOL ret = OpenClipboard(hwnd); + if (ret || GetLastError() != ERROR_ACCESS_DENIED) + return ret; + if (GetTickCount() - start > 100) + { + char classname[256]; + DWORD le = GetLastError(); + HWND clipwnd = GetOpenClipboardWindow(); + /* Provide a hint as to the source of interference: + * - The class name would typically be CLIPBRDWNDCLASS if the + * clipboard was opened by a Windows application using the + * ole32 API. + * - And it would be __wine_clipboard_manager if it was opened in + * response to a native application. + */ + GetClassNameA(clipwnd, classname, ARRAY_SIZE(classname)); + trace("%p (%s) opened the clipboard\n", clipwnd, classname); + SetLastError(le); + return ret; + } + Sleep(15); + } +} + struct edit_notify { int en_change, en_maxtext, en_update; }; @@ -661,7 +690,7 @@ static void set_client_height(HWND Wnd, unsigned Height) GetClientRect(Wnd, &ClientRect); ok(ClientRect.bottom - ClientRect.top == Height, - "The client height should be %d, but is %d\n", + "The client height should be %d, but is %ld\n", Height, ClientRect.bottom - ClientRect.top); } @@ -677,52 +706,52 @@ static void test_edit_control_1(void) trace("EDIT: Single line\n"); hwEdit = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); r = get_edit_style(hwEdit); - ok(r == (ES_AUTOVSCROLL | ES_AUTOHSCROLL), "Wrong style expected 0xc0 got: 0x%x\n", r); + ok(r == (ES_AUTOVSCROLL | ES_AUTOHSCROLL), "Wrong style expected 0xc0 got: 0x%lx\n", r); for (i=0;i<65535;i++) { msMessage.wParam = i; r = SendMessageA(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage); ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS), - "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS got %x\n", r); + "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS got %lx\n", r); } DestroyWindow (hwEdit); trace("EDIT: Single line want returns\n"); hwEdit = create_editcontrol(ES_WANTRETURN | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); r = get_edit_style(hwEdit); - ok(r == (ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN), "Wrong style expected 0x10c0 got: 0x%x\n", r); + ok(r == (ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN), "Wrong style expected 0x10c0 got: 0x%lx\n", r); for (i=0;i<65535;i++) { msMessage.wParam = i; r = SendMessageA(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage); ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS), - "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS got %x\n", r); + "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS got %lx\n", r); } DestroyWindow (hwEdit); trace("EDIT: Multiline line\n"); hwEdit = create_editcontrol(ES_MULTILINE | WS_VSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); r = get_edit_style(hwEdit); - ok(r == (ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE), "Wrong style expected 0xc4 got: 0x%x\n", r); + ok(r == (ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE), "Wrong style expected 0xc4 got: 0x%lx\n", r); for (i=0;i<65535;i++) { msMessage.wParam = i; r = SendMessageA(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage); ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS), - "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS got %x\n", r); + "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS got %lx\n", r); } DestroyWindow (hwEdit); trace("EDIT: Multi line want returns\n"); hwEdit = create_editcontrol(ES_MULTILINE | WS_VSCROLL | ES_WANTRETURN | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); r = get_edit_style(hwEdit); - ok(r == (ES_WANTRETURN | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE), "Wrong style expected 0x10c4 got: 0x%x\n", r); + ok(r == (ES_WANTRETURN | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE), "Wrong style expected 0x10c4 got: 0x%lx\n", r); for (i=0;i<65535;i++) { msMessage.wParam = i; r = SendMessageA(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage); ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS), - "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS got %x\n", r); + "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS got %lx\n", r); } DestroyWindow (hwEdit); } @@ -758,11 +787,11 @@ static void test_edit_control_2(void) trace("EDIT: SETTEXT atomicity\n"); /* Send messages to "type" in the word 'foo'. */ r = SendMessageA(hwndET2, WM_CHAR, 'f', 1); - ok(1 == r, "Expected: %d, got: %d\n", 1, r); + ok(1 == r, "Expected: %d, got: %ld\n", 1, r); r = SendMessageA(hwndET2, WM_CHAR, 'o', 1); - ok(1 == r, "Expected: %d, got: %d\n", 1, r); + ok(1 == r, "Expected: %d, got: %ld\n", 1, r); r = SendMessageA(hwndET2, WM_CHAR, 'o', 1); - ok(1 == r, "Expected: %d, got: %d\n", 1, r); + ok(1 == r, "Expected: %d, got: %ld\n", 1, r); /* 'foo' should have been changed to 'bar' by the UPDATE handler. */ GetWindowTextA(hwndET2, szLocalString, MAXLEN); ok(strcmp(szLocalString, "bar")==0, @@ -770,34 +799,34 @@ static void test_edit_control_2(void) /* try setting the caret before it's visible */ r = SetCaretPos(0, 0); - todo_wine ok(0 == r, "SetCaretPos succeeded unexpectedly, expected: 0, got: %d\n", r); + todo_wine ok(0 == r, "SetCaretPos succeeded unexpectedly, expected: 0, got: %ld\n", r); phwnd = SetFocus(hwndET2); ok(phwnd != NULL, "SetFocus failed unexpectedly, expected non-zero, got NULL\n"); r = SetCaretPos(0, 0); - ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %d\n", r); + ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r); r = GetCaretPos(&cpos); - ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %d\n", r); - ok(cpos.x == 0 && cpos.y == 0, "Wrong caret position, expected: (0,0), got: (%d,%d)\n", cpos.x, cpos.y); + ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r); + ok(cpos.x == 0 && cpos.y == 0, "Wrong caret position, expected: (0,0), got: (%ld,%ld)\n", cpos.x, cpos.y); r = SetCaretPos(-1, -1); - ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %d\n", r); + ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r); r = GetCaretPos(&cpos); - ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %d\n", r); - ok(cpos.x == -1 && cpos.y == -1, "Wrong caret position, expected: (-1,-1), got: (%d,%d)\n", cpos.x, cpos.y); + ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r); + ok(cpos.x == -1 && cpos.y == -1, "Wrong caret position, expected: (-1,-1), got: (%ld,%ld)\n", cpos.x, cpos.y); r = SetCaretPos(w << 1, h << 1); - ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %d\n", r); + ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r); r = GetCaretPos(&cpos); - ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %d\n", r); - ok(cpos.x == (w << 1) && cpos.y == (h << 1), "Wrong caret position, expected: (%d,%d), got: (%d,%d)\n", w << 1, h << 1, cpos.x, cpos.y); + ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r); + ok(cpos.x == (w << 1) && cpos.y == (h << 1), "Wrong caret position, expected: (%ld,%ld), got: (%ld,%ld)\n", w << 1, h << 1, cpos.x, cpos.y); r = SetCaretPos(w, h); - ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %d\n", r); + ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r); r = GetCaretPos(&cpos); - ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %d\n", r); - ok(cpos.x == w && cpos.y == h, "Wrong caret position, expected: (%d,%d), got: (%d,%d)\n", w, h, cpos.x, cpos.y); + ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r); + ok(cpos.x == w && cpos.y == h, "Wrong caret position, expected: (%ld,%ld), got: (%ld,%ld)\n", w, h, cpos.x, cpos.y); r = SetCaretPos(w - 1, h - 1); - ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %d\n", r); + ok(1 == r, "SetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r); r = GetCaretPos(&cpos); - ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %d\n", r); - ok(cpos.x == (w - 1) && cpos.y == (h - 1), "Wrong caret position, expected: (%d,%d), got: (%d,%d)\n", w - 1, h - 1, cpos.x, cpos.y); + ok(1 == r, "GetCaretPos failed unexpectedly, expected: 1, got: %ld\n", r); + ok(cpos.x == (w - 1) && cpos.y == (h - 1), "Wrong caret position, expected: (%ld,%ld), got: (%ld,%ld)\n", w - 1, h - 1, cpos.x, cpos.y); /* OK, done! */ DestroyWindow (hwndET2); @@ -1136,27 +1165,29 @@ static void test_edit_control_3(void) /* Test EM_CHARFROMPOS and EM_POSFROMCHAR */ -static void test_edit_control_4(void) +static void test_char_from_pos(void) { HWND hwEdit; int lo, hi, mid; int ret; int i; + HDC dc; + SIZE size; trace("EDIT: Test EM_CHARFROMPOS and EM_POSFROMCHAR\n"); hwEdit = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa"); lo = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 0, 0)); hi = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 1, 0)); - mid = lo + (hi - lo) / 2; + mid = lo + (hi - lo + 1) / 2; for (i = lo; i < mid; i++) { ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i)); - ok(0 == ret, "expected 0 got %d\n", ret); + ok(0 == ret, "%d/%d/%d: expected 0 got %d\n", lo, i, mid, ret); } for (i = mid; i <= hi; i++) { ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i)); - ok(1 == ret, "expected 1 got %d\n", ret); + ok(1 == ret, "%d/%d/%d: expected 1 got %d\n", mid, i, hi, ret); } ret = SendMessageA(hwEdit, EM_POSFROMCHAR, 2, 0); ok(-1 == ret, "expected -1 got %d\n", ret); @@ -1166,15 +1197,15 @@ static void test_edit_control_4(void) SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa"); lo = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 0, 0)); hi = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 1, 0)); - mid = lo + (hi - lo) / 2; + mid = lo + (hi - lo + 1) / 2; for (i = lo; i < mid; i++) { ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i)); - ok(0 == ret, "expected 0 got %d\n", ret); + ok(0 == ret, "%d/%d/%d: expected 0 got %d\n", lo, i, mid, ret); } for (i = mid; i <= hi; i++) { ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i)); - ok(1 == ret, "expected 1 got %d\n", ret); + ok(1 == ret, "%d/%d/%d: expected 1 got %d\n", mid, i, hi, ret); } ret = SendMessageA(hwEdit, EM_POSFROMCHAR, 2, 0); ok(-1 == ret, "expected -1 got %d\n", ret); @@ -1184,15 +1215,15 @@ static void test_edit_control_4(void) SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa"); lo = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 0, 0)); hi = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 1, 0)); - mid = lo + (hi - lo) / 2; + mid = lo + (hi - lo + 1) / 2; for (i = lo; i < mid; i++) { ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i)); - ok(0 == ret, "expected 0 got %d\n", ret); + ok(0 == ret, "%d/%d/%d: expected 0 got %d\n", lo, i, mid, ret); } for (i = mid; i <= hi; i++) { ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i)); - ok(1 == ret, "expected 1 got %d\n", ret); + ok(1 == ret, "%d/%d/%d: expected 1 got %d\n", mid, i, hi, ret); } ret = SendMessageA(hwEdit, EM_POSFROMCHAR, 2, 0); ok(-1 == ret, "expected -1 got %d\n", ret); @@ -1202,15 +1233,20 @@ static void test_edit_control_4(void) SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa"); lo = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 0, 0)); hi = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 1, 0)); - mid = lo + (hi - lo) / 2 +1; + mid = lo + (hi - lo + 1) / 2; for (i = lo; i < mid; i++) { ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i)); - ok((0 == ret || 1 == ret /* Vista */), "expected 0 or 1 got %d\n", ret); + ok(0 == ret || 1 == ret /* Vista */, + "%d/%d/%d: expected 0 or 1 got %d\n", lo, i, mid, ret); } for (i = mid; i <= hi; i++) { ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i)); - ok(1 == ret, "expected 1 got %d\n", ret); +#ifdef __REACTOS__ + ok(1 == ret || broken(0 == ret) /* Vista */, "%d/%d/%d: expected 0 or 1 got %d\n", mid, i, hi, ret); +#else + ok(1 == ret, "%d/%d/%d: expected 1 got %d\n", mid, i, hi, ret); +#endif } ret = SendMessageA(hwEdit, EM_POSFROMCHAR, 2, 0); ok(-1 == ret, "expected -1 got %d\n", ret); @@ -1220,15 +1256,20 @@ static void test_edit_control_4(void) SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa"); lo = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 0, 0)); hi = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 1, 0)); - mid = lo + (hi - lo) / 2 +1; + mid = lo + (hi - lo + 1) / 2; for (i = lo; i < mid; i++) { ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i)); - ok((0 == ret || 1 == ret /* Vista */), "expected 0 or 1 got %d\n", ret); + ok(0 == ret || 1 == ret /* Vista */, + "%d/%d/%d: expected 0 or 1 got %d\n", lo, i, mid, ret); } for (i = mid; i <= hi; i++) { ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i)); - ok(1 == ret, "expected 1 got %d\n", ret); +#ifdef __REACTOS__ + ok(1 == ret || broken(0 == ret) /* Vista */, "%d/%d/%d: expected 0 or 1 got %d\n", mid, i, hi, ret); +#else + ok(1 == ret, "%d/%d/%d: expected 1 got %d\n", mid, i, hi, ret); +#endif } ret = SendMessageA(hwEdit, EM_POSFROMCHAR, 2, 0); ok(-1 == ret, "expected -1 got %d\n", ret); @@ -1238,19 +1279,38 @@ static void test_edit_control_4(void) SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa"); lo = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 0, 0)); hi = LOWORD(SendMessageA(hwEdit, EM_POSFROMCHAR, 1, 0)); - mid = lo + (hi - lo) / 2 +1; + mid = lo + (hi - lo + 2) / 2; for (i = lo; i < mid; i++) { ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i)); - ok((0 == ret || 1 == ret /* Vista */), "expected 0 or 1 got %d\n", ret); + ok(0 == ret || 1 == ret /* Vista */, + "%d/%d/%d: expected 0 or 1 got %d\n", lo, i, mid, ret); } for (i = mid; i <= hi; i++) { ret = LOWORD(SendMessageA(hwEdit, EM_CHARFROMPOS, 0, i)); - ok(1 == ret, "expected 1 got %d\n", ret); + ok(1 == ret, "%d/%d/%d: expected 1 got %d\n", mid, i, hi, ret); } ret = SendMessageA(hwEdit, EM_POSFROMCHAR, 2, 0); ok(-1 == ret, "expected -1 got %d\n", ret); DestroyWindow(hwEdit); + + /* Scrolled to the right with partially visible line, position on next line. */ + hwEdit = create_editcontrol(ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); + + dc = GetDC(hwEdit); + GetTextExtentPoint32A(dc, "w", 1, &size); + ReleaseDC(hwEdit, dc); + + SetWindowPos(hwEdit, NULL, 0, 0, size.cx * 15, size.cy * 5, SWP_NOMOVE | SWP_NOZORDER); + SendMessageA(hwEdit, WM_SETTEXT, 0, (LPARAM)"wwwwwwwwwwwwwwwwwwww\r\n\r\n"); + SendMessageA(hwEdit, EM_SETSEL, 40, 40); + + lo = (short)SendMessageA(hwEdit, EM_POSFROMCHAR, 22, 0); + ret = (short)SendMessageA(hwEdit, EM_POSFROMCHAR, 20, 0); + ret -= 20 * size.cx; /* Calculate expected position, 20 characters back. */ + ok(ret == lo, "Unexpected position %d vs %d.\n", lo, ret); + + DestroyWindow(hwEdit); } /* Test if creating edit control without ES_AUTOHSCROLL and ES_AUTOVSCROLL @@ -1275,7 +1335,7 @@ static void test_edit_control_5(void) assert(hWnd); /* size of non-child edit control is (much) bigger than requested */ GetWindowRect( hWnd, &rc); - ok( rc.right - rc.left > 20, "size of the window (%d) is smaller than expected\n", + ok( rc.right - rc.left > 20, "size of the window (%ld) is smaller than expected\n", rc.right - rc.left); DestroyWindow(hWnd); /* so create a parent, and give it edit controls children to test with */ @@ -1338,21 +1398,21 @@ static void test_edit_control_6(void) assert(hWnd); ret = SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str); - ok(ret == TRUE, "Expected %d, got %d\n", TRUE, ret); + ok(ret == TRUE, "Expected %d, got %ld\n", TRUE, ret); ret = SendMessageA(hWnd, WM_GETTEXT, MAXLEN, (LPARAM)buf); - ok(ret == strlen(str), "Expected %s, got len %d\n", str, ret); + ok(ret == strlen(str), "Expected %s, got len %ld\n", str, ret); ok(!strcmp(buf, str), "Expected %s, got %s\n", str, buf); buf[0] = 0; ret = SendMessageA(hWnd, WM_DESTROY, 0, 0); - ok(ret == 0, "Expected 0, got %d\n", ret); + ok(ret == 0, "Expected 0, got %ld\n", ret); ret = SendMessageA(hWnd, WM_GETTEXT, MAXLEN, (LPARAM)buf); - ok(ret == strlen(str), "Expected %s, got len %d\n", str, ret); + ok(ret == strlen(str), "Expected %s, got len %ld\n", str, ret); ok(!strcmp(buf, str), "Expected %s, got %s\n", str, buf); buf[0] = 0; ret = SendMessageA(hWnd, WM_NCDESTROY, 0, 0); - ok(ret == 0, "Expected 0, got %d\n", ret); + ok(ret == 0, "Expected 0, got %ld\n", ret); ret = SendMessageA(hWnd, WM_GETTEXT, MAXLEN, (LPARAM)buf); - ok(ret == 0, "Expected 0, got len %d\n", ret); + ok(ret == 0, "Expected 0, got len %ld\n", ret); ok(!strcmp(buf, ""), "Expected empty string, got %s\n", buf); DestroyWindow(hWnd); @@ -1367,20 +1427,20 @@ static void test_edit_control_limittext(void) trace("EDIT: buffer limit for single-line\n"); hwEdit = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); r = SendMessageA(hwEdit, EM_GETLIMITTEXT, 0, 0); - ok(r == 30000, "Incorrect default text limit, expected 30000 got %u\n", r); + ok(r == 30000, "Incorrect default text limit, expected 30000 got %lu\n", r); SendMessageA(hwEdit, EM_SETLIMITTEXT, 0, 0); r = SendMessageA(hwEdit, EM_GETLIMITTEXT, 0, 0); - ok( r == 2147483646, "got limit %u (expected 2147483646)\n", r); + ok( r == 2147483646, "got limit %lu (expected 2147483646)\n", r); DestroyWindow(hwEdit); /* Test default limit for multi-line control */ trace("EDIT: buffer limit for multi-line\n"); hwEdit = create_editcontrol(ES_MULTILINE | WS_VSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); r = SendMessageA(hwEdit, EM_GETLIMITTEXT, 0, 0); - ok(r == 30000, "Incorrect default text limit, expected 30000 got %u\n", r); + ok(r == 30000, "Incorrect default text limit, expected 30000 got %lu\n", r); SendMessageA(hwEdit, EM_SETLIMITTEXT, 0, 0); r = SendMessageA(hwEdit, EM_GETLIMITTEXT, 0, 0); - ok( r == 4294967295U, "got limit %u (expected 4294967295)\n", r); + ok( r == 4294967295U, "got limit %lu (expected 4294967295)\n", r); DestroyWindow(hwEdit); } @@ -1405,16 +1465,16 @@ static void test_edit_control_scroll(void) assert(hwEdit); ret = SendMessageA(hwEdit, EM_SCROLL, SB_PAGEDOWN, 0); - ok(!ret, "Returned %x, expected 0.\n", ret); + ok(!ret, "Returned %lx, expected 0.\n", ret); ret = SendMessageA(hwEdit, EM_SCROLL, SB_PAGEUP, 0); - ok(!ret, "Returned %x, expected 0.\n", ret); + ok(!ret, "Returned %lx, expected 0.\n", ret); ret = SendMessageA(hwEdit, EM_SCROLL, SB_LINEUP, 0); - ok(!ret, "Returned %x, expected 0.\n", ret); + ok(!ret, "Returned %lx, expected 0.\n", ret); ret = SendMessageA(hwEdit, EM_SCROLL, SB_LINEDOWN, 0); - ok(!ret, "Returned %x, expected 0.\n", ret); + ok(!ret, "Returned %lx, expected 0.\n", ret); DestroyWindow (hwEdit); @@ -1430,7 +1490,7 @@ static void test_edit_control_scroll(void) assert(hwEdit); ret = SendMessageA(hwEdit, EM_SCROLL, SB_PAGEDOWN, 0); - ok(!ret, "Returned %x, expected 0.\n", ret); + ok(!ret, "Returned %lx, expected 0.\n", ret); DestroyWindow (hwEdit); } @@ -1723,6 +1783,81 @@ static BOOL is_font_installed(const char*name) return ret; } +static WNDPROC orig_class_proc; + +static LRESULT CALLBACK test_class_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + RECT rect; + LRESULT result, r; + + switch (message) + { + case WM_NCCREATE: + result = CallWindowProcA(orig_class_proc, hwnd, message, wParam, lParam); + + memset(&rect, 0, sizeof(rect)); + SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rect); + ok(!rect.right && !rect.bottom, "Invalid size after NCCREATE: %ld x %ld\n", rect.right, rect.bottom); + + /* test that messages between WM_NCCREATE and WM_CREATE + don't crash or cause unexpected behavior */ + r = SendMessageA(hwnd, EM_SETSEL, 0, 0); + ok(r == 1, "Returned %Id, expected 1.\n", r); + r = SendMessageA(hwnd, WM_SIZE, 0, 0x00100010); + todo_wine ok(r == 1, "Returned %Id, expected 1.\n", r); + r = SendMessageA(hwnd, EM_LINESCROLL, 1, 1); + ok(r == 1, "Returned %Id, expected 1.\n", r); + + return result; + + case WM_CREATE: + /* test that messages between WM_NCCREATE and WM_CREATE + don't crash or cause unexpected behavior */ + r = SendMessageA(hwnd, EM_SETSEL, 0, 0); + ok(r == 1, "Returned %Id, expected 1.\n", r); + r = SendMessageA(hwnd, WM_SIZE, 0, 0x00100010); + todo_wine ok(r == 1, "Returned %Id, expected 1.\n", r); + r = SendMessageA(hwnd, EM_LINESCROLL, 1, 1); + ok(r == 1, "Returned %Id, expected 1.\n", r); + + break; + } + + return CallWindowProcA(orig_class_proc, hwnd, message, wParam, lParam); +} + +static void test_initialization(void) +{ + BOOL ret; + ATOM atom; + HWND hwEdit; + WNDCLASSA cls; + +#ifdef __REACTOS__ + if (is_reactos()) { + ok(FALSE, "FIXME: ReactOS crashes on this test!\n"); + return; + } +#endif + ret = GetClassInfoA(NULL, "Edit", &cls); + ok(ret, "Failed to get class info.\n"); + + orig_class_proc = cls.lpfnWndProc; + cls.lpfnWndProc = test_class_proc; + cls.lpszClassName = "TestClassName"; + + atom = RegisterClassA(&cls); + ok(atom != 0, "Failed to register class.\n"); + + hwEdit = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atom), "Text Text", + ES_MULTILINE | WS_BORDER | ES_AUTOHSCROLL | ES_AUTOVSCROLL | WS_VSCROLL, + 10, 10, 300, 300, NULL, NULL, hinst, NULL); + ok(hwEdit != NULL, "Failed to create a window.\n"); + + DestroyWindow(hwEdit); + UnregisterClassA((LPCSTR)MAKEINTATOM(atom), hinst); +} + static void test_margins(void) { HWND hwEdit; @@ -1929,8 +2064,11 @@ static void test_margins_font_change(void) } -#define edit_pos_ok(exp, got, txt) \ - ok(exp == got, "wrong " #txt " expected %d got %d\n", exp, got); +#define edit_pos_ok(exp, got, txt) edit_pos_ok_(__LINE__, exp, got, #txt) +static inline void edit_pos_ok_(unsigned line, DWORD exp, DWORD got, const char* txt) +{ + ok_(__FILE__, line)(exp == got, "wrong %s expected %ld got %ld\n", txt, exp, got); +} #define check_pos(hwEdit, set_height, test_top, test_height, test_left) \ do { \ @@ -2082,39 +2220,39 @@ static void test_espassword(void) hwEdit = create_editcontrol(ES_PASSWORD, 0); r = get_edit_style(hwEdit); - ok(r == ES_PASSWORD, "Wrong style expected ES_PASSWORD got: 0x%x\n", r); + ok(r == ES_PASSWORD, "Wrong style expected ES_PASSWORD got: 0x%lx\n", r); /* set text */ r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) password); - ok(r == TRUE, "Expected: %d, got: %d\n", TRUE, r); + ok(r == TRUE, "Expected: %d, got: %ld\n", TRUE, r); /* select all, cut (ctrl-x) */ SendMessageA(hwEdit, EM_SETSEL, 0, -1); r = SendMessageA(hwEdit, WM_CHAR, 24, 0); - ok(1 == r, "Expected: %d, got: %d\n", 1, r); + ok(1 == r, "Expected: %d, got: %ld\n", 1, r); /* get text */ r = SendMessageA(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer); - ok(r == strlen(password), "Expected: %s, got len %d\n", password, r); + ok(r == strlen(password), "Expected: %s, got len %ld\n", password, r); ok(strcmp(buffer, password) == 0, "expected %s, got %s\n", password, buffer); - r = OpenClipboard(hwEdit); - ok(r == TRUE, "expected %d, got %d\n", TRUE, r); + r = open_clipboard(hwEdit); + ok(r == TRUE, "expected %d, got %ld le=%lu\n", TRUE, r, GetLastError()); r = EmptyClipboard(); - ok(r == TRUE, "expected %d, got %d\n", TRUE, r); + ok(r == TRUE, "expected %d, got %ld\n", TRUE, r); r = CloseClipboard(); - ok(r == TRUE, "expected %d, got %d\n", TRUE, r); + ok(r == TRUE, "expected %d, got %ld\n", TRUE, r); /* select all, copy (ctrl-c) and paste (ctrl-v) */ SendMessageA(hwEdit, EM_SETSEL, 0, -1); r = SendMessageA(hwEdit, WM_CHAR, 3, 0); - ok(1 == r, "Expected: %d, got: %d\n", 1, r); + ok(1 == r, "Expected: %d, got: %ld\n", 1, r); r = SendMessageA(hwEdit, WM_CHAR, 22, 0); - ok(1 == r, "Expected: %d, got: %d\n", 1, r); + ok(1 == r, "Expected: %d, got: %ld\n", 1, r); /* get text */ buffer[0] = 0; r = SendMessageA(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer); - ok(r == 0, "Expected: 0, got: %d\n", r); + ok(r == 0, "Expected: 0, got: %ld\n", r); ok(strcmp(buffer, "") == 0, "expected empty string, got %s\n", buffer); DestroyWindow (hwEdit); @@ -2130,48 +2268,48 @@ static void test_undo(void) hwEdit = create_editcontrol(0, 0); r = get_edit_style(hwEdit); - ok(0 == r, "Wrong style expected 0x%x got: 0x%x\n", 0, r); + ok(0 == r, "Wrong style expected 0x%x got: 0x%lx\n", 0, r); /* set text */ r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) text); - ok(TRUE == r, "Expected: %d, got: %d\n", TRUE, r); + ok(TRUE == r, "Expected: %d, got: %ld\n", TRUE, r); /* select all, */ cpMin = cpMax = 0xdeadbeef; SendMessageA(hwEdit, EM_SETSEL, 0, -1); r = SendMessageA(hwEdit, EM_GETSEL, (WPARAM) &cpMin, (LPARAM) &cpMax); - ok((strlen(text) << 16) == r, "Unexpected length %d\n", r); - ok(0 == cpMin, "Expected: %d, got %d\n", 0, cpMin); - ok(9 == cpMax, "Expected: %d, got %d\n", 9, cpMax); + ok((strlen(text) << 16) == r, "Unexpected length %ld\n", r); + ok(0 == cpMin, "Expected: %d, got %ld\n", 0, cpMin); + ok(9 == cpMax, "Expected: %d, got %ld\n", 9, cpMax); /* cut (ctrl-x) */ r = SendMessageA(hwEdit, WM_CHAR, 24, 0); - ok(1 == r, "Expected: %d, got: %d\n", 1, r); + ok(1 == r, "Expected: %d, got: %ld\n", 1, r); /* get text */ buffer[0] = 0; r = SendMessageA(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer); - ok(0 == r, "Expected: %d, got len %d\n", 0, r); + ok(0 == r, "Expected: %d, got len %ld\n", 0, r); ok(0 == strcmp(buffer, ""), "expected %s, got %s\n", "", buffer); /* undo (ctrl-z) */ r = SendMessageA(hwEdit, WM_CHAR, 26, 0); - ok(1 == r, "Expected: %d, got: %d\n", 1, r); + ok(1 == r, "Expected: %d, got: %ld\n", 1, r); /* get text */ buffer[0] = 0; r = SendMessageA(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer); - ok(strlen(text) == r, "Unexpected length %d\n", r); + ok(strlen(text) == r, "Unexpected length %ld\n", r); ok(0 == strcmp(buffer, text), "expected %s, got %s\n", text, buffer); /* undo again (ctrl-z) */ r = SendMessageA(hwEdit, WM_CHAR, 26, 0); - ok(1 == r, "Expected: %d, got: %d\n", 1, r); + ok(1 == r, "Expected: %d, got: %ld\n", 1, r); /* get text */ buffer[0] = 0; r = SendMessageA(hwEdit, WM_GETTEXT, 1024, (LPARAM) buffer); - ok(r == 0, "Expected: %d, got len %d\n", 0, r); + ok(r == 0, "Expected: %d, got len %ld\n", 0, r); ok(0 == strcmp(buffer, ""), "expected %s, got %s\n", "", buffer); DestroyWindow (hwEdit); @@ -2186,19 +2324,19 @@ static void test_enter(void) /* multiline */ hwEdit = create_editcontrol(ES_MULTILINE, 0); r = get_edit_style(hwEdit); - ok(ES_MULTILINE == r, "Wrong style expected ES_MULTILINE got: 0x%x\n", r); + ok(ES_MULTILINE == r, "Wrong style expected ES_MULTILINE got: 0x%lx\n", r); /* set text */ r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) ""); - ok(TRUE == r, "Expected: %d, got: %d\n", TRUE, r); + ok(TRUE == r, "Expected: %d, got: %ld\n", TRUE, r); r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0); - ok(1 == r, "Expected: %d, got: %d\n", 1, r); + ok(1 == r, "Expected: %d, got: %ld\n", 1, r); /* get text */ buffer[0] = 0; r = SendMessageA(hwEdit, WM_GETTEXT, 16, (LPARAM) buffer); - ok(2 == r, "Expected: %d, got len %d\n", 2, r); + ok(2 == r, "Expected: %d, got len %ld\n", 2, r); ok(0 == strcmp(buffer, "\r\n"), "expected \"\\r\\n\", got \"%s\"\n", buffer); DestroyWindow (hwEdit); @@ -2206,19 +2344,19 @@ static void test_enter(void) /* single line */ hwEdit = create_editcontrol(0, 0); r = get_edit_style(hwEdit); - ok(0 == r, "Wrong style expected 0x%x got: 0x%x\n", 0, r); + ok(0 == r, "Wrong style expected 0x%x got: 0x%lx\n", 0, r); /* set text */ r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) ""); - ok(TRUE == r, "Expected: %d, got: %d\n", TRUE, r); + ok(TRUE == r, "Expected: %d, got: %ld\n", TRUE, r); r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0); - ok(1 == r, "Expected: %d, got: %d\n", 1, r); + ok(1 == r, "Expected: %d, got: %ld\n", 1, r); /* get text */ buffer[0] = 0; r = SendMessageA(hwEdit, WM_GETTEXT, 16, (LPARAM) buffer); - ok(0 == r, "Expected: %d, got len %d\n", 0, r); + ok(0 == r, "Expected: %d, got len %ld\n", 0, r); ok(0 == strcmp(buffer, ""), "expected \"\", got \"%s\"\n", buffer); DestroyWindow (hwEdit); @@ -2226,19 +2364,19 @@ static void test_enter(void) /* single line with ES_WANTRETURN */ hwEdit = create_editcontrol(ES_WANTRETURN, 0); r = get_edit_style(hwEdit); - ok(ES_WANTRETURN == r, "Wrong style expected ES_WANTRETURN got: 0x%x\n", r); + ok(ES_WANTRETURN == r, "Wrong style expected ES_WANTRETURN got: 0x%lx\n", r); /* set text */ r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) ""); - ok(TRUE == r, "Expected: %d, got: %d\n", TRUE, r); + ok(TRUE == r, "Expected: %d, got: %ld\n", TRUE, r); r = SendMessageA(hwEdit, WM_CHAR, VK_RETURN, 0); - ok(1 == r, "Expected: %d, got: %d\n", 1, r); + ok(1 == r, "Expected: %d, got: %ld\n", 1, r); /* get text */ buffer[0] = 0; r = SendMessageA(hwEdit, WM_GETTEXT, 16, (LPARAM) buffer); - ok(0 == r, "Expected: %d, got len %d\n", 0, r); + ok(0 == r, "Expected: %d, got len %ld\n", 0, r); ok(0 == strcmp(buffer, ""), "expected \"\", got \"%s\"\n", buffer); DestroyWindow (hwEdit); @@ -2253,19 +2391,19 @@ static void test_tab(void) /* multiline */ hwEdit = create_editcontrol(ES_MULTILINE, 0); r = get_edit_style(hwEdit); - ok(ES_MULTILINE == r, "Wrong style expected ES_MULTILINE got: 0x%x\n", r); + ok(ES_MULTILINE == r, "Wrong style expected ES_MULTILINE got: 0x%lx\n", r); /* set text */ r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) ""); - ok(TRUE == r, "Expected: %d, got: %d\n", TRUE, r); + ok(TRUE == r, "Expected: %d, got: %ld\n", TRUE, r); r = SendMessageA(hwEdit, WM_CHAR, VK_TAB, 0); - ok(1 == r, "Expected: %d, got: %d\n", 1, r); + ok(1 == r, "Expected: %d, got: %ld\n", 1, r); /* get text */ buffer[0] = 0; r = SendMessageA(hwEdit, WM_GETTEXT, 16, (LPARAM) buffer); - ok(1 == r, "Expected: %d, got len %d\n", 1, r); + ok(1 == r, "Expected: %d, got len %ld\n", 1, r); ok(0 == strcmp(buffer, "\t"), "expected \"\\t\", got \"%s\"\n", buffer); DestroyWindow (hwEdit); @@ -2273,19 +2411,19 @@ static void test_tab(void) /* single line */ hwEdit = create_editcontrol(0, 0); r = get_edit_style(hwEdit); - ok(0 == r, "Wrong style expected 0x%x got: 0x%x\n", 0, r); + ok(0 == r, "Wrong style expected 0x%x got: 0x%lx\n", 0, r); /* set text */ r = SendMessageA(hwEdit , WM_SETTEXT, 0, (LPARAM) ""); - ok(TRUE == r, "Expected: %d, got: %d\n", TRUE, r); + ok(TRUE == r, "Expected: %d, got: %ld\n", TRUE, r); r = SendMessageA(hwEdit, WM_CHAR, VK_TAB, 0); - ok(1 == r, "Expected: %d, got: %d\n", 1, r); + ok(1 == r, "Expected: %d, got: %ld\n", 1, r); /* get text */ buffer[0] = 0; r = SendMessageA(hwEdit, WM_GETTEXT, 16, (LPARAM) buffer); - ok(0 == r, "Expected: %d, got len %d\n", 0, r); + ok(0 == r, "Expected: %d, got len %ld\n", 0, r); ok(0 == strcmp(buffer, ""), "expected \"\", got \"%s\"\n", buffer); DestroyWindow (hwEdit); @@ -2727,11 +2865,11 @@ static void test_fontsize(void) ShowWindow (hwEdit, SW_SHOW); r = SendMessageA(hwEdit, WM_CHAR, 'A', 1); - ok(1 == r, "Expected: %d, got: %d\n", 1, r); + ok(1 == r, "Expected: %d, got: %ld\n", 1, r); r = SendMessageA(hwEdit, WM_CHAR, 'B', 1); - ok(1 == r, "Expected: %d, got: %d\n", 1, r); + ok(1 == r, "Expected: %d, got: %ld\n", 1, r); r = SendMessageA(hwEdit, WM_CHAR, 'C', 1); - ok(1 == r, "Expected: %d, got: %d\n", 1, r); + ok(1 == r, "Expected: %d, got: %ld\n", 1, r); GetWindowTextA(hwEdit, szLocalString, MAXLEN); ok(strcmp(szLocalString, "ABC")==0, @@ -2917,7 +3055,7 @@ static void test_dialogmode(void) hwButton = CreateWindowA("BUTTON", "OK", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON, 100, 100, 50, 20, hwParent, (HMENU)ID_EDITTESTDBUTTON, hinst, NULL); - ok(hwButton!=NULL, "CreateWindow failed with error code %d\n", GetLastError()); + ok(hwButton!=NULL, "CreateWindow failed with error code %ld\n", GetLastError()); r = SendMessageA(hwEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); ok(1 == r, "expected 1, got %d\n", r); @@ -3080,12 +3218,32 @@ static void test_EM_GETHANDLE(void) DestroyWindow(hEdit); } +/* In Windows 10+, the WM_PASTE message isn't always successful. + * So retry in case of failure. + */ +#define check_paste(a, b) _check_paste(__LINE__, (a), (b)) +static void _check_paste(unsigned int line, HWND hedit, const char *content) +{ + /* only retry on windows platform */ + int tries = strcmp(winetest_platform, "wine") ? 3 : 1; + int len = 0; + + SendMessageA(hedit, WM_SETTEXT, 0, (LPARAM)""); + do + { + SendMessageA(hedit, WM_PASTE, 0, 0); + if ((len = SendMessageA(hedit, WM_GETTEXTLENGTH, 0, 0))) break; + Sleep(1); + } while (--tries > 0); + ok_(__FILE__, line)(len == strlen(content), "Unexpected len %u in edit\n", len); +} + static void test_paste(void) { HWND hEdit, hMultilineEdit; HANDLE hmem, hmem_ret; char *buffer; - int r, len; + int r; static const char *str = "this is a simple text"; static const char *str2 = "first line\r\nsecond line"; @@ -3100,8 +3258,8 @@ static void test_paste(void) strcpy(buffer, str); GlobalUnlock(hmem); - r = OpenClipboard(hEdit); - ok(r == TRUE, "expected %d, got %d\n", TRUE, r); + r = open_clipboard(hEdit); + ok(r == TRUE, "expected %d, got %d le=%lu\n", TRUE, r, GetLastError()); r = EmptyClipboard(); ok(r == TRUE, "expected %d, got %d\n", TRUE, r); hmem_ret = SetClipboardData(CF_TEXT, hmem); @@ -3110,10 +3268,7 @@ static void test_paste(void) ok(r == TRUE, "expected %d, got %d\n", TRUE, r); /* Paste single line */ - SendMessageA(hEdit, WM_SETTEXT, 0, (LPARAM)""); - r = SendMessageA(hEdit, WM_PASTE, 0, 0); - len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0); - ok(strlen(str) == len, "got %d\n", len); + check_paste(hEdit, str); /* Prepare clipboard data with multiline text */ hmem = GlobalAlloc(GMEM_MOVEABLE, 255); @@ -3123,8 +3278,8 @@ static void test_paste(void) strcpy(buffer, str2); GlobalUnlock(hmem); - r = OpenClipboard(hEdit); - ok(r == TRUE, "expected %d, got %d\n", TRUE, r); + r = open_clipboard(hEdit); + ok(r == TRUE, "expected %d, got %d le=%lu\n", TRUE, r, GetLastError()); r = EmptyClipboard(); ok(r == TRUE, "expected %d, got %d\n", TRUE, r); hmem_ret = SetClipboardData(CF_TEXT, hmem); @@ -3133,16 +3288,10 @@ static void test_paste(void) ok(r == TRUE, "expected %d, got %d\n", TRUE, r); /* Paste multiline text in singleline edit - should be cut */ - SendMessageA(hEdit, WM_SETTEXT, 0, (LPARAM)""); - r = SendMessageA(hEdit, WM_PASTE, 0, 0); - len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0); - ok(strlen("first line") == len, "got %d\n", len); + check_paste(hEdit, "first line"); /* Paste multiline text in multiline edit */ - SendMessageA(hMultilineEdit, WM_SETTEXT, 0, (LPARAM)""); - r = SendMessageA(hMultilineEdit, WM_PASTE, 0, 0); - len = SendMessageA(hMultilineEdit, WM_GETTEXTLENGTH, 0, 0); - ok(strlen(str2) == len, "got %d\n", len); + check_paste(hMultilineEdit, str2); /* Cleanup */ DestroyWindow(hEdit); @@ -3217,13 +3366,13 @@ static void test_wordbreak_proc(void) ok(proc == NULL, "Unexpected wordbreak proc %p.\n", proc); ret = SendMessageA(hwnd, EM_SETWORDBREAKPROC, 0, (LPARAM)test_wordbreak_procA); - ok(ret == 1, "Unexpected return value %ld.\n", ret); + ok(ret == 1, "Unexpected return value %Id.\n", ret); proc = (void *)SendMessageA(hwnd, EM_GETWORDBREAKPROC, 0, 0); ok(proc == test_wordbreak_procA, "Unexpected wordbreak proc %p.\n", proc); ret = SendMessageA(hwnd, EM_SETWORDBREAKPROC, 0, 0); - ok(ret == 1, "Unexpected return value %ld.\n", ret); + ok(ret == 1, "Unexpected return value %Id.\n", ret); proc = (void *)SendMessageA(hwnd, EM_GETWORDBREAKPROC, 0, 0); ok(proc == NULL, "Unexpected wordbreak proc %p.\n", proc); @@ -3231,6 +3380,114 @@ static void test_wordbreak_proc(void) DestroyWindow(hwnd); } +static void test_dbcs_WM_CHAR(void) +{ + HKL hkl; + UINT cp; + WCHAR textW[] = { 0x4e00, 0x4e8c, 0x4e09, 0 }; /* one, two, three */ + unsigned char bytes[7]; + BOOL hasdefault; + HWND hwnd[2]; + int i; + + hkl = GetKeyboardLayout( 0 ); + if (!GetLocaleInfoW(LOWORD(hkl), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (WCHAR *)&cp, sizeof(cp) / sizeof(WCHAR))) + cp = CP_ACP; + + WideCharToMultiByte(cp, WC_NO_BEST_FIT_CHARS, textW, -1, (char *)bytes, ARRAY_SIZE(bytes), NULL, &hasdefault); + if (hasdefault || !IsDBCSLeadByteEx(cp, bytes[0])) + { + skip("Skipping DBCS WM_CHAR test in the %d codepage\n", cp); + return; + } + hwnd[0] = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); + hwnd[1] = create_editcontrolW(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); + + for (i = 0; i < ARRAY_SIZE(hwnd); i++) + { + const unsigned char* p; + WCHAR strW[4]; + char str[7]; + MSG msg; + BOOL r; + int n; + + winetest_push_context("%c", i ? 'W' : 'A'); + + r = SetWindowTextA(hwnd[i], ""); + ok(r, "SetWindowText failed\n"); + + /* sending the lead byte separately works for DBCS locales */ + for (p = bytes; *p; p++) + PostMessageA(hwnd[i], WM_CHAR, *p, 1); + + while (PeekMessageA(&msg, hwnd[i], 0, 0, PM_REMOVE)) + DispatchMessageA(&msg); + + n = GetWindowTextW(hwnd[i], strW, ARRAY_SIZE(strW)); + ok(n > 0, "GetWindowTextW failed\n"); + ok(!wcscmp(strW, textW), "got %s, expected %s\n", + wine_dbgstr_w(strW), wine_dbgstr_w(textW)); + + n = GetWindowTextA(hwnd[i], str, ARRAY_SIZE(str)); + ok(n > 0, "GetWindowText failed\n"); + ok(!strcmp(str, (char*)bytes), "got %s, expected %s\n", + wine_dbgstr_a(str), wine_dbgstr_a((char *)bytes)); + + DestroyWindow(hwnd[i]); + + winetest_pop_context(); + } +} + +static void test_format_rect(void) +{ + HWND edit; + RECT rect, old_rect; + + static const struct + { + int style_ex; + RECT input; + int expected_equal; + } + tests[] = + { + {0, {0, 0, 0, 0}, 1}, + {0, {0, 0, 10, 10}, 1}, + {0, {1, 1, 10, 10}, 1}, + {0, {1, 1, 10, 250}, 1}, + {0, {1, 1, 250, 10}, 1}, + {0, {1, 1, 10, 1000}, 1}, + {0, {1, 1, 1000, 10}, 1}, + {0, {1, 1, 1000, 1000}, 0}, + {WS_EX_CLIENTEDGE, {0, 0, 0, 0}, 1}, + {WS_EX_CLIENTEDGE, {0, 0, 10, 10}, 1}, + {WS_EX_CLIENTEDGE, {1, 1, 10, 10}, 1}, + {WS_EX_CLIENTEDGE, {1, 1, 10, 250}, 1}, + {WS_EX_CLIENTEDGE, {1, 1, 250, 10}, 1}, + {WS_EX_CLIENTEDGE, {1, 1, 10, 1000}, 1}, + {WS_EX_CLIENTEDGE, {1, 1, 1000, 10}, 1}, + {WS_EX_CLIENTEDGE, {1, 1, 1000, 1000}, 0} + }; + + for (int i = 0; i < ARRAY_SIZE(tests); i++) + { + edit = create_editcontrol(ES_MULTILINE | WS_VISIBLE, tests[i].style_ex); + + SendMessageA(edit, EM_GETRECT, 0, (LPARAM)&old_rect); + SetWindowTextA(edit, "Test Test Test\r\n\r\nTest Test Test Test Test Test Test Test Test Test Test Test\r\n\r\nTest Test Test"); + SendMessageA(edit, EM_SETRECT, 0, (LPARAM)&tests[i].input); + SendMessageA(edit, EM_GETRECT, 0, (LPARAM)&rect); + + if (tests[i].expected_equal) + ok(EqualRect(&old_rect, &rect), "Expected format rectangle to be equal to client rectangle.\n"); + else + ok((rect.right - rect.left) > (old_rect.right - old_rect.left), "Expected format rect to be larger than client rectangle.\n"); + DestroyWindow(edit); + } +} + START_TEST(edit) { BOOL b; @@ -3243,11 +3500,12 @@ START_TEST(edit) test_edit_control_1(); test_edit_control_2(); test_edit_control_3(); - test_edit_control_4(); + test_char_from_pos(); test_edit_control_5(); test_edit_control_6(); test_edit_control_limittext(); test_edit_control_scroll(); + test_initialization(); test_margins(); test_margins_font_change(); test_text_position(); @@ -3267,6 +3525,8 @@ START_TEST(edit) test_paste(); test_EM_GETLINE(); test_wordbreak_proc(); + test_dbcs_WM_CHAR(); + test_format_rect(); UnregisterWindowClasses(); } diff --git a/modules/rostests/winetests/user32/generated.c b/modules/rostests/winetests/user32/generated.c index be1b698a2ce..6b80ad8d6f0 100644 --- a/modules/rostests/winetests/user32/generated.c +++ b/modules/rostests/winetests/user32/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) diff --git a/modules/rostests/winetests/user32/input.c b/modules/rostests/winetests/user32/input.c index 8e1838953e3..dd65990ae2c 100644 --- a/modules/rostests/winetests/user32/input.c +++ b/modules/rostests/winetests/user32/input.c @@ -1,6 +1,7 @@ /* Test Key event to Key message translation * * Copyright 2003 Rein Klazes + * Copyright 2019 Remi Bernon for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -49,105 +50,408 @@ #include "windef.h" #include "winbase.h" +#include "wingdi.h" #include "winuser.h" #include "wingdi.h" #include "winnls.h" +#include "winreg.h" +#include "ddk/hidsdi.h" +#include "imm.h" +#include "kbd.h" #include "wine/test.h" - #ifdef __REACTOS__ -#include +/* printf with temp buffer allocation */ +const char *wine_dbg_sprintf( const char *format, ... ) +{ + static const int max_size = 200; + static char buffer[256]; + char *ret; + int len; + va_list valist; + + va_start(valist, format); + ret = buffer; + len = vsnprintf( ret, max_size, format, valist ); + if (len == -1 || len >= max_size) ret[max_size-1] = 0; + va_end(valist); + return ret; +} #endif +#define check_member_( file, line, val, exp, fmt, member ) \ + ok_(file, line)( (val).member == (exp).member, "got " #member " " fmt "\n", (val).member ) +#define check_member( val, exp, fmt, member ) \ + check_member_( __FILE__, __LINE__, val, exp, fmt, member ) + +static const char *debugstr_ok( const char *cond ) +{ + int c, n = 0; + /* skip possible casts */ + while ((c = *cond++)) + { + if (c == '(') n++; + if (!n) break; + if (c == ')') n--; + } + if (!strchr( cond - 1, '(' )) return wine_dbg_sprintf( "got %s", cond - 1 ); + return wine_dbg_sprintf( "%.*s returned", (int)strcspn( cond - 1, "( " ), cond - 1 ); +} + +#define ok_eq( e, r, t, f, ... ) \ + do \ + { \ + t v = (r); \ + ok( v == (e), "%s " f "\n", debugstr_ok( #r ), v, ##__VA_ARGS__ ); \ + } while (0) +#define ok_ne( e, r, t, f, ... ) \ + do \ + { \ + t v = (r); \ + ok( v != (e), "%s " f "\n", debugstr_ok( #r ), v, ##__VA_ARGS__ ); \ + } while (0) +#define ok_rect( e, r ) \ + do \ + { \ + RECT v = (r); \ + ok( EqualRect( &v, &(e) ), "%s %s\n", debugstr_ok(#r), wine_dbgstr_rect(&v) ); \ + } while (0) +#define ok_point( e, r ) \ + do \ + { \ + POINT v = (r); \ + ok( !memcmp( &v, &(e), sizeof(v) ), "%s %s\n", debugstr_ok(#r), wine_dbgstr_point(&v) ); \ + } while (0) +#define ok_ret( e, r ) ok_eq( e, r, UINT_PTR, "%Iu, error %ld", GetLastError() ) + +enum user_function +{ + MSG_TEST_WIN = 1, + LL_HOOK_KEYBD, + LL_HOOK_MOUSE, + RAW_INPUT_KEYBOARD, +}; + +struct user_call +{ + enum user_function func; + + union + { + struct + { + HWND hwnd; + UINT msg; + WPARAM wparam; + LPARAM lparam; + } message; + struct + { + UINT msg; + UINT scan; + UINT vkey; + UINT flags; + UINT_PTR extra; + } ll_hook_kbd; + struct + { + UINT msg; + POINT point; + UINT data; + UINT flags; + UINT time; + UINT_PTR extra; + } ll_hook_ms; + struct + { + HWND hwnd; + BYTE code; + RAWKEYBOARD kbd; + } raw_input; + }; + + BOOL todo; + BOOL todo_value; + BOOL broken; +}; + +static const struct user_call empty_sequence[] = {{0}}; +static struct user_call current_sequence[1024]; +static LONG current_sequence_len; + +static const char *debugstr_wm( UINT msg ) +{ + switch (msg) + { + case WM_CHAR: return "WM_CHAR"; + case WM_KEYDOWN: return "WM_KEYDOWN"; + case WM_KEYUP: return "WM_KEYUP"; + case WM_SYSCHAR: return "WM_SYSCHAR"; + case WM_SYSCOMMAND: return "WM_SYSCOMMAND"; + case WM_SYSKEYDOWN: return "WM_SYSKEYDOWN"; + case WM_SYSKEYUP: return "WM_SYSKEYUP"; + case WM_MOUSEMOVE: return "WM_MOUSEMOVE"; + case WM_LBUTTONDOWN: return "WM_LBUTTONDOWN"; + case WM_LBUTTONUP: return "WM_LBUTTONUP"; + case WM_LBUTTONDBLCLK: return "WM_LBUTTONDBLCLK"; + case WM_NCHITTEST: return "WM_NCHITTEST"; + } + return wine_dbg_sprintf( "%#x", msg ); +} + +static const char *debugstr_vk( UINT vkey ) +{ + switch (vkey) + { + case VK_CONTROL: return "VK_CONTROL"; + case VK_LCONTROL: return "VK_LCONTROL"; + case VK_LMENU: return "VK_LMENU"; + case VK_LSHIFT: return "VK_LSHIFT"; + case VK_MENU: return "VK_MENU"; + case VK_RCONTROL: return "VK_RCONTROL"; + case VK_RMENU: return "VK_RMENU"; + case VK_RSHIFT: return "VK_RSHIFT"; + case VK_SHIFT: return "VK_SHIFT"; + } + + if (vkey >= '0' && vkey <= '9') return wine_dbg_sprintf( "%c", vkey ); + if (vkey >= 'A' && vkey <= 'Z') return wine_dbg_sprintf( "%c", vkey ); + return wine_dbg_sprintf( "%#x", vkey ); +} + +#define ok_call( a, b ) ok_call_( __FILE__, __LINE__, a, b ) +static int ok_call_( const char *file, int line, const struct user_call *expected, const struct user_call *received ) +{ + int ret; + + if ((ret = expected->func - received->func)) goto done; + + switch (expected->func) + { + case MSG_TEST_WIN: + if ((ret = expected->message.hwnd - received->message.hwnd)) goto done; + if ((ret = expected->message.msg - received->message.msg)) goto done; + if ((ret = (expected->message.wparam - received->message.wparam))) goto done; + if ((ret = (expected->message.lparam - received->message.lparam))) goto done; + break; + case LL_HOOK_KEYBD: + if ((ret = expected->ll_hook_kbd.msg - received->ll_hook_kbd.msg)) goto done; + if ((ret = (expected->ll_hook_kbd.scan - received->ll_hook_kbd.scan))) goto done; + if ((ret = expected->ll_hook_kbd.vkey - received->ll_hook_kbd.vkey)) goto done; + if ((ret = (expected->ll_hook_kbd.flags - received->ll_hook_kbd.flags))) goto done; + if ((ret = (expected->ll_hook_kbd.extra - received->ll_hook_kbd.extra))) goto done; + break; + case LL_HOOK_MOUSE: + if ((ret = expected->ll_hook_ms.msg - received->ll_hook_ms.msg)) goto done; + if ((ret = expected->ll_hook_ms.point.x - received->ll_hook_ms.point.x)) goto done; + if ((ret = expected->ll_hook_ms.point.y - received->ll_hook_ms.point.y)) goto done; + if ((ret = (expected->ll_hook_ms.data - received->ll_hook_ms.data))) goto done; + if ((ret = (expected->ll_hook_ms.flags - received->ll_hook_ms.flags))) goto done; + if (0 && (ret = expected->ll_hook_ms.time - received->ll_hook_ms.time)) goto done; + if ((ret = (expected->ll_hook_ms.extra - received->ll_hook_ms.extra))) goto done; + break; + case RAW_INPUT_KEYBOARD: + if ((ret = expected->raw_input.hwnd - received->raw_input.hwnd)) goto done; + if ((ret = expected->raw_input.code - received->raw_input.code)) goto done; + if ((ret = expected->raw_input.kbd.MakeCode - received->raw_input.kbd.MakeCode)) goto done; + if ((ret = expected->raw_input.kbd.Flags - received->raw_input.kbd.Flags)) goto done; + if ((ret = expected->raw_input.kbd.VKey - received->raw_input.kbd.VKey)) goto done; + if ((ret = expected->raw_input.kbd.Message - received->raw_input.kbd.Message)) goto done; + if ((ret = expected->raw_input.kbd.ExtraInformation - received->raw_input.kbd.ExtraInformation)) goto done; + break; + } + +done: + if (ret && broken( expected->broken )) return ret; + + switch (received->func) + { + case MSG_TEST_WIN: + todo_wine_if( expected->todo || expected->todo_value ) + ok_(file, line)( !ret, "got MSG_TEST_WIN hwnd %p, msg %s, wparam %#Ix, lparam %#Ix\n", received->message.hwnd, + debugstr_wm(received->message.msg), received->message.wparam, received->message.lparam ); + return ret; + case LL_HOOK_KEYBD: + todo_wine_if( expected->todo || expected->todo_value ) + ok_(file, line)( !ret, "got LL_HOOK_KEYBD msg %s scan %#x, vkey %s, flags %#x, extra %#Ix\n", debugstr_wm(received->ll_hook_kbd.msg), + received->ll_hook_kbd.scan, debugstr_vk(received->ll_hook_kbd.vkey), received->ll_hook_kbd.flags, + received->ll_hook_kbd.extra ); + return ret; + case LL_HOOK_MOUSE: + todo_wine_if( expected->todo || expected->todo_value ) + ok_(file, line)( !ret, "got LL_HOOK_MOUSE msg %s, point %s, data %#x, flags %#x, time %u, extra %#Ix\n", debugstr_wm(received->ll_hook_ms.msg), + wine_dbgstr_point(&received->ll_hook_ms.point), received->ll_hook_ms.data, received->ll_hook_ms.flags, received->ll_hook_ms.time, + received->ll_hook_ms.extra ); + return ret; + case RAW_INPUT_KEYBOARD: + todo_wine_if( expected->todo || expected->todo_value ) + ok_(file, line)( !ret, "got WM_INPUT key hwnd %p, code %d, make_code %#x, flags %#x, vkey %s, message %s, extra %#lx\n", + received->raw_input.hwnd, received->raw_input.code, received->raw_input.kbd.MakeCode, + received->raw_input.kbd.Flags, debugstr_vk(received->raw_input.kbd.VKey), + debugstr_wm(received->raw_input.kbd.Message), received->raw_input.kbd.ExtraInformation ); + return ret; + } + + switch (expected->func) + { + case MSG_TEST_WIN: + todo_wine_if( expected->todo || expected->todo_value ) + ok_(file, line)( !ret, "MSG_TEST_WIN hwnd %p, %s, wparam %#Ix, lparam %#Ix\n", expected->message.hwnd, + debugstr_wm(expected->message.msg), expected->message.wparam, expected->message.lparam ); + break; + case LL_HOOK_KEYBD: + todo_wine_if( expected->todo || expected->todo_value ) + ok_(file, line)( !ret, "LL_HOOK_KBD msg %s scan %#x, vkey %s, flags %#x, extra %#Ix\n", debugstr_wm(expected->ll_hook_kbd.msg), + expected->ll_hook_kbd.scan, debugstr_vk(expected->ll_hook_kbd.vkey), expected->ll_hook_kbd.flags, + expected->ll_hook_kbd.extra ); + break; + case LL_HOOK_MOUSE: + todo_wine_if( expected->todo || expected->todo_value ) + ok_(file, line)( !ret, "LL_HOOK_MOUSE msg %s, point %s, data %#x, flags %#x, time %u, extra %#Ix\n", debugstr_wm(received->ll_hook_ms.msg), + wine_dbgstr_point(&received->ll_hook_ms.point), received->ll_hook_ms.data, received->ll_hook_ms.flags, received->ll_hook_ms.time, + received->ll_hook_ms.extra ); + return ret; + case RAW_INPUT_KEYBOARD: + todo_wine_if( expected->todo || expected->todo_value ) + ok_(file, line)( !ret, "got WM_INPUT key hwnd %p, code %d, make_code %#x, flags %#x, vkey %s, message %s, extra %#lx\n", + expected->raw_input.hwnd, expected->raw_input.code, expected->raw_input.kbd.MakeCode, + expected->raw_input.kbd.Flags, debugstr_vk(expected->raw_input.kbd.VKey), + debugstr_wm(expected->raw_input.kbd.Message), expected->raw_input.kbd.ExtraInformation ); + return ret; + } + + return 0; +} + +#define ok_seq( a ) ok_seq_( __FILE__, __LINE__, a, #a ) +static void ok_seq_( const char *file, int line, const struct user_call *expected, const char *context ) +{ + const struct user_call *received = current_sequence; + UINT i = 0, ret; + + while (expected->func || received->func) + { + winetest_push_context( "%s %u%s%s", context, i++, !expected->func ? " (spurious)" : "", + !received->func ? " (missing)" : "" ); + ret = ok_call_( file, line, expected, received ); + if (ret && expected->todo && expected->func && + !strcmp( winetest_platform, "wine" )) + expected++; + else if (ret && broken(expected->broken)) + expected++; + else + { + if (expected->func) expected++; + if (received->func) received++; + } + winetest_pop_context(); + } + + memset( current_sequence, 0, sizeof(current_sequence) ); + current_sequence_len = 0; +} + +static BOOL append_message_hwnd; +static BOOL (*p_accept_message)( UINT msg ); + +static void append_ll_hook_kbd( UINT msg, const KBDLLHOOKSTRUCT *info ) +{ + struct user_call call = + { + .func = LL_HOOK_KEYBD, .ll_hook_kbd = + { + .msg = msg, .scan = info->scanCode, .vkey = info->vkCode, + .flags = info->flags, .extra = info->dwExtraInfo + } + }; + if (!p_accept_message || p_accept_message( msg )) + { + ULONG index = InterlockedIncrement( ¤t_sequence_len ) - 1; + ok( index < ARRAY_SIZE(current_sequence), "got %lu calls\n", index ); + current_sequence[index] = call; + } +} + +static void append_ll_hook_ms( UINT msg, const MSLLHOOKSTRUCT *info ) +{ + struct user_call call = + { + .func = LL_HOOK_MOUSE, .ll_hook_ms = + { + .msg = msg, .point = info->pt, .data = info->mouseData, .flags = info->flags, + .time = info->time, .extra = info->dwExtraInfo + } + }; + if (!p_accept_message || p_accept_message( msg )) + { + ULONG index = InterlockedIncrement( ¤t_sequence_len ) - 1; + ok( index < ARRAY_SIZE(current_sequence), "got %lu calls\n", index ); + current_sequence[index] = call; + } +} + +static void append_rawinput_message( HWND hwnd, WPARAM wparam, HRAWINPUT handle ) +{ + RAWINPUT rawinput; + UINT size = sizeof(rawinput), ret; + + ret = GetRawInputData( handle, RID_INPUT, &rawinput, &size, sizeof(RAWINPUTHEADER) ); + ok_ne( ret, (UINT)-1, UINT, "%u" ); + + if (rawinput.header.dwType == RIM_TYPEKEYBOARD) + { + struct user_call call = + { + .func = RAW_INPUT_KEYBOARD, + .raw_input = {.hwnd = hwnd, .code = GET_RAWINPUT_CODE_WPARAM(wparam), .kbd = rawinput.data.keyboard} + }; + ULONG index = InterlockedIncrement( ¤t_sequence_len ) - 1; + ok( index < ARRAY_SIZE(current_sequence), "got %lu calls\n", index ); + if (!append_message_hwnd) call.message.hwnd = 0; + current_sequence[index] = call; + } +} + +static void append_message( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + if (msg == WM_INPUT) append_rawinput_message( hwnd, wparam, (HRAWINPUT)lparam ); + else if (!p_accept_message || p_accept_message( msg )) + { + struct user_call call = {.func = MSG_TEST_WIN, .message = {.hwnd = hwnd, .msg = msg, .wparam = wparam, .lparam = lparam}}; + ULONG index = InterlockedIncrement( ¤t_sequence_len ) - 1; + ok( index < ARRAY_SIZE(current_sequence), "got %lu calls\n", index ); + if (!append_message_hwnd) call.message.hwnd = 0; + current_sequence[index] = call; + } +} + +static LRESULT CALLBACK append_message_wndproc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + append_message( hwnd, msg, wparam, lparam ); + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + /* globals */ -static HWND hWndTest; -static LONG timetag = 0x10000000; - -static struct { - LONG last_key_down; - LONG last_key_up; - LONG last_syskey_down; - LONG last_syskey_up; - LONG last_char; - LONG last_syschar; - LONG last_hook_down; - LONG last_hook_up; - LONG last_hook_syskey_down; - LONG last_hook_syskey_up; - WORD vk; - BOOL expect_alt; - BOOL sendinput_broken; -} key_status; +#define DESKTOP_ALL_ACCESS 0x01ff +static BOOL (WINAPI *pEnableMouseInPointer)( BOOL ); +static BOOL (WINAPI *pIsMouseInPointerEnabled)(void); static BOOL (WINAPI *pGetCurrentInputMessageSource)( INPUT_MESSAGE_SOURCE *source ); static BOOL (WINAPI *pGetPointerType)(UINT32, POINTER_INPUT_TYPE*); +static BOOL (WINAPI *pGetPointerInfo)(UINT32, POINTER_INFO*); +static BOOL (WINAPI *pGetPointerInfoHistory)(UINT32, UINT32*, POINTER_INFO*); +static BOOL (WINAPI *pGetPointerFrameInfo)(UINT32, UINT32*, POINTER_INFO*); +static BOOL (WINAPI *pGetPointerFrameInfoHistory)(UINT32, UINT32*, UINT32*, POINTER_INFO*); static int (WINAPI *pGetMouseMovePointsEx) (UINT, LPMOUSEMOVEPOINT, LPMOUSEMOVEPOINT, int, DWORD); static UINT (WINAPI *pGetRawInputDeviceList) (PRAWINPUTDEVICELIST, PUINT, UINT); static UINT (WINAPI *pGetRawInputDeviceInfoW) (HANDLE, UINT, void *, UINT *); static UINT (WINAPI *pGetRawInputDeviceInfoA) (HANDLE, UINT, void *, UINT *); -static int (WINAPI *pGetWindowRgnBox)(HWND, LPRECT); - -#define MAXKEYEVENTS 12 -#define MAXKEYMESSAGES MAXKEYEVENTS /* assuming a key event generates one - and only one message */ - -/* keyboard message names, sorted as their value */ -static const char *MSGNAME[]={"WM_KEYDOWN", "WM_KEYUP", "WM_CHAR","WM_DEADCHAR", - "WM_SYSKEYDOWN", "WM_SYSKEYUP", "WM_SYSCHAR", "WM_SYSDEADCHAR" ,"WM_KEYLAST"}; - -/* keyevents, add more as needed */ -typedef enum KEVtag -{ ALTDOWN = 1, ALTUP, XDOWN, XUP, SHIFTDOWN, SHIFTUP, CTRLDOWN, CTRLUP } KEV; -/* matching VK's */ -static const int GETVKEY[]={0, VK_MENU, VK_MENU, 'X', 'X', VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL}; -/* matching scan codes */ -static const int GETSCAN[]={0, 0x38, 0x38, 0x2D, 0x2D, 0x2A, 0x2A, 0x1D, 0x1D }; -/* matching updown events */ -static const int GETFLAGS[]={0, 0, KEYEVENTF_KEYUP, 0, KEYEVENTF_KEYUP, 0, KEYEVENTF_KEYUP, 0, KEYEVENTF_KEYUP}; -/* matching descriptions */ -static const char *getdesc[]={"", "+alt","-alt","+X","-X","+shift","-shift","+ctrl","-ctrl"}; - -/* The MSVC headers ignore our NONAMELESSUNION requests so we have to define our own type */ -typedef struct -{ - DWORD type; - union - { - MOUSEINPUT mi; - KEYBDINPUT ki; - HARDWAREINPUT hi; - } u; -} TEST_INPUT; - -typedef struct { - UINT message; - WPARAM wParam; - LPARAM lParam; -} KMSG; - -/******************************************* - * add new test sets here - * the software will make all combinations of the - * keyevent defined here - */ -static const struct { - int nrkev; - KEV keydwn[MAXKEYEVENTS]; - KEV keyup[MAXKEYEVENTS]; -} testkeyset[]= { - { 2, { ALTDOWN, XDOWN }, { ALTUP, XUP}}, - { 3, { ALTDOWN, XDOWN , SHIFTDOWN}, { ALTUP, XUP, SHIFTUP}}, - { 3, { ALTDOWN, XDOWN , CTRLDOWN}, { ALTUP, XUP, CTRLUP}}, - { 3, { SHIFTDOWN, XDOWN , CTRLDOWN}, { SHIFTUP, XUP, CTRLUP}}, - { 0 } /* mark the end */ -}; +static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL); +static HKL (WINAPI *pLoadKeyboardLayoutEx)(HKL, const WCHAR *, UINT); /**********************adapted from input.c **********************************/ -static BYTE InputKeyStateTable[256]; -static BYTE AsyncKeyStateTable[256]; -static BYTE TrackSysKey = 0; /* determine whether ALT key up will cause a WM_SYSKEYUP - or a WM_KEYUP message */ +static BOOL is_wow64; static void init_function_pointers(void) { @@ -157,227 +461,112 @@ static void init_function_pointers(void) if (!(p ## func = (void*)GetProcAddress(hdll, #func))) \ trace("GetProcAddress(%s) failed\n", #func) + GET_PROC(EnableMouseInPointer); + GET_PROC(IsMouseInPointerEnabled); GET_PROC(GetCurrentInputMessageSource); GET_PROC(GetMouseMovePointsEx); + GET_PROC(GetPointerInfo); + GET_PROC(GetPointerInfoHistory); + GET_PROC(GetPointerFrameInfo); + GET_PROC(GetPointerFrameInfoHistory); GET_PROC(GetPointerType); GET_PROC(GetRawInputDeviceList); GET_PROC(GetRawInputDeviceInfoW); GET_PROC(GetRawInputDeviceInfoA); - GET_PROC(GetWindowRgnBox); + GET_PROC(LoadKeyboardLayoutEx); + + hdll = GetModuleHandleA("kernel32"); + GET_PROC(IsWow64Process); #undef GET_PROC + + if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) + is_wow64 = FALSE; } -static int KbdMessage( KEV kev, WPARAM *pwParam, LPARAM *plParam ) +#define run_in_process( a, b ) run_in_process_( __FILE__, __LINE__, a, b ) +static void run_in_process_( const char *file, int line, char **argv, const char *args ) { - UINT message; - int VKey = GETVKEY[kev]; - WORD flags; + STARTUPINFOA startup = {.cb = sizeof(STARTUPINFOA)}; + PROCESS_INFORMATION info = {0}; + char cmdline[MAX_PATH * 2]; + DWORD ret; - flags = LOBYTE(GETSCAN[kev]); - if (GETFLAGS[kev] & KEYEVENTF_EXTENDEDKEY) flags |= KF_EXTENDED; + sprintf( cmdline, "%s %s %s", argv[0], argv[1], args ); + ret = CreateProcessA( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info ); + ok_(file, line)( ret, "CreateProcessA failed, error %lu\n", GetLastError() ); + if (!ret) return; - if (GETFLAGS[kev] & KEYEVENTF_KEYUP ) - { - message = WM_KEYUP; - if( (InputKeyStateTable[VK_MENU] & 0x80) && ( - (VKey == VK_MENU) || (VKey == VK_CONTROL) || - !(InputKeyStateTable[VK_CONTROL] & 0x80))) { - if( TrackSysKey == VK_MENU || /* -down/-up sequence */ - (VKey != VK_MENU)) /* -down...-up */ - message = WM_SYSKEYUP; - TrackSysKey = 0; - } - InputKeyStateTable[VKey] &= ~0x80; - flags |= KF_REPEAT | KF_UP; - } - else - { - if (InputKeyStateTable[VKey] & 0x80) flags |= KF_REPEAT; - if (!(InputKeyStateTable[VKey] & 0x80)) InputKeyStateTable[VKey] ^= 0x01; - InputKeyStateTable[VKey] |= 0x80; - AsyncKeyStateTable[VKey] |= 0x80; - - message = WM_KEYDOWN; - if( (InputKeyStateTable[VK_MENU] & 0x80) && - !(InputKeyStateTable[VK_CONTROL] & 0x80)) { - message = WM_SYSKEYDOWN; - TrackSysKey = VKey; - } - } - - if (InputKeyStateTable[VK_MENU] & 0x80) flags |= KF_ALTDOWN; - - if( plParam) *plParam = MAKELPARAM( 1, flags ); - if( pwParam) *pwParam = VKey; - return message; + wait_child_process( info.hProcess ); + CloseHandle( info.hThread ); + CloseHandle( info.hProcess ); } -/****************************** end copy input.c ****************************/ - -/* - * . prepare the keyevents for SendInputs - * . calculate the "expected" messages - * . Send the events to our window - * . retrieve the messages from the input queue - * . verify - */ -static BOOL do_test( HWND hwnd, int seqnr, const KEV td[] ) +#define run_in_desktop( a, b, c ) run_in_desktop_( __FILE__, __LINE__, a, b, c ) +static void run_in_desktop_( const char *file, int line, char **argv, + const char *args, BOOL input ) { - TEST_INPUT inputs[MAXKEYEVENTS]; - KMSG expmsg[MAXKEYEVENTS]; + const char *desktop_name = "WineTest Desktop"; + STARTUPINFOA startup = {.cb = sizeof(STARTUPINFOA)}; + PROCESS_INFORMATION info = {0}; + HDESK old_desktop, desktop; + char cmdline[MAX_PATH * 2]; + DWORD ret; + + old_desktop = OpenInputDesktop( 0, FALSE, DESKTOP_ALL_ACCESS ); + ok_(file, line)( !!old_desktop, "OpenInputDesktop failed, error %lu\n", GetLastError() ); + desktop = CreateDesktopA( desktop_name, NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ); + ok_(file, line)( !!desktop, "CreateDesktopA failed, error %lu\n", GetLastError() ); + if (input) + { + ret = SwitchDesktop( desktop ); + ok_(file, line)( ret, "SwitchDesktop failed, error %lu\n", GetLastError() ); + } + + startup.lpDesktop = (char *)desktop_name; + sprintf( cmdline, "%s %s %s", argv[0], argv[1], args ); + ret = CreateProcessA( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info ); + ok_(file, line)( ret, "CreateProcessA failed, error %lu\n", GetLastError() ); + if (!ret) return; + + wait_child_process( info.hProcess ); + CloseHandle( info.hThread ); + CloseHandle( info.hProcess ); + + if (input) + { + ret = SwitchDesktop( old_desktop ); + ok_(file, line)( ret, "SwitchDesktop failed, error %lu\n", GetLastError() ); + } + ret = CloseDesktop( desktop ); + ok_(file, line)( ret, "CloseDesktop failed, error %lu\n", GetLastError() ); + ret = CloseDesktop( old_desktop ); + ok_(file, line)( ret, "CloseDesktop failed, error %lu\n", GetLastError() ); +} + +#define wait_messages( a, b ) msg_wait_for_events_( __FILE__, __LINE__, 0, NULL, a, b ) +#define msg_wait_for_events( a, b, c ) msg_wait_for_events_( __FILE__, __LINE__, a, b, c, FALSE ) +static DWORD msg_wait_for_events_( const char *file, int line, DWORD count, HANDLE *events, DWORD timeout, BOOL append_peeked ) +{ + DWORD ret, end = GetTickCount() + min( timeout, 5000 ); MSG msg; - char buf[100]; - UINT evtctr=0, ret; - int kmctr, i; - buf[0]='\0'; - TrackSysKey=0; /* see input.c */ - for (i = 0; i < MAXKEYEVENTS; i++) + while ((ret = MsgWaitForMultipleObjects( count, events, FALSE, min( timeout, 5000 ), QS_ALLINPUT )) <= count) { - inputs[evtctr].type = INPUT_KEYBOARD; - inputs[evtctr].u.ki.wVk = GETVKEY[td[i]]; - inputs[evtctr].u.ki.wScan = GETSCAN[td[i]]; - inputs[evtctr].u.ki.dwFlags = GETFLAGS[td[i]]; - inputs[evtctr].u.ki.dwExtraInfo = 0; - inputs[evtctr].u.ki.time = ++timetag; - if (td[i]) evtctr++; - - strcat(buf, getdesc[td[i]]); - if(td[i]) - expmsg[i].message = KbdMessage(td[i], &(expmsg[i].wParam), &(expmsg[i].lParam)); - else - expmsg[i].message = 0; - } - for( kmctr = 0; kmctr < MAXKEYEVENTS && expmsg[kmctr].message; kmctr++) - ; - ok( evtctr <= MAXKEYEVENTS, "evtctr is above MAXKEYEVENTS\n" ); - ret = SendInput(evtctr, (INPUT *)inputs, sizeof(INPUT)); - ok(ret == evtctr, "SendInput failed to send some events\n"); - i = 0; - if (winetest_debug > 1) - trace("======== key stroke sequence #%d: %s =============\n", - seqnr + 1, buf); - while( PeekMessageA(&msg,hwnd,WM_KEYFIRST,WM_KEYLAST,PM_REMOVE) ) { - if (winetest_debug > 1) - trace("message[%d] %-15s wParam %04lx lParam %08lx time %x\n", i, - MSGNAME[msg.message - WM_KEYFIRST], msg.wParam, msg.lParam, msg.time); - if( i < kmctr ) { - ok( msg.message == expmsg[i].message && - msg.wParam == expmsg[i].wParam && - msg.lParam == expmsg[i].lParam, - "%u/%u: wrong message %x/%08lx/%08lx expected %s/%08lx/%08lx\n", - seqnr, i, msg.message, msg.wParam, msg.lParam, - MSGNAME[(expmsg[i]).message - WM_KEYFIRST], expmsg[i].wParam, expmsg[i].lParam ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) + { + if (append_peeked) append_message( msg.hwnd, msg.message, msg.wParam, msg.lParam ); + TranslateMessage( &msg ); + DispatchMessageW( &msg ); } - i++; + if (ret < count) return ret; + if (timeout >= 5000) continue; + if (end <= GetTickCount()) timeout = 0; + else timeout = end - GetTickCount(); } - if (winetest_debug > 1) - trace("%d messages retrieved\n", i); - if (!i && kmctr) - { - skip( "simulated keyboard input doesn't work\n" ); - return FALSE; - } - ok( i == kmctr, "message count is wrong: got %d expected: %d\n", i, kmctr); - return TRUE; -} -/* test all combinations of the specified key events */ -static BOOL TestASet( HWND hWnd, int nrkev, const KEV kevdwn[], const KEV kevup[] ) -{ - int i,j,k,l,m,n; - static int count=0; - KEV kbuf[MAXKEYEVENTS]; - assert( nrkev==2 || nrkev==3); - for(i=0;i= 5000) ok_(file, line)( 0, "MsgWaitForMultipleObjects returned %#lx\n", ret ); + else ok_(file, line)( ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %#lx\n", ret ); + return ret; } static inline BOOL is_keyboard_message( UINT message ) @@ -390,6 +579,42 @@ static inline BOOL is_mouse_message( UINT message ) return (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST); } +#define create_foreground_window( a ) create_foreground_window_( __FILE__, __LINE__, a, 5 ) +HWND create_foreground_window_( const char *file, int line, BOOL fullscreen, UINT retries ) +{ + for (;;) + { + HWND hwnd; + BOOL ret; + + hwnd = CreateWindowW( L"static", NULL, WS_POPUP | (fullscreen ? 0 : WS_VISIBLE), + 100, 100, 200, 200, NULL, NULL, NULL, NULL ); + ok_(file, line)( hwnd != NULL, "CreateWindowW failed, error %lu\n", GetLastError() ); + + if (fullscreen) + { + HMONITOR hmonitor = MonitorFromWindow( hwnd, MONITOR_DEFAULTTOPRIMARY ); + MONITORINFO mi = {.cbSize = sizeof(MONITORINFO)}; + + ok_(file, line)( hmonitor != NULL, "MonitorFromWindow failed, error %lu\n", GetLastError() ); + ret = GetMonitorInfoW( hmonitor, &mi ); + ok_(file, line)( ret, "GetMonitorInfoW failed, error %lu\n", GetLastError() ); + ret = SetWindowPos( hwnd, 0, mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right - mi.rcMonitor.left, + mi.rcMonitor.bottom - mi.rcMonitor.top, SWP_FRAMECHANGED | SWP_SHOWWINDOW ); + ok_(file, line)( ret, "SetWindowPos failed, error %lu\n", GetLastError() ); + } + wait_messages( 100, FALSE ); + + if (GetForegroundWindow() == hwnd) return hwnd; + ok_(file, line)( retries > 0, "failed to create foreground window\n" ); + if (!retries--) return hwnd; + + ret = DestroyWindow( hwnd ); + ok_(file, line)( ret, "DestroyWindow failed, error %lu\n", GetLastError() ); + wait_messages( 0, FALSE ); + } +} + /* try to make sure pending X events have been processed before continuing */ static void empty_message_queue(void) { @@ -413,833 +638,828 @@ static void empty_message_queue(void) } } -struct transition_s { - WORD wVk; - BYTE before_state; - BYTE optional; -}; - -typedef enum { - sent=0x1, - posted=0x2, - parent=0x4, - wparam=0x8, - lparam=0x10, - defwinproc=0x20, - beginpaint=0x40, - optional=0x80, - hook=0x100, - winevent_hook=0x200 -} msg_flags_t; - -struct message { - UINT message; /* the WM_* code */ - msg_flags_t flags; /* message props */ - WPARAM wParam; /* expected value of wParam */ - LPARAM lParam; /* expected value of lParam */ -}; - -static const struct sendinput_test_s { - WORD wVk; - DWORD dwFlags; - BOOL _todo_wine; - struct transition_s expected_transitions[MAXKEYEVENTS+1]; - struct message expected_messages[MAXKEYMESSAGES+1]; -} sendinput_test[] = { - /* test ALT+F */ - /* 0 */ - {VK_LMENU, 0, FALSE, {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {0}}, - {{WM_SYSKEYDOWN, hook|wparam, VK_LMENU}, {WM_SYSKEYDOWN}, {0}}}, - {'F', 0, FALSE, {{'F', 0x00}, {0}}, - {{WM_SYSKEYDOWN, hook}, {WM_SYSKEYDOWN}, - {WM_SYSCHAR}, - {WM_SYSCOMMAND}, {0}}}, - {'F', KEYEVENTF_KEYUP, FALSE, {{'F', 0x80}, {0}}, - {{WM_SYSKEYUP, hook}, {WM_SYSKEYUP}, {0}}}, - {VK_LMENU, KEYEVENTF_KEYUP, FALSE, {{VK_MENU, 0x80}, {VK_LMENU, 0x80}, {0}}, - {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}}, - - /* test CTRL+O */ - /* 4 */ - {VK_LCONTROL, 0, FALSE, {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}}, - {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {0}}}, - {'O', 0, FALSE, {{'O', 0x00}, {0}}, - {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {WM_CHAR}, {0}}}, - {'O', KEYEVENTF_KEYUP, FALSE, {{'O', 0x80}, {0}}, - {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}}, - {VK_LCONTROL, KEYEVENTF_KEYUP, FALSE, {{VK_CONTROL, 0x80}, {VK_LCONTROL, 0x80}, {0}}, - {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}}, - - /* test ALT+CTRL+X */ - /* 8 */ - {VK_LMENU, 0, FALSE, {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {0}}, - {{WM_SYSKEYDOWN, hook}, {WM_SYSKEYDOWN}, {0}}}, - {VK_LCONTROL, 0, FALSE, {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}}, - {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {0}}}, - {'X', 0, FALSE, {{'X', 0x00}, {0}}, - {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {0}}}, - {'X', KEYEVENTF_KEYUP, FALSE, {{'X', 0x80}, {0}}, - {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}}, - {VK_LCONTROL, KEYEVENTF_KEYUP, FALSE, {{VK_CONTROL, 0x80}, {VK_LCONTROL, 0x80}, {0}}, - {{WM_SYSKEYUP, hook}, {WM_SYSKEYUP}, {0}}}, - {VK_LMENU, KEYEVENTF_KEYUP, FALSE, {{VK_MENU, 0x80}, {VK_LMENU, 0x80}, {0}}, - {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}}, - - /* test SHIFT+A */ - /* 14 */ - {VK_LSHIFT, 0, FALSE, {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00}, {0}}, - {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {0}}}, - {'A', 0, FALSE, {{'A', 0x00}, {0}}, - {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {WM_CHAR}, {0}}}, - {'A', KEYEVENTF_KEYUP, FALSE, {{'A', 0x80}, {0}}, - {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}}, - {VK_LSHIFT, KEYEVENTF_KEYUP, FALSE, {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80}, {0}}, - {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}}, - /* test L-SHIFT & R-SHIFT: */ - /* RSHIFT == LSHIFT */ - /* 18 */ - {VK_RSHIFT, 0, FALSE, - /* recent windows versions (>= w2k3) correctly report an RSHIFT transition */ - {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00, TRUE}, {VK_RSHIFT, 0x00, TRUE}, {0}}, - {{WM_KEYDOWN, hook|wparam, VK_RSHIFT}, - {WM_KEYDOWN}, {0}}}, - {VK_RSHIFT, KEYEVENTF_KEYUP, FALSE, - {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80, TRUE}, {VK_RSHIFT, 0x80, TRUE}, {0}}, - {{WM_KEYUP, hook, hook|wparam, VK_RSHIFT}, - {WM_KEYUP}, {0}}}, - - /* LSHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */ - /* 20 */ - {VK_LSHIFT, KEYEVENTF_EXTENDEDKEY, FALSE, - {{VK_SHIFT, 0x00}, {VK_RSHIFT, 0x00}, {0}}, - {{WM_KEYDOWN, hook|wparam|lparam, VK_LSHIFT, LLKHF_EXTENDED}, - {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}}, - {VK_LSHIFT, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, FALSE, - {{VK_SHIFT, 0x80}, {VK_RSHIFT, 0x80}, {0}}, - {{WM_KEYUP, hook|wparam|lparam, VK_LSHIFT, LLKHF_UP|LLKHF_EXTENDED}, - {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}}, - /* RSHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */ - /* 22 */ - {VK_RSHIFT, KEYEVENTF_EXTENDEDKEY, FALSE, - {{VK_SHIFT, 0x00}, {VK_RSHIFT, 0x00}, {0}}, - {{WM_KEYDOWN, hook|wparam|lparam, VK_RSHIFT, LLKHF_EXTENDED}, - {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}}, - {VK_RSHIFT, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, FALSE, - {{VK_SHIFT, 0x80}, {VK_RSHIFT, 0x80}, {0}}, - {{WM_KEYUP, hook|wparam|lparam, VK_RSHIFT, LLKHF_UP|LLKHF_EXTENDED}, - {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}}, - - /* Note about wparam for hook with generic key (VK_SHIFT, VK_CONTROL, VK_MENU): - win2k - sends to hook whatever we generated here - winXP+ - Attempts to convert key to L/R key but not always correct - */ - /* SHIFT == LSHIFT */ - /* 24 */ - {VK_SHIFT, 0, FALSE, - {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00}, {0}}, - {{WM_KEYDOWN, hook/* |wparam */|lparam, VK_SHIFT, 0}, - {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}}, - {VK_SHIFT, KEYEVENTF_KEYUP, FALSE, - {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80}, {0}}, - {{WM_KEYUP, hook/*|wparam*/|lparam, VK_SHIFT, LLKHF_UP}, - {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}}, - /* SHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */ - /* 26 */ - {VK_SHIFT, KEYEVENTF_EXTENDEDKEY, FALSE, - {{VK_SHIFT, 0x00}, {VK_RSHIFT, 0x00}, {0}}, - {{WM_KEYDOWN, hook/*|wparam*/|lparam, VK_SHIFT, LLKHF_EXTENDED}, - {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}}, - {VK_SHIFT, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, FALSE, - {{VK_SHIFT, 0x80}, {VK_RSHIFT, 0x80}, {0}}, - {{WM_KEYUP, hook/*|wparam*/|lparam, VK_SHIFT, LLKHF_UP|LLKHF_EXTENDED}, - {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}}, - - /* test L-CONTROL & R-CONTROL: */ - /* RCONTROL == LCONTROL */ - /* 28 */ - {VK_RCONTROL, 0, FALSE, - {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}}, - {{WM_KEYDOWN, hook|wparam, VK_RCONTROL}, - {WM_KEYDOWN, wparam|lparam, VK_CONTROL, 0}, {0}}}, - {VK_RCONTROL, KEYEVENTF_KEYUP, FALSE, - {{VK_CONTROL, 0x80}, {VK_LCONTROL, 0x80}, {0}}, - {{WM_KEYUP, hook|wparam, VK_RCONTROL}, - {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP}, {0}}}, - /* LCONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */ - /* 30 */ - {VK_LCONTROL, KEYEVENTF_EXTENDEDKEY, FALSE, - {{VK_CONTROL, 0x00}, {VK_RCONTROL, 0x00}, {0}}, - {{WM_KEYDOWN, hook|wparam|lparam, VK_LCONTROL, LLKHF_EXTENDED}, - {WM_KEYDOWN, wparam|lparam, VK_CONTROL, KF_EXTENDED}, {0}}}, - {VK_LCONTROL, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, FALSE, - {{VK_CONTROL, 0x80}, {VK_RCONTROL, 0x80}, {0}}, - {{WM_KEYUP, hook|wparam|lparam, VK_LCONTROL, LLKHF_UP|LLKHF_EXTENDED}, - {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP|KF_EXTENDED}, {0}}}, - /* RCONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */ - /* 32 */ - {VK_RCONTROL, KEYEVENTF_EXTENDEDKEY, FALSE, - {{VK_CONTROL, 0x00}, {VK_RCONTROL, 0x00}, {0}}, - {{WM_KEYDOWN, hook|wparam|lparam, VK_RCONTROL, LLKHF_EXTENDED}, - {WM_KEYDOWN, wparam|lparam, VK_CONTROL, KF_EXTENDED}, {0}}}, - {VK_RCONTROL, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, FALSE, - {{VK_CONTROL, 0x80}, {VK_RCONTROL, 0x80}, {0}}, - {{WM_KEYUP, hook|wparam|lparam, VK_RCONTROL, LLKHF_UP|LLKHF_EXTENDED}, - {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP|KF_EXTENDED}, {0}}}, - /* CONTROL == LCONTROL */ - /* 34 */ - {VK_CONTROL, 0, FALSE, - {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}}, - {{WM_KEYDOWN, hook/*|wparam, VK_CONTROL*/}, - {WM_KEYDOWN, wparam|lparam, VK_CONTROL, 0}, {0}}}, - {VK_CONTROL, KEYEVENTF_KEYUP, FALSE, - {{VK_CONTROL, 0x80}, {VK_LCONTROL, 0x80}, {0}}, - {{WM_KEYUP, hook/*|wparam, VK_CONTROL*/}, - {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP}, {0}}}, - /* CONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */ - /* 36 */ - {VK_CONTROL, KEYEVENTF_EXTENDEDKEY, FALSE, - {{VK_CONTROL, 0x00}, {VK_RCONTROL, 0x00}, {0}}, - {{WM_KEYDOWN, hook/*|wparam*/|lparam, VK_CONTROL, LLKHF_EXTENDED}, - {WM_KEYDOWN, wparam|lparam, VK_CONTROL, KF_EXTENDED}, {0}}}, - {VK_CONTROL, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, FALSE, - {{VK_CONTROL, 0x80}, {VK_RCONTROL, 0x80}, {0}}, - {{WM_KEYUP, hook/*|wparam*/|lparam, VK_CONTROL, LLKHF_UP|LLKHF_EXTENDED}, - {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP|KF_EXTENDED}, {0}}}, - - /* test L-MENU & R-MENU: */ - /* RMENU == LMENU */ - /* 38 */ - {VK_RMENU, 0, FALSE, - {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {VK_CONTROL, 0x00, 1}, {VK_LCONTROL, 0x01, 1}, {0}}, - {{WM_SYSKEYDOWN, hook|wparam|optional, VK_LCONTROL}, - {WM_SYSKEYDOWN, hook|wparam, VK_RMENU}, - {WM_KEYDOWN, wparam|lparam|optional, VK_CONTROL, 0}, - {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0}, {0}}}, - {VK_RMENU, KEYEVENTF_KEYUP, TRUE, - {{VK_MENU, 0x80}, {VK_LMENU, 0x80}, {VK_CONTROL, 0x81, 1}, {VK_LCONTROL, 0x80, 1}, {0}}, - {{WM_KEYUP, hook|wparam|optional, VK_LCONTROL}, - {WM_KEYUP, hook|wparam, VK_RMENU}, - {WM_SYSKEYUP, wparam|lparam|optional, VK_CONTROL, KF_UP}, - {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP}, - {WM_SYSCOMMAND, optional}, {0}}}, - /* LMENU | KEYEVENTF_EXTENDEDKEY == RMENU */ - /* 40 */ - {VK_LMENU, KEYEVENTF_EXTENDEDKEY, FALSE, - {{VK_MENU, 0x00}, {VK_RMENU, 0x00}, {0}}, - {{WM_SYSKEYDOWN, hook|wparam|lparam, VK_LMENU, LLKHF_EXTENDED}, - {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, KF_EXTENDED}, {0}}}, - {VK_LMENU, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, TRUE, - {{VK_MENU, 0x80}, {VK_RMENU, 0x80}, {0}}, - {{WM_KEYUP, hook|wparam|lparam, VK_LMENU, LLKHF_UP|LLKHF_EXTENDED}, - {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP|KF_EXTENDED}, - {WM_SYSCOMMAND}, {0}}}, - /* RMENU | KEYEVENTF_EXTENDEDKEY == RMENU */ - /* 42 */ - {VK_RMENU, KEYEVENTF_EXTENDEDKEY, FALSE, - {{VK_MENU, 0x00}, {VK_RMENU, 0x00}, {VK_CONTROL, 0x00, 1}, {VK_LCONTROL, 0x01, 1}, {0}}, - {{WM_SYSKEYDOWN, hook|wparam|lparam|optional, VK_LCONTROL, 0}, - {WM_SYSKEYDOWN, hook|wparam|lparam, VK_RMENU, LLKHF_EXTENDED}, - {WM_KEYDOWN, wparam|lparam|optional, VK_CONTROL, 0}, - {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, KF_EXTENDED}, {0}}}, - {VK_RMENU, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, TRUE, - {{VK_MENU, 0x80}, {VK_RMENU, 0x80}, {VK_CONTROL, 0x81, 1}, {VK_LCONTROL, 0x80, 1}, {0}}, - {{WM_KEYUP, hook|wparam|lparam|optional, VK_LCONTROL, LLKHF_UP}, - {WM_KEYUP, hook|wparam|lparam, VK_RMENU, LLKHF_UP|LLKHF_EXTENDED}, - {WM_SYSKEYUP, wparam|lparam|optional, VK_CONTROL, KF_UP}, - {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP|KF_EXTENDED}, - {WM_SYSCOMMAND, optional}, {0}}}, - /* MENU == LMENU */ - /* 44 */ - {VK_MENU, 0, FALSE, - {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {0}}, - {{WM_SYSKEYDOWN, hook/*|wparam, VK_MENU*/}, - {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0}, {0}}}, - {VK_MENU, KEYEVENTF_KEYUP, TRUE, - {{VK_MENU, 0x80}, {VK_LMENU, 0x80}, {0}}, - {{WM_KEYUP, hook/*|wparam, VK_MENU*/}, - {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP}, - {WM_SYSCOMMAND}, {0}}}, - /* MENU | KEYEVENTF_EXTENDEDKEY == RMENU */ - /* 46 */ - {VK_MENU, KEYEVENTF_EXTENDEDKEY, FALSE, - {{VK_MENU, 0x00}, {VK_RMENU, 0x00}, {VK_CONTROL, 0x00, 1}, {VK_LCONTROL, 0x01, 1}, {0}}, - {{WM_SYSKEYDOWN, hook|wparam|lparam|optional, VK_CONTROL, 0}, - {WM_SYSKEYDOWN, hook/*|wparam*/|lparam, VK_MENU, LLKHF_EXTENDED}, - {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, KF_EXTENDED}, {0}}}, - {VK_MENU, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, TRUE, - {{VK_MENU, 0x80}, {VK_RMENU, 0x80}, {VK_CONTROL, 0x81, 1}, {VK_LCONTROL, 0x80, 1}, {0}}, - {{WM_KEYUP, hook|wparam|lparam|optional, VK_CONTROL, LLKHF_UP}, - {WM_KEYUP, hook/*|wparam*/|lparam, VK_MENU, LLKHF_UP|LLKHF_EXTENDED}, - {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP|KF_EXTENDED}, - {WM_SYSCOMMAND}, {0}}}, - - /* test LSHIFT & RSHIFT */ - /* 48 */ - {VK_LSHIFT, 0, FALSE, - {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00}, {0}}, - {{WM_KEYDOWN, hook|wparam|lparam, VK_LSHIFT, 0}, - {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}}, - {VK_RSHIFT, KEYEVENTF_EXTENDEDKEY, FALSE, - {{VK_RSHIFT, 0x00}, {0}}, - {{WM_KEYDOWN, hook|wparam|lparam, VK_RSHIFT, LLKHF_EXTENDED}, - {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}}, - {VK_RSHIFT, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, FALSE, - {{VK_RSHIFT, 0x80}, {0}}, - {{WM_KEYUP, hook|wparam|lparam, VK_RSHIFT, LLKHF_UP|LLKHF_EXTENDED}, - {WM_KEYUP, optional}, {0}}}, - {VK_LSHIFT, KEYEVENTF_KEYUP, FALSE, - {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80}, {0}}, - {{WM_KEYUP, hook|wparam, VK_LSHIFT}, - {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}}, - - {0, 0, FALSE, {{0}}, {{0}}} /* end */ -}; - -static struct message sent_messages[MAXKEYMESSAGES]; -static UINT sent_messages_cnt; - -/* Verify that only specified key state transitions occur */ -static void compare_and_check(int id, BYTE *ks1, BYTE *ks2, - const struct sendinput_test_s *test, BOOL foreground) +struct send_input_keyboard_test { - int i, failcount = 0; - const struct transition_s *t = test->expected_transitions; - UINT actual_cnt = 0; - const struct message *expected = test->expected_messages; + WORD scan; + WORD vkey; + DWORD flags; + struct user_call expect[8]; + BYTE expect_state[256]; + BOOL todo_state[256]; + BOOL async; + BYTE expect_async[256]; + BOOL todo_async[256]; +}; - while (t->wVk && foreground) { - /* We won't receive any information from GetKeyboardState() if we're - * not the foreground window. */ - BOOL matched = ((ks1[t->wVk]&0x80) == (t->before_state&0x80) - && (ks2[t->wVk]&0x80) == (~t->before_state&0x80)); - - if (!matched && !t->optional && test->_todo_wine) - { - failcount++; - todo_wine { - ok(matched, "%2d (%x/%x): %02x from %02x -> %02x " - "instead of %02x -> %02x\n", id, test->wVk, test->dwFlags, - t->wVk, ks1[t->wVk]&0x80, ks2[t->wVk]&0x80, t->before_state, - ~t->before_state&0x80); - } - } else { - ok(matched || t->optional, "%2d (%x/%x): %02x from %02x -> %02x " - "instead of %02x -> %02x\n", id, test->wVk, test->dwFlags, - t->wVk, ks1[t->wVk]&0x80, ks2[t->wVk]&0x80, t->before_state, - ~t->before_state&0x80); - } - ks2[t->wVk] = ks1[t->wVk]; /* clear the match */ - t++; - } - for (i = 0; i < 256; i++) - if (ks2[i] != ks1[i] && test->_todo_wine) - { - failcount++; - todo_wine - ok(FALSE, "%2d (%x/%x): %02x from %02x -> %02x unexpected\n", - id, test->wVk, test->dwFlags, i, ks1[i], ks2[i]); - } - else - ok(ks2[i] == ks1[i], "%2d (%x/%x): %02x from %02x -> %02x unexpected\n", - id, test->wVk, test->dwFlags, i, ks1[i], ks2[i]); - - while (expected->message && actual_cnt < sent_messages_cnt) - { - const struct message *actual = &sent_messages[actual_cnt]; - - if (expected->message == actual->message) - { - if (expected->flags & wparam) - { - if ((expected->flags & optional) && (expected->wParam != actual->wParam)) - { - expected++; - continue; - } - if (expected->wParam != actual->wParam && test->_todo_wine) - { - failcount++; - todo_wine - ok(FALSE, "%2d (%x/%x): in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n", - id, test->wVk, test->dwFlags, expected->message, expected->wParam, actual->wParam); - } - else - ok(expected->wParam == actual->wParam, - "%2d (%x/%x): in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n", - id, test->wVk, test->dwFlags, expected->message, expected->wParam, actual->wParam); - } - if (expected->flags & lparam) - { - if (expected->lParam != actual->lParam && test->_todo_wine) - { - failcount++; - todo_wine - ok(FALSE, "%2d (%x/%x): in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n", - id, test->wVk, test->dwFlags, expected->message, expected->lParam, actual->lParam); - } - else - ok(expected->lParam == actual->lParam, - "%2d (%x/%x): in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n", - id, test->wVk, test->dwFlags, expected->message, expected->lParam, actual->lParam); - } - ok((expected->flags & hook) == (actual->flags & hook), - "%2d (%x/%x): the msg 0x%04x should have been sent by a hook\n", - id, test->wVk, test->dwFlags, expected->message); - - } - else if (expected->flags & optional) - { - expected++; - continue; - } - else if (!(expected->flags & hook) && !foreground) - { - /* If we weren't able to receive foreground status, we won't get - * any window messages. */ - expected++; - continue; - } - /* NT4 doesn't send SYSKEYDOWN/UP to hooks, only KEYDOWN/UP */ - else if ((expected->flags & hook) && - (expected->message == WM_SYSKEYDOWN || expected->message == WM_SYSKEYUP) && - (actual->message == expected->message - 4)) - { - ok((expected->flags & hook) == (actual->flags & hook), - "%2d (%x/%x): the msg 0x%04x should have been sent by a hook\n", - id, test->wVk, test->dwFlags, expected->message); - } - /* For VK_RMENU, at least localized Win2k/XP sends KEYDOWN/UP - * instead of SYSKEYDOWN/UP to the WNDPROC */ - else if (test->wVk == VK_RMENU && !(expected->flags & hook) && - (expected->message == WM_SYSKEYDOWN || expected->message == WM_SYSKEYUP) && - (actual->message == expected->message - 4)) - { - ok(expected->wParam == actual->wParam && expected->lParam == actual->lParam, - "%2d (%x/%x): the msg 0x%04x was expected, but got msg 0x%04x instead\n", - id, test->wVk, test->dwFlags, expected->message, actual->message); - } - else if (test->_todo_wine) - { - failcount++; - todo_wine - ok(FALSE, - "%2d (%x/%x): the msg 0x%04x was expected, but got msg 0x%04x instead\n", - id, test->wVk, test->dwFlags, expected->message, actual->message); - } - else - ok(FALSE, - "%2d (%x/%x): the msg 0x%04x was expected, but got msg 0x%04x instead\n", - id, test->wVk, test->dwFlags, expected->message, actual->message); - - actual_cnt++; - expected++; - } - /* skip all optional trailing messages */ - while (expected->message && ((expected->flags & optional) || (!(expected->flags & hook) && !foreground))) - expected++; - - - if (expected->message || actual_cnt < sent_messages_cnt) - { - if (test->_todo_wine) - { - failcount++; - todo_wine - ok(FALSE, "%2d (%x/%x): the msg sequence is not complete: expected %04x - actual %04x\n", - id, test->wVk, test->dwFlags, expected->message, sent_messages[actual_cnt].message); - } - else - ok(FALSE, "%2d (%x/%x): the msg sequence is not complete: expected %04x - actual %04x\n", - id, test->wVk, test->dwFlags, expected->message, sent_messages[actual_cnt].message); - } - - if( test->_todo_wine && !failcount) /* succeeded yet marked todo */ - todo_wine - ok(TRUE, "%2d (%x/%x): marked \"todo_wine\" but succeeds\n", id, test->wVk, test->dwFlags); - - sent_messages_cnt = 0; -} - -/* WndProc2 checks that we get at least the messages specified */ -static LRESULT CALLBACK WndProc2(HWND hWnd, UINT Msg, WPARAM wParam, - LPARAM lParam) -{ - if (winetest_debug > 1) trace("MSG: %8x W:%8lx L:%8lx\n", Msg, wParam, lParam); - - if ((Msg >= WM_KEYFIRST && Msg <= WM_KEYLAST) || Msg == WM_SYSCOMMAND) - { - ok(sent_messages_cnt < MAXKEYMESSAGES, "Too many messages\n"); - if (sent_messages_cnt < MAXKEYMESSAGES) - { - sent_messages[sent_messages_cnt].message = Msg; - sent_messages[sent_messages_cnt].flags = 0; - sent_messages[sent_messages_cnt].wParam = wParam; - sent_messages[sent_messages_cnt++].lParam = HIWORD(lParam) & (KF_UP|KF_EXTENDED); - } - } - return DefWindowProcA(hWnd, Msg, wParam, lParam); -} - -static LRESULT CALLBACK hook_proc(int code, WPARAM wparam, LPARAM lparam) +static LRESULT CALLBACK ll_hook_kbd_proc(int code, WPARAM wparam, LPARAM lparam) { KBDLLHOOKSTRUCT *hook_info = (KBDLLHOOKSTRUCT *)lparam; if (code == HC_ACTION) { - ok(sent_messages_cnt < MAXKEYMESSAGES, "Too many messages\n"); - if (sent_messages_cnt < MAXKEYMESSAGES) - { - sent_messages[sent_messages_cnt].message = wparam; - sent_messages[sent_messages_cnt].flags = hook; - sent_messages[sent_messages_cnt].wParam = hook_info->vkCode; - sent_messages[sent_messages_cnt++].lParam = hook_info->flags & (LLKHF_UP|LLKHF_EXTENDED); - } + append_ll_hook_kbd( wparam, hook_info ); if(0) /* For some reason not stable on Wine */ { if (wparam == WM_KEYDOWN || wparam == WM_SYSKEYDOWN) - ok(!(GetAsyncKeyState(hook_info->vkCode) & 0x8000), "key %x should be up\n", hook_info->vkCode); + ok(!(GetAsyncKeyState(hook_info->vkCode) & 0x8000), "key %lx should be up\n", hook_info->vkCode); else if (wparam == WM_KEYUP || wparam == WM_SYSKEYUP) - ok(GetAsyncKeyState(hook_info->vkCode) & 0x8000, "key %x should be down\n", hook_info->vkCode); + ok(GetAsyncKeyState(hook_info->vkCode) & 0x8000, "key %lx should be down\n", hook_info->vkCode); } if (winetest_debug > 1) - trace("Hook: w=%lx vk:%8x sc:%8x fl:%8x %lx\n", wparam, + trace("Hook: w=%Ix vk:%8lx sc:%8lx fl:%8lx %Ix\n", wparam, hook_info->vkCode, hook_info->scanCode, hook_info->flags, hook_info->dwExtraInfo); } return CallNextHookEx( 0, code, wparam, lparam ); } -static void test_Input_blackbox(void) + +#define check_keyboard_state( a, b ) check_keyboard_state_( __LINE__, a, b ) +static void check_keyboard_state_( int line, const BYTE expect_state[256], const BOOL todo_state[256] ) { - TEST_INPUT i; - int ii; - BYTE ks1[256], ks2[256]; - LONG_PTR prevWndProc; - BOOL foreground; - HWND window; + BYTE state[256]; + UINT i; + + ok_ret( 1, GetKeyboardState( state ) ); + for (i = 0; i < ARRAY_SIZE(state); i++) + { + todo_wine_if( todo_state[i] ) + ok_(__FILE__, line)( (expect_state[i] & 0x80) == (state[i] & 0x80), + "got %s: %#x\n", debugstr_vk( i ), state[i] ); + } +} + +#define check_keyboard_async( a, b ) check_keyboard_async_( __LINE__, a, b ) +static void check_keyboard_async_( int line, const BYTE expect_state[256], const BOOL todo_state[256] ) +{ + UINT i; + + /* TODO: figure out if the async state for vkey 0 provides any information and + * add it to the check. */ + for (i = 1; i < 256; i++) + { + BYTE state = GetAsyncKeyState(i) >> 8; + todo_wine_if( todo_state[i] ) + ok_(__FILE__, line)( (expect_state[i] & 0x80) == (state & 0x80), + "async got %s: %#x\n", debugstr_vk( i ), state ); + } +} + +static void clear_keyboard_state( void ) +{ + static BYTE empty_state[256] = {0}; + INPUT input = {.type = INPUT_KEYBOARD}; + BYTE lock_keys[] = {VK_NUMLOCK, VK_CAPITAL, VK_SCROLL}; + UINT i; + + for (i = 0; i < ARRAY_SIZE(lock_keys); ++i) + { + if (GetKeyState( lock_keys[i] ) & 0x0001) + { + input.ki.wVk = lock_keys[i]; + SendInput( 1, &input, sizeof(input) ); + input.ki.dwFlags = KEYEVENTF_KEYUP; + SendInput( 1, &input, sizeof(input) ); + wait_messages( 5, FALSE ); + memset( current_sequence, 0, sizeof(current_sequence) ); + current_sequence_len = 0; + } + } + + SetKeyboardState( empty_state ); +} + +#define check_send_input_keyboard_test( a, b ) check_send_input_keyboard_test_( a, #a, b ) +static void check_send_input_keyboard_test_( const struct send_input_keyboard_test *test, const char *context, BOOL peeked ) +{ + INPUT input = {.type = INPUT_KEYBOARD}; + UINT i; + + winetest_push_context( "%s", context ); + clear_keyboard_state(); + + for (i = 0; test->vkey || test->scan; i++, test++) + { + winetest_push_context( "%u", i ); + + input.ki.wScan = test->flags & (KEYEVENTF_SCANCODE | KEYEVENTF_UNICODE) ? test->scan : (i + 1); + input.ki.dwFlags = test->flags; + input.ki.wVk = test->vkey; + ok_ret( 1, SendInput( 1, &input, sizeof(input) ) ); + wait_messages( 5, peeked ); + + ok_seq( test->expect ); + check_keyboard_state( test->expect_state, test->todo_state ); + if (test->async) check_keyboard_async( test->expect_async, test->todo_async ); + + winetest_pop_context(); + } + + clear_keyboard_state(); + winetest_pop_context(); +} + +static BOOL accept_keyboard_messages_syscommand( UINT msg ) +{ + return is_keyboard_message( msg ) || msg == WM_SYSCOMMAND; +} + +static BOOL keyboard_layout_has_altgr(void) +{ + typedef struct + { + UINT64 pCharModifiers; + UINT64 pVkToWcharTable; + UINT64 pDeadKey; + UINT64 pKeyNames; + UINT64 pKeyNamesExt; + UINT64 pKeyNamesDead; + UINT64 pusVSCtoVK; + BYTE bMaxVSCtoVK; + UINT64 pVSCtoVK_E0; + UINT64 pVSCtoVK_E1; + DWORD fLocaleFlags; + } KBDTABLES64; + + WCHAR layout_path[MAX_PATH] = {L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\"}, value[MAX_PATH]; + KBDTABLES *(CDECL *pKbdLayerDescriptor)(void); + DWORD value_size = sizeof(value), flags; + KBDTABLES *tables; + HMODULE module; + + ok_ret( 1, GetKeyboardLayoutNameW( layout_path + wcslen(layout_path) ) ); + todo_wine + ok_ret( 0, RegGetValueW( HKEY_LOCAL_MACHINE, layout_path, L"Layout File", RRF_RT_REG_SZ, + NULL, (void *)&value, &value_size) ); + + module = LoadLibraryW( value ); + todo_wine + ok_ne( NULL, module, HMODULE, "%p" ); + pKbdLayerDescriptor = (void *)GetProcAddress( module, "KbdLayerDescriptor" ); + todo_wine + ok_ne( NULL, pKbdLayerDescriptor, void *, "%p" ); + /* FIXME: Wine doesn't implement ALTGR behavior */ + if (!pKbdLayerDescriptor) return FALSE; + tables = pKbdLayerDescriptor(); + ok_ne( NULL, tables, KBDTABLES *, "%p" ); + flags = is_wow64 ? ((KBDTABLES64 *)tables)->fLocaleFlags : tables->fLocaleFlags; + ok_ret( 1, FreeLibrary( module ) ); + + trace( "%s flags %#lx\n", debugstr_w(value), flags ); + return !!(flags & KLLF_ALTGR); +} + +static void get_test_scan( WORD vkey, WORD *scan, WCHAR *wch, WCHAR *wch_shift ) +{ + HKL hkl = GetKeyboardLayout( 0 ); + BYTE state[256] = {0}; + + *scan = MapVirtualKeyExW( vkey, MAPVK_VK_TO_VSC_EX, hkl ); + ok_ne( 0, *scan, WORD, "%#x" ); + ok_ret( 1, ToUnicodeEx( vkey, *scan, state, wch, 1, 0, hkl ) ); + state[VK_SHIFT] = 0x80; + ok_ret( 1, ToUnicodeEx( vkey, *scan, state, wch_shift, 1, 0, hkl ) ); +} + +static void test_SendInput_keyboard_messages( WORD vkey, WORD scan, WCHAR wch, WCHAR wch_shift, WCHAR wch_control, HKL hkl ) +{ +#define WIN_MSG(m, w, l, ...) {.func = MSG_TEST_WIN, .message = {.msg = m, .wparam = w, .lparam = l}, ## __VA_ARGS__} +#define KBD_HOOK(m, s, v, f, ...) {.func = LL_HOOK_KEYBD, .ll_hook_kbd = {.msg = m, .scan = s, .vkey = v, .flags = f}, ## __VA_ARGS__} + +#define KEY_HOOK_(m, s, v, f, ...) KBD_HOOK( m, s, v, LLKHF_INJECTED | (m == WM_KEYUP || m == WM_SYSKEYUP ? LLKHF_UP : 0) | (f), ## __VA_ARGS__ ) +#define KEY_HOOK(m, s, v, ...) KEY_HOOK_( m, s, v, 0, ## __VA_ARGS__ ) + +#define KEY_MSG_(m, s, v, f, ...) WIN_MSG( m, v, MAKELONG(1, (s) | (m == WM_KEYUP || m == WM_SYSKEYUP ? (KF_UP | KF_REPEAT) : 0) | (f)), ## __VA_ARGS__ ) +#define KEY_MSG(m, s, v, ...) KEY_MSG_( m, s, v, 0, ## __VA_ARGS__ ) + + struct send_input_keyboard_test lmenu_vkey[] = + { + {.vkey = VK_LMENU, .expect_state = {[VK_MENU] = 0x80, [VK_LMENU] = 0x80}, + .expect = {KEY_HOOK_(WM_SYSKEYDOWN, 1, VK_LMENU, LLKHF_ALTDOWN, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYDOWN, 1, VK_MENU, KF_ALTDOWN), {0}}}, + { + .vkey = vkey, .expect_state = {[VK_MENU] = 0x80, [VK_LMENU] = 0x80, /*[vkey] = 0x80*/}, + .expect = + { + KEY_HOOK_(WM_SYSKEYDOWN, 2, vkey, LLKHF_ALTDOWN, .todo_value = TRUE), + KEY_MSG_(WM_SYSKEYDOWN, 2, vkey, KF_ALTDOWN), + WIN_MSG(WM_SYSCHAR, wch, MAKELONG(1, 2|KF_ALTDOWN)), + WIN_MSG(WM_SYSCOMMAND, SC_KEYMENU, wch), + {0} + } + }, + {.vkey = vkey, .flags = KEYEVENTF_KEYUP, .expect_state = {[VK_MENU] = 0x80, [VK_LMENU] = 0x80}, + .expect = {KEY_HOOK_(WM_SYSKEYUP, 3, vkey, LLKHF_ALTDOWN, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYUP, 3, vkey, KF_ALTDOWN), {0}}}, + {.vkey = VK_LMENU, .flags = KEYEVENTF_KEYUP, + .expect = {KEY_HOOK(WM_KEYUP, 4, VK_LMENU), KEY_MSG(WM_KEYUP, 4, VK_MENU), {0}}}, + {0}, + }; + + struct send_input_keyboard_test lmenu_vkey_peeked[] = + { + {.vkey = VK_LMENU, .expect_state = {[VK_MENU] = 0x80, [VK_LMENU] = 0x80}, + .expect = {KEY_HOOK_(WM_SYSKEYDOWN, 1, VK_LMENU, LLKHF_ALTDOWN, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYDOWN, 1, VK_MENU, KF_ALTDOWN), {0}}}, + { + .vkey = vkey, .expect_state = {[VK_MENU] = 0x80, [VK_LMENU] = 0x80, /*[vkey] = 0x80*/}, + .expect = + { + KEY_HOOK_(WM_SYSKEYDOWN, 2, vkey, LLKHF_ALTDOWN, .todo_value = TRUE), + KEY_MSG_(WM_SYSKEYDOWN, 2, vkey, KF_ALTDOWN), + WIN_MSG(WM_SYSCHAR, wch, MAKELONG(1, 2|KF_ALTDOWN)), + {0} + } + }, + {.vkey = vkey, .flags = KEYEVENTF_KEYUP, .expect_state = {[VK_MENU] = 0x80, [VK_LMENU] = 0x80}, + .expect = {KEY_HOOK_(WM_SYSKEYUP, 3, vkey, LLKHF_ALTDOWN, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYUP, 3, vkey, KF_ALTDOWN), {0}}}, + {.vkey = VK_LMENU, .flags = KEYEVENTF_KEYUP, + .expect = {KEY_HOOK(WM_KEYUP, 4, VK_LMENU), KEY_MSG(WM_KEYUP, 4, VK_MENU), {0}}}, + {0}, + }; + + struct send_input_keyboard_test lcontrol_vkey[] = + { + {.vkey = VK_LCONTROL, .expect_state = {[VK_CONTROL] = 0x80, [VK_LCONTROL] = 0x80}, + .expect = {KEY_HOOK(WM_KEYDOWN, 1, VK_LCONTROL), KEY_MSG(WM_KEYDOWN, 1, VK_CONTROL), {0}}}, + {.vkey = vkey, .expect_state = {[VK_CONTROL] = 0x80, [VK_LCONTROL] = 0x80, /*[vkey] = 0x80*/}, + .expect = {KEY_HOOK(WM_KEYDOWN, 2, vkey), KEY_MSG(WM_KEYDOWN, 2, vkey), WIN_MSG(WM_CHAR, wch_control, MAKELONG(1, 2)), {0}}}, + {.vkey = vkey, .flags = KEYEVENTF_KEYUP, .expect_state = {[VK_CONTROL] = 0x80, [VK_LCONTROL] = 0x80}, + .expect = {KEY_HOOK(WM_KEYUP, 3, vkey), KEY_MSG(WM_KEYUP, 3, vkey), {0}}}, + {.vkey = VK_LCONTROL, .flags = KEYEVENTF_KEYUP, + .expect = {KEY_HOOK(WM_KEYUP, 4, VK_LCONTROL), KEY_MSG(WM_KEYUP, 4, VK_CONTROL), {0}}}, + {0}, + }; + + struct send_input_keyboard_test lmenu_lcontrol_vkey[] = + { + {.vkey = VK_LMENU, .expect_state = {[VK_MENU] = 0x80, [VK_LMENU] = 0x80}, + .expect = {KEY_HOOK_(WM_SYSKEYDOWN, 1, VK_LMENU, LLKHF_ALTDOWN, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYDOWN, 1, VK_MENU, KF_ALTDOWN), {0}}}, + {.vkey = VK_LCONTROL, .expect_state = {[VK_MENU] = 0x80, [VK_LMENU] = 0x80, [VK_CONTROL] = 0x80, [VK_LCONTROL] = 0x80}, + .expect = {KEY_HOOK(WM_KEYDOWN, 2, VK_LCONTROL), KEY_MSG_(WM_KEYDOWN, 2, VK_CONTROL, KF_ALTDOWN), {0}}}, + {.vkey = vkey, .expect_state = {[VK_MENU] = 0x80, [VK_LMENU] = 0x80, [VK_CONTROL] = 0x80, [VK_LCONTROL] = 0x80, /*[vkey] = 0x80*/}, + .expect = {KEY_HOOK(WM_KEYDOWN, 3, vkey), KEY_MSG_(WM_KEYDOWN, 3, vkey, KF_ALTDOWN), {0}}}, + {.vkey = vkey, .flags = KEYEVENTF_KEYUP, .expect_state = {[VK_MENU] = 0x80, [VK_LMENU] = 0x80, [VK_CONTROL] = 0x80, [VK_LCONTROL] = 0x80}, + .expect = {KEY_HOOK(WM_KEYUP, 4, vkey), KEY_MSG_(WM_KEYUP, 4, vkey, KF_ALTDOWN), {0}}}, + {.vkey = VK_LCONTROL, .flags = KEYEVENTF_KEYUP, .expect_state = {[VK_MENU] = 0x80, [VK_LMENU] = 0x80}, + .expect = {KEY_HOOK_(WM_SYSKEYUP, 5, VK_LCONTROL, LLKHF_ALTDOWN, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYUP, 5, VK_CONTROL, KF_ALTDOWN), {0}}}, + {.vkey = VK_LMENU, .flags = KEYEVENTF_KEYUP, + .expect = {KEY_HOOK(WM_KEYUP, 6, VK_LMENU), KEY_MSG(WM_KEYUP, 6, VK_MENU), {0}}}, + {0}, + }; + + struct send_input_keyboard_test shift_vkey[] = + { + {.vkey = VK_LSHIFT, .expect_state = {[VK_SHIFT] = 0x80, [VK_LSHIFT] = 0x80}, + .expect = {KEY_HOOK(WM_KEYDOWN, 1, VK_LSHIFT), KEY_MSG(WM_KEYDOWN, 1, VK_SHIFT), {0}}}, + {.vkey = vkey, .expect_state = {[VK_SHIFT] = 0x80, [VK_LSHIFT] = 0x80, /*[vkey] = 0x80*/}, + .expect = {KEY_HOOK(WM_KEYDOWN, 2, vkey), KEY_MSG(WM_KEYDOWN, 2, vkey), WIN_MSG(WM_CHAR, wch_shift, MAKELONG(1, 2)), {0}}}, + {.vkey = vkey, .flags = KEYEVENTF_KEYUP, .expect_state = {[VK_SHIFT] = 0x80, [VK_LSHIFT] = 0x80}, + .expect = {KEY_HOOK(WM_KEYUP, 3, vkey), KEY_MSG(WM_KEYUP, 3, vkey), {0}}}, + {.vkey = VK_LSHIFT, .flags = KEYEVENTF_KEYUP, + .expect = {KEY_HOOK(WM_KEYUP, 4, VK_LSHIFT), KEY_MSG(WM_KEYUP, 4, VK_SHIFT), {0}}}, + {0}, + }; + + static const struct send_input_keyboard_test rshift[] = + { + {.vkey = VK_RSHIFT, .expect_state = {[VK_SHIFT] = 0x80, [VK_RSHIFT] = 0x80}, .todo_state = {[VK_RSHIFT] = TRUE, [VK_LSHIFT] = TRUE}, + .expect = {KEY_HOOK_(WM_KEYDOWN, 1, VK_RSHIFT, LLKHF_EXTENDED, .todo_value = TRUE), KEY_MSG(WM_KEYDOWN, 1, VK_SHIFT), {0}}}, + {.vkey = VK_RSHIFT, .flags = KEYEVENTF_KEYUP, .expect_state = {0}, + .expect = {KEY_HOOK_(WM_KEYUP, 2, VK_RSHIFT, LLKHF_EXTENDED, .todo_value = TRUE), KEY_MSG(WM_KEYUP, 2, VK_SHIFT), {0}}}, + {0}, + }; + static const struct send_input_keyboard_test lshift_ext[] = + { + {.vkey = VK_LSHIFT, .flags = KEYEVENTF_EXTENDEDKEY, .expect_state = {[VK_SHIFT] = 0x80, [VK_RSHIFT] = 0x80}, + .expect = {KEY_HOOK_(WM_KEYDOWN, 1, VK_LSHIFT, LLKHF_EXTENDED), KEY_MSG(WM_KEYDOWN, 1, VK_SHIFT), {0}}}, + {.vkey = VK_LSHIFT, .flags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, + .expect = {KEY_HOOK_(WM_KEYUP, 2, VK_LSHIFT, LLKHF_EXTENDED), KEY_MSG(WM_KEYUP, 2, VK_SHIFT), {0}}}, + {0}, + }; + static const struct send_input_keyboard_test rshift_ext[] = + { + {.vkey = VK_RSHIFT, .flags = KEYEVENTF_EXTENDEDKEY, .expect_state = {[VK_SHIFT] = 0x80, [VK_RSHIFT] = 0x80}, + .expect = {KEY_HOOK_(WM_KEYDOWN, 1, VK_RSHIFT, LLKHF_EXTENDED), KEY_MSG(WM_KEYDOWN, 1, VK_SHIFT), {0}}}, + {.vkey = VK_RSHIFT, .flags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, .expect_state = {0}, + .expect = {KEY_HOOK_(WM_KEYUP, 2, VK_RSHIFT, LLKHF_EXTENDED), KEY_MSG(WM_KEYUP, 2, VK_SHIFT), {0}}}, + {0}, + }; + static const struct send_input_keyboard_test shift[] = + { + {.vkey = VK_SHIFT, .expect_state = {[VK_SHIFT] = 0x80, [VK_LSHIFT] = 0x80}, + .expect = {KEY_HOOK(WM_KEYDOWN, 1, VK_LSHIFT), KEY_MSG(WM_KEYDOWN, 1, VK_SHIFT), {0}}}, + {.vkey = VK_SHIFT, .flags = KEYEVENTF_KEYUP, + .expect = {KEY_HOOK(WM_KEYUP, 2, VK_LSHIFT), KEY_MSG(WM_KEYUP, 2, VK_SHIFT), {0}}}, + {0}, + }; + static const struct send_input_keyboard_test shift_ext[] = + { + {.vkey = VK_SHIFT, .flags = KEYEVENTF_EXTENDEDKEY, .expect_state = {[VK_SHIFT] = 0x80, [VK_RSHIFT] = 0x80}, + .expect = {KEY_HOOK_(WM_KEYDOWN, 1, VK_LSHIFT, LLKHF_EXTENDED, .todo_value = TRUE), KEY_MSG(WM_KEYDOWN, 1, VK_SHIFT), {0}}}, + {.vkey = VK_SHIFT, .flags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, + .expect = {KEY_HOOK_(WM_KEYUP, 2, VK_LSHIFT, LLKHF_EXTENDED, .todo_value = TRUE), KEY_MSG(WM_KEYUP, 2, VK_SHIFT), {0}}}, + {0}, + }; + + static const struct send_input_keyboard_test rcontrol[] = + { + {.vkey = VK_RCONTROL, .expect_state = {[VK_CONTROL] = 0x80, [VK_LCONTROL] = 0x80}, + .expect = {KEY_HOOK(WM_KEYDOWN, 1, VK_RCONTROL), KEY_MSG(WM_KEYDOWN, 1, VK_CONTROL), {0}}}, + {.vkey = VK_RCONTROL, .flags = KEYEVENTF_KEYUP, + .expect = {KEY_HOOK(WM_KEYUP, 2, VK_RCONTROL), KEY_MSG(WM_KEYUP, 2, VK_CONTROL), {0}}}, + {0}, + }; + static const struct send_input_keyboard_test lcontrol_ext[] = + { + {.vkey = VK_LCONTROL, .flags = KEYEVENTF_EXTENDEDKEY, .expect_state = {[VK_CONTROL] = 0x80, [VK_RCONTROL] = 0x80}, + .expect = {KEY_HOOK_(WM_KEYDOWN, 1, VK_LCONTROL, LLKHF_EXTENDED), KEY_MSG_(WM_KEYDOWN, 1, VK_CONTROL, KF_EXTENDED), {0}}}, + {.vkey = VK_LCONTROL, .flags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, + .expect = {KEY_HOOK_(WM_KEYUP, 2, VK_LCONTROL, LLKHF_EXTENDED), KEY_MSG_(WM_KEYUP, 2, VK_CONTROL, KF_EXTENDED), {0}}}, + {0}, + }; + static const struct send_input_keyboard_test rcontrol_ext[] = + { + {.vkey = VK_RCONTROL, .flags = KEYEVENTF_EXTENDEDKEY, .expect_state = {[VK_CONTROL] = 0x80, [VK_RCONTROL] = 0x80}, + .expect = {KEY_HOOK_(WM_KEYDOWN, 1, VK_RCONTROL, LLKHF_EXTENDED), KEY_MSG_(WM_KEYDOWN, 1, VK_CONTROL, KF_EXTENDED), {0}}}, + {.vkey = VK_RCONTROL, .flags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, + .expect = {KEY_HOOK_(WM_KEYUP, 2, VK_RCONTROL, LLKHF_EXTENDED), KEY_MSG_(WM_KEYUP, 2, VK_CONTROL, KF_EXTENDED), {0}}}, + {0}, + }; + static const struct send_input_keyboard_test control[] = + { + {.vkey = VK_CONTROL, .expect_state = {[VK_CONTROL] = 0x80, [VK_LCONTROL] = 0x80}, + .expect = {KEY_HOOK(WM_KEYDOWN, 1, VK_LCONTROL), KEY_MSG(WM_KEYDOWN, 1, VK_CONTROL), {0}}}, + {.vkey = VK_CONTROL, .flags = KEYEVENTF_KEYUP, .expect_state = {0}, + .expect = {KEY_HOOK(WM_KEYUP, 2, VK_LCONTROL), KEY_MSG(WM_KEYUP, 2, VK_CONTROL), {0}}}, + {0}, + }; + static const struct send_input_keyboard_test control_ext[] = + { + {.vkey = VK_CONTROL, .flags = KEYEVENTF_EXTENDEDKEY, .expect_state = {[VK_CONTROL] = 0x80, [VK_RCONTROL] = 0x80}, + .expect = {KEY_HOOK_(WM_KEYDOWN, 1, VK_RCONTROL, LLKHF_EXTENDED), KEY_MSG_(WM_KEYDOWN, 1, VK_CONTROL, KF_EXTENDED), {0}}}, + {.vkey = VK_CONTROL, .flags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, + .expect = {KEY_HOOK_(WM_KEYUP, 2, VK_RCONTROL, LLKHF_EXTENDED), KEY_MSG_(WM_KEYUP, 2, VK_CONTROL, KF_EXTENDED), {0}}}, + {0}, + }; + + static const struct send_input_keyboard_test rmenu[] = + { + {.vkey = VK_RMENU, .expect_state = {[VK_MENU] = 0x80, [VK_LMENU] = 0x80}, + .expect = {KEY_HOOK_(WM_SYSKEYDOWN, 1, VK_RMENU, LLKHF_ALTDOWN, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYDOWN, 1, VK_MENU, KF_ALTDOWN), {0}}}, + {.vkey = VK_RMENU, .flags = KEYEVENTF_KEYUP, + .expect = {KEY_HOOK(WM_KEYUP, 2, VK_RMENU, .todo_value = TRUE), KEY_MSG(WM_SYSKEYUP, 2, VK_MENU), WIN_MSG(WM_SYSCOMMAND, SC_KEYMENU, 0), {0}}}, + {0}, + }; + static const struct send_input_keyboard_test lmenu_ext[] = + { + {.vkey = VK_LMENU, .flags = KEYEVENTF_EXTENDEDKEY, .expect_state = {[VK_MENU] = 0x80, [VK_RMENU] = 0x80}, + .expect = {KEY_HOOK_(WM_SYSKEYDOWN, 1, VK_LMENU, LLKHF_ALTDOWN|LLKHF_EXTENDED, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYDOWN, 1, VK_MENU, KF_ALTDOWN|KF_EXTENDED), {0}}}, + {.vkey = VK_LMENU, .flags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, + .expect = {KEY_HOOK_(WM_KEYUP, 2, VK_LMENU, LLKHF_EXTENDED, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYUP, 2, VK_MENU, KF_EXTENDED), WIN_MSG(WM_SYSCOMMAND, SC_KEYMENU, 0), {0}}}, + {0}, + }; + static const struct send_input_keyboard_test rmenu_ext[] = + { + {.vkey = VK_RMENU, .flags = KEYEVENTF_EXTENDEDKEY, .expect_state = {[VK_MENU] = 0x80, [VK_RMENU] = 0x80}, + .expect = {KEY_HOOK_(WM_SYSKEYDOWN, 1, VK_RMENU, LLKHF_ALTDOWN|LLKHF_EXTENDED, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYDOWN, 1, VK_MENU, KF_ALTDOWN|KF_EXTENDED), {0}}}, + {.vkey = VK_RMENU, .flags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, + .expect = {KEY_HOOK_(WM_KEYUP, 2, VK_RMENU, LLKHF_EXTENDED, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYUP, 2, VK_MENU, KF_EXTENDED), WIN_MSG(WM_SYSCOMMAND, SC_KEYMENU, 0), {0}}}, + {0}, + }; + static const struct send_input_keyboard_test menu[] = + { + {.vkey = VK_MENU, .expect_state = {[VK_MENU] = 0x80, [VK_LMENU] = 0x80}, + .expect = {KEY_HOOK_(WM_SYSKEYDOWN, 1, VK_LMENU, LLKHF_ALTDOWN, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYDOWN, 1, VK_MENU, KF_ALTDOWN), {0}}}, + {.vkey = VK_MENU, .flags = KEYEVENTF_KEYUP, .expect_state = {0}, + .expect = {KEY_HOOK(WM_KEYUP, 2, VK_LMENU, .todo_value = TRUE), KEY_MSG(WM_SYSKEYUP, 2, VK_MENU), WIN_MSG(WM_SYSCOMMAND, SC_KEYMENU, 0), {0}}}, + {0}, + }; + static const struct send_input_keyboard_test menu_ext[] = + { + {.vkey = VK_MENU, .flags = KEYEVENTF_EXTENDEDKEY, .expect_state = {[VK_MENU] = 0x80, [VK_RMENU] = 0x80}, + .expect = {KEY_HOOK_(WM_SYSKEYDOWN, 1, VK_RMENU, LLKHF_ALTDOWN|LLKHF_EXTENDED, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYDOWN, 1, VK_MENU, KF_ALTDOWN|KF_EXTENDED), {0}}}, + {.vkey = VK_MENU, .flags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, + .expect = {KEY_HOOK_(WM_KEYUP, 2, VK_RMENU, LLKHF_EXTENDED, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYUP, 2, VK_MENU, KF_EXTENDED), WIN_MSG(WM_SYSCOMMAND, SC_KEYMENU, 0), {0}}}, + {0}, + }; + + static const struct send_input_keyboard_test rmenu_peeked[] = + { + {.vkey = VK_RMENU, .expect_state = {[VK_MENU] = 0x80, [VK_LMENU] = 0x80}, + .expect = {KEY_HOOK_(WM_SYSKEYDOWN, 1, VK_RMENU, LLKHF_ALTDOWN, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYDOWN, 1, VK_MENU, KF_ALTDOWN), {0}}}, + {.vkey = VK_RMENU, .flags = KEYEVENTF_KEYUP, + .expect = {KEY_HOOK(WM_KEYUP, 2, VK_RMENU, .todo_value = TRUE), KEY_MSG(WM_SYSKEYUP, 2, VK_MENU), {0}}}, + {0}, + }; + static const struct send_input_keyboard_test lmenu_ext_peeked[] = + { + {.vkey = VK_LMENU, .flags = KEYEVENTF_EXTENDEDKEY, .expect_state = {[VK_MENU] = 0x80, [VK_RMENU] = 0x80}, + .expect = {KEY_HOOK_(WM_SYSKEYDOWN, 1, VK_LMENU, LLKHF_ALTDOWN|LLKHF_EXTENDED, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYDOWN, 1, VK_MENU, KF_ALTDOWN|KF_EXTENDED), {0}}}, + {.vkey = VK_LMENU, .flags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, + .expect = {KEY_HOOK_(WM_KEYUP, 2, VK_LMENU, LLKHF_EXTENDED, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYUP, 2, VK_MENU, KF_EXTENDED), {0}}}, + {0}, + }; + static const struct send_input_keyboard_test rmenu_ext_peeked[] = + { + {.vkey = VK_RMENU, .flags = KEYEVENTF_EXTENDEDKEY, .expect_state = {[VK_MENU] = 0x80, [VK_RMENU] = 0x80}, + .expect = {KEY_HOOK_(WM_SYSKEYDOWN, 1, VK_RMENU, LLKHF_ALTDOWN|LLKHF_EXTENDED, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYDOWN, 1, VK_MENU, KF_ALTDOWN|KF_EXTENDED), {0}}}, + {.vkey = VK_RMENU, .flags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, + .expect = {KEY_HOOK_(WM_KEYUP, 2, VK_RMENU, LLKHF_EXTENDED, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYUP, 2, VK_MENU, KF_EXTENDED), {0}}}, + {0}, + }; + static const struct send_input_keyboard_test menu_peeked[] = + { + {.vkey = VK_MENU, .expect_state = {[VK_MENU] = 0x80, [VK_LMENU] = 0x80}, + .expect = {KEY_HOOK_(WM_SYSKEYDOWN, 1, VK_LMENU, LLKHF_ALTDOWN, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYDOWN, 1, VK_MENU, KF_ALTDOWN), {0}}}, + {.vkey = VK_MENU, .flags = KEYEVENTF_KEYUP, .expect_state = {0}, + .expect = {KEY_HOOK(WM_KEYUP, 2, VK_LMENU, .todo_value = TRUE), KEY_MSG(WM_SYSKEYUP, 2, VK_MENU), {0}}}, + {0}, + }; + static const struct send_input_keyboard_test menu_ext_peeked[] = + { + {.vkey = VK_MENU, .flags = KEYEVENTF_EXTENDEDKEY, .expect_state = {[VK_MENU] = 0x80, [VK_RMENU] = 0x80}, + .expect = {KEY_HOOK_(WM_SYSKEYDOWN, 1, VK_RMENU, LLKHF_ALTDOWN|LLKHF_EXTENDED, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYDOWN, 1, VK_MENU, KF_ALTDOWN|KF_EXTENDED), {0}}}, + {.vkey = VK_MENU, .flags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, + .expect = {KEY_HOOK_(WM_KEYUP, 2, VK_RMENU, LLKHF_EXTENDED, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYUP, 2, VK_MENU, KF_EXTENDED), {0}}}, + {0}, + }; + + struct send_input_keyboard_test rmenu_altgr[] = + { + { + .vkey = VK_RMENU, .expect_state = {[VK_MENU] = 0x80, [VK_LMENU] = 0x80, [VK_CONTROL] = 0x80, [VK_LCONTROL] = 0x80}, + .expect = + { + KEY_HOOK_(WM_SYSKEYDOWN, 0x21d, VK_LCONTROL, LLKHF_ALTDOWN), + KEY_HOOK_(WM_SYSKEYDOWN, 1, VK_RMENU, LLKHF_ALTDOWN, .todo_value = TRUE), + KEY_MSG(WM_KEYDOWN, 0x1d, VK_CONTROL), + KEY_MSG_(WM_KEYDOWN, 1, VK_MENU, KF_ALTDOWN), + {0} + } + }, + { + .vkey = VK_RMENU, .flags = KEYEVENTF_KEYUP, + .expect = + { + KEY_HOOK(WM_KEYUP, 0x21d, VK_LCONTROL), + KEY_HOOK(WM_KEYUP, 2, VK_RMENU), + KEY_MSG_(WM_SYSKEYUP, 0x1d, VK_CONTROL, KF_ALTDOWN), + KEY_MSG(WM_KEYUP, 2, VK_MENU), + {0} + } + }, + {0}, + }; + struct send_input_keyboard_test rmenu_ext_altgr[] = + { + { + .vkey = VK_RMENU, .flags = KEYEVENTF_EXTENDEDKEY, .expect_state = {[VK_MENU] = 0x80, [VK_RMENU] = 0x80, [VK_CONTROL] = 0x80, [VK_LCONTROL] = 0x80}, + .expect = + { + KEY_HOOK_(WM_SYSKEYDOWN, 0x21d, VK_LCONTROL, LLKHF_ALTDOWN), + KEY_HOOK_(WM_SYSKEYDOWN, 1, VK_RMENU, LLKHF_ALTDOWN|LLKHF_EXTENDED, .todo_value = TRUE), + KEY_MSG(WM_KEYDOWN, 0x1d, VK_CONTROL), + KEY_MSG_(WM_KEYDOWN, 1, VK_MENU, KF_ALTDOWN|KF_EXTENDED), + {0} + } + }, + { + .vkey = VK_RMENU, .flags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, + .expect = + { + KEY_HOOK(WM_KEYUP, 0x21d, VK_LCONTROL), + KEY_HOOK_(WM_KEYUP, 2, VK_RMENU, LLKHF_EXTENDED, .todo_value = TRUE), + KEY_MSG_(WM_SYSKEYUP, 0x1d, VK_CONTROL, KF_ALTDOWN), + KEY_MSG_(WM_KEYUP, 2, VK_MENU, KF_EXTENDED), + {0} + } + }, + {0}, + }; + struct send_input_keyboard_test menu_ext_altgr[] = + { + { + .vkey = VK_MENU, .flags = KEYEVENTF_EXTENDEDKEY, .expect_state = {[VK_MENU] = 0x80, [VK_RMENU] = 0x80, [VK_CONTROL] = 0x80, [VK_LCONTROL] = 0x80}, + .expect = + { + KEY_HOOK_(WM_SYSKEYDOWN, 0x21d, VK_LCONTROL, LLKHF_ALTDOWN), + KEY_HOOK_(WM_SYSKEYDOWN, 1, VK_RMENU, LLKHF_ALTDOWN|LLKHF_EXTENDED, .todo_value = TRUE), + KEY_MSG(WM_KEYDOWN, 0x1d, VK_CONTROL), + KEY_MSG_(WM_KEYDOWN, 1, VK_MENU, KF_ALTDOWN|KF_EXTENDED), + {0} + } + }, + { + .vkey = VK_MENU, .flags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, + .expect = + { + KEY_HOOK(WM_KEYUP, 0x21d, VK_LCONTROL), + KEY_HOOK_(WM_KEYUP, 2, VK_RMENU, LLKHF_EXTENDED, .todo_value = TRUE), + KEY_MSG_(WM_SYSKEYUP, 0x1d, VK_CONTROL, KF_ALTDOWN), + KEY_MSG_(WM_KEYUP, 2, VK_MENU, KF_EXTENDED), + {0} + } + }, + {0}, + }; + + static const struct send_input_keyboard_test lrshift_ext[] = + { + {.vkey = VK_LSHIFT, .expect_state = {[VK_SHIFT] = 0x80, [VK_LSHIFT] = 0x80}, + .expect = {KEY_HOOK(WM_KEYDOWN, 1, VK_LSHIFT), KEY_MSG(WM_KEYDOWN, 1, VK_SHIFT), {0}}}, + {.vkey = VK_RSHIFT, .flags = KEYEVENTF_EXTENDEDKEY, .expect_state = {[VK_SHIFT] = 0x80, [VK_LSHIFT] = 0x80, [VK_RSHIFT] = 0x80}, + .expect = {KEY_HOOK_(WM_KEYDOWN, 2, VK_RSHIFT, LLKHF_EXTENDED), KEY_MSG_(WM_KEYDOWN, 2, VK_SHIFT, KF_REPEAT, .todo_value = TRUE), {0}}}, + {.vkey = VK_RSHIFT, .flags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, .expect_state = {[VK_SHIFT] = 0x80, [VK_LSHIFT] = 0x80}, + .expect = {KEY_HOOK_(WM_KEYUP, 3, VK_RSHIFT, LLKHF_EXTENDED), {0, .todo = TRUE}, {0}}}, + {.vkey = VK_LSHIFT, .flags = KEYEVENTF_KEYUP, + .expect = {KEY_HOOK(WM_KEYUP, 4, VK_LSHIFT), KEY_MSG(WM_KEYUP, 4, VK_SHIFT), {0}}}, + {0}, + }; + + struct send_input_keyboard_test rshift_scan[] = + { + {.scan = 0x36, .flags = KEYEVENTF_SCANCODE, .expect_state = {[VK_SHIFT] = 0x80, [VK_LSHIFT] = 0x80}, + .expect = {KEY_HOOK(WM_KEYDOWN, 0x36, VK_RSHIFT), KEY_MSG(WM_KEYDOWN, 0x36, VK_SHIFT), {0}}}, + {.scan = scan, .flags = KEYEVENTF_SCANCODE, .expect_state = {[VK_SHIFT] = 0x80, [VK_LSHIFT] = 0x80, /*[vkey] = 0x80*/}, + .expect = {KEY_HOOK(WM_KEYDOWN, scan, vkey), KEY_MSG(WM_KEYDOWN, scan, vkey), WIN_MSG(WM_CHAR, wch_shift, MAKELONG(1, scan)), {0}}}, + {.scan = scan, .flags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP, .expect_state = {[VK_SHIFT] = 0x80, [VK_LSHIFT] = 0x80}, + .expect = {KEY_HOOK(WM_KEYUP, scan, vkey), KEY_MSG(WM_KEYUP, scan, vkey), {0}}}, + {.scan = 0x36, .flags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP, + .expect = {KEY_HOOK(WM_KEYUP, 0x36, VK_RSHIFT), KEY_MSG(WM_KEYUP, 0x36, VK_SHIFT), {0}}}, + {0}, + }; + + struct send_input_keyboard_test rctrl_scan[] = + { + {.scan = 0xe01d, .flags = KEYEVENTF_SCANCODE, .expect_state = {[VK_CONTROL] = 0x80, [VK_LCONTROL] = 0x80}, + .expect = {KEY_HOOK(WM_KEYDOWN, 0x1d, VK_LCONTROL), KEY_MSG(WM_KEYDOWN, 0x1d, VK_CONTROL), {0}}}, + {.scan = 0xe01d, .flags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP, + .expect = {KEY_HOOK(WM_KEYUP, 0x1d, VK_LCONTROL), KEY_MSG(WM_KEYUP, 0x1d, VK_CONTROL), {0}}}, + {.scan = 0x1d, .flags = KEYEVENTF_SCANCODE | KEYEVENTF_EXTENDEDKEY, .expect_state = {[VK_CONTROL] = 0x80, [VK_RCONTROL] = 0x80}, + .expect = {KEY_HOOK_(WM_KEYDOWN, 0x1d, VK_RCONTROL, LLKHF_EXTENDED, .todo_value = TRUE), KEY_MSG(WM_KEYDOWN, 0x11d, VK_CONTROL), {0}}}, + {.scan = 0x1d, .flags = KEYEVENTF_SCANCODE | KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, + .expect = {KEY_HOOK_(WM_KEYUP, 0x1d, VK_RCONTROL, LLKHF_EXTENDED, .todo_value = TRUE), KEY_MSG(WM_KEYUP, 0x11d, VK_CONTROL), {0}}}, + {0}, + }; + + struct send_input_keyboard_test unicode[] = + { + {.scan = 0x3c0, .flags = KEYEVENTF_UNICODE, .expect_state = {[VK_PACKET] = 0x80}, + .expect = {KEY_HOOK(WM_KEYDOWN, 0x3c0, VK_PACKET), KEY_MSG(WM_KEYDOWN, 0, VK_PACKET, .todo_value = TRUE), WIN_MSG(WM_CHAR, 0x3c0, 1), {0}}}, + {.scan = 0x3c0, .flags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP, + .expect = {KEY_HOOK(WM_KEYUP, 0x3c0, VK_PACKET, .todo_value = TRUE), KEY_MSG(WM_KEYUP, 0, VK_PACKET, .todo_value = TRUE), {0}}}, + {0}, + }; + + struct send_input_keyboard_test lmenu_unicode[] = + { + {.vkey = VK_LMENU, .expect_state = {[VK_MENU] = 0x80, [VK_LMENU] = 0x80}, + .expect = {KEY_HOOK_(WM_SYSKEYDOWN, 1, VK_LMENU, LLKHF_ALTDOWN, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYDOWN, 1, VK_MENU, KF_ALTDOWN), {0}}}, + { + .scan = 0x3c0, .flags = KEYEVENTF_UNICODE, .expect_state = {[VK_MENU] = 0x80, [VK_LMENU] = 0x80, [VK_PACKET] = 0x80}, + .expect = + { + KEY_HOOK_(WM_SYSKEYDOWN, 0x3c0, VK_PACKET, LLKHF_ALTDOWN, .todo_value = TRUE), + KEY_MSG_(WM_SYSKEYDOWN, 0, VK_PACKET, KF_ALTDOWN, .todo_value = TRUE), + WIN_MSG(WM_SYSCHAR, 0x3c0, MAKELONG(1, KF_ALTDOWN), .todo_value = TRUE), + WIN_MSG(WM_SYSCOMMAND, SC_KEYMENU, 0x3c0, .todo = TRUE), + {0}, + }, + }, + {.scan = 0x3c0, .flags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP, .expect_state = {[VK_MENU] = 0x80, [VK_LMENU] = 0x80}, + .expect = {KEY_HOOK_(WM_SYSKEYUP, 0x3c0, VK_PACKET, LLKHF_ALTDOWN, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYUP, 0, VK_PACKET, KF_ALTDOWN, .todo_value = TRUE), {0}}}, + {.vkey = VK_LMENU, .flags = KEYEVENTF_KEYUP, + .expect = {KEY_HOOK(WM_KEYUP, 4, VK_LMENU), KEY_MSG(WM_KEYUP, 4, VK_MENU), {0}}}, + {0}, + }; + struct send_input_keyboard_test lmenu_unicode_peeked[] = + { + {.vkey = VK_LMENU, .expect_state = {[VK_MENU] = 0x80, [VK_LMENU] = 0x80}, + .expect = {KEY_HOOK_(WM_SYSKEYDOWN, 1, VK_LMENU, LLKHF_ALTDOWN, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYDOWN, 1, VK_MENU, KF_ALTDOWN), {0}}}, + { + .scan = 0x3c0, .flags = KEYEVENTF_UNICODE, .expect_state = {[VK_MENU] = 0x80, [VK_LMENU] = 0x80, [VK_PACKET] = 0x80}, + .expect = + { + KEY_HOOK_(WM_SYSKEYDOWN, 0x3c0, VK_PACKET, LLKHF_ALTDOWN, .todo_value = TRUE), + KEY_MSG_(WM_SYSKEYDOWN, 0, VK_PACKET, KF_ALTDOWN, .todo_value = TRUE), + WIN_MSG(WM_SYSCHAR, 0x3c0, MAKELONG(1, KF_ALTDOWN), .todo_value = TRUE), + {0}, + }, + }, + {.scan = 0x3c0, .flags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP, .expect_state = {[VK_MENU] = 0x80, [VK_LMENU] = 0x80}, + .expect = {KEY_HOOK_(WM_SYSKEYUP, 0x3c0, VK_PACKET, LLKHF_ALTDOWN, .todo_value = TRUE), KEY_MSG_(WM_SYSKEYUP, 0, VK_PACKET, KF_ALTDOWN, .todo_value = TRUE), {0}}}, + {.vkey = VK_LMENU, .flags = KEYEVENTF_KEYUP, + .expect = {KEY_HOOK(WM_KEYUP, 4, VK_LMENU), KEY_MSG(WM_KEYUP, 4, VK_MENU), {0}}}, + {0}, + }; + + struct send_input_keyboard_test unicode_vkey[] = + { +#if defined(__REACTOS__) && defined(_MSC_VER) + {.scan = 0x3c0, .vkey = vkey, .flags = KEYEVENTF_UNICODE, .expect_state = { 0 /*[vkey] = 0x80*/}, +#else + {.scan = 0x3c0, .vkey = vkey, .flags = KEYEVENTF_UNICODE, .expect_state = {/*[vkey] = 0x80*/}, +#endif + .expect = {KEY_HOOK(WM_KEYDOWN, 0xc0, vkey), KEY_MSG(WM_KEYDOWN, 0xc0, vkey), WIN_MSG(WM_CHAR, wch, MAKELONG(1, 0xc0)), {0}}}, + {.scan = 0x3c0, .vkey = vkey, .flags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP, + .expect = {KEY_HOOK(WM_KEYUP, 0xc0, vkey), KEY_MSG(WM_KEYUP, 0xc0, vkey), {0}}}, + {0}, + }; + + struct send_input_keyboard_test unicode_vkey_ctrl[] = + { + {.scan = 0x3c0, .vkey = VK_CONTROL, .flags = KEYEVENTF_UNICODE, .expect_state = {[VK_CONTROL] = 0x80, [VK_LCONTROL] = 0x80}, + .expect = {KEY_HOOK(WM_KEYDOWN, 0xc0, VK_LCONTROL), KEY_MSG(WM_KEYDOWN, 0xc0, VK_CONTROL), {0}}}, + {.scan = 0x3c0, .vkey = VK_CONTROL, .flags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP, + .expect = {KEY_HOOK(WM_KEYUP, 0xc0, VK_LCONTROL), KEY_MSG(WM_KEYUP, 0xc0, VK_CONTROL), {0}}}, + {0}, + }; + + struct send_input_keyboard_test unicode_vkey_packet[] = + { + {.scan = 0x3c0, .vkey = VK_PACKET, .flags = KEYEVENTF_UNICODE, .expect_state = {[VK_PACKET] = 0x80}, + .expect = {KEY_HOOK(WM_KEYDOWN, 0xc0, VK_PACKET), KEY_MSG(WM_KEYDOWN, 0, VK_PACKET, .todo_value = TRUE), WIN_MSG(WM_CHAR, 0xc0, 1), {0}}}, + {.scan = 0x3c0, .vkey = VK_PACKET, .flags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP, + .expect = {KEY_HOOK(WM_KEYUP, 0xc0, VK_PACKET), KEY_MSG(WM_KEYUP, 0, VK_PACKET, .todo_value = TRUE), {0}}}, + {0}, + }; + + struct send_input_keyboard_test numpad_scan[] = + { + {.scan = 0x4b, .flags = KEYEVENTF_SCANCODE, .expect_state = {[VK_LEFT] = 0x80}, + .expect = {KEY_HOOK(WM_KEYDOWN, 0x4b, VK_LEFT), KEY_MSG(WM_KEYDOWN, 0x4b, VK_LEFT), {0}}}, + {.scan = 0x4b, .flags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP, + .expect = {KEY_HOOK(WM_KEYUP, 0x4b, VK_LEFT), KEY_MSG(WM_KEYUP, 0x4b, VK_LEFT), {0}}}, + {0}, + }; + + struct send_input_keyboard_test numpad_scan_numlock[] = + { + {.scan = 0x45, .flags = KEYEVENTF_SCANCODE, .expect_state = {[VK_NUMLOCK] = 0x80}, + .expect = {KEY_HOOK(WM_KEYDOWN, 0x45, VK_NUMLOCK), KEY_MSG(WM_KEYDOWN, 0x45, VK_NUMLOCK), {0}}}, + {.scan = 0x45, .flags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP, .expect_state = {[VK_NUMLOCK] = 0x01}, + .expect = {KEY_HOOK(WM_KEYUP, 0x45, VK_NUMLOCK), KEY_MSG(WM_KEYUP, 0x45, VK_NUMLOCK), {0}}}, + { + .scan = 0x4b, .flags = KEYEVENTF_SCANCODE, + .expect_state = {[VK_NUMPAD4] = 0x80, [VK_NUMLOCK] = 0x01}, + .todo_state = {[VK_NUMPAD4] = TRUE, [VK_LEFT] = TRUE}, + .expect = + { + KEY_HOOK(WM_KEYDOWN, 0x4b, VK_NUMPAD4, .todo_value = TRUE), + KEY_MSG(WM_KEYDOWN, 0x4b, VK_NUMPAD4, .todo_value = TRUE), + WIN_MSG(WM_CHAR, '4', MAKELONG(1, 0x4b), .todo_value = TRUE), + {0} + } + }, + { + .scan = 0x4b, .flags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP, .expect_state = {[VK_NUMLOCK] = 0x01}, + .expect = + { + KEY_HOOK(WM_KEYUP, 0x4b, VK_NUMPAD4, .todo_value = TRUE), + KEY_MSG(WM_KEYUP, 0x4b, VK_NUMPAD4, .todo_value = TRUE), + {0} + } + }, + {0}, + }; + +#undef WIN_MSG +#undef KBD_HOOK +#undef KEY_HOOK_ +#undef KEY_HOOK +#undef KEY_MSG_ +#undef KEY_MSG + + BOOL altgr = keyboard_layout_has_altgr(), skip_altgr = FALSE; + LONG_PTR old_proc; HHOOK hook; + HWND hwnd; - if (GetKeyboardLayout(0) != (HKL)(ULONG_PTR)0x04090409) - { - skip("Skipping Input_blackbox test on non-US keyboard\n"); - return; - } - window = CreateWindowA("Static", NULL, WS_POPUP|WS_HSCROLL|WS_VSCROLL - |WS_VISIBLE, 0, 0, 200, 60, NULL, NULL, - NULL, NULL); - ok(window != NULL, "error: %d\n", (int) GetLastError()); - SetWindowPos( window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE ); - foreground = SetForegroundWindow( window ); - if (!foreground) - skip("Failed to set foreground window; some tests will be skipped.\n"); + /* on 32-bit with ALTGR keyboard, the CONTROL key is sent to the hooks without the + * LLKHF_INJECTED flag, skip the tests to keep it simple */ + if (altgr && sizeof(void *) == 4 && !is_wow64) skip_altgr = TRUE; - if (!(hook = SetWindowsHookExA(WH_KEYBOARD_LL, hook_proc, GetModuleHandleA( NULL ), 0))) + hwnd = CreateWindowW( L"static", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, NULL, NULL ); + ok_ne( NULL, hwnd, HWND, "%p" ); + wait_messages( 100, FALSE ); + + /* If we have had a spurious layout change, wch(_shift) may be incorrect. */ + if (GetKeyboardLayout( 0 ) != hkl) { - DestroyWindow(window); - win_skip("WH_KEYBOARD_LL is not supported\n"); + win_skip( "Spurious keyboard layout changed detected (expected: %p got: %p)\n", + hkl, GetKeyboardLayout( 0 ) ); + ok_ret( 1, DestroyWindow( hwnd ) ); + wait_messages( 100, FALSE ); + ok_seq( empty_sequence ); return; } - /* must process all initial messages, otherwise X11DRV_KeymapNotify unsets - * key state set by SendInput(). */ - empty_message_queue(); + hook = SetWindowsHookExW( WH_KEYBOARD_LL, ll_hook_kbd_proc, GetModuleHandleW( NULL ), 0 ); + ok_ne( NULL, hook, HHOOK, "%p" ); - prevWndProc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR) WndProc2); - ok(prevWndProc != 0 || GetLastError() == 0, "error: %d\n", (int) GetLastError()); + p_accept_message = accept_keyboard_messages_syscommand; + ok_seq( empty_sequence ); - i.type = INPUT_KEYBOARD; - i.u.ki.time = 0; - i.u.ki.dwExtraInfo = 0; + lmenu_vkey_peeked[1].expect_state[vkey] = 0x80; + lmenu_vkey[1].expect_state[vkey] = 0x80; + lcontrol_vkey[1].expect_state[vkey] = 0x80; + lmenu_lcontrol_vkey[2].expect_state[vkey] = 0x80; + shift_vkey[1].expect_state[vkey] = 0x80; + rshift_scan[1].expect_state[vkey] = 0x80; + unicode_vkey[0].expect_state[vkey] = 0x80; - for (ii = 0; ii < ARRAY_SIZE(sendinput_test)-1; ii++) { - GetKeyboardState(ks1); - i.u.ki.wScan = ii+1 /* useful for debugging */; - i.u.ki.dwFlags = sendinput_test[ii].dwFlags; - i.u.ki.wVk = sendinput_test[ii].wVk; - SendInput(1, (INPUT*)&i, sizeof(TEST_INPUT)); - empty_message_queue(); - GetKeyboardState(ks2); - compare_and_check(ii, ks1, ks2, &sendinput_test[ii], foreground); - } + /* test peeked messages */ + winetest_push_context( "peek" ); + check_send_input_keyboard_test( lmenu_vkey_peeked, TRUE ); + check_send_input_keyboard_test( lcontrol_vkey, TRUE ); + check_send_input_keyboard_test( lmenu_lcontrol_vkey, TRUE ); + check_send_input_keyboard_test( shift_vkey, TRUE ); + check_send_input_keyboard_test( rshift, TRUE ); + check_send_input_keyboard_test( lshift_ext, TRUE ); + check_send_input_keyboard_test( rshift_ext, TRUE ); + check_send_input_keyboard_test( shift, TRUE ); + check_send_input_keyboard_test( shift_ext, TRUE ); + check_send_input_keyboard_test( rcontrol, TRUE ); + check_send_input_keyboard_test( lcontrol_ext, TRUE ); + check_send_input_keyboard_test( rcontrol_ext, TRUE ); + check_send_input_keyboard_test( control, TRUE ); + check_send_input_keyboard_test( control_ext, TRUE ); + if (skip_altgr) skip( "skipping rmenu_altgr test\n" ); + else if (altgr) check_send_input_keyboard_test( rmenu_altgr, TRUE ); + else check_send_input_keyboard_test( rmenu_peeked, TRUE ); + check_send_input_keyboard_test( lmenu_ext_peeked, TRUE ); + if (skip_altgr) skip( "skipping rmenu_ext_altgr test\n" ); + else if (altgr) check_send_input_keyboard_test( rmenu_ext_altgr, TRUE ); + else check_send_input_keyboard_test( rmenu_ext_peeked, TRUE ); + check_send_input_keyboard_test( menu_peeked, TRUE ); + if (skip_altgr) skip( "skipping menu_ext_altgr test\n" ); + else if (altgr) check_send_input_keyboard_test( menu_ext_altgr, TRUE ); + else check_send_input_keyboard_test( menu_ext_peeked, TRUE ); + check_send_input_keyboard_test( lrshift_ext, TRUE ); + check_send_input_keyboard_test( rshift_scan, TRUE ); + /* Skip on Korean layouts since they map the right control key to VK_HANJA */ + if (hkl == (HKL)0x04120412) skip( "skipping rctrl_scan test on Korean layout" ); + else check_send_input_keyboard_test( rctrl_scan, TRUE ); + check_send_input_keyboard_test( unicode, TRUE ); + check_send_input_keyboard_test( lmenu_unicode_peeked, TRUE ); + check_send_input_keyboard_test( unicode_vkey, TRUE ); + check_send_input_keyboard_test( unicode_vkey_ctrl, TRUE ); + check_send_input_keyboard_test( unicode_vkey_packet, TRUE ); + check_send_input_keyboard_test( numpad_scan, TRUE ); + check_send_input_keyboard_test( numpad_scan_numlock, TRUE ); + winetest_pop_context(); - empty_message_queue(); - DestroyWindow(window); - UnhookWindowsHookEx(hook); -} + wait_messages( 100, FALSE ); + ok_seq( empty_sequence ); -static void reset_key_status(WORD vk) -{ - key_status.last_key_down = -1; - key_status.last_key_up = -1; - key_status.last_syskey_down = -1; - key_status.last_syskey_up = -1; - key_status.last_char = -1; - key_status.last_syschar = -1; - key_status.last_hook_down = -1; - key_status.last_hook_up = -1; - key_status.last_hook_syskey_down = -1; - key_status.last_hook_syskey_up = -1; - key_status.vk = vk; - key_status.expect_alt = FALSE; - key_status.sendinput_broken = FALSE; -} + /* test received messages */ + old_proc = SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)append_message_wndproc ); + ok_ne( 0, old_proc, LONG_PTR, "%#Ix" ); -static void test_unicode_keys(HWND hwnd, HHOOK hook) -{ - TEST_INPUT inputs[2]; - MSG msg; + winetest_push_context( "receive" ); + check_send_input_keyboard_test( lmenu_vkey, FALSE ); + check_send_input_keyboard_test( lcontrol_vkey, FALSE ); + check_send_input_keyboard_test( lmenu_lcontrol_vkey, FALSE ); + check_send_input_keyboard_test( shift_vkey, FALSE ); + check_send_input_keyboard_test( rshift, FALSE ); + check_send_input_keyboard_test( lshift_ext, FALSE ); + check_send_input_keyboard_test( rshift_ext, FALSE ); + check_send_input_keyboard_test( shift, FALSE ); + check_send_input_keyboard_test( shift_ext, FALSE ); + check_send_input_keyboard_test( rcontrol, FALSE ); + check_send_input_keyboard_test( lcontrol_ext, FALSE ); + check_send_input_keyboard_test( rcontrol_ext, FALSE ); + check_send_input_keyboard_test( control, FALSE ); + check_send_input_keyboard_test( control_ext, FALSE ); + if (skip_altgr) skip( "skipping rmenu_altgr test\n" ); + else if (altgr) check_send_input_keyboard_test( rmenu_altgr, FALSE ); + else check_send_input_keyboard_test( rmenu, FALSE ); + check_send_input_keyboard_test( lmenu_ext, FALSE ); + if (skip_altgr) skip( "skipping rmenu_ext_altgr test\n" ); + else if (altgr) check_send_input_keyboard_test( rmenu_ext_altgr, FALSE ); + else check_send_input_keyboard_test( rmenu_ext, FALSE ); + check_send_input_keyboard_test( menu, FALSE ); + if (skip_altgr) skip( "skipping menu_ext_altgr test\n" ); + else if (altgr) check_send_input_keyboard_test( menu_ext_altgr, FALSE ); + else check_send_input_keyboard_test( menu_ext, FALSE ); + check_send_input_keyboard_test( lrshift_ext, FALSE ); + check_send_input_keyboard_test( rshift_scan, FALSE ); + /* Skip on Korean layouts since they map the right control key to VK_HANJA */ + if (hkl == (HKL)0x04120412) skip( "skipping rctrl_scan test on Korean layout" ); + else check_send_input_keyboard_test( rctrl_scan, FALSE ); + check_send_input_keyboard_test( unicode, FALSE ); + check_send_input_keyboard_test( lmenu_unicode, FALSE ); + check_send_input_keyboard_test( unicode_vkey, FALSE ); + check_send_input_keyboard_test( unicode_vkey_ctrl, FALSE ); + check_send_input_keyboard_test( unicode_vkey_packet, FALSE ); + check_send_input_keyboard_test( numpad_scan, FALSE ); + check_send_input_keyboard_test( numpad_scan_numlock, FALSE ); + winetest_pop_context(); - /* init input data that never changes */ - inputs[1].type = inputs[0].type = INPUT_KEYBOARD; - inputs[1].u.ki.dwExtraInfo = inputs[0].u.ki.dwExtraInfo = 0; - inputs[1].u.ki.time = inputs[0].u.ki.time = 0; + ok_ret( 1, DestroyWindow( hwnd ) ); + ok_ret( 1, UnhookWindowsHookEx( hook ) ); - /* pressing & releasing a single unicode character */ - inputs[0].u.ki.wVk = 0; - inputs[0].u.ki.wScan = 0x3c0; - inputs[0].u.ki.dwFlags = KEYEVENTF_UNICODE; - - reset_key_status(VK_PACKET); - SendInput(1, (INPUT*)inputs, sizeof(INPUT)); - while(PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)){ - if(msg.message == WM_KEYDOWN && msg.wParam == VK_PACKET){ - TranslateMessage(&msg); - } - DispatchMessageW(&msg); - } - if(!key_status.sendinput_broken){ - ok(key_status.last_key_down == VK_PACKET, - "Last keydown msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET, key_status.last_key_down); - ok(key_status.last_char == 0x3c0, - "Last char msg wparam should have been 0x3c0 (was: 0x%x)\n", key_status.last_char); - if(hook) - ok(key_status.last_hook_down == 0x3c0, - "Last hookdown msg should have been 0x3c0, was: 0x%x\n", key_status.last_hook_down); - } - - inputs[1].u.ki.wVk = 0; - inputs[1].u.ki.wScan = 0x3c0; - inputs[1].u.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP; - - reset_key_status(VK_PACKET); - SendInput(1, (INPUT*)(inputs+1), sizeof(INPUT)); - while(PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)){ - if(msg.message == WM_KEYDOWN && msg.wParam == VK_PACKET){ - TranslateMessage(&msg); - } - DispatchMessageW(&msg); - } - if(!key_status.sendinput_broken){ - ok(key_status.last_key_up == VK_PACKET, - "Last keyup msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET, key_status.last_key_up); - if(hook) - ok(key_status.last_hook_up == 0x3c0, - "Last hookup msg should have been 0x3c0, was: 0x%x\n", key_status.last_hook_up); - } - - /* holding alt, pressing & releasing a unicode character, releasing alt */ - inputs[0].u.ki.wVk = VK_LMENU; - inputs[0].u.ki.wScan = 0; - inputs[0].u.ki.dwFlags = 0; - - inputs[1].u.ki.wVk = 0; - inputs[1].u.ki.wScan = 0x3041; - inputs[1].u.ki.dwFlags = KEYEVENTF_UNICODE; - - reset_key_status(VK_PACKET); - key_status.expect_alt = TRUE; - SendInput(2, (INPUT*)inputs, sizeof(INPUT)); - while(PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)){ - if(msg.message == WM_SYSKEYDOWN && msg.wParam == VK_PACKET){ - TranslateMessage(&msg); - } - DispatchMessageW(&msg); - } - if(!key_status.sendinput_broken){ - ok(key_status.last_syskey_down == VK_PACKET, - "Last syskeydown msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET, key_status.last_syskey_down); - ok(key_status.last_syschar == 0x3041, - "Last syschar msg should have been 0x3041 (was: 0x%x)\n", key_status.last_syschar); - if(hook) - ok(key_status.last_hook_syskey_down == 0x3041, - "Last hooksysdown msg should have been 0x3041, was: 0x%x\n", key_status.last_hook_syskey_down); - } - - inputs[1].u.ki.wVk = 0; - inputs[1].u.ki.wScan = 0x3041; - inputs[1].u.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP; - - inputs[0].u.ki.wVk = VK_LMENU; - inputs[0].u.ki.wScan = 0; - inputs[0].u.ki.dwFlags = KEYEVENTF_KEYUP; - - reset_key_status(VK_PACKET); - key_status.expect_alt = TRUE; - SendInput(2, (INPUT*)inputs, sizeof(INPUT)); - while(PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)){ - if(msg.message == WM_SYSKEYDOWN && msg.wParam == VK_PACKET){ - TranslateMessage(&msg); - } - DispatchMessageW(&msg); - } - if(!key_status.sendinput_broken){ - ok(key_status.last_key_up == VK_PACKET, - "Last keyup msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET, key_status.last_key_up); - if(hook) - ok(key_status.last_hook_up == 0x3041, - "Last hook up msg should have been 0x3041, was: 0x%x\n", key_status.last_hook_up); - } - - /* Press and release, non-zero key code. */ - inputs[0].u.ki.wVk = 0x51; - inputs[0].u.ki.wScan = 0x123; - inputs[0].u.ki.dwFlags = KEYEVENTF_UNICODE; - - inputs[1].u.ki.wVk = 0x51; - inputs[1].u.ki.wScan = 0x123; - inputs[1].u.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP; - - reset_key_status(inputs[0].u.ki.wVk); - SendInput(2, (INPUT*)inputs, sizeof(INPUT)); - while (PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)) - { - TranslateMessage(&msg); - DispatchMessageW(&msg); - } - - if (!key_status.sendinput_broken) - { - ok(key_status.last_key_down == 0x51, "Unexpected key down %#x.\n", key_status.last_key_down); - ok(key_status.last_key_up == 0x51, "Unexpected key up %#x.\n", key_status.last_key_up); - if (hook) - todo_wine - ok(key_status.last_hook_up == 0x23, "Unexpected hook message %#x.\n", key_status.last_hook_up); - } -} - -static LRESULT CALLBACK unicode_wnd_proc( HWND hWnd, UINT msg, WPARAM wParam, - LPARAM lParam ) -{ - switch(msg){ - case WM_KEYDOWN: - key_status.last_key_down = wParam; - break; - case WM_SYSKEYDOWN: - key_status.last_syskey_down = wParam; - break; - case WM_KEYUP: - key_status.last_key_up = wParam; - break; - case WM_SYSKEYUP: - key_status.last_syskey_up = wParam; - break; - case WM_CHAR: - key_status.last_char = wParam; - break; - case WM_SYSCHAR: - key_status.last_syschar = wParam; - break; - } - return DefWindowProcW(hWnd, msg, wParam, lParam); -} - -static LRESULT CALLBACK llkbd_unicode_hook(int nCode, WPARAM wParam, LPARAM lParam) -{ - if(nCode == HC_ACTION){ - LPKBDLLHOOKSTRUCT info = (LPKBDLLHOOKSTRUCT)lParam; - if(!info->vkCode){ - key_status.sendinput_broken = TRUE; - win_skip("SendInput doesn't support unicode on this platform\n"); - }else{ - if(key_status.expect_alt){ - ok(info->vkCode == VK_LMENU, "vkCode should have been VK_LMENU[0x%04x], was: 0x%x\n", VK_LMENU, info->vkCode); - key_status.expect_alt = FALSE; - }else - todo_wine_if(key_status.vk != VK_PACKET) - ok(info->vkCode == key_status.vk, "Unexpected vkCode %#x, expected %#x.\n", info->vkCode, key_status.vk); - } - switch(wParam){ - case WM_KEYDOWN: - key_status.last_hook_down = info->scanCode; - break; - case WM_KEYUP: - key_status.last_hook_up = info->scanCode; - break; - case WM_SYSKEYDOWN: - key_status.last_hook_syskey_down = info->scanCode; - break; - case WM_SYSKEYUP: - key_status.last_hook_syskey_up = info->scanCode; - break; - } - } - return CallNextHookEx(NULL, nCode, wParam, lParam); -} - -static void test_Input_unicode(void) -{ - WCHAR classNameW[] = {'I','n','p','u','t','U','n','i','c','o','d','e', - 'K','e','y','T','e','s','t','C','l','a','s','s',0}; - WCHAR windowNameW[] = {'I','n','p','u','t','U','n','i','c','o','d','e', - 'K','e','y','T','e','s','t',0}; - MSG msg; - WNDCLASSW wclass; - HANDLE hInstance = GetModuleHandleW(NULL); - HHOOK hook; - HMODULE hModuleImm32; - BOOL (WINAPI *pImmDisableIME)(DWORD); - - wclass.lpszClassName = classNameW; - wclass.style = CS_HREDRAW | CS_VREDRAW; - wclass.lpfnWndProc = unicode_wnd_proc; - wclass.hInstance = hInstance; - wclass.hIcon = LoadIconW(0, (LPCWSTR)IDI_APPLICATION); - wclass.hCursor = LoadCursorW( NULL, (LPCWSTR)IDC_ARROW); - wclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wclass.lpszMenuName = 0; - wclass.cbClsExtra = 0; - wclass.cbWndExtra = 0; - if(!RegisterClassW(&wclass)){ - win_skip("Unicode functions not supported\n"); - return; - } - - hModuleImm32 = LoadLibraryA("imm32.dll"); - if (hModuleImm32) { - pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME"); - if (pImmDisableIME) - pImmDisableIME(0); - } - pImmDisableIME = NULL; - FreeLibrary(hModuleImm32); - - /* create the test window that will receive the keystrokes */ - hWndTest = CreateWindowW(wclass.lpszClassName, windowNameW, - WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 100, 100, - NULL, NULL, hInstance, NULL); - - assert(hWndTest); - assert(IsWindowUnicode(hWndTest)); - - hook = SetWindowsHookExW(WH_KEYBOARD_LL, llkbd_unicode_hook, GetModuleHandleW(NULL), 0); - if(!hook) - win_skip("unable to set WH_KEYBOARD_LL hook\n"); - - ShowWindow(hWndTest, SW_SHOW); - SetWindowPos(hWndTest, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); - SetForegroundWindow(hWndTest); - UpdateWindow(hWndTest); - - /* flush pending messages */ - while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageW(&msg); - - SetFocus(hWndTest); - - test_unicode_keys(hWndTest, hook); - - if(hook) - UnhookWindowsHookEx(hook); - DestroyWindow(hWndTest); + wait_messages( 100, FALSE ); + ok_seq( empty_sequence ); + p_accept_message = NULL; } static void test_keynames(void) @@ -1255,215 +1475,162 @@ static void test_keynames(void) } } -static POINT pt_old, pt_new; -static BOOL clipped; -#define STEP 3 - -static LRESULT CALLBACK hook_proc1( int code, WPARAM wparam, LPARAM lparam ) +static BOOL accept_keyboard_messages_raw( UINT msg ) { - MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam; - POINT pt, pt1; - - if (code == HC_ACTION) - { - /* This is our new cursor position */ - pt_new = hook->pt; - /* Should return previous position */ - GetCursorPos(&pt); - ok(pt.x == pt_old.x && pt.y == pt_old.y, "GetCursorPos: (%d,%d)\n", pt.x, pt.y); - - /* Should set new position until hook chain is finished. */ - pt.x = pt_old.x + STEP; - pt.y = pt_old.y + STEP; - SetCursorPos(pt.x, pt.y); - GetCursorPos(&pt1); - if (clipped) - ok(pt1.x == pt_old.x && pt1.y == pt_old.y, "Wrong set pos: (%d,%d)\n", pt1.x, pt1.y); - else - ok(pt1.x == pt.x && pt1.y == pt.y, "Wrong set pos: (%d,%d)\n", pt1.x, pt1.y); - } - return CallNextHookEx( 0, code, wparam, lparam ); + return is_keyboard_message( msg ) || msg == WM_INPUT; } -static LRESULT CALLBACK hook_proc2( int code, WPARAM wparam, LPARAM lparam ) +static void test_SendInput_raw_key_messages( WORD vkey, WORD wch, HKL hkl ) { - MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam; - POINT pt; - - if (code == HC_ACTION) +#define WIN_MSG(m, w, l, ...) {.func = MSG_TEST_WIN, .message = {.msg = m, .wparam = w, .lparam = l}, ## __VA_ARGS__} +#define RAW_KEY(s, f, v, m, ...) {.func = RAW_INPUT_KEYBOARD, .raw_input.kbd = {.MakeCode = s, .Flags = f, .VKey = v, .Message = m}, ## __VA_ARGS__} +#define KEY_MSG(m, s, v, ...) WIN_MSG( m, v, MAKELONG(1, (s) | (m == WM_KEYUP || m == WM_SYSKEYUP ? (KF_UP | KF_REPEAT) : 0)), ## __VA_ARGS__ ) + struct send_input_keyboard_test raw_legacy[] = { - ok(hook->pt.x == pt_new.x && hook->pt.y == pt_new.y, - "Wrong hook coords: (%d %d) != (%d,%d)\n", hook->pt.x, hook->pt.y, pt_new.x, pt_new.y); - - /* Should match position set above */ - GetCursorPos(&pt); - if (clipped) - ok(pt.x == pt_old.x && pt.y == pt_old.y, "GetCursorPos: (%d,%d)\n", pt.x, pt.y); - else - ok(pt.x == pt_old.x +STEP && pt.y == pt_old.y +STEP, "GetCursorPos: (%d,%d)\n", pt.x, pt.y); - } - return CallNextHookEx( 0, code, wparam, lparam ); -} - -static LRESULT CALLBACK hook_proc3( int code, WPARAM wparam, LPARAM lparam ) -{ - POINT pt; - - if (code == HC_ACTION) + {.vkey = vkey, + .expect = {RAW_KEY(1, RI_KEY_MAKE, vkey, WM_KEYDOWN), KEY_MSG(WM_KEYDOWN, 1, vkey), WIN_MSG(WM_CHAR, wch, MAKELONG(1, 1)), {0}}}, + {.vkey = vkey, .flags = KEYEVENTF_KEYUP, + .expect = {RAW_KEY(2, RI_KEY_BREAK, vkey, WM_KEYUP), KEY_MSG(WM_KEYUP, 2, vkey), {0}}}, + {0}, + }; + struct send_input_keyboard_test raw_nolegacy[] = { - /* MSLLHOOKSTRUCT does not seem to be reliable and contains different data on each run. */ - GetCursorPos(&pt); - ok(pt.x == pt_old.x && pt.y == pt_old.y, "GetCursorPos: (%d,%d)\n", pt.x, pt.y); - } - return CallNextHookEx( 0, code, wparam, lparam ); -} - -static void test_mouse_ll_hook(void) -{ + {.vkey = vkey, .async = TRUE, .expect = {RAW_KEY(1, RI_KEY_MAKE, vkey, WM_KEYDOWN), {0}}}, + {.vkey = vkey, .flags = KEYEVENTF_KEYUP, .expect = {RAW_KEY(2, RI_KEY_BREAK, vkey, WM_KEYUP), {0}}}, + {0}, + }; + struct send_input_keyboard_test raw_vk_packet_legacy[] = + { + {.vkey = VK_PACKET, .expect_state = {[VK_PACKET] = 0x80}, + .expect = {RAW_KEY(1, RI_KEY_MAKE, VK_PACKET, WM_KEYDOWN), KEY_MSG(WM_KEYDOWN, 1, VK_PACKET), {0, .todo = TRUE}}}, + {.vkey = VK_PACKET, .flags = KEYEVENTF_KEYUP, + .expect = {RAW_KEY(2, RI_KEY_BREAK, VK_PACKET, WM_KEYUP), KEY_MSG(WM_KEYUP, 2, VK_PACKET), {0}}}, + {0}, + }; + struct send_input_keyboard_test raw_vk_packet_nolegacy[] = + { + {.vkey = VK_PACKET, .async = TRUE, .expect_async = {[VK_PACKET] = 0x80}, + .expect = {RAW_KEY(1, RI_KEY_MAKE, VK_PACKET, WM_KEYDOWN), {0}}}, + {.vkey = VK_PACKET, .flags = KEYEVENTF_KEYUP, .expect = {RAW_KEY(2, RI_KEY_BREAK, VK_PACKET, WM_KEYUP), {0}}}, + {0}, + }; + struct send_input_keyboard_test raw_unicode_legacy[] = + { + {.scan = 0x3c0, .flags = KEYEVENTF_UNICODE, .expect_state = {[VK_PACKET] = 0x80}, + .expect = {KEY_MSG(WM_KEYDOWN, 0, VK_PACKET, .todo_value = TRUE), WIN_MSG(WM_CHAR, 0x3c0, 1), {0}}}, + {.scan = 0x3c0, .flags = KEYEVENTF_KEYUP | KEYEVENTF_UNICODE, + .expect = {KEY_MSG(WM_KEYUP, 0, VK_PACKET, .todo_value = TRUE), {0}}}, + {0}, + }; + struct send_input_keyboard_test raw_unicode_nolegacy[] = + { + {.scan = 0x3c0, .flags = KEYEVENTF_UNICODE, .async = TRUE, .expect_async = {[VK_PACKET] = 0x80}}, + {.scan = 0x3c0, .flags = KEYEVENTF_KEYUP | KEYEVENTF_UNICODE}, + {0}, + }; + struct send_input_keyboard_test raw_unicode_vkey_ctrl_legacy[] = + { + {.scan = 0x3c0, .vkey = VK_CONTROL, .flags = KEYEVENTF_UNICODE, + .expect_state = {[VK_CONTROL] = 0x80, [VK_LCONTROL] = 0x80}, + .expect = {KEY_MSG(WM_KEYDOWN, 0xc0, VK_CONTROL), {0}}}, + {.scan = 0x3c0, .vkey = VK_CONTROL, .flags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP, + .expect = {KEY_MSG(WM_KEYUP, 0xc0, VK_CONTROL), {0}}}, + {0}, + }; + struct send_input_keyboard_test raw_unicode_vkey_ctrl_nolegacy[] = + { + {.scan = 0x3c0, .vkey = VK_CONTROL, .flags = KEYEVENTF_UNICODE, .async = TRUE, + .expect_async = {[VK_CONTROL] = 0x80, [VK_LCONTROL] = 0x80}}, + {.scan = 0x3c0, .vkey = VK_CONTROL, .flags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP}, + {0}, + }; +#undef WIN_MSG +#undef RAW_KEY +#undef KEY_MSG + RAWINPUTDEVICE rid = {.usUsagePage = HID_USAGE_PAGE_GENERIC, .usUsage = HID_USAGE_GENERIC_KEYBOARD}; + int receive; HWND hwnd; - HHOOK hook1, hook2; - POINT pt_org, pt; - RECT rc; - GetCursorPos(&pt_org); - hwnd = CreateWindowA("static", "Title", WS_OVERLAPPEDWINDOW | WS_VISIBLE, - 10, 10, 200, 200, NULL, NULL, NULL, NULL); - SetCursorPos(100, 100); + raw_legacy[0].expect_state[vkey] = 0x80; + raw_nolegacy[0].expect_async[vkey] = 0x80; - if (!(hook2 = SetWindowsHookExA(WH_MOUSE_LL, hook_proc2, GetModuleHandleA(0), 0))) + hwnd = CreateWindowW( L"static", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, NULL, NULL ); + ok_ne( NULL, hwnd, HWND, "%p" ); + wait_messages( 100, FALSE ); + + /* If we have had a spurious layout change, wch may be incorrect. */ + if (GetKeyboardLayout( 0 ) != hkl) { - win_skip( "cannot set MOUSE_LL hook\n" ); - goto done; + win_skip( "Spurious keyboard layout changed detected (expected: %p got: %p)\n", + hkl, GetKeyboardLayout( 0 ) ); + ok_ret( 1, DestroyWindow( hwnd ) ); + wait_messages( 100, FALSE ); + ok_seq( empty_sequence ); + return; } - hook1 = SetWindowsHookExA(WH_MOUSE_LL, hook_proc1, GetModuleHandleA(0), 0); - GetCursorPos(&pt_old); - mouse_event(MOUSEEVENTF_MOVE, -STEP, 0, 0, 0); - GetCursorPos(&pt_old); - ok(pt_old.x == pt_new.x && pt_old.y == pt_new.y, "Wrong new pos: (%d,%d)\n", pt_old.x, pt_old.y); - mouse_event(MOUSEEVENTF_MOVE, +STEP, 0, 0, 0); - GetCursorPos(&pt_old); - ok(pt_old.x == pt_new.x && pt_old.y == pt_new.y, "Wrong new pos: (%d,%d)\n", pt_old.x, pt_old.y); - mouse_event(MOUSEEVENTF_MOVE, 0, -STEP, 0, 0); - GetCursorPos(&pt_old); - ok(pt_old.x == pt_new.x && pt_old.y == pt_new.y, "Wrong new pos: (%d,%d)\n", pt_old.x, pt_old.y); - mouse_event(MOUSEEVENTF_MOVE, 0, +STEP, 0, 0); - GetCursorPos(&pt_old); - ok(pt_old.x == pt_new.x && pt_old.y == pt_new.y, "Wrong new pos: (%d,%d)\n", pt_old.x, pt_old.y); + p_accept_message = accept_keyboard_messages_raw; - SetRect(&rc, 50, 50, 151, 151); - ClipCursor(&rc); - clipped = TRUE; + for (receive = 0; receive <= 1; receive++) + { + winetest_push_context( receive ? "receive" : "peek" ); - SetCursorPos(40, 40); - GetCursorPos(&pt_old); - ok(pt_old.x == 50 && pt_old.y == 50, "Wrong new pos: (%d,%d)\n", pt_new.x, pt_new.y); - SetCursorPos(160, 160); - GetCursorPos(&pt_old); - ok(pt_old.x == 150 && pt_old.y == 150, "Wrong new pos: (%d,%d)\n", pt_new.x, pt_new.y); - mouse_event(MOUSEEVENTF_MOVE, +STEP, +STEP, 0, 0); - GetCursorPos(&pt_old); - ok(pt_old.x == 150 && pt_old.y == 150, "Wrong new pos: (%d,%d)\n", pt_new.x, pt_new.y); + if (receive) + { + /* test received messages */ + LONG_PTR old_proc = SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)append_message_wndproc ); + ok_ne( 0, old_proc, LONG_PTR, "%#Ix" ); + } - clipped = FALSE; - pt_new.x = pt_new.y = 150; - ClipCursor(NULL); - UnhookWindowsHookEx(hook1); + rid.dwFlags = 0; + ok_ret( 1, RegisterRawInputDevices( &rid, 1, sizeof(rid) ) ); - /* Now check that mouse buttons do not change mouse position - if we don't have MOUSEEVENTF_MOVE flag specified. */ + /* get both WM_INPUT and legacy messages */ + check_send_input_keyboard_test( raw_legacy, !receive ); + check_send_input_keyboard_test( raw_vk_packet_legacy, !receive ); + /* no WM_INPUT message for unicode */ + check_send_input_keyboard_test( raw_unicode_legacy, !receive ); + check_send_input_keyboard_test( raw_unicode_vkey_ctrl_legacy, !receive ); - /* We reusing the same hook callback, so make it happy */ - pt_old.x = pt_new.x - STEP; - pt_old.y = pt_new.y - STEP; - mouse_event(MOUSEEVENTF_LEFTUP, 123, 456, 0, 0); - GetCursorPos(&pt); - ok(pt.x == pt_new.x && pt.y == pt_new.y, "Position changed: (%d,%d)\n", pt.x, pt.y); - mouse_event(MOUSEEVENTF_RIGHTUP, 456, 123, 0, 0); - GetCursorPos(&pt); - ok(pt.x == pt_new.x && pt.y == pt_new.y, "Position changed: (%d,%d)\n", pt.x, pt.y); + rid.dwFlags = RIDEV_REMOVE; + ok_ret( 1, RegisterRawInputDevices( &rid, 1, sizeof(rid) ) ); - mouse_event(MOUSEEVENTF_LEFTUP | MOUSEEVENTF_ABSOLUTE, 123, 456, 0, 0); - GetCursorPos(&pt); - ok(pt.x == pt_new.x && pt.y == pt_new.y, "Position changed: (%d,%d)\n", pt.x, pt.y); - mouse_event(MOUSEEVENTF_RIGHTUP | MOUSEEVENTF_ABSOLUTE, 456, 123, 0, 0); - GetCursorPos(&pt); - ok(pt.x == pt_new.x && pt.y == pt_new.y, "Position changed: (%d,%d)\n", pt.x, pt.y); + rid.dwFlags = RIDEV_NOLEGACY; + ok_ret( 1, RegisterRawInputDevices( &rid, 1, sizeof(rid) ) ); - UnhookWindowsHookEx(hook2); - hook1 = SetWindowsHookExA(WH_MOUSE_LL, hook_proc3, GetModuleHandleA(0), 0); + /* get only WM_INPUT messages */ + check_send_input_keyboard_test( raw_nolegacy, !receive ); + check_send_input_keyboard_test( raw_vk_packet_nolegacy, !receive ); + /* no WM_INPUT message for unicode */ + check_send_input_keyboard_test( raw_unicode_nolegacy, !receive ); + check_send_input_keyboard_test( raw_unicode_vkey_ctrl_nolegacy, !receive ); - SetRect(&rc, 150, 150, 150, 150); - ClipCursor(&rc); - clipped = TRUE; + rid.dwFlags = RIDEV_REMOVE; + ok_ret( 1, RegisterRawInputDevices( &rid, 1, sizeof(rid) ) ); - SetCursorPos(140, 140); - GetCursorPos(&pt_old); - ok(pt_old.x == 150 && pt_old.y == 150, "Wrong new pos: (%d,%d)\n", pt_old.x, pt_old.y); - SetCursorPos(160, 160); - GetCursorPos(&pt_old); - todo_wine - ok(pt_old.x == 149 && pt_old.y == 149, "Wrong new pos: (%d,%d)\n", pt_old.x, pt_old.y); - mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0); - GetCursorPos(&pt_old); - ok(pt_old.x == 150 && pt_old.y == 150, "Wrong new pos: (%d,%d)\n", pt_old.x, pt_old.y); - mouse_event(MOUSEEVENTF_MOVE, +STEP, +STEP, 0, 0); - GetCursorPos(&pt_old); - todo_wine - ok(pt_old.x == 149 && pt_old.y == 149, "Wrong new pos: (%d,%d)\n", pt_old.x, pt_old.y); - mouse_event(MOUSEEVENTF_MOVE, 0, 0, 0, 0); - GetCursorPos(&pt_old); - ok(pt_old.x == 150 && pt_old.y == 150, "Wrong new pos: (%d,%d)\n", pt_old.x, pt_old.y); - mouse_event(MOUSEEVENTF_MOVE, 0, 0, 0, 0); - GetCursorPos(&pt_old); - todo_wine - ok(pt_old.x == 149 && pt_old.y == 149, "Wrong new pos: (%d,%d)\n", pt_old.x, pt_old.y); + winetest_pop_context(); + } - clipped = FALSE; - ClipCursor(NULL); + ok_ret( 1, DestroyWindow( hwnd ) ); + wait_messages( 100, FALSE ); + ok_seq( empty_sequence ); - SetCursorPos(140, 140); - SetRect(&rc, 150, 150, 150, 150); - ClipCursor(&rc); - GetCursorPos(&pt_old); - ok(pt_old.x == 150 && pt_old.y == 150, "Wrong new pos: (%d,%d)\n", pt_old.x, pt_old.y); - ClipCursor(NULL); - - SetCursorPos(160, 160); - SetRect(&rc, 150, 150, 150, 150); - ClipCursor(&rc); - GetCursorPos(&pt_old); - todo_wine - ok(pt_old.x == 149 && pt_old.y == 149, "Wrong new pos: (%d,%d)\n", pt_old.x, pt_old.y); - ClipCursor(NULL); - - SetCursorPos(150, 150); - SetRect(&rc, 150, 150, 150, 150); - ClipCursor(&rc); - GetCursorPos(&pt_old); - todo_wine - ok(pt_old.x == 149 && pt_old.y == 149, "Wrong new pos: (%d,%d)\n", pt_old.x, pt_old.y); - ClipCursor(NULL); - - UnhookWindowsHookEx(hook1); - -done: - DestroyWindow(hwnd); - SetCursorPos(pt_org.x, pt_org.y); + p_accept_message = NULL; } -static void test_GetMouseMovePointsEx(void) +static void test_GetMouseMovePointsEx( char **argv ) { #define BUFLIM 64 #define MYERROR 0xdeadbeef - int count, retval; + int i, count, retval; MOUSEMOVEPOINT in; MOUSEMOVEPOINT out[200]; POINT point; + INPUT input; /* Get a valid content for the input struct */ if(!GetCursorPos(&point)) { - win_skip("GetCursorPos() failed with error %u\n", GetLastError()); + win_skip("GetCursorPos() failed with error %lu\n", GetLastError()); return; } memset(&in, 0, sizeof(MOUSEMOVEPOINT)); @@ -1483,19 +1650,19 @@ static void test_GetMouseMovePointsEx(void) } ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval); ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR, - "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected error ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(MYERROR); retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT)-1, &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS); ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval); ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR, - "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected error ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(MYERROR); retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT)+1, &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS); ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval); ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR, - "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected error ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); /* test second and third parameter */ @@ -1503,25 +1670,25 @@ static void test_GetMouseMovePointsEx(void) retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), NULL, out, BUFLIM, GMMP_USE_DISPLAY_POINTS); ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval); ok(GetLastError() == ERROR_NOACCESS || GetLastError() == MYERROR, - "expected error ERROR_NOACCESS, got %u\n", GetLastError()); + "expected error ERROR_NOACCESS, got %lu\n", GetLastError()); SetLastError(MYERROR); retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, NULL, BUFLIM, GMMP_USE_DISPLAY_POINTS); ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval); ok(ERROR_NOACCESS == GetLastError(), - "expected error ERROR_NOACCESS, got %u\n", GetLastError()); + "expected error ERROR_NOACCESS, got %lu\n", GetLastError()); SetLastError(MYERROR); retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), NULL, NULL, BUFLIM, GMMP_USE_DISPLAY_POINTS); ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval); ok(ERROR_NOACCESS == GetLastError(), - "expected error ERROR_NOACCESS, got %u\n", GetLastError()); + "expected error ERROR_NOACCESS, got %lu\n", GetLastError()); SetLastError(MYERROR); count = 0; retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, NULL, count, GMMP_USE_DISPLAY_POINTS); if (retval == -1) - ok(GetLastError() == ERROR_POINT_NOT_FOUND, "unexpected error %u\n", GetLastError()); + ok(GetLastError() == ERROR_POINT_NOT_FOUND, "unexpected error %lu\n", GetLastError()); else ok(retval == count, "expected GetMouseMovePointsEx to succeed, got %d\n", retval); @@ -1533,13 +1700,13 @@ static void test_GetMouseMovePointsEx(void) retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, out, count, GMMP_USE_DISPLAY_POINTS); ok(retval == count, "expected GetMouseMovePointsEx to fail, got %d\n", retval); ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR, - "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected error ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(MYERROR); count = 0; retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, out, count, GMMP_USE_DISPLAY_POINTS); if (retval == -1) - ok(GetLastError() == ERROR_POINT_NOT_FOUND, "unexpected error %u\n", GetLastError()); + ok(GetLastError() == ERROR_POINT_NOT_FOUND, "unexpected error %lu\n", GetLastError()); else ok(retval == count, "expected GetMouseMovePointsEx to succeed, got %d\n", retval); @@ -1547,7 +1714,7 @@ static void test_GetMouseMovePointsEx(void) count = BUFLIM; retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, out, count, GMMP_USE_DISPLAY_POINTS); if (retval == -1) - ok(GetLastError() == ERROR_POINT_NOT_FOUND, "unexpected error %u\n", GetLastError()); + ok(GetLastError() == ERROR_POINT_NOT_FOUND, "unexpected error %lu\n", GetLastError()); else ok((0 <= retval) && (retval <= count), "expected GetMouseMovePointsEx to succeed, got %d\n", retval); @@ -1555,7 +1722,7 @@ static void test_GetMouseMovePointsEx(void) retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, out, BUFLIM+1, GMMP_USE_DISPLAY_POINTS); ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval); ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR, - "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected error ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); /* it was not possible to force an error with the fifth parameter on win2k */ @@ -1564,47 +1731,223 @@ static void test_GetMouseMovePointsEx(void) retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT)-1, NULL, out, BUFLIM, GMMP_USE_DISPLAY_POINTS); ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval); ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR, - "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected error ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(MYERROR); retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT)-1, &in, NULL, BUFLIM, GMMP_USE_DISPLAY_POINTS); ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval); ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR, - "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected error ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(MYERROR); retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), NULL, out, BUFLIM+1, GMMP_USE_DISPLAY_POINTS); ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval); ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR, - "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected error ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); SetLastError(MYERROR); retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, NULL, BUFLIM+1, GMMP_USE_DISPLAY_POINTS); ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval); ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR, - "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + "expected error ERROR_INVALID_PARAMETER, got %lu\n", GetLastError()); + /* more than 64 to be sure we wrap around */ + for (i = 0; i < 67; i++) + { + in.x = i; + in.y = i*2; + SetCursorPos( in.x, in.y ); + } + + SetLastError( MYERROR ); + retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS ); + ok( retval == 64, "expected to get 64 mouse move points but got %d\n", retval ); + ok( GetLastError() == MYERROR, "expected error to stay %x, got %lx\n", MYERROR, GetLastError() ); + + for (i = 0; i < retval; i++) + { + ok( out[i].x == in.x && out[i].y == in.y, "wrong position %d, expected %dx%d got %dx%d\n", i, in.x, in.y, out[i].x, out[i].y ); + in.x--; + in.y -= 2; + } + + in.x = 1500; + in.y = 1500; + SetLastError( MYERROR ); + retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS ); + ok( retval == -1, "expected to get -1 but got %d\n", retval ); + ok( GetLastError() == ERROR_POINT_NOT_FOUND, "expected error to be set to %x, got %lx\n", ERROR_POINT_NOT_FOUND, GetLastError() ); + + /* make sure there's no deduplication */ + in.x = 6; + in.y = 6; + SetCursorPos( in.x, in.y ); + SetCursorPos( in.x, in.y ); + retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS ); + ok( retval == 64, "expected to get 64 mouse move points but got %d\n", retval ); + ok( out[0].x == 6 && out[0].y == 6, "expected cursor position to be 6x6 but got %d %d\n", out[0].x, out[0].y ); + ok( out[1].x == 6 && out[1].y == 6, "expected cursor position to be 6x6 but got %d %d\n", out[1].x, out[1].y ); + + /* make sure 2 events are distinguishable by their timestamps */ + in.x = 150; + in.y = 75; + SetCursorPos( 30, 30 ); + SetCursorPos( in.x, in.y ); + SetCursorPos( 150, 150 ); + Sleep( 3 ); + SetCursorPos( in.x, in.y ); + + retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS ); + ok( retval == 64, "expected to get 64 mouse move points but got %d\n", retval ); + ok( out[0].x == 150 && out[0].y == 75, "expected cursor position to be 150x75 but got %d %d\n", out[0].x, out[0].y ); + ok( out[1].x == 150 && out[1].y == 150, "expected cursor position to be 150x150 but got %d %d\n", out[1].x, out[1].y ); + ok( out[2].x == 150 && out[2].y == 75, "expected cursor position to be 150x75 but got %d %d\n", out[2].x, out[2].y ); + + in.time = out[2].time; + retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS ); + ok( retval == 62, "expected to get 62 mouse move points but got %d\n", retval ); + ok( out[0].x == 150 && out[0].y == 75, "expected cursor position to be 150x75 but got %d %d\n", out[0].x, out[0].y ); + ok( out[1].x == 30 && out[1].y == 30, "expected cursor position to be 30x30 but got %d %d\n", out[1].x, out[1].y ); + + /* events created through other means should also be on the list with correct extra info */ + mouse_event( MOUSEEVENTF_MOVE, -13, 17, 0, 0xcafecafe ); + ok( GetCursorPos( &point ), "failed to get cursor position\n" ); + ok( in.x != point.x && in.y != point.y, "cursor didn't change position after mouse_event()\n" ); + in.time = 0; + in.x = point.x; + in.y = point.y; + retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS ); + ok( retval == 64, "expected to get 64 mouse move points but got %d\n", retval ); + ok( out[0].dwExtraInfo == 0xcafecafe, "wrong extra info, got 0x%Ix expected 0xcafecafe\n", out[0].dwExtraInfo ); + + input.type = INPUT_MOUSE; + memset( &input, 0, sizeof(input) ); + input.mi.dwFlags = MOUSEEVENTF_MOVE; + input.mi.dwExtraInfo = 0xdeadbeef; + input.mi.dx = -17; + input.mi.dy = 13; + SendInput( 1, (INPUT *)&input, sizeof(INPUT) ); + ok( GetCursorPos( &point ), "failed to get cursor position\n" ); + ok( in.x != point.x && in.y != point.y, "cursor didn't change position after mouse_event()\n" ); + in.time = 0; + in.x = point.x; + in.y = point.y; + retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS ); + ok( retval == 64, "expected to get 64 mouse move points but got %d\n", retval ); + ok( out[0].dwExtraInfo == 0xdeadbeef, "wrong extra info, got 0x%Ix expected 0xdeadbeef\n", out[0].dwExtraInfo ); + + retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out, BUFLIM, GMMP_USE_HIGH_RESOLUTION_POINTS ); + todo_wine ok( retval == 64, "expected to get 64 high resolution mouse move points but got %d\n", retval ); + + run_in_process( argv, "test_GetMouseMovePointsEx_process" ); #undef BUFLIM #undef MYERROR } +static void test_GetMouseMovePointsEx_process(void) +{ + int retval; + MOUSEMOVEPOINT in; + MOUSEMOVEPOINT out[64], out2[64]; + POINT point; + HDESK desk0, desk1; + HWINSTA winstation0, winstation1; + + memset( out, 0, sizeof(out) ); + memset( out2, 0, sizeof(out2) ); + + /* move point history is shared between desktops within the same windowstation */ + ok( GetCursorPos( &point ), "failed to get cursor position\n" ); + in.time = 0; + in.x = point.x; + in.y = point.y; + retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out, ARRAY_SIZE(out), GMMP_USE_DISPLAY_POINTS ); + ok( retval == 64, "expected to get 64 mouse move points but got %d\n", retval ); + + desk0 = OpenInputDesktop( 0, FALSE, DESKTOP_ALL_ACCESS ); + ok( desk0 != NULL, "OpenInputDesktop has failed with %ld\n", GetLastError() ); + desk1 = CreateDesktopA( "getmousemovepointsex_test_desktop", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ); + ok( desk1 != NULL, "CreateDesktopA failed with %ld\n", GetLastError() ); + + ok( SetThreadDesktop( desk1 ), "SetThreadDesktop failed!\n" ); + ok( SwitchDesktop( desk1 ), "SwitchDesktop failed\n" ); + + retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out2, ARRAY_SIZE(out2), GMMP_USE_DISPLAY_POINTS ); + ok( retval == 64, "expected to get 64 mouse move points but got %d\n", retval ); + + ok( memcmp( out, out2, sizeof(out2) ) == 0, "expected to get exact same history on the new desktop\n" ); + + in.time = 0; + in.x = 38; + in.y = 27; + SetCursorPos( in.x, in.y ); + + retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out2, ARRAY_SIZE(out2), GMMP_USE_DISPLAY_POINTS ); + ok( retval == 64, "expected to get 64 mouse move points but got %d\n", retval ); + + ok( SetThreadDesktop( desk0 ), "SetThreadDesktop failed!\n" ); + ok( SwitchDesktop( desk0 ), "SwitchDesktop failed\n" ); + + retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out, ARRAY_SIZE(out), GMMP_USE_DISPLAY_POINTS ); + ok( retval == 64, "expected to get 64 mouse move points but got %d\n", retval ); + ok( memcmp( out, out2, sizeof( out2 ) ) == 0, "expected to get exact same history on the old desktop\n" ); + + CloseDesktop( desk1 ); + CloseDesktop( desk0 ); + + /* non-default windowstations are non-interactive */ + winstation0 = GetProcessWindowStation(); + ok( winstation0 != NULL, "GetProcessWindowStation has failed with %ld\n", GetLastError() ); + desk0 = OpenInputDesktop( 0, FALSE, DESKTOP_ALL_ACCESS ); + ok( desk0 != NULL, "OpenInputDesktop has failed with %ld\n", GetLastError() ); + winstation1 = CreateWindowStationA( "test_winstation", 0, WINSTA_ALL_ACCESS, NULL ); + + if (winstation1 == NULL && GetLastError() == ERROR_ACCESS_DENIED) + { + win_skip("not enough privileges for CreateWindowStation\n"); + CloseDesktop( desk0 ); + CloseWindowStation( winstation0 ); + return; + } + + ok( winstation1 != NULL, "CreateWindowStationA has failed with %ld\n", GetLastError() ); + ok( SetProcessWindowStation( winstation1 ), "SetProcessWindowStation has failed\n" ); + + desk1 = CreateDesktopA( "getmousemovepointsex_test_desktop", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ); + ok( desk1 != NULL, "CreateDesktopA failed with %ld\n", GetLastError() ); + ok( SetThreadDesktop( desk1 ), "SetThreadDesktop failed!\n" ); + + SetLastError( 0xDEADBEEF ); + retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out, ARRAY_SIZE(out), GMMP_USE_DISPLAY_POINTS ); + todo_wine ok( retval == -1, "expected to get -1 mouse move points but got %d\n", retval ); + todo_wine ok( GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED got %ld\n", GetLastError() ); + + ok( SetProcessWindowStation( winstation0 ), "SetProcessWindowStation has failed\n" ); + ok( SetThreadDesktop( desk0 ), "SetThreadDesktop failed!\n" ); + CloseDesktop( desk1 ); + CloseWindowStation( winstation1 ); + CloseDesktop( desk0 ); + CloseWindowStation( winstation0 ); +} + static void test_GetRawInputDeviceList(void) { RAWINPUTDEVICELIST devices[32]; UINT ret, oret, devcount, odevcount, i; DWORD err; + BOOLEAN br; SetLastError(0xdeadbeef); ret = pGetRawInputDeviceList(NULL, NULL, 0); err = GetLastError(); ok(ret == -1, "expected -1, got %d\n", ret); - ok(err == ERROR_INVALID_PARAMETER, "expected 87, got %d\n", err); + ok(err == ERROR_INVALID_PARAMETER, "expected 87, got %ld\n", err); SetLastError(0xdeadbeef); ret = pGetRawInputDeviceList(NULL, NULL, sizeof(devices[0])); err = GetLastError(); ok(ret == -1, "expected -1, got %d\n", ret); - ok(err == ERROR_NOACCESS, "expected 998, got %d\n", err); + ok(err == ERROR_NOACCESS, "expected 998, got %ld\n", err); devcount = 0; ret = pGetRawInputDeviceList(NULL, &devcount, sizeof(devices[0])); @@ -1616,13 +1959,50 @@ static void test_GetRawInputDeviceList(void) ret = pGetRawInputDeviceList(devices, &devcount, sizeof(devices[0])); err = GetLastError(); ok(ret == -1, "expected -1, got %d\n", ret); - ok(err == ERROR_INSUFFICIENT_BUFFER, "expected 122, got %d\n", err); + ok(err == ERROR_INSUFFICIENT_BUFFER, "expected 122, got %ld\n", err); ok(devcount > 0, "expected non-zero\n"); /* devcount contains now the correct number of devices */ ret = pGetRawInputDeviceList(devices, &devcount, sizeof(devices[0])); ok(ret > 0, "expected non-zero\n"); + if (devcount) + { + RID_DEVICE_INFO info; + UINT size; + + SetLastError( 0xdeadbeef ); + ret = pGetRawInputDeviceInfoW( UlongToHandle( 0xdeadbeef ), RIDI_DEVICEINFO, NULL, NULL ); + ok( ret == ~0U, "GetRawInputDeviceInfoW returned %#x, expected ~0.\n", ret ); + ok( GetLastError() == ERROR_NOACCESS, "GetRawInputDeviceInfoW last error %#lx, expected 0xdeadbeef.\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + size = 0xdeadbeef; + ret = pGetRawInputDeviceInfoW( UlongToHandle( 0xdeadbeef ), RIDI_DEVICEINFO, NULL, &size ); + ok( ret == ~0U, "GetRawInputDeviceInfoW returned %#x, expected ~0.\n", ret ); + ok( size == 0xdeadbeef, "GetRawInputDeviceInfoW returned size %#x, expected 0.\n", size ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "GetRawInputDeviceInfoW last error %#lx, expected 0xdeadbeef.\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + size = 0xdeadbeef; + ret = pGetRawInputDeviceInfoW( devices[0].hDevice, 0xdeadbeef, NULL, &size ); + ok( ret == ~0U, "GetRawInputDeviceInfoW returned %#x, expected ~0.\n", ret ); + ok( size == 0xdeadbeef, "GetRawInputDeviceInfoW returned size %#x, expected 0.\n", size ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputDeviceInfoW last error %#lx, expected 0xdeadbeef.\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + ret = pGetRawInputDeviceInfoW( devices[0].hDevice, RIDI_DEVICEINFO, &info, NULL ); + ok( ret == ~0U, "GetRawInputDeviceInfoW returned %#x, expected ~0.\n", ret ); + ok( GetLastError() == ERROR_NOACCESS, "GetRawInputDeviceInfoW last error %#lx, expected 0xdeadbeef.\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + size = 0; + ret = pGetRawInputDeviceInfoW( devices[0].hDevice, RIDI_DEVICEINFO, &info, &size ); + ok( ret == ~0U, "GetRawInputDeviceInfoW returned %#x, expected ~0.\n", ret ); + ok( size == sizeof(info), "GetRawInputDeviceInfoW returned size %#x, expected %#Ix.\n", size, sizeof(info) ); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetRawInputDeviceInfoW last error %#lx, expected 0xdeadbeef.\n", GetLastError() ); + } + for(i = 0; i < devcount; ++i) { WCHAR name[128]; @@ -1630,23 +2010,24 @@ static void test_GetRawInputDeviceList(void) UINT sz, len; RID_DEVICE_INFO info; HANDLE file; + char *ppd; /* get required buffer size */ name[0] = '\0'; sz = 5; ret = pGetRawInputDeviceInfoW(devices[i].hDevice, RIDI_DEVICENAME, name, &sz); - ok(ret == -1, "GetRawInputDeviceInfo gave wrong failure: %d\n", err); + ok(ret == -1, "GetRawInputDeviceInfo gave wrong failure: %ld\n", err); ok(sz > 5 && sz < ARRAY_SIZE(name), "Size should have been set and not too large (got: %u)\n", sz); /* buffer size for RIDI_DEVICENAME is in CHARs, not BYTEs */ ret = pGetRawInputDeviceInfoW(devices[i].hDevice, RIDI_DEVICENAME, name, &sz); - ok(ret == sz, "GetRawInputDeviceInfo gave wrong return: %d\n", err); + ok(ret == sz, "GetRawInputDeviceInfo gave wrong return: %ld\n", err); len = lstrlenW(name); ok(len + 1 == ret, "GetRawInputDeviceInfo returned wrong length (name: %u, ret: %u)\n", len + 1, ret); /* test A variant with same size */ ret = pGetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICENAME, nameA, &sz); - ok(ret == sz, "GetRawInputDeviceInfoA gave wrong return: %d\n", err); + ok(ret == sz, "GetRawInputDeviceInfoA gave wrong return: %ld\n", err); len = strlen(nameA); ok(len + 1 == ret, "GetRawInputDeviceInfoA returned wrong length (name: %u, ret: %u)\n", len + 1, ret); @@ -1655,27 +2036,63 @@ static void test_GetRawInputDeviceList(void) info.cbSize = sizeof(info); sz = sizeof(info) - 1; ret = pGetRawInputDeviceInfoW(devices[i].hDevice, RIDI_DEVICEINFO, &info, &sz); - ok(ret == -1, "GetRawInputDeviceInfo gave wrong failure: %d\n", err); + ok(ret == -1, "GetRawInputDeviceInfo gave wrong failure: %ld\n", err); ok(sz == sizeof(info), "GetRawInputDeviceInfo set wrong size\n"); ret = pGetRawInputDeviceInfoW(devices[i].hDevice, RIDI_DEVICEINFO, &info, &sz); - ok(ret == sizeof(info), "GetRawInputDeviceInfo gave wrong return: %d\n", err); + ok(ret == sizeof(info), "GetRawInputDeviceInfo gave wrong return: %ld\n", err); ok(sz == sizeof(info), "GetRawInputDeviceInfo set wrong size\n"); - ok(info.dwType == devices[i].dwType, "GetRawInputDeviceInfo set wrong type: 0x%x\n", info.dwType); + ok(info.dwType == devices[i].dwType, "GetRawInputDeviceInfo set wrong type: 0x%lx\n", info.dwType); memset(&info, 0, sizeof(info)); info.cbSize = sizeof(info); ret = pGetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICEINFO, &info, &sz); - ok(ret == sizeof(info), "GetRawInputDeviceInfo gave wrong return: %d\n", err); + ok(ret == sizeof(info), "GetRawInputDeviceInfo gave wrong return: %ld\n", err); ok(sz == sizeof(info), "GetRawInputDeviceInfo set wrong size\n"); - ok(info.dwType == devices[i].dwType, "GetRawInputDeviceInfo set wrong type: 0x%x\n", info.dwType); + ok(info.dwType == devices[i].dwType, "GetRawInputDeviceInfo set wrong type: 0x%lx\n", info.dwType); /* setupapi returns an NT device path, but CreateFile() < Vista can't * understand that; so use the \\?\ prefix instead */ name[1] = '\\'; file = CreateFileW(name, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); - todo_wine_if(info.dwType != RIM_TYPEHID) - ok(file != INVALID_HANDLE_VALUE, "Failed to open %s, error %u\n", wine_dbgstr_w(name), GetLastError()); + ok(file != INVALID_HANDLE_VALUE, "Failed to open %s, error %lu\n", wine_dbgstr_w(name), GetLastError()); + + sz = 0; + ret = pGetRawInputDeviceInfoW(devices[i].hDevice, RIDI_PREPARSEDDATA, NULL, &sz); + ok(ret == 0, "GetRawInputDeviceInfo gave wrong return: %u\n", ret); + ok((info.dwType == RIM_TYPEHID && sz != 0) || + (info.dwType != RIM_TYPEHID && sz == 0), + "Got wrong PPD size for type 0x%lx: %u\n", info.dwType, sz); + + ppd = malloc(sz); + ret = pGetRawInputDeviceInfoW(devices[i].hDevice, RIDI_PREPARSEDDATA, ppd, &sz); + ok(ret == sz, "GetRawInputDeviceInfo gave wrong return: %u, should be %u\n", ret, sz); + + if (file != INVALID_HANDLE_VALUE && ret == sz) + { + PHIDP_PREPARSED_DATA preparsed; + + if (info.dwType == RIM_TYPEHID) + { + br = HidD_GetPreparsedData(file, &preparsed); + ok(br == TRUE, "HidD_GetPreparsedData failed\n"); + + if (br) + ok(!memcmp(preparsed, ppd, sz), "Expected to get same preparsed data\n"); + } + else + { + /* succeeds on hardware, fails in some VMs */ + br = HidD_GetPreparsedData(file, &preparsed); + ok(br == TRUE || broken(br == FALSE), "HidD_GetPreparsedData failed\n"); + } + + if (br) + HidD_FreePreparsedData(preparsed); + } + + free(ppd); + CloseHandle(file); } @@ -1693,12 +2110,1100 @@ static void test_GetRawInputDeviceList(void) static void test_GetRawInputData(void) { - UINT size; - UINT ret; + UINT size = 0; /* Null raw input handle */ - ret = GetRawInputData(NULL, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)); - ok(ret == ~0U, "Expect ret %u, got %u\n", ~0U, ret); + SetLastError( 0xdeadbeef ); + ok_ret( (UINT)-1, GetRawInputData( NULL, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER) ) ); + ok_ret( ERROR_INVALID_HANDLE, GetLastError() ); +} + +static void test_RegisterRawInputDevices(void) +{ + HWND hwnd; + RAWINPUTDEVICE raw_devices[2] = {0}; + UINT count, raw_devices_count; + MSG msg; + + raw_devices[0].usUsagePage = HID_USAGE_PAGE_GENERIC; + raw_devices[0].usUsage = HID_USAGE_GENERIC_GAMEPAD; + raw_devices[1].usUsagePage = HID_USAGE_PAGE_GENERIC; + raw_devices[1].usUsage = HID_USAGE_GENERIC_JOYSTICK; + + hwnd = create_foreground_window( FALSE ); + + SetLastError( 0xdeadbeef ); + ok_ret( 0, RegisterRawInputDevices( NULL, 0, 0 ) ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + + SetLastError( 0xdeadbeef ); + ok_ret( 0, RegisterRawInputDevices( raw_devices, ARRAY_SIZE( raw_devices ), 0 ) ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + + ok_ret( 1, RegisterRawInputDevices( raw_devices, ARRAY_SIZE( raw_devices ), sizeof(RAWINPUTDEVICE) ) ); + + SetLastError( 0xdeadbeef ); + ok_ret( (UINT)-1, GetRegisteredRawInputDevices( NULL, NULL, 0 ) ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + + SetLastError( 0xdeadbeef ); + ok_ret( (UINT)-1, GetRegisteredRawInputDevices( NULL, &raw_devices_count, 0 ) ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + + raw_devices_count = 0; + ok_ret( 0, GetRegisteredRawInputDevices( NULL, &raw_devices_count, sizeof(RAWINPUTDEVICE) ) ); + ok_eq( 2, raw_devices_count, UINT, "%u" ); + + SetLastError( 0xdeadbeef ); + raw_devices_count = 0; + count = GetRegisteredRawInputDevices( raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE) ); + if (broken(count == 0) /* depends on windows versions */) + win_skip( "Ignoring GetRegisteredRawInputDevices success\n" ); + else + { + ok_eq( -1, count, int, "%d" ); + ok_eq( 0, raw_devices_count, UINT, "%u" ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + } + + SetLastError( 0xdeadbeef ); + raw_devices_count = 1; + ok_ret( (UINT)-1, GetRegisteredRawInputDevices( raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE) ) ); + ok_eq( 2, raw_devices_count, UINT, "%u" ); + ok_ret( ERROR_INSUFFICIENT_BUFFER, GetLastError() ); + + memset( raw_devices, 0, sizeof(raw_devices) ); + raw_devices_count = ARRAY_SIZE(raw_devices); + ok_ret( 2, GetRegisteredRawInputDevices( raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE) ) ); + ok_eq( 2, raw_devices_count, UINT, "%u" ); + ok_eq( HID_USAGE_PAGE_GENERIC, raw_devices[0].usUsagePage, USHORT, "%#x" ); + ok_eq( HID_USAGE_GENERIC_JOYSTICK, raw_devices[0].usUsage, USHORT, "%#x" ); + ok_eq( HID_USAGE_PAGE_GENERIC, raw_devices[1].usUsagePage, USHORT, "%#x" ); + ok_eq( HID_USAGE_GENERIC_GAMEPAD, raw_devices[1].usUsage, USHORT, "%#x" ); + + /* RIDEV_INPUTSINK requires hwndTarget != NULL */ + raw_devices[0].dwFlags = RIDEV_INPUTSINK; + raw_devices[0].hwndTarget = 0; + raw_devices[1].dwFlags = RIDEV_INPUTSINK; + raw_devices[1].hwndTarget = 0; + + SetLastError(0xdeadbeef); + ok_ret( 0, RegisterRawInputDevices( raw_devices, ARRAY_SIZE( raw_devices ), sizeof(RAWINPUTDEVICE) ) ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + + raw_devices[0].hwndTarget = hwnd; + raw_devices[1].hwndTarget = hwnd; + ok_ret( 1, RegisterRawInputDevices( raw_devices, ARRAY_SIZE( raw_devices ), sizeof(RAWINPUTDEVICE) ) ); + + /* RIDEV_DEVNOTIFY send messages for any pre-existing device */ + raw_devices[0].dwFlags = RIDEV_DEVNOTIFY; + raw_devices[0].hwndTarget = 0; + raw_devices[0].usUsagePage = HID_USAGE_PAGE_GENERIC; + raw_devices[0].usUsage = HID_USAGE_GENERIC_MOUSE; + raw_devices[1].dwFlags = RIDEV_DEVNOTIFY; + raw_devices[1].hwndTarget = 0; + raw_devices[1].usUsagePage = HID_USAGE_PAGE_GENERIC; + raw_devices[1].usUsage = HID_USAGE_GENERIC_KEYBOARD; + + ok_ret( 1, RegisterRawInputDevices( raw_devices, ARRAY_SIZE( raw_devices ), sizeof(RAWINPUTDEVICE) ) ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) + { + ok_ne( WM_INPUT_DEVICE_CHANGE, msg.message, UINT, "%#x" ); + TranslateMessage( &msg ); + DispatchMessageW( &msg ); + } + + /* RIDEV_DEVNOTIFY send messages only to hwndTarget */ + raw_devices[0].hwndTarget = hwnd; + raw_devices[1].hwndTarget = hwnd; + + count = 0; + ok_ret( 1, RegisterRawInputDevices( raw_devices, ARRAY_SIZE( raw_devices ), sizeof(RAWINPUTDEVICE) ) ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) + { + if (msg.message == WM_INPUT_DEVICE_CHANGE) count++; + TranslateMessage( &msg ); + DispatchMessageW( &msg ); + } + ok( count >= 2, "got %u messages\n", count ); + + count = 0; + ok_ret( 1, RegisterRawInputDevices( raw_devices, ARRAY_SIZE( raw_devices ), sizeof(RAWINPUTDEVICE) ) ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) + { + if (msg.message == WM_INPUT_DEVICE_CHANGE) count++; + TranslateMessage( &msg ); + DispatchMessageW( &msg ); + } + ok( count >= 2, "got %u messages\n", count ); + + /* RIDEV_REMOVE requires hwndTarget == NULL */ + raw_devices[0].dwFlags = RIDEV_REMOVE; + raw_devices[0].hwndTarget = hwnd; + raw_devices[1].dwFlags = RIDEV_REMOVE; + raw_devices[1].hwndTarget = hwnd; + + SetLastError(0xdeadbeef); + ok_ret( 0, RegisterRawInputDevices( raw_devices, ARRAY_SIZE( raw_devices ), sizeof(RAWINPUTDEVICE) ) ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + + raw_devices[0].hwndTarget = 0; + raw_devices[1].hwndTarget = 0; + ok_ret( 1, RegisterRawInputDevices( raw_devices, ARRAY_SIZE( raw_devices ), sizeof(RAWINPUTDEVICE) ) ); + + ok_ret( 1, DestroyWindow( hwnd ) ); +} + +static int rawinputbuffer_wndproc_count; + +typedef struct +{ + DWORD dwType; + DWORD dwSize; + ULONG hDevice; + ULONG wParam; +} RAWINPUTHEADER32; + +#ifdef _WIN64 +typedef RAWINPUTHEADER RAWINPUTHEADER64; +typedef RAWINPUT RAWINPUT64; +#else +typedef struct +{ + DWORD dwType; + DWORD dwSize; + ULONGLONG hDevice; + ULONGLONG wParam; +} RAWINPUTHEADER64; + +typedef struct +{ + RAWINPUTHEADER64 header; + union { + RAWMOUSE mouse; + RAWKEYBOARD keyboard; + RAWHID hid; + } data; +} RAWINPUT64; +#endif + +static LRESULT CALLBACK rawinputbuffer_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if (msg == WM_INPUT) + { + UINT i, size, rawinput_size, iteration = rawinputbuffer_wndproc_count++; + char buffer[16 * sizeof(RAWINPUT64)]; + RAWINPUT64 *rawbuffer64 = (RAWINPUT64 *)buffer; + RAWINPUT *rawbuffer = (RAWINPUT *)buffer; + HRAWINPUT handle = (HRAWINPUT)lparam; + RAWINPUT rawinput = {{0}}; + + winetest_push_context( "%u", iteration ); + + if (is_wow64) rawinput_size = sizeof(RAWINPUTHEADER64) + sizeof(RAWKEYBOARD); + else rawinput_size = sizeof(RAWINPUTHEADER) + sizeof(RAWKEYBOARD); + + size = sizeof(buffer); + memset( buffer, 0, sizeof(buffer) ); + ok_ret( 3, GetRawInputBuffer( rawbuffer, &size, sizeof(RAWINPUTHEADER)) ); + ok_eq( sizeof(buffer), size, UINT, "%u" ); + + for (i = 0; i < 3; ++i) + { + winetest_push_context( "%u", i ); + if (is_wow64) + { + RAWINPUT64 *rawinput = (RAWINPUT64 *)(buffer + i * rawinput_size); + ok_eq( RIM_TYPEKEYBOARD, rawinput->header.dwType, UINT, "%u" ); + ok_eq( rawinput_size, rawinput->header.dwSize, UINT, "%u" ); + ok_eq( wparam, rawinput->header.wParam, WPARAM, "%Iu" ); + ok_eq( i + 2, rawinput->data.keyboard.MakeCode, WPARAM, "%Iu" ); + } + else + { + RAWINPUT *rawinput = (RAWINPUT *)(buffer + i * rawinput_size); + ok_eq( RIM_TYPEKEYBOARD, rawinput->header.dwType, UINT, "%u" ); + ok_eq( rawinput_size, rawinput->header.dwSize, UINT, "%u" ); + ok_eq( wparam, rawinput->header.wParam, WPARAM, "%Iu" ); + ok_eq( i + 2, rawinput->data.keyboard.MakeCode, WPARAM, "%Iu" ); + } + winetest_pop_context(); + } + + /* the first event should be removed by the next GetRawInputBuffer call + * and the others should do another round through the message loop but not more */ + if (iteration == 0) + { + keybd_event( 'X', 5, 0, 0 ); + keybd_event( 'X', 6, KEYEVENTF_KEYUP, 0 ); + keybd_event( 'X', 2, KEYEVENTF_KEYUP, 0 ); + keybd_event( 'X', 3, 0, 0 ); + keybd_event( 'X', 4, KEYEVENTF_KEYUP, 0 ); + + /* even though rawinput_size is the minimum required size, + * it needs one more byte to return success */ + size = sizeof(rawinput) + 1; + memset( buffer, 0, sizeof(buffer) ); + ok_ret( 1, GetRawInputBuffer( rawbuffer, &size, sizeof(RAWINPUTHEADER) ) ); + if (is_wow64) ok_eq( 5, rawbuffer64->data.keyboard.MakeCode, WPARAM, "%Iu" ); + else ok_eq( 5, rawbuffer->data.keyboard.MakeCode, WPARAM, "%Iu" ); + + /* peek the messages now, they should still arrive in the correct order */ + winetest_pop_context(); + wait_messages( 0, FALSE ); + winetest_push_context( "%u", iteration ); + + /* reading the message data now should fail, the data + * from the first message has been overwritten. */ + SetLastError( 0xdeadbeef ); + size = sizeof(rawinput); + ok_ret( (UINT)-1, GetRawInputData( handle, RID_HEADER, &rawinput, &size, sizeof(RAWINPUTHEADER) ) ); + ok_ret( ERROR_INVALID_HANDLE, GetLastError() ); + } + else + { + SetLastError( 0xdeadbeef ); + ok_ret( (UINT)-1, GetRawInputData( handle, RID_HEADER, &rawinput, &size, 0) ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + + SetLastError( 0xdeadbeef ); + ok_ret( (UINT)-1, GetRawInputData( handle, RID_HEADER, &rawinput, &size, sizeof(RAWINPUTHEADER) + 1 ) ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + + size = sizeof(RAWINPUTHEADER); + rawinput_size = sizeof(RAWINPUTHEADER) + sizeof(RAWKEYBOARD); + ok_ret( sizeof(RAWINPUTHEADER), GetRawInputData( handle, RID_HEADER, &rawinput, &size, sizeof(RAWINPUTHEADER) ) ); + ok_eq( rawinput_size, rawinput.header.dwSize, UINT, "%u" ); + ok_eq( RIM_TYPEKEYBOARD, rawinput.header.dwType, UINT, "%u" ); + + + SetLastError( 0xdeadbeef ); + ok_ret( (UINT)-1, GetRawInputData( handle, RID_INPUT, &rawinput, &size, 0) ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + + SetLastError( 0xdeadbeef ); + ok_ret( (UINT)-1, GetRawInputData( handle, RID_INPUT, &rawinput, &size, sizeof(RAWINPUTHEADER) + 1 ) ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + + SetLastError( 0xdeadbeef ); + size = 0; + ok_ret( (UINT)-1, GetRawInputData( handle, RID_INPUT, &rawinput, &size, sizeof(RAWINPUTHEADER) ) ); + ok_ret( ERROR_INSUFFICIENT_BUFFER, GetLastError() ); + + SetLastError( 0xdeadbeef ); + size = sizeof(rawinput); + ok_ret( (UINT)-1, GetRawInputData( handle, 0, &rawinput, &size, sizeof(RAWINPUTHEADER) ) ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + + SetLastError( 0xdeadbeef ); + size = sizeof(rawinput); + ok_ret( rawinput_size, GetRawInputData( handle, RID_INPUT, &rawinput, &size, sizeof(RAWINPUTHEADER) ) ); + ok_eq( 6, rawinput.data.keyboard.MakeCode, UINT, "%u" ); + + SetLastError( 0xdeadbeef ); + size = sizeof(buffer); + if (sizeof(void *) == 8) + { + ok_ret( (UINT)-1, GetRawInputData( handle, RID_INPUT, &rawinput, &size, sizeof(RAWINPUTHEADER32) ) ); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputData returned %08lx\n", GetLastError()); + } + else if (is_wow64) + { + todo_wine + ok_ret( rawinput_size, GetRawInputData( handle, RID_INPUT, &rawinput, &size, sizeof(RAWINPUTHEADER64) ) ); + ok_eq( 6, rawinput.data.keyboard.MakeCode, UINT, "%u" ); + todo_wine + ok_ret( 0xdeadbeef, GetLastError() ); + } + else + { + ok_ret( (UINT)-1, GetRawInputData( handle, RID_INPUT, &rawinput, &size, sizeof(RAWINPUTHEADER64) ) ); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputData returned %08lx\n", GetLastError()); + } + } + + winetest_pop_context(); + return 0; + } + + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + +static void test_GetRawInputBuffer(void) +{ + unsigned int size, rawinput_size, header_size; + RAWINPUTDEVICE raw_devices[1]; + char buffer[16 * sizeof(RAWINPUT64)]; + RAWINPUT64 *rawbuffer64 = (RAWINPUT64 *)buffer; + RAWINPUT *rawbuffer = (RAWINPUT *)buffer; + DWORD t1, t2, t3, now, pos1, pos2; + LPARAM extra_info1, extra_info2; + INPUT_MESSAGE_SOURCE source; + POINT pt; + HWND hwnd; + BOOL ret; + + if (is_wow64) rawinput_size = sizeof(RAWINPUTHEADER64) + sizeof(RAWMOUSE); + else rawinput_size = sizeof(RAWINPUTHEADER) + sizeof(RAWMOUSE); + + hwnd = create_foreground_window( TRUE ); + SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)rawinputbuffer_wndproc ); + + if (pGetCurrentInputMessageSource) + { + ret = pGetCurrentInputMessageSource( &source ); + ok( ret, "got error %lu.\n", GetLastError() ); + ok( !source.deviceType, "got %#x.\n", source.deviceType ); + ok( !source.originId, "got %#x.\n", source.originId ); + } + + raw_devices[0].usUsagePage = HID_USAGE_PAGE_GENERIC; + raw_devices[0].usUsage = HID_USAGE_GENERIC_MOUSE; + raw_devices[0].dwFlags = RIDEV_INPUTSINK; + raw_devices[0].hwndTarget = hwnd; + ok_ret( 1, RegisterRawInputDevices( raw_devices, ARRAY_SIZE( raw_devices ), sizeof(RAWINPUTDEVICE) ) ); + + /* check basic error cases */ + + SetLastError( 0xdeadbeef ); + ok_ret( (UINT)-1, GetRawInputBuffer( NULL, NULL, sizeof(RAWINPUTHEADER) ) ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + SetLastError( 0xdeadbeef ); + size = sizeof(buffer); + ok_ret( (UINT)-1, GetRawInputBuffer( rawbuffer, &size, 0 ) ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + + /* valid calls, but no input */ + t1 = GetMessageTime(); + pos1 = GetMessagePos(); + extra_info1 = GetMessageExtraInfo(); + now = GetTickCount(); + ok( t1 <= now, "got %lu, %lu.\n", t1, now ); + + size = sizeof(buffer); + ok_ret( 0, GetRawInputBuffer( NULL, &size, sizeof(RAWINPUTHEADER) ) ); + ok_eq( 0, size, UINT, "%u" ); + size = 0; + ok_ret( 0, GetRawInputBuffer( rawbuffer, &size, sizeof(RAWINPUTHEADER) ) ); + ok_eq( 0, size, UINT, "%u" ); + size = sizeof(buffer); + ok_ret( 0, GetRawInputBuffer( rawbuffer, &size, sizeof(RAWINPUTHEADER) ) ); + ok_eq( 0, size, UINT, "%u" ); + + + Sleep( 20 ); + mouse_event( MOUSEEVENTF_MOVE, 5, 0, 0, 0xdeadbeef ); + t2 = GetMessageTime(); + ok( t2 == t1, "got %lu, %lu.\n", t1, t2 ); + /* invalid calls with input */ + + SetLastError( 0xdeadbeef ); + size = 0; + ok_ret( (UINT)-1, GetRawInputBuffer( rawbuffer, &size, sizeof(RAWINPUTHEADER) ) ); + ok_eq( rawinput_size, size, UINT, "%u" ); + ok_ret( ERROR_INSUFFICIENT_BUFFER, GetLastError() ); + t2 = GetMessageTime(); + ok( t2 == t1, "got %lu, %lu.\n", t1, t2 ); + + SetLastError( 0xdeadbeef ); + size = sizeof(buffer); + ok_ret( (UINT)-1, GetRawInputBuffer( rawbuffer, &size, 0 ) ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + SetLastError( 0xdeadbeef ); + size = sizeof(buffer); + ok_ret( (UINT)-1, GetRawInputBuffer( rawbuffer, &size, sizeof(RAWINPUTHEADER) + 1 ) ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + + /* the function returns 64-bit RAWINPUT structures on WoW64, but still + * forbids sizeof(RAWINPUTHEADER) from the wrong architecture */ + SetLastError( 0xdeadbeef ); + size = sizeof(buffer); + header_size = (sizeof(void *) == 8 ? sizeof(RAWINPUTHEADER32) : sizeof(RAWINPUTHEADER64)); + ok_ret( (UINT)-1, GetRawInputBuffer( rawbuffer, &size, header_size ) ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + + + /* NOTE: calling with size == rawinput_size returns an error, */ + /* BUT it fills the buffer nonetheless and empties the internal buffer (!!) */ + + Sleep( 20 ); + t2 = GetTickCount(); + size = 0; + ok_ret( 0, GetRawInputBuffer( NULL, &size, sizeof(RAWINPUTHEADER) ) ); + ok_eq( rawinput_size, size, UINT, "%u" ); + + SetLastError( 0xdeadbeef ); + size = rawinput_size; + memset( buffer, 0, sizeof(buffer) ); + ok_ret( (UINT)-1, GetRawInputBuffer( rawbuffer, &size, sizeof(RAWINPUTHEADER) ) ); + ok_ret( ERROR_INSUFFICIENT_BUFFER, GetLastError() ); + if (is_wow64) ok_eq( 5, rawbuffer64->data.mouse.lLastX, UINT, "%u" ); + else ok_eq( 5, rawbuffer->data.mouse.lLastX, UINT, "%u" ); + + t3 = GetMessageTime(); + pos2 = GetMessagePos(); + extra_info2 = GetMessageExtraInfo(); + ok( extra_info2 == extra_info1, "got %#Ix, %#Ix.\n", extra_info1, extra_info2 ); + GetCursorPos( &pt ); + ok( t3 > t1, "got %lu, %lu.\n", t1, t3 ); + ok( t3 < t2, "got %lu, %lu.\n", t2, t3 ); + ok( pos1 == pos2, "got pos1 (%ld, %ld), pos2 (%ld, %ld), pt (%ld %ld).\n", + pos1 & 0xffff, pos1 >> 16, pos2 & 0xffff, pos2 >> 16, pt.x, pt.y ); + if (pGetCurrentInputMessageSource) + { + ret = pGetCurrentInputMessageSource( &source ); + ok( ret, "got error %lu.\n", GetLastError() ); + ok( !source.deviceType, "got %#x.\n", source.deviceType ); + ok( !source.originId, "got %#x.\n", source.originId ); + } + + /* no more data to read */ + + size = sizeof(buffer); + ok_ret( 0, GetRawInputBuffer( NULL, &size, sizeof(RAWINPUTHEADER) ) ); + ok_eq( 0, size, UINT, "%u" ); + + + /* rawinput_size + 1 succeeds */ + t1 = GetMessageTime(); + pos1 = GetMessagePos(); + extra_info1 = GetMessageExtraInfo(); + now = GetTickCount(); + ok( t1 <= now, "got %lu, %lu.\n", t1, now ); + + Sleep( 20 ); + mouse_event( MOUSEEVENTF_MOVE, 5, 0, 0, 0xfeedcafe ); + + t2 = GetMessageTime(); + ok( t2 == t1, "got %lu, %lu.\n", t1, t2 ); + + Sleep( 20 ); + t2 = GetTickCount(); + + size = rawinput_size + 1; + memset( buffer, 0, sizeof(buffer) ); + ok_ret( 1, GetRawInputBuffer( rawbuffer, &size, sizeof(RAWINPUTHEADER) ) ); + ok_eq( rawinput_size + 1, size, UINT, "%u" ); + if (is_wow64) + { + ok_eq( RIM_TYPEMOUSE, rawbuffer64->header.dwType, UINT, "%#x" ); + ok_eq( 0, rawbuffer64->header.wParam, WPARAM, "%Iu" ); + ok_eq( 5, rawbuffer64->data.mouse.lLastX, UINT, "%u" ); + } + else + { + ok_eq( RIM_TYPEMOUSE, rawbuffer->header.dwType, UINT, "%#x" ); + ok_eq( 0, rawbuffer->header.wParam, WPARAM, "%Iu" ); + ok_eq( 5, rawbuffer->data.mouse.lLastX, UINT, "%u" ); + } + + size = sizeof(buffer); + ok_ret( 0, GetRawInputBuffer( NULL, &size, sizeof(RAWINPUTHEADER) ) ); + ok_eq( 0, size, UINT, "%u" ); + + t3 = GetMessageTime(); + pos2 = GetMessagePos(); + extra_info2 = GetMessageExtraInfo(); + GetCursorPos(&pt); + ok( extra_info2 == extra_info1, "got %#Ix, %#Ix.\n", extra_info1, extra_info2 ); + ok( t3 > t1, "got %lu, %lu.\n", t1, t3 ); + ok( t3 < t2, "got %lu, %lu.\n", t2, t3 ); + ok( pos1 == pos2, "got pos1 (%ld, %ld), pos2 (%ld, %ld), pt (%ld %ld).\n", + pos1 & 0xffff, pos1 >> 16, pos2 & 0xffff, pos2 >> 16, pt.x, pt.y ); + + raw_devices[0].dwFlags = RIDEV_REMOVE; + raw_devices[0].hwndTarget = 0; + ok_ret( 1, RegisterRawInputDevices( raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE) ) ); + + + /* some keyboard tests to better check fields under wow64 */ + raw_devices[0].usUsagePage = HID_USAGE_PAGE_GENERIC; + raw_devices[0].usUsage = HID_USAGE_GENERIC_KEYBOARD; + raw_devices[0].dwFlags = RIDEV_INPUTSINK; + raw_devices[0].hwndTarget = hwnd; + ok_ret( 1, RegisterRawInputDevices( raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE) ) ); + + keybd_event( 'X', 0x2d, 0, 0 ); + keybd_event( 'X', 0x2d, KEYEVENTF_KEYUP, 0 ); + + if (is_wow64) rawinput_size = sizeof(RAWINPUTHEADER64) + sizeof(RAWKEYBOARD); + else rawinput_size = sizeof(RAWINPUTHEADER) + sizeof(RAWKEYBOARD); + + size = 0; + ok_ret( 0, GetRawInputBuffer( NULL, &size, sizeof(RAWINPUTHEADER) ) ); + ok_eq( rawinput_size, size, UINT, "%u" ); + + size = sizeof(buffer); + memset( buffer, 0, sizeof(buffer) ); + ok_ret( 2, GetRawInputBuffer( rawbuffer, &size, sizeof(RAWINPUTHEADER) ) ); + ok_eq( sizeof(buffer), size, UINT, "%u" ); + if (is_wow64) + { + ok_eq( RIM_TYPEKEYBOARD, rawbuffer64->header.dwType, UINT, "%u" ); + ok_eq( 0, rawbuffer64->header.wParam, UINT, "%u" ); + ok_eq( 0x2d, rawbuffer64->data.keyboard.MakeCode, UINT, "%#x" ); + } + else + { + ok_eq( RIM_TYPEKEYBOARD, rawbuffer->header.dwType, UINT, "%u" ); + ok_eq( 0, rawbuffer->header.wParam, UINT, "%u" ); + ok_eq( 0x2d, rawbuffer->data.keyboard.MakeCode, UINT, "%#x" ); + } + + + /* test GetRawInputBuffer interaction with WM_INPUT messages */ + + rawinputbuffer_wndproc_count = 0; + keybd_event( 'X', 1, 0, 0 ); + keybd_event( 'X', 2, KEYEVENTF_KEYUP, 0 ); + keybd_event( 'X', 3, 0, 0 ); + keybd_event( 'X', 4, KEYEVENTF_KEYUP, 0 ); + wait_messages( 100, FALSE ); + ok_eq( 2, rawinputbuffer_wndproc_count, UINT, "%u" ); + + keybd_event( 'X', 3, 0, 0 ); + keybd_event( 'X', 4, KEYEVENTF_KEYUP, 0 ); + + raw_devices[0].dwFlags = RIDEV_REMOVE; + raw_devices[0].hwndTarget = 0; + ok_ret( 1, RegisterRawInputDevices( raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE) ) ); + + + /* rawinput buffer survives registered device changes */ + + size = rawinput_size + 1; + ok_ret( 1, GetRawInputBuffer( rawbuffer, &size, sizeof(RAWINPUTHEADER) ) ); + ok_eq( rawinput_size + 1, size, UINT, "%u" ); + + raw_devices[0].usUsagePage = HID_USAGE_PAGE_GENERIC; + raw_devices[0].usUsage = HID_USAGE_GENERIC_MOUSE; + raw_devices[0].dwFlags = RIDEV_INPUTSINK; + raw_devices[0].hwndTarget = hwnd; + ok_ret( 1, RegisterRawInputDevices( raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE) ) ); + + if (is_wow64) rawinput_size = sizeof(RAWINPUTHEADER64) + sizeof(RAWMOUSE); + else rawinput_size = sizeof(RAWINPUTHEADER) + sizeof(RAWMOUSE); + + size = rawinput_size + 1; + ok_ret( 1, GetRawInputBuffer( rawbuffer, &size, sizeof(RAWINPUTHEADER) ) ); + ok_eq( rawinput_size + 1, size, UINT, "%u" ); + size = sizeof(buffer); + ok_ret( 0, GetRawInputBuffer( rawbuffer, &size, sizeof(RAWINPUTHEADER) ) ); + ok_eq( 0, size, UINT, "%u" ); + + raw_devices[0].dwFlags = RIDEV_REMOVE; + raw_devices[0].hwndTarget = 0; + ok_ret( 1, RegisterRawInputDevices( raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE) ) ); + + + ok_ret( 1, DestroyWindow( hwnd ) ); +} + +static BOOL rawinput_test_received_legacy; +static BOOL rawinput_test_received_raw; +static BOOL rawinput_test_received_rawfg; + +static LRESULT CALLBACK rawinput_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + UINT ret, raw_size; + RAWINPUT raw; + + if (msg == WM_INPUT) + { + todo_wine_if(rawinput_test_received_raw) + ok(!rawinput_test_received_raw, "Unexpected spurious WM_INPUT message.\n"); + ok(wparam == RIM_INPUT || wparam == RIM_INPUTSINK, "Unexpected wparam: %Iu\n", wparam); + + rawinput_test_received_raw = TRUE; + if (wparam == RIM_INPUT) rawinput_test_received_rawfg = TRUE; + + ret = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, NULL, &raw_size, sizeof(RAWINPUTHEADER)); + ok(ret == 0, "GetRawInputData failed\n"); + ok(raw_size <= sizeof(raw), "Unexpected rawinput data size: %u\n", raw_size); + + raw_size = sizeof(raw); + ret = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &raw, &raw_size, sizeof(RAWINPUTHEADER)); + ok(ret > 0 && ret != (UINT)-1, "GetRawInputData failed\n"); + ok(raw.header.dwType == RIM_TYPEMOUSE, "Unexpected rawinput type: %lu\n", raw.header.dwType); + ok(raw.header.dwSize == raw_size, "Expected size %u, got %lu\n", raw_size, raw.header.dwSize); + todo_wine_if (wparam) + ok(raw.header.wParam == wparam, "Expected wparam %Iu, got %Iu\n", wparam, raw.header.wParam); + + ok(!(raw.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE), "Unexpected absolute rawinput motion\n"); + ok(!(raw.data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP), "Unexpected virtual desktop rawinput motion\n"); + } + + if (msg == WM_MOUSEMOVE) rawinput_test_received_legacy = TRUE; + + return DefWindowProcA(hwnd, msg, wparam, lparam); +} + +struct rawinput_test +{ + BOOL register_device; + BOOL register_window; + DWORD register_flags; + BOOL expect_legacy; + BOOL expect_raw; + BOOL expect_rawfg; + BOOL todo_legacy; + BOOL todo_raw; + BOOL todo_rawfg; +}; + +struct rawinput_test rawinput_tests[] = +{ + { FALSE, FALSE, 0, TRUE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, + { TRUE, FALSE, 0, TRUE, TRUE, TRUE, /* todos: */ FALSE, FALSE, FALSE }, + { TRUE, TRUE, 0, TRUE, TRUE, TRUE, /* todos: */ FALSE, FALSE, FALSE }, + { TRUE, TRUE, RIDEV_NOLEGACY, FALSE, TRUE, TRUE, /* todos: */ FALSE, FALSE, FALSE }, + + /* same-process foreground tests */ + { TRUE, FALSE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, + { TRUE, TRUE, 0, FALSE, TRUE, TRUE, /* todos: */ FALSE, FALSE, FALSE }, + + /* cross-process foreground tests */ + { TRUE, TRUE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, + { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, + { TRUE, TRUE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, + + /* multi-process rawinput tests */ + { TRUE, TRUE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, + { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, + { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, + + { TRUE, TRUE, RIDEV_EXINPUTSINK, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, + { TRUE, TRUE, RIDEV_EXINPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, TRUE, FALSE }, + + /* cross-desktop foreground tests */ + { TRUE, FALSE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, + { TRUE, TRUE, 0, FALSE, TRUE, TRUE, /* todos: */ FALSE, FALSE, FALSE }, + { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, +}; + +static void rawinput_test_process(void) +{ + RAWINPUTDEVICE raw_devices[1]; + HANDLE ready, start, done; + DWORD ret; + POINT pt; + HWND hwnd = NULL; + MSG msg; + int i; + + ready = OpenEventA(EVENT_ALL_ACCESS, FALSE, "rawinput_test_process_ready"); + ok(ready != 0, "OpenEventA failed, error: %lu\n", GetLastError()); + + start = OpenEventA(EVENT_ALL_ACCESS, FALSE, "rawinput_test_process_start"); + ok(start != 0, "OpenEventA failed, error: %lu\n", GetLastError()); + + done = OpenEventA(EVENT_ALL_ACCESS, FALSE, "rawinput_test_process_done"); + ok(done != 0, "OpenEventA failed, error: %lu\n", GetLastError()); + + for (i = 0; i < ARRAY_SIZE(rawinput_tests); ++i) + { + WaitForSingleObject(ready, INFINITE); + ResetEvent(ready); + + switch (i) + { + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 16: + GetCursorPos(&pt); + + hwnd = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP, + pt.x - 50, pt.y - 50, 100, 100, 0, NULL, NULL, NULL); + SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)rawinput_wndproc); + ok(hwnd != 0, "CreateWindow failed\n"); + empty_message_queue(); + + /* FIXME: Try to workaround X11/Win32 focus inconsistencies and + * make the window visible and foreground as hard as possible. */ + ShowWindow(hwnd, SW_SHOW); + SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); + SetForegroundWindow(hwnd); + UpdateWindow(hwnd); + empty_message_queue(); + + if (i == 9 || i == 10 || i == 11 || i == 12) + { + raw_devices[0].usUsagePage = 0x01; + raw_devices[0].usUsage = 0x02; + raw_devices[0].dwFlags = i == 11 ? RIDEV_INPUTSINK : 0; + raw_devices[0].hwndTarget = i == 11 ? hwnd : 0; + + SetLastError(0xdeadbeef); + ret = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE)); + ok(ret, "%d: RegisterRawInputDevices failed\n", i); + ok(GetLastError() == 0xdeadbeef, "%d: RegisterRawInputDevices returned %08lx\n", i, GetLastError()); + } + + rawinput_test_received_legacy = FALSE; + rawinput_test_received_raw = FALSE; + rawinput_test_received_rawfg = FALSE; + + /* fallthrough */ + case 14: + case 15: + if (i != 8) mouse_event(MOUSEEVENTF_MOVE, 5, 0, 0, 0); + empty_message_queue(); + break; + } + + SetEvent(start); + + while (MsgWaitForMultipleObjects(1, &done, FALSE, INFINITE, QS_ALLINPUT) != WAIT_OBJECT_0) + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + + ResetEvent(done); + + if (i == 9 || i == 10 || i == 11 || i == 12) + { + raw_devices[0].dwFlags = RIDEV_REMOVE; + raw_devices[0].hwndTarget = 0; + + flaky_wine + ok(rawinput_test_received_legacy, "%d: foreground process expected WM_MOUSEMOVE message\n", i); + ok(rawinput_test_received_raw, "%d: foreground process expected WM_INPUT message\n", i); + ok(rawinput_test_received_rawfg, "%d: foreground process expected RIM_INPUT message\n", i); + + SetLastError(0xdeadbeef); + ret = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE)); + ok(ret, "%d: RegisterRawInputDevices failed\n", i); + ok(GetLastError() == 0xdeadbeef, "%d: RegisterRawInputDevices returned %08lx\n", i, GetLastError()); + } + + if (hwnd) DestroyWindow(hwnd); + } + + WaitForSingleObject(ready, INFINITE); + CloseHandle(done); + CloseHandle(start); + CloseHandle(ready); +} + +struct rawinput_test_thread_params +{ + HDESK desk; + HANDLE ready; + HANDLE start; + HANDLE done; +}; + +static DWORD WINAPI rawinput_test_desk_thread(void *arg) +{ + struct rawinput_test_thread_params *params = arg; + RAWINPUTDEVICE raw_devices[1]; + DWORD ret; + POINT pt; + HWND hwnd = NULL; + MSG msg; + int i; + + ok( SetThreadDesktop( params->desk ), "SetThreadDesktop failed\n" ); + + for (i = 14; i < ARRAY_SIZE(rawinput_tests); ++i) + { + WaitForSingleObject(params->ready, INFINITE); + ResetEvent(params->ready); + + switch (i) + { + case 14: + case 15: + case 16: + GetCursorPos(&pt); + + hwnd = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP, + pt.x - 50, pt.y - 50, 100, 100, 0, NULL, NULL, NULL); + ok(hwnd != 0, "CreateWindow failed\n"); + SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)rawinput_wndproc); + empty_message_queue(); + + /* FIXME: Try to workaround X11/Win32 focus inconsistencies and + * make the window visible and foreground as hard as possible. */ + ShowWindow(hwnd, SW_SHOW); + SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); + SetForegroundWindow(hwnd); + UpdateWindow(hwnd); + empty_message_queue(); + + raw_devices[0].usUsagePage = 0x01; + raw_devices[0].usUsage = 0x02; + raw_devices[0].dwFlags = rawinput_tests[i].register_flags; + raw_devices[0].hwndTarget = rawinput_tests[i].register_window ? hwnd : 0; + + rawinput_test_received_legacy = FALSE; + rawinput_test_received_raw = FALSE; + rawinput_test_received_rawfg = FALSE; + + SetLastError(0xdeadbeef); + ret = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE)); + ok(ret, "%d: RegisterRawInputDevices failed\n", i); + ok(GetLastError() == 0xdeadbeef, "%d: RegisterRawInputDevices returned %08lx\n", i, GetLastError()); + break; + } + + SetEvent(params->start); + + while (MsgWaitForMultipleObjects(1, ¶ms->done, FALSE, INFINITE, QS_ALLINPUT) != WAIT_OBJECT_0) + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + + ResetEvent(params->done); + if (hwnd) DestroyWindow(hwnd); + } + + return 0; +} + +static DWORD WINAPI rawinput_test_thread(void *arg) +{ + struct rawinput_test_thread_params *params = arg; + HANDLE thread; + POINT pt; + HWND hwnd = NULL; + int i; + + for (i = 0; i < 14; ++i) + { + WaitForSingleObject(params->ready, INFINITE); + ResetEvent(params->ready); + + switch (i) + { + case 4: + case 5: + GetCursorPos(&pt); + + hwnd = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP, + pt.x - 50, pt.y - 50, 100, 100, 0, NULL, NULL, NULL); + ok(hwnd != 0, "CreateWindow failed\n"); + empty_message_queue(); + + /* FIXME: Try to workaround X11/Win32 focus inconsistencies and + * make the window visible and foreground as hard as possible. */ + ShowWindow(hwnd, SW_SHOW); + SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); + SetForegroundWindow(hwnd); + UpdateWindow(hwnd); + empty_message_queue(); + + mouse_event(MOUSEEVENTF_MOVE, 5, 0, 0, 0); + empty_message_queue(); + break; + } + + SetEvent(params->start); + + WaitForSingleObject(params->done, INFINITE); + ResetEvent(params->done); + if (hwnd) DestroyWindow(hwnd); + } + + thread = CreateThread(NULL, 0, rawinput_test_desk_thread, params, 0, NULL); + ok(thread != NULL, "CreateThread failed\n"); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + + return 0; +} + +static void test_rawinput(const char* argv0) +{ + struct rawinput_test_thread_params params; + PROCESS_INFORMATION process_info; + RAWINPUTDEVICE raw_devices[1]; + STARTUPINFOA startup_info; + HANDLE thread, process_ready, process_start, process_done; + DWORD ret; + POINT pt, newpt; + HWND hwnd; + BOOL skipped; + char path[MAX_PATH]; + int i; + + params.desk = CreateDesktopA( "rawinput_test_desktop", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ); + ok( params.desk != NULL, "CreateDesktopA failed, last error: %lu\n", GetLastError() ); + + params.ready = CreateEventA(NULL, FALSE, FALSE, NULL); + ok(params.ready != NULL, "CreateEvent failed\n"); + + params.start = CreateEventA(NULL, FALSE, FALSE, NULL); + ok(params.start != NULL, "CreateEvent failed\n"); + + params.done = CreateEventA(NULL, FALSE, FALSE, NULL); + ok(params.done != NULL, "CreateEvent failed\n"); + + thread = CreateThread(NULL, 0, rawinput_test_thread, ¶ms, 0, NULL); + ok(thread != NULL, "CreateThread failed\n"); + + process_ready = CreateEventA(NULL, FALSE, FALSE, "rawinput_test_process_ready"); + ok(process_ready != NULL, "CreateEventA failed\n"); + + process_start = CreateEventA(NULL, FALSE, FALSE, "rawinput_test_process_start"); + ok(process_start != NULL, "CreateEventA failed\n"); + + process_done = CreateEventA(NULL, FALSE, FALSE, "rawinput_test_process_done"); + ok(process_done != NULL, "CreateEventA failed\n"); + + memset(&startup_info, 0, sizeof(startup_info)); + startup_info.cb = sizeof(startup_info); + startup_info.dwFlags = STARTF_USESHOWWINDOW; + startup_info.wShowWindow = SW_SHOWNORMAL; + + sprintf(path, "%s input rawinput_test", argv0); + ret = CreateProcessA(NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup_info, &process_info ); + ok(ret, "CreateProcess \"%s\" failed err %lu.\n", path, GetLastError()); + + SetCursorPos(100, 100); + empty_message_queue(); + + for (i = 0; i < ARRAY_SIZE(rawinput_tests); ++i) + { + GetCursorPos(&pt); + + hwnd = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP, + pt.x - 50, pt.y - 50, 100, 100, 0, NULL, NULL, NULL); + ok(hwnd != 0, "CreateWindow failed\n"); + if (i != 14 && i != 15 && i != 16) + SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)rawinput_wndproc); + empty_message_queue(); + + /* FIXME: Try to workaround X11/Win32 focus inconsistencies and + * make the window visible and foreground as hard as possible. */ + ShowWindow(hwnd, SW_SHOW); + SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); + SetForegroundWindow(hwnd); + UpdateWindow(hwnd); + empty_message_queue(); + + rawinput_test_received_legacy = FALSE; + rawinput_test_received_raw = FALSE; + rawinput_test_received_rawfg = FALSE; + + raw_devices[0].usUsagePage = 0x01; + raw_devices[0].usUsage = 0x02; + raw_devices[0].dwFlags = rawinput_tests[i].register_flags; + raw_devices[0].hwndTarget = rawinput_tests[i].register_window ? hwnd : 0; + + if (!rawinput_tests[i].register_device) + skipped = FALSE; + else + { + SetLastError(0xdeadbeef); + skipped = !RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE)); + if (rawinput_tests[i].register_flags == RIDEV_EXINPUTSINK && skipped) + win_skip("RIDEV_EXINPUTSINK not supported\n"); + else + ok(!skipped, "%d: RegisterRawInputDevices failed: %lu\n", i, GetLastError()); + } + + SetEvent(params.ready); + WaitForSingleObject(params.start, INFINITE); + ResetEvent(params.start); + + /* we need the main window to be over the other thread window, as although + * it is in another desktop, it will receive the messages directly otherwise */ + switch (i) + { + case 14: + case 15: + DestroyWindow(hwnd); + hwnd = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP, + pt.x - 50, pt.y - 50, 100, 100, 0, NULL, NULL, NULL); + ok(hwnd != 0, "CreateWindow failed\n"); + SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); + SetForegroundWindow(hwnd); + empty_message_queue(); + + rawinput_test_received_legacy = FALSE; + rawinput_test_received_raw = FALSE; + rawinput_test_received_rawfg = FALSE; + break; + } + + SetEvent(process_ready); + WaitForSingleObject(process_start, INFINITE); + ResetEvent(process_start); + + if (i <= 3 || i == 8) mouse_event(MOUSEEVENTF_MOVE, 5, 0, 0, 0); + empty_message_queue(); + + SetEvent(process_done); + SetEvent(params.done); + + flaky_wine + if (!skipped) + { + todo_wine_if(rawinput_tests[i].todo_legacy) + ok(rawinput_test_received_legacy == rawinput_tests[i].expect_legacy, + "%d: %sexpected WM_MOUSEMOVE message\n", i, rawinput_tests[i].expect_legacy ? "" : "un"); + todo_wine_if(rawinput_tests[i].todo_raw) + ok(rawinput_test_received_raw == rawinput_tests[i].expect_raw, + "%d: %sexpected WM_INPUT message\n", i, rawinput_tests[i].expect_raw ? "" : "un"); + todo_wine_if(rawinput_tests[i].todo_rawfg) + ok(rawinput_test_received_rawfg == rawinput_tests[i].expect_rawfg, + "%d: %sexpected RIM_INPUT message\n", i, rawinput_tests[i].expect_rawfg ? "" : "un"); + } + + GetCursorPos(&newpt); + ok((newpt.x - pt.x) == 5 || (newpt.x - pt.x) == 4, "%d: Unexpected cursor movement\n", i); + + if (rawinput_tests[i].register_device) + { + raw_devices[0].dwFlags = RIDEV_REMOVE; + raw_devices[0].hwndTarget = 0; + + SetLastError(0xdeadbeef); + ret = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE)); + ok(ret, "%d: RegisterRawInputDevices failed: %lu\n", i, GetLastError()); + } + + DestroyWindow(hwnd); + } + + SetEvent(process_ready); + winetest_wait_child_process(process_info.hProcess); + CloseHandle(process_info.hProcess); + CloseHandle(process_info.hThread); + CloseHandle(process_done); + CloseHandle(process_start); + CloseHandle(process_ready); + + WaitForSingleObject(thread, INFINITE); + + CloseHandle(params.done); + CloseHandle(params.start); + CloseHandle(params.ready); + CloseHandle(thread); + + CloseDesktop(params.desk); +} + +static void test_DefRawInputProc(void) +{ + LRESULT ret; + + SetLastError(0xdeadbeef); + ret = DefRawInputProc(NULL, 0, sizeof(RAWINPUTHEADER)); + ok(!ret, "got %Id\n", ret); + ok(GetLastError() == 0xdeadbeef, "got %ld\n", GetLastError()); + ret = DefRawInputProc(LongToPtr(0xcafe), 0xbeef, sizeof(RAWINPUTHEADER)); + ok(!ret, "got %Id\n", ret); + ok(GetLastError() == 0xdeadbeef, "got %ld\n", GetLastError()); + ret = DefRawInputProc(NULL, 0, sizeof(RAWINPUTHEADER) - 1); + ok(ret == -1, "got %Id\n", ret); + ok(GetLastError() == 0xdeadbeef, "got %ld\n", GetLastError()); + ret = DefRawInputProc(NULL, 0, sizeof(RAWINPUTHEADER) + 1); + ok(ret == -1, "got %Id\n", ret); + ok(GetLastError() == 0xdeadbeef, "got %ld\n", GetLastError()); } static void test_key_map(void) @@ -1751,10 +3256,21 @@ static void test_key_map(void) vkey, numpad_scan); } } + + /* test the scan code prefixes of the right variant of a keys */ + s = MapVirtualKeyExA(VK_RCONTROL, MAPVK_VK_TO_VSC, kl); + ok(s >> 8 == 0x00, "Scan code prefixes should not be returned when not using MAPVK_VK_TO_VSC_EX %#1x\n", s >> 8); + s = MapVirtualKeyExA(VK_RCONTROL, MAPVK_VK_TO_VSC_EX, kl); + ok(s >> 8 == 0xE0 || broken(s == 0), "Scan code prefix for VK_RCONTROL should be 0xE0 when MAPVK_VK_TO_VSC_EX is set, was %#1x\n", s >> 8); + s = MapVirtualKeyExA(VK_RMENU, MAPVK_VK_TO_VSC_EX, kl); + ok(s >> 8 == 0xE0 || broken(s == 0), "Scan code prefix for VK_RMENU should be 0xE0 when MAPVK_VK_TO_VSC_EX is set, was %#1x\n", s >> 8); + s = MapVirtualKeyExA(VK_RSHIFT, MAPVK_VK_TO_VSC_EX, kl); + ok(s >> 8 == 0x00 || broken(s == 0), "The scan code shouldn't have a prefix, got %#1x\n", s >> 8); } #define shift 1 #define ctrl 2 +#define menu 4 static const struct tounicode_tests { @@ -1765,15 +3281,29 @@ static const struct tounicode_tests WCHAR expect_buf[4]; } utests[] = { - { 'A', 0, 0, 1, {'a',0}}, - { 'A', ctrl, 0, 1, {1, 0}}, - { 'A', shift|ctrl, 0, 1, {1, 0}}, + { 0, 0, 'a', 1, {'a',0}}, + { 0, shift, 'a', 1, {'A',0}}, + { 0, menu, 'a', 1, {'a',0}}, + { 0, shift|menu, 'a', 1, {'A',0}}, +#if defined(__REACTOS__) && defined(_MSC_VER) + { 0, shift|ctrl|menu, 'a', 0, {0}}, +#else + { 0, shift|ctrl|menu, 'a', 0, {}}, +#endif + { 0, ctrl, 'a', 1, {1, 0}}, + { 0, shift|ctrl, 'a', 1, {1, 0}}, +#if defined(__REACTOS__) && defined(_MSC_VER) { VK_TAB, ctrl, 0, 0, {0}}, { VK_TAB, shift|ctrl, 0, 0, {0}}, +#else + { VK_TAB, ctrl, 0, 0, {}}, + { VK_TAB, shift|ctrl, 0, 0, {}}, +#endif { VK_RETURN, ctrl, 0, 1, {'\n', 0}}, +#if defined(__REACTOS__) && defined(_MSC_VER) { VK_RETURN, shift|ctrl, 0, 0, {0}}, - { '4', ctrl, 0, 0, {0}}, - { '4', shift|ctrl, 0, 0, {0}}, + { 0, ctrl, '4', 0, {0}}, + { 0, shift|ctrl, '4', 0, {0}}, { 0, ctrl, '!', 0, {0}}, { 0, ctrl, '\"', 0, {0}}, { 0, ctrl, '#', 0, {0}}, @@ -1794,13 +3324,42 @@ static const struct tounicode_tests { 0, ctrl, '=', 0, {0}}, { 0, ctrl, '>', 0, {0}}, { 0, ctrl, '?', 0, {0}}, +#else + { VK_RETURN, shift|ctrl, 0, 0, {}}, + { 0, ctrl, '4', 0, {}}, + { 0, shift|ctrl, '4', 0, {}}, + { 0, ctrl, '!', 0, {}}, + { 0, ctrl, '\"', 0, {}}, + { 0, ctrl, '#', 0, {}}, + { 0, ctrl, '$', 0, {}}, + { 0, ctrl, '%', 0, {}}, + { 0, ctrl, '\'', 0, {}}, + { 0, ctrl, '(', 0, {}}, + { 0, ctrl, ')', 0, {}}, + { 0, ctrl, '*', 0, {}}, + { 0, ctrl, '+', 0, {}}, + { 0, ctrl, ',', 0, {}}, + { 0, ctrl, '-', 0, {}}, + { 0, ctrl, '.', 0, {}}, + { 0, ctrl, '/', 0, {}}, + { 0, ctrl, ':', 0, {}}, + { 0, ctrl, ';', 0, {}}, + { 0, ctrl, '<', 0, {}}, + { 0, ctrl, '=', 0, {}}, + { 0, ctrl, '>', 0, {}}, + { 0, ctrl, '?', 0, {}}, +#endif { 0, ctrl, '@', 1, {0}}, { 0, ctrl, '[', 1, {0x1b}}, { 0, ctrl, '\\', 1, {0x1c}}, { 0, ctrl, ']', 1, {0x1d}}, { 0, ctrl, '^', 1, {0x1e}}, { 0, ctrl, '_', 1, {0x1f}}, +#if defined(__REACTOS__) && defined(_MSC_VER) { 0, ctrl, '`', 0, {0}}, +#else + { 0, ctrl, '`', 0, {}}, +#endif { VK_SPACE, 0, 0, 1, {' ',0}}, { VK_SPACE, shift, 0, 1, {' ',0}}, { VK_SPACE, ctrl, 0, 1, {' ',0}}, @@ -1854,6 +3413,7 @@ static void test_ToUnicode(void) state[VK_SHIFT] = state[VK_LSHIFT] = (mod & shift) ? HIGHEST_BIT : 0; state[VK_CONTROL] = state[VK_LCONTROL] = (mod & ctrl) ? HIGHEST_BIT : 0; + state[VK_MENU] = state[VK_LMENU] = (mod & menu) ? HIGHEST_BIT : 0; ret = ToUnicode(vk, scan, state, wStr, 4, 0); ok(ret == utests[i].expect_ret, "%d: got %d expected %d\n", i, ret, utests[i].expect_ret); @@ -1881,11 +3441,14 @@ static void test_ToUnicode(void) static void test_ToAscii(void) { + WCHAR wstr[16]; + char str[16]; WORD character; BYTE state[256]; const BYTE SC_RETURN = 0x1c, SC_A = 0x1e; const BYTE HIGHEST_BIT = 0x80; - int ret; + int ret, len; + DWORD gle; memset(state, 0, sizeof(state)); @@ -1894,10 +3457,32 @@ static void test_ToAscii(void) ok(ret == 1, "ToAscii for Return key didn't return 1 (was %i)\n", ret); ok(character == '\r', "ToAscii for Return was %i (expected 13)\n", character); + wstr[0] = 0; + ret = ToUnicode('A', SC_A, state, wstr, ARRAY_SIZE(wstr), 0); + ok(ret == 1, "ToUnicode(A) returned %i, expected 1\n", ret); + + str[0] = '\0'; + len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, sizeof(str), NULL, NULL); + gle = GetLastError(); + ok(len > 0, "Could not convert %s (gle %lu)\n", wine_dbgstr_w(wstr), gle); + character = 0; ret = ToAscii('A', SC_A, state, &character, 0); - ok(ret == 1, "ToAscii for character 'A' didn't return 1 (was %i)\n", ret); - ok(character == 'a', "ToAscii for character 'A' was %i (expected %i)\n", character, 'a'); + if (len == 1 || len == 2) + ok(ret == 1, "ToAscii(A) returned %i, expected 1\n", ret); + else + /* ToAscii() can only return 2 chars => it fails if len > 2 */ + ok(ret == 0, "ToAscii(A) returned %i, expected 0\n", ret); + switch ((ULONG_PTR)GetKeyboardLayout(0)) + { + case 0x04090409: /* Qwerty */ + case 0x04070407: /* Qwertz */ + case 0x040c040c: /* Azerty */ + ok(lstrcmpW(wstr, L"a") == 0, "ToUnicode(A) returned %s\n", wine_dbgstr_w(wstr)); + ok(character == 'a', "ToAscii(A) returned char=%i, expected %i\n", character, 'a'); + break; + /* Other keyboard layouts may or may not return 'a' */ + } state[VK_CONTROL] |= HIGHEST_BIT; state[VK_LCONTROL] |= HIGHEST_BIT; @@ -1933,10 +3518,29 @@ static void test_get_async_key_state(void) ok(0 == GetAsyncKeyState(-1000000), "GetAsyncKeyState did not return 0\n"); } +static HKL *get_keyboard_layouts( UINT *count ) +{ + HKL *layouts; + + *count = GetKeyboardLayoutList( 0, NULL ); + ok_ne( 0, *count, UINT, "%u" ); + layouts = malloc( *count * sizeof(HKL) ); + ok_ne( NULL, layouts, void *, "%p" ); + *count = GetKeyboardLayoutList( *count, layouts ); + ok_ne( 0, *count, UINT, "%u" ); + + return layouts; +} + static void test_keyboard_layout_name(void) { + WCHAR klid[KL_NAMELENGTH], tmpklid[KL_NAMELENGTH], layout_path[MAX_PATH], value[5]; + HKL layout, tmplayout, *layouts, *layouts_preload; + DWORD status, value_size, klid_size, type, id; + int i, j; + HKEY hkey; + UINT len; BOOL ret; - char klid[KL_NAMELENGTH]; if (0) /* crashes on native system */ ret = GetKeyboardLayoutNameA(NULL); @@ -1944,14 +3548,316 @@ static void test_keyboard_layout_name(void) SetLastError(0xdeadbeef); ret = GetKeyboardLayoutNameW(NULL); ok(!ret, "got %d\n", ret); - ok(GetLastError() == ERROR_NOACCESS, "got %d\n", GetLastError()); + ok(GetLastError() == ERROR_NOACCESS, "got %ld\n", GetLastError()); - if (GetKeyboardLayout(0) != (HKL)(ULONG_PTR)0x04090409) return; + layout = GetKeyboardLayout(0); + if (broken( layout == (HKL)0x040a0c0a )) + { + /* The testbot w7u_es has a broken layout configuration, its active layout is 040a:0c0a, + * with 0c0a its user locale and 040a its layout langid. Its layout preload list contains + * a 00000c0a layout but the system layouts OTOH only contains the standard 0000040a layout. + * Later, after activating 0409:0409 layout, GetKeyboardLayoutNameW returns 00000c0a. + */ + win_skip( "broken keyboard layout, skipping tests\n" ); + return; + } - klid[0] = 0; - ret = GetKeyboardLayoutNameA(klid); - ok(ret, "GetKeyboardLayoutNameA failed %u\n", GetLastError()); - ok(!strcmp(klid, "00000409"), "expected 00000409, got %s\n", klid); + layouts = get_keyboard_layouts( &len ); + ok(layouts != NULL, "Could not allocate memory\n"); + + layouts_preload = calloc(1, sizeof(HKL)); + ok(layouts_preload != NULL, "Could not allocate memory\n"); + + if (!RegOpenKeyW( HKEY_CURRENT_USER, L"Keyboard Layout\\Preload", &hkey )) + { + i = 0; + type = REG_SZ; + klid_size = sizeof(klid); + value_size = ARRAY_SIZE(value); + while (!RegEnumValueW( hkey, i++, value, &value_size, NULL, &type, (void *)&klid, &klid_size )) + { + klid_size = sizeof(klid); + value_size = ARRAY_SIZE(value); + layouts_preload = realloc( layouts_preload, (i + 1) * sizeof(*layouts_preload) ); + ok(layouts_preload != NULL, "Could not allocate memory\n"); + layouts_preload[i - 1] = UlongToHandle( wcstoul( klid, NULL, 16 ) ); + layouts_preload[i] = 0; + + id = (DWORD_PTR)layouts_preload[i - 1]; + if (id & 0x80000000) todo_wine_if(HIWORD(id) == 0xe001) ok((id & 0xf0000000) == 0xd0000000, "Unexpected preloaded keyboard layout high bits %#lx\n", id); + else ok(!(id & 0xf0000000), "Unexpected preloaded keyboard layout high bits %#lx\n", id); + } + + RegCloseKey( hkey ); + } + + if (!RegOpenKeyW( HKEY_CURRENT_USER, L"Keyboard Layout\\Substitutes", &hkey )) + { + for (i = 0; layouts_preload[i]; ++i) + { + type = REG_SZ; + klid_size = sizeof(klid); + swprintf( tmpklid, KL_NAMELENGTH, L"%08x", HandleToUlong( layouts_preload[i] ) ); + if (!RegQueryValueExW( hkey, tmpklid, NULL, &type, (void *)&klid, &klid_size )) + { + layouts_preload[i] = UlongToHandle( wcstoul( klid, NULL, 16 ) ); + + /* Substitute should contain the keyboard layout id, not the HKL high word */ + id = (DWORD_PTR)layouts_preload[i]; + ok(!(id & 0xf0000000), "Unexpected substitute keyboard layout high bits %#lx\n", id); + } + else + { + id = (DWORD_PTR)layouts_preload[i]; + ok(!(id & 0xf0000000), "Unexpected preloaded keyboard layout high bits %#lx\n", id); + } + } + + RegCloseKey( hkey ); + } + + for (i = len - 1; i >= 0; --i) + { + id = (DWORD_PTR)layouts[i]; + + winetest_push_context( "%08lx", id ); + + ActivateKeyboardLayout(layouts[i], 0); + + tmplayout = GetKeyboardLayout(0); + todo_wine_if(tmplayout != layouts[i]) + ok( tmplayout == layouts[i], "Failed to activate keyboard layout\n"); + if (tmplayout != layouts[i]) + { + winetest_pop_context(); + continue; + } + + GetKeyboardLayoutNameW(klid); + + for (j = 0; layouts_preload[j]; ++j) + { + swprintf( tmpklid, KL_NAMELENGTH, L"%08X", layouts_preload[j] ); + if (!wcscmp( tmpklid, klid )) break; + } + ok(j < len, "Could not find keyboard layout %s in preload list\n", wine_dbgstr_w(klid)); + + if (id & 0x80000000) + { + todo_wine ok((id >> 28) == 0xf, "hkl high bits %#lx, expected 0xf\n", id >> 28); + + value_size = sizeof(value); + wcscpy(layout_path, L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\"); + wcscat(layout_path, klid); + status = RegGetValueW(HKEY_LOCAL_MACHINE, layout_path, L"Layout Id", RRF_RT_REG_SZ, NULL, (void *)&value, &value_size); + todo_wine ok(!status, "RegGetValueW returned %lx\n", status); + ok(value_size == 5 * sizeof(WCHAR), "RegGetValueW returned size %ld\n", value_size); + + swprintf(tmpklid, KL_NAMELENGTH, L"%04X", (id >> 16) & 0x0fff); + todo_wine ok(!wcsicmp(value, tmpklid), "RegGetValueW returned %s, expected %s\n", debugstr_w(value), debugstr_w(tmpklid)); + } + else + { + swprintf(tmpklid, KL_NAMELENGTH, L"%08X", id >> 16); + ok(!wcsicmp(klid, tmpklid), "GetKeyboardLayoutNameW returned %s, expected %s\n", debugstr_w(klid), debugstr_w(tmpklid)); + } + + ActivateKeyboardLayout(layout, 0); + tmplayout = LoadKeyboardLayoutW(klid, KLF_ACTIVATE); + + /* The low word of HKL is the selected user lang and may be different as LoadKeyboardLayoutW also selects the default lang from the layout */ + ok(((UINT_PTR)tmplayout & ~0xffff) == ((UINT_PTR)layouts[i] & ~0xffff), "LoadKeyboardLayoutW returned %p, expected %p\n", tmplayout, layouts[i]); + + /* The layout name only depends on the keyboard layout: the high word of HKL. */ + GetKeyboardLayoutNameW(tmpklid); + ok(!wcsicmp(klid, tmpklid), "GetKeyboardLayoutNameW returned %s, expected %s\n", debugstr_w(tmpklid), debugstr_w(klid)); + + winetest_pop_context(); + } + + ActivateKeyboardLayout(layout, 0); + + free(layouts); + free(layouts_preload); +} + +static HKL expect_hkl; +static HKL change_hkl; +static int got_setfocus; + +static LRESULT CALLBACK test_ActivateKeyboardLayout_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + ok( msg != WM_INPUTLANGCHANGEREQUEST, "got WM_INPUTLANGCHANGEREQUEST\n" ); + + if (msg == WM_SETFOCUS) got_setfocus = 1; + if (msg == WM_INPUTLANGCHANGE) + { + HKL layout = GetKeyboardLayout( 0 ); + CHARSETINFO info; + WCHAR klidW[64]; + UINT codepage; + LCID lcid; + + /* get keyboard layout lcid from its name, as the HKL might be aliased */ + GetKeyboardLayoutNameW( klidW ); + swscanf( klidW, L"%x", &lcid ); + lcid = LOWORD(lcid); + + if (!(HIWORD(layout) & 0x8000)) ok( lcid == HIWORD(layout), "got lcid %#lx\n", lcid ); + + GetLocaleInfoA( lcid, LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, + (char *)&codepage, sizeof(codepage) ); + TranslateCharsetInfo( UlongToPtr( codepage ), &info, TCI_SRCCODEPAGE ); + + ok( !got_setfocus, "got WM_SETFOCUS before WM_INPUTLANGCHANGE\n" ); + ok( layout == expect_hkl, "got layout %p\n", layout ); + ok( wparam == info.ciCharset || broken(wparam == 0 && (HIWORD(layout) & 0x8000)), + "got wparam %#Ix\n", wparam ); + ok( lparam == (LPARAM)expect_hkl, "got lparam %#Ix\n", lparam ); + change_hkl = (HKL)lparam; + } + + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + +static DWORD CALLBACK test_ActivateKeyboardLayout_thread_proc( void *arg ) +{ + ActivateKeyboardLayout( arg, 0 ); + return 0; +} + +static void test_ActivateKeyboardLayout( char **argv ) +{ + HKL layout, tmp_layout, *layouts; + HWND hwnd1, hwnd2; + HANDLE thread; + UINT i, count; + DWORD ret; + + layout = GetKeyboardLayout( 0 ); + if (broken( layout == (HKL)0x040a0c0a )) + { + /* The testbot w7u_es has a broken layout configuration, see test_keyboard_layout_name above. */ + win_skip( "broken keyboard layout, skipping tests\n" ); + return; + } + + count = GetKeyboardLayoutList( 0, NULL ); + ok( count > 0, "GetKeyboardLayoutList returned %d\n", count ); + layouts = malloc( count * sizeof(HKL) ); + ok( layouts != NULL, "Could not allocate memory\n" ); + count = GetKeyboardLayoutList( count, layouts ); + ok( count > 0, "GetKeyboardLayoutList returned %d\n", count ); + + hwnd1 = CreateWindowA( "static", "static", WS_VISIBLE | WS_POPUP, + 100, 100, 100, 100, 0, NULL, NULL, NULL ); + ok( !!hwnd1, "CreateWindow failed, error %lu\n", GetLastError() ); + empty_message_queue(); + + SetWindowLongPtrA( hwnd1, GWLP_WNDPROC, (LONG_PTR)test_ActivateKeyboardLayout_window_proc ); + + for (i = 0; i < count; ++i) + { + BOOL broken_focus_activate = FALSE; + HKL other_layout = layouts[i]; + + winetest_push_context( "%08x / %08x", (UINT)(UINT_PTR)layout, (UINT)(UINT_PTR)other_layout ); + + /* test WM_INPUTLANGCHANGE message */ + + change_hkl = 0; + expect_hkl = other_layout; + got_setfocus = 0; + ActivateKeyboardLayout( other_layout, 0 ); + if (other_layout == layout) ok( change_hkl == 0, "got change_hkl %p\n", change_hkl ); + else todo_wine ok( change_hkl == other_layout, "got change_hkl %p\n", change_hkl ); + change_hkl = expect_hkl = 0; + + tmp_layout = GetKeyboardLayout( 0 ); + todo_wine_if(layout != other_layout) + ok( tmp_layout == other_layout, "got tmp_layout %p\n", tmp_layout ); + + /* changing the layout from another thread doesn't send the message */ + + thread = CreateThread( NULL, 0, test_ActivateKeyboardLayout_thread_proc, layout, 0, 0 ); + ret = WaitForSingleObject( thread, 1000 ); + ok( !ret, "WaitForSingleObject returned %#lx\n", ret ); + CloseHandle( thread ); + + /* and has no immediate effect */ + + empty_message_queue(); + tmp_layout = GetKeyboardLayout( 0 ); + todo_wine_if(layout != other_layout) + ok( tmp_layout == other_layout, "got tmp_layout %p\n", tmp_layout ); + + /* but the change only takes effect after focus changes */ + + hwnd2 = CreateWindowA( "static", "static", WS_VISIBLE | WS_POPUP, + 100, 100, 100, 100, 0, NULL, NULL, NULL ); + ok( !!hwnd2, "CreateWindow failed, error %lu\n", GetLastError() ); + + tmp_layout = GetKeyboardLayout( 0 ); + todo_wine_if(layout != other_layout) + ok( tmp_layout == layout || broken(layout != other_layout && tmp_layout == other_layout) /* w7u */, + "got tmp_layout %p\n", tmp_layout ); + if (broken(layout != other_layout && tmp_layout == other_layout)) + { + win_skip( "Broken layout activation on focus change, skipping some tests\n" ); + broken_focus_activate = TRUE; + } + empty_message_queue(); + + /* only the focused window receives the WM_INPUTLANGCHANGE message */ + + ActivateKeyboardLayout( other_layout, 0 ); + ok( change_hkl == 0, "got change_hkl %p\n", change_hkl ); + + tmp_layout = GetKeyboardLayout( 0 ); + todo_wine_if(layout != other_layout) + ok( tmp_layout == other_layout, "got tmp_layout %p\n", tmp_layout ); + + thread = CreateThread( NULL, 0, test_ActivateKeyboardLayout_thread_proc, layout, 0, 0 ); + ret = WaitForSingleObject( thread, 1000 ); + ok( !ret, "WaitForSingleObject returned %#lx\n", ret ); + CloseHandle( thread ); + + tmp_layout = GetKeyboardLayout( 0 ); + todo_wine_if(layout != other_layout) + ok( tmp_layout == other_layout, "got tmp_layout %p\n", tmp_layout ); + + /* changing focus is enough for the layout change to take effect */ + + change_hkl = 0; + expect_hkl = layout; + got_setfocus = 0; + SetFocus( hwnd1 ); + + if (broken_focus_activate) + { + ok( got_setfocus == 1, "got got_setfocus %d\n", got_setfocus ); + ok( change_hkl == 0, "got change_hkl %p\n", change_hkl ); + got_setfocus = 0; + ActivateKeyboardLayout( layout, 0 ); + } + + if (other_layout == layout) ok( change_hkl == 0, "got change_hkl %p\n", change_hkl ); + else todo_wine ok( change_hkl == layout, "got change_hkl %p\n", change_hkl ); + change_hkl = expect_hkl = 0; + + tmp_layout = GetKeyboardLayout( 0 ); + todo_wine_if(layout != other_layout) + ok( tmp_layout == layout, "got tmp_layout %p\n", tmp_layout ); + + DestroyWindow( hwnd2 ); + empty_message_queue(); + + winetest_pop_context(); + } + + DestroyWindow( hwnd1 ); + + free( layouts ); } static void test_key_names(void) @@ -2002,35 +3908,17 @@ static void simulate_click(BOOL left, int x, int y) SetCursorPos(x, y); memset(input, 0, sizeof(input)); input[0].type = INPUT_MOUSE; - U(input[0]).mi.dx = x; - U(input[0]).mi.dy = y; - U(input[0]).mi.dwFlags = left ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_RIGHTDOWN; + input[0].mi.dx = x; + input[0].mi.dy = y; + input[0].mi.dwFlags = left ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_RIGHTDOWN; input[1].type = INPUT_MOUSE; - U(input[1]).mi.dx = x; - U(input[1]).mi.dy = y; - U(input[1]).mi.dwFlags = left ? MOUSEEVENTF_LEFTUP : MOUSEEVENTF_RIGHTUP; + input[1].mi.dx = x; + input[1].mi.dy = y; + input[1].mi.dwFlags = left ? MOUSEEVENTF_LEFTUP : MOUSEEVENTF_RIGHTUP; events_no = SendInput(2, input, sizeof(input[0])); ok(events_no == 2, "SendInput returned %d\n", events_no); } -static BOOL wait_for_message( MSG *msg ) -{ - BOOL ret; - - for (;;) - { - ret = PeekMessageA(msg, 0, 0, 0, PM_REMOVE); - if (ret) - { - if (msg->message == WM_PAINT) DispatchMessageA(msg); - else break; - } - else if (MsgWaitForMultipleObjects(0, NULL, FALSE, 100, QS_ALLINPUT) == WAIT_TIMEOUT) break; - } - if (!ret) msg->message = 0; - return ret; -} - static BOOL wait_for_event(HANDLE event, int timeout) { DWORD end_time = GetTickCount() + timeout; @@ -2047,532 +3935,640 @@ static BOOL wait_for_event(HANDLE event, int timeout) return FALSE; } -static WNDPROC def_static_proc; -static DWORD hittest_no; -static LRESULT WINAPI static_hook_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) +static LRESULT CALLBACK httransparent_wndproc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { - if (msg == WM_NCHITTEST) - { - /* break infinite hittest loop */ - if(hittest_no > 50) return HTCLIENT; - hittest_no++; - } - - return def_static_proc(hwnd, msg, wp, lp); + append_message( hwnd, msg, wparam, lparam ); + if (msg == WM_NCHITTEST) return HTTRANSPARENT; + return DefWindowProcW( hwnd, msg, wparam, lparam ); } -struct thread_data +struct create_transparent_window_params { HANDLE start_event; HANDLE end_event; - HWND win; + HWND hwnd; }; -static DWORD WINAPI create_static_win(void *arg) +static DWORD WINAPI create_transparent_window_thread(void *arg) { - struct thread_data *thread_data = arg; - HWND win; + struct create_transparent_window_params *params = arg; + ULONG_PTR old_proc; - win = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP, - 100, 100, 100, 100, 0, NULL, NULL, NULL); - ok(win != 0, "CreateWindow failed\n"); - def_static_proc = (void*)SetWindowLongPtrA(win, - GWLP_WNDPROC, (LONG_PTR)static_hook_proc); - thread_data->win = win; + params->hwnd = CreateWindowW( L"static", NULL, WS_VISIBLE | WS_POPUP, 0, 0, 100, 100, NULL, NULL, NULL, NULL ); + ok_ne( NULL, params->hwnd, HWND, "%p" ); + wait_messages( 100, FALSE ); + old_proc = SetWindowLongPtrW( params->hwnd, GWLP_WNDPROC, (LONG_PTR)httransparent_wndproc ); + ok_ne( 0, old_proc, LONG_PTR, "%#Ix" ); - SetEvent(thread_data->start_event); - wait_for_event(thread_data->end_event, 5000); + ok_ret( 1, SetEvent( params->start_event ) ); + wait_for_event( params->end_event, 5000 ); + + ok_ret( 1, DestroyWindow( params->hwnd ) ); + wait_messages( 100, FALSE ); return 0; } -static void get_dc_region(RECT *region, HWND hwnd, DWORD flags) +static LRESULT CALLBACK mouse_move_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { - int region_type; - HRGN hregion; - HDC hdc; + static DWORD last_x = 50, expect_x = 60; - hdc = GetDCEx(hwnd, 0, flags); - ok(hdc != NULL, "GetDCEx failed\n"); - hregion = CreateRectRgn(40, 40, 60, 60); - ok(hregion != NULL, "CreateRectRgn failed\n"); - GetRandomRgn(hdc, hregion, SYSRGN); - region_type = GetRgnBox(hregion, region); - ok(region_type == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", region_type); - DeleteObject(hregion); - ReleaseDC(hwnd, hdc); + if (msg == WM_MOUSEMOVE) + { + POINT pt = {LOWORD(lparam), HIWORD(lparam)}; + MapWindowPoints(hwnd, NULL, &pt, 1); + + flaky + if (pt.x != last_x) ok( pt.x == expect_x, "got unexpected WM_MOUSEMOVE x %ld, expected %ld\n", pt.x, expect_x ); + + expect_x = pt.x == 50 ? 60 : 50; + last_x = pt.x; + } + + return DefWindowProcW(hwnd, msg, wparam, lparam); } -static void test_Input_mouse(void) +static LRESULT CALLBACK mouse_layered_wndproc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { - BOOL got_button_down, got_button_up; - HWND hwnd, button_win, static_win; - struct thread_data thread_data; - HANDLE thread; + append_message( hwnd, msg, wparam, lparam ); + + if (msg == WM_PAINT) + { + HBRUSH brush = CreateSolidBrush( RGB(50, 100, 255) ); + PAINTSTRUCT paint; + RECT client_rect; + + HDC hdc = BeginPaint( hwnd, &paint ); + GetClientRect( hwnd, &client_rect ); + FillRect( hdc, &client_rect, brush ); + EndPaint( hwnd, &paint ); + + DeleteObject( brush ); + return 0; + } + + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + +struct send_input_mouse_test +{ + BOOL set_cursor_pos; + POINT cursor_pos; + UINT data; + UINT flags; + ULONG_PTR extra; + struct user_call expect[8]; + BYTE expect_state[256]; + BOOL todo_state[256]; +}; + +static LRESULT CALLBACK ll_hook_ms_proc( int code, WPARAM wparam, LPARAM lparam ) +{ + MSLLHOOKSTRUCT *hook_info = (MSLLHOOKSTRUCT *)lparam; + if (code == HC_ACTION) append_ll_hook_ms( wparam, hook_info ); + return CallNextHookEx( 0, code, wparam, lparam ); +} + +static LRESULT CALLBACK ll_hook_setpos_proc( int code, WPARAM wparam, LPARAM lparam ) +{ + if (code == HC_ACTION) + { + MSLLHOOKSTRUCT *hook_info = (MSLLHOOKSTRUCT *)lparam; + POINT pos, hook_pos = {40, 40}; + + ok( abs( hook_info->pt.x - 51 ) <= 1, "got x %ld\n", hook_info->pt.x ); + ok( abs( hook_info->pt.y - 49 ) <= 1, "got y %ld\n", hook_info->pt.y ); + + /* spuriously moves by 0 or 1 pixels on Windows */ + ok_ret( 1, GetCursorPos( &pos ) ); + ok( abs( pos.x - 51 ) <= 1, "got x %ld\n", pos.x ); + ok( abs( pos.y - 49 ) <= 1, "got y %ld\n", pos.y ); + + ok_ret( 1, SetCursorPos( 60, 60 ) ); + hook_info->pt = hook_pos; + } + + return CallNextHookEx( 0, code, wparam, lparam ); +} + +static LRESULT CALLBACK ll_hook_getpos_proc( int code, WPARAM wparam, LPARAM lparam ) +{ + if (code == HC_ACTION) + { + MSLLHOOKSTRUCT *hook_info = (MSLLHOOKSTRUCT *)lparam; + POINT pos, expect_pos = {60, 60}, hook_pos = {40, 40}; + ok_point( hook_pos, hook_info->pt ); + ok_ret( 1, GetCursorPos( &pos ) ); + ok_point( expect_pos, pos ); + } + + return CallNextHookEx( 0, code, wparam, lparam ); +} + +static BOOL accept_mouse_messages_nomove( UINT msg ) +{ + return is_mouse_message( msg ) && msg != WM_MOUSEMOVE; +} + +static void test_SendInput_mouse_messages(void) +{ +#define WIN_MSG(m, h, w, l, ...) {.func = MSG_TEST_WIN, .message = {.msg = m, .hwnd = h, .wparam = w, .lparam = l}, ## __VA_ARGS__} +#define MS_HOOK(m, x, y, ...) {.func = LL_HOOK_MOUSE, .ll_hook_ms = {.msg = m, .point = {x, y}, .flags = 1}, ## __VA_ARGS__} + struct user_call mouse_move[] = + { + MS_HOOK(WM_MOUSEMOVE, 40, 40), + {0}, + }; + struct user_call button_down_hwnd[] = + { + MS_HOOK(WM_LBUTTONDOWN, 50, 50), + WIN_MSG(WM_LBUTTONDOWN, (HWND)-1/*hwnd*/, 0x1, MAKELONG(50, 50)), + {0}, + }; + struct user_call button_down_hwnd_todo[] = + { + MS_HOOK(WM_LBUTTONDOWN, 50, 50), + WIN_MSG(WM_LBUTTONDOWN, (HWND)-1/*hwnd*/, 0x1, MAKELONG(50, 50), .todo = TRUE), + {0/* placeholder for Wine spurious messages */}, + {0}, + }; + struct user_call button_up_hwnd[] = + { + MS_HOOK(WM_LBUTTONUP, 50, 50), + WIN_MSG(WM_LBUTTONUP, (HWND)-1/*hwnd*/, 0, MAKELONG(50, 50)), + {0}, + }; + struct user_call button_up_hwnd_todo[] = + { + MS_HOOK(WM_LBUTTONUP, 50, 50), + WIN_MSG(WM_LBUTTONUP, (HWND)-1/*hwnd*/, 0, MAKELONG(50, 50), .todo = TRUE), + {0/* placeholder for Wine spurious messages */}, + {0}, + }; + struct user_call button_down_no_message[] = + { + MS_HOOK(WM_LBUTTONDOWN, 50, 50), + {.todo = TRUE /* spurious message on Wine */}, + {0}, + }; + struct user_call button_up_no_message[] = + { + MS_HOOK(WM_LBUTTONUP, 50, 50), + {.todo = TRUE /* spurious message on Wine */}, + {0}, + }; +#undef WIN_MSG +#undef MS_HOOK + static const POINT expect_60x50 = {60, 50}, expect_50x50 = {50, 50}; + + static const struct layered_test + { + UINT color; + UINT alpha; + UINT flags; + BOOL expect_click; + } + layered_tests[] = + { + {.flags = LWA_ALPHA, .expect_click = FALSE}, + {.alpha = 1, .flags = LWA_ALPHA, .expect_click = TRUE}, + {.color = RGB(0, 255, 0), .flags = LWA_COLORKEY, .expect_click = TRUE}, + {.color = RGB(50, 100, 255), .flags = LWA_COLORKEY, .expect_click = TRUE}, + {.color = RGB(0, 255, 0), .flags = LWA_COLORKEY | LWA_ALPHA, .expect_click = FALSE}, + {.color = RGB(0, 255, 0), .alpha = 1, .flags = LWA_COLORKEY | LWA_ALPHA, .expect_click = TRUE}, + {.color = RGB(50, 100, 255), .alpha = 1, .flags = LWA_COLORKEY | LWA_ALPHA, .expect_click = TRUE}, + }; + + struct create_transparent_window_params params = {0}; + ULONG_PTR old_proc, old_other_proc; + RECT clip_rect = {55, 55, 55, 55}; + UINT dblclk_time, i; + HWND hwnd, other; DWORD thread_id; - WNDCLASSA wclass; - POINT pt, pt_org; - int region_type; + HANDLE thread; + HHOOK hook, hook_setpos, hook_getpos; HRGN hregion; RECT region; - MSG msg; - BOOL ret; + POINT pt; - SetLastError(0xdeadbeef); - ret = GetCursorPos(NULL); - ok(!ret, "GetCursorPos succeed\n"); - ok(GetLastError() == 0xdeadbeef || GetLastError() == ERROR_NOACCESS, "error %u\n", GetLastError()); + params.start_event = CreateEventA( NULL, FALSE, FALSE, NULL ); + ok( !!params.start_event, "CreateEvent failed\n" ); + params.end_event = CreateEventA( NULL, FALSE, FALSE, NULL ); + ok( !!params.end_event, "CreateEvent failed\n" ); - SetLastError(0xdeadbeef); - ret = GetCursorPos(&pt_org); - ok(ret, "GetCursorPos failed\n"); - ok(GetLastError() == 0xdeadbeef, "error %u\n", GetLastError()); - button_win = CreateWindowA("button", "button", WS_VISIBLE | WS_POPUP, - 100, 100, 100, 100, 0, NULL, NULL, NULL); - ok(button_win != 0, "CreateWindow failed\n"); + dblclk_time = GetDoubleClickTime(); + ok_eq( 500, dblclk_time, UINT, "%u" ); - pt.x = pt.y = 150; - hwnd = WindowFromPoint(pt); - if (hwnd != button_win) + ok_ret( 1, SetCursorPos( 50, 50 ) ); + ok_ret( 1, SetDoubleClickTime( 1 ) ); + + hwnd = CreateWindowW( L"static", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, NULL, NULL ); + ok_ne( NULL, hwnd, HWND, "%p" ); + wait_messages( 100, FALSE ); + trace( "hwnd %p\n", hwnd ); + + hook = SetWindowsHookExW( WH_MOUSE_LL, ll_hook_ms_proc, GetModuleHandleW( NULL ), 0 ); + ok_ne( NULL, hook, HHOOK, "%p" ); + + /* test hooks only, WM_MOUSEMOVE messages are very brittle */ + p_accept_message = is_mouse_message; + ok_seq( empty_sequence ); + + /* SetCursorPos or ClipCursor don't call mouse ll hooks */ + ok_ret( 1, SetCursorPos( 60, 60 ) ); + wait_messages( 5, FALSE ); + ok_ret( 1, ClipCursor( &clip_rect ) ); + wait_messages( 5, FALSE ); + ok_ret( 1, ClipCursor( NULL ) ); + wait_messages( 5, FALSE ); + ok_ret( 1, SetCursorPos( 50, 50 ) ); + wait_messages( 100, FALSE ); + todo_wine ok_seq( empty_sequence ); + + hook_getpos = SetWindowsHookExW( WH_MOUSE_LL, ll_hook_getpos_proc, GetModuleHandleW( NULL ), 0 ); + ok_ne( NULL, hook_getpos, HHOOK, "%p" ); + hook_setpos = SetWindowsHookExW( WH_MOUSE_LL, ll_hook_setpos_proc, GetModuleHandleW( NULL ), 0 ); + ok_ne( NULL, hook_setpos, HHOOK, "%p" ); + + mouse_event( MOUSEEVENTF_MOVE, 0, 0, 0, 0 ); + /* recent Windows versions don't call the hooks with no movement */ + if (current_sequence_len) { - skip("there's another window covering test window\n"); - DestroyWindow(button_win); - return; + ok_seq( mouse_move ); + ok_ret( 1, SetCursorPos( 50, 50 ) ); } + ok_seq( empty_sequence ); - /* simple button click test */ - simulate_click(TRUE, 150, 150); - got_button_down = got_button_up = FALSE; - while (wait_for_message(&msg)) - { - DispatchMessageA(&msg); + /* WH_MOUSE_LL hook is called even with 1 pixel moves */ + mouse_event( MOUSEEVENTF_MOVE, +1, -1, 0, 0 ); + ok_seq( mouse_move ); - if (msg.message == WM_LBUTTONDOWN) - { - got_button_down = TRUE; - } - else if (msg.message == WM_LBUTTONUP) - { - got_button_up = TRUE; - break; - } - } - ok(got_button_down, "expected WM_LBUTTONDOWN message\n"); - ok(got_button_up, "expected WM_LBUTTONUP message\n"); + ok_ret( 1, UnhookWindowsHookEx( hook_getpos ) ); + ok_ret( 1, UnhookWindowsHookEx( hook_setpos ) ); - /* click through HTTRANSPARENT child window */ - static_win = CreateWindowA("static", "static", WS_VISIBLE | WS_CHILD, - 0, 0, 100, 100, button_win, NULL, NULL, NULL); - ok(static_win != 0, "CreateWindow failed\n"); - def_static_proc = (void*)SetWindowLongPtrA(static_win, - GWLP_WNDPROC, (LONG_PTR)static_hook_proc); - simulate_click(FALSE, 150, 150); - hittest_no = 0; - got_button_down = got_button_up = FALSE; - while (wait_for_message(&msg)) - { - DispatchMessageA(&msg); - if (msg.message == WM_RBUTTONDOWN) - { - ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); - got_button_down = TRUE; - } - else if (msg.message == WM_RBUTTONUP) - { - ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); - got_button_up = TRUE; - break; - } - } - ok(hittest_no && hittest_no<50, "expected WM_NCHITTEST message\n"); - ok(got_button_down, "expected WM_RBUTTONDOWN message\n"); - ok(got_button_up, "expected WM_RBUTTONUP message\n"); - DestroyWindow(static_win); + append_message_hwnd = TRUE; + p_accept_message = accept_mouse_messages_nomove; + ok_seq( empty_sequence ); + + + /* basic button messages */ + + old_proc = SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)append_message_wndproc ); + ok_ne( 0, old_proc, LONG_PTR, "%#Ix" ); + + ok_ret( 1, SetCursorPos( 50, 50 ) ); + wait_messages( 100, FALSE ); + todo_wine ok_seq( empty_sequence ); + + mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 ); + wait_messages( 5, FALSE ); + button_down_hwnd[1].message.hwnd = hwnd; + ok_seq( button_down_hwnd ); + + mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 ); + wait_messages( 5, FALSE ); + button_up_hwnd[1].message.hwnd = hwnd; + ok_seq( button_up_hwnd ); + mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 ); + wait_messages( 5, FALSE ); + button_up_hwnd[1].message.hwnd = hwnd; + ok_seq( button_up_hwnd ); + + + /* click through top-level window */ + + other = CreateWindowW( L"static", NULL, WS_VISIBLE | WS_POPUP, 0, 0, 100, 100, NULL, NULL, NULL, NULL ); + ok_ne( NULL, hwnd, HWND, "%p" ); + wait_messages( 100, FALSE ); + current_sequence_len = 0; + + old_other_proc = SetWindowLongPtrW( other, GWLP_WNDPROC, (LONG_PTR)append_message_wndproc ); + ok_ne( 0, old_other_proc, LONG_PTR, "%#Ix" ); + + mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 ); + wait_messages( 5, FALSE ); + button_down_hwnd[1].message.hwnd = other; + ok_seq( button_down_hwnd ); + mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 ); + wait_messages( 5, FALSE ); + button_up_hwnd[1].message.hwnd = other; + ok_seq( button_up_hwnd ); + + ok_ret( 1, DestroyWindow( other ) ); + wait_messages( 0, FALSE ); + + + /* click through child window */ + + other = CreateWindowW( L"static", NULL, WS_VISIBLE | WS_CHILD, 0, 0, 100, 100, hwnd, NULL, NULL, NULL ); + ok_ne( NULL, hwnd, HWND, "%p" ); + wait_messages( 100, FALSE ); + current_sequence_len = 0; + + old_other_proc = SetWindowLongPtrW( other, GWLP_WNDPROC, (LONG_PTR)append_message_wndproc ); + ok_ne( 0, old_other_proc, LONG_PTR, "%#Ix" ); + + mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 ); + wait_messages( 5, FALSE ); + button_down_hwnd[1].message.hwnd = other; + ok_seq( button_down_hwnd ); + mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 ); + wait_messages( 5, FALSE ); + button_up_hwnd[1].message.hwnd = other; + ok_seq( button_up_hwnd ); + + ok_ret( 1, DestroyWindow( other ) ); + wait_messages( 0, FALSE ); + /* click through HTTRANSPARENT top-level window */ - static_win = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP, - 100, 100, 100, 100, 0, NULL, NULL, NULL); - ok(static_win != 0, "CreateWindow failed\n"); - def_static_proc = (void*)SetWindowLongPtrA(static_win, - GWLP_WNDPROC, (LONG_PTR)static_hook_proc); - simulate_click(TRUE, 150, 150); - hittest_no = 0; - got_button_down = got_button_up = FALSE; - while (wait_for_message(&msg)) - { - DispatchMessageA(&msg); - if (msg.message == WM_LBUTTONDOWN) - { - ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); - got_button_down = TRUE; - } - else if (msg.message == WM_LBUTTONUP) - { - ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); - got_button_up = TRUE; - break; - } - } - ok(hittest_no && hittest_no<50, "expected WM_NCHITTEST message\n"); - ok(got_button_down, "expected WM_LBUTTONDOWN message\n"); - ok(got_button_up, "expected WM_LBUTTONUP message\n"); - DestroyWindow(static_win); + other = CreateWindowW( L"static", NULL, WS_VISIBLE | WS_POPUP, 0, 0, 100, 100, NULL, NULL, NULL, NULL ); + ok_ne( NULL, hwnd, HWND, "%p" ); + wait_messages( 100, FALSE ); + current_sequence_len = 0; + + old_other_proc = SetWindowLongPtrW( other, GWLP_WNDPROC, (LONG_PTR)httransparent_wndproc ); + ok_ne( 0, old_other_proc, LONG_PTR, "%#Ix" ); + + mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 ); + wait_messages( 5, FALSE ); + button_down_hwnd_todo[1].message.hwnd = hwnd; + ok_seq( button_down_hwnd_todo ); + mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 ); + wait_messages( 5, FALSE ); + button_up_hwnd_todo[1].message.hwnd = hwnd; + ok_seq( button_up_hwnd_todo ); + + ok_ret( 1, DestroyWindow( other ) ); + wait_messages( 0, FALSE ); + + + /* click through HTTRANSPARENT child window */ + + other = CreateWindowW( L"static", NULL, WS_VISIBLE | WS_CHILD, 0, 0, 100, 100, hwnd, NULL, NULL, NULL ); + ok_ne( NULL, hwnd, HWND, "%p" ); + wait_messages( 100, FALSE ); + current_sequence_len = 0; + + old_other_proc = SetWindowLongPtrW( other, GWLP_WNDPROC, (LONG_PTR)httransparent_wndproc ); + ok_ne( 0, old_other_proc, LONG_PTR, "%#Ix" ); + + mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 ); + wait_messages( 5, FALSE ); + button_down_hwnd[1].message.hwnd = hwnd; + ok_seq( button_down_hwnd ); + mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 ); + wait_messages( 5, FALSE ); + button_up_hwnd[1].message.hwnd = hwnd; + ok_seq( button_up_hwnd ); + + ok_ret( 1, DestroyWindow( other ) ); + wait_messages( 0, FALSE ); + /* click on HTTRANSPARENT top-level window that belongs to other thread */ - thread_data.start_event = CreateEventA(NULL, FALSE, FALSE, NULL); - ok(thread_data.start_event != NULL, "CreateEvent failed\n"); - thread_data.end_event = CreateEventA(NULL, FALSE, FALSE, NULL); - ok(thread_data.end_event != NULL, "CreateEvent failed\n"); - thread = CreateThread(NULL, 0, create_static_win, &thread_data, 0, NULL); - ok(thread != NULL, "CreateThread failed\n"); - hittest_no = 0; - got_button_down = got_button_up = FALSE; - WaitForSingleObject(thread_data.start_event, INFINITE); - simulate_click(FALSE, 150, 150); - while (wait_for_message(&msg)) - { - DispatchMessageA(&msg); - if (msg.message == WM_RBUTTONDOWN) - got_button_down = TRUE; - else if (msg.message == WM_RBUTTONUP) - got_button_up = TRUE; - } - SetEvent(thread_data.end_event); - WaitForSingleObject(thread, INFINITE); - CloseHandle(thread); - ok(hittest_no && hittest_no<50, "expected WM_NCHITTEST message\n"); - ok(!got_button_down, "unexpected WM_RBUTTONDOWN message\n"); - ok(!got_button_up, "unexpected WM_RBUTTONUP message\n"); + thread = CreateThread( NULL, 0, create_transparent_window_thread, ¶ms, 0, NULL ); + ok_ne( NULL, thread, HANDLE, "%p" ); + + ok_ret( 0, WaitForSingleObject( params.start_event, 5000 ) ); + ok_ret( 0, SendMessageW( params.hwnd, WM_USER, 0, 0 ) ); + + mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 ); + wait_messages( 5, FALSE ); + ok_seq( button_down_no_message ); + mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 ); + wait_messages( 5, FALSE ); + ok_seq( button_up_no_message ); + + ok_ret( 1, SetEvent( params.end_event ) ); + ok_ret( 0, WaitForSingleObject( thread, 5000 ) ); + ok_ret( 1, CloseHandle( thread ) ); + ResetEvent( params.start_event ); + ResetEvent( params.end_event ); + /* click on HTTRANSPARENT top-level window that belongs to other thread, * thread input queues are attached */ - thread = CreateThread(NULL, 0, create_static_win, &thread_data, 0, &thread_id); - ok(thread != NULL, "CreateThread failed\n"); - hittest_no = 0; - got_button_down = got_button_up = FALSE; - WaitForSingleObject(thread_data.start_event, INFINITE); - ok(AttachThreadInput(thread_id, GetCurrentThreadId(), TRUE), - "AttachThreadInput failed\n"); - while (wait_for_message(&msg)) DispatchMessageA(&msg); - SetWindowPos(thread_data.win, button_win, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); - simulate_click(TRUE, 150, 150); - while (wait_for_message(&msg)) - { - DispatchMessageA(&msg); - if (msg.message == WM_LBUTTONDOWN) - got_button_down = TRUE; - else if (msg.message == WM_LBUTTONUP) - got_button_up = TRUE; - } - SetEvent(thread_data.end_event); - WaitForSingleObject(thread, INFINITE); - todo_wine ok(hittest_no > 50, "expected loop with WM_NCHITTEST messages\n"); - ok(!got_button_down, "unexpected WM_LBUTTONDOWN message\n"); - ok(!got_button_up, "unexpected WM_LBUTTONUP message\n"); + thread = CreateThread( NULL, 0, create_transparent_window_thread, ¶ms, 0, &thread_id ); + ok_ne( NULL, thread, HANDLE, "%p" ); - /* click after SetCapture call */ - hwnd = CreateWindowA("button", "button", WS_VISIBLE | WS_POPUP, - 0, 0, 100, 100, 0, NULL, NULL, NULL); - ok(hwnd != 0, "CreateWindow failed\n"); - SetCapture(button_win); - got_button_down = got_button_up = FALSE; - simulate_click(FALSE, 50, 50); - while (wait_for_message(&msg)) - { - DispatchMessageA(&msg); + ok_ret( 0, WaitForSingleObject( params.start_event, 5000 ) ); + ok_ret( 1, AttachThreadInput( thread_id, GetCurrentThreadId(), TRUE ) ); + ok_ret( 0, SendMessageW( params.hwnd, WM_USER, 0, 0 ) ); - if (msg.message == WM_RBUTTONDOWN) - { - ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); - got_button_down = TRUE; - } - else if (msg.message == WM_RBUTTONUP) - { - ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); - got_button_up = TRUE; - break; - } - } - ok(got_button_down, "expected WM_RBUTTONDOWN message\n"); - ok(got_button_up, "expected WM_RBUTTONUP message\n"); - DestroyWindow(hwnd); + mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 ); + wait_messages( 5, FALSE ); + button_down_hwnd_todo[1].message.hwnd = hwnd; + ok_seq( button_down_hwnd_todo ); + mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 ); + wait_messages( 5, FALSE ); + button_up_hwnd[1].message.hwnd = hwnd; + ok_seq( button_up_hwnd ); - /* click on child window after SetCapture call */ - hwnd = CreateWindowA("button", "button2", WS_VISIBLE | WS_CHILD, - 0, 0, 100, 100, button_win, NULL, NULL, NULL); - ok(hwnd != 0, "CreateWindow failed\n"); - got_button_down = got_button_up = FALSE; - simulate_click(TRUE, 150, 150); - while (wait_for_message(&msg)) - { - DispatchMessageA(&msg); + ok_ret( 1, AttachThreadInput( thread_id, GetCurrentThreadId(), FALSE ) ); + ok_ret( 1, SetEvent( params.end_event ) ); + ok_ret( 0, WaitForSingleObject( thread, 5000 ) ); + ok_ret( 1, CloseHandle( thread ) ); + ResetEvent( params.start_event ); + ResetEvent( params.end_event ); + + + /* click on top-level window with SetCapture called for the underlying window */ + + other = CreateWindowW( L"static", NULL, WS_VISIBLE | WS_POPUP, 0, 0, 100, 100, NULL, NULL, NULL, NULL ); + ok_ne( NULL, hwnd, HWND, "%p" ); + wait_messages( 100, FALSE ); + current_sequence_len = 0; + + old_other_proc = SetWindowLongPtrW( other, GWLP_WNDPROC, (LONG_PTR)append_message_wndproc ); + ok_ne( 0, old_other_proc, LONG_PTR, "%#Ix" ); + + SetCapture( hwnd ); + + mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 ); + wait_messages( 5, FALSE ); + button_down_hwnd[1].message.hwnd = hwnd; + ok_seq( button_down_hwnd ); + mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 ); + wait_messages( 5, FALSE ); + button_up_hwnd[1].message.hwnd = hwnd; + ok_seq( button_up_hwnd ); + + ok_ret( 1, DestroyWindow( other ) ); + wait_messages( 0, FALSE ); + + SetCapture( 0 ); + + + /* click through child window with SetCapture called for the underlying window */ + + other = CreateWindowW( L"static", NULL, WS_VISIBLE | WS_CHILD, 0, 0, 100, 100, hwnd, NULL, NULL, NULL ); + ok_ne( NULL, hwnd, HWND, "%p" ); + wait_messages( 100, FALSE ); + current_sequence_len = 0; + + old_other_proc = SetWindowLongPtrW( other, GWLP_WNDPROC, (LONG_PTR)append_message_wndproc ); + ok_ne( 0, old_other_proc, LONG_PTR, "%#Ix" ); + + SetCapture( hwnd ); + + mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 ); + wait_messages( 5, FALSE ); + button_down_hwnd[1].message.hwnd = hwnd; + ok_seq( button_down_hwnd ); + mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 ); + wait_messages( 5, FALSE ); + button_up_hwnd[1].message.hwnd = hwnd; + ok_seq( button_up_hwnd ); + + ok_ret( 1, DestroyWindow( other ) ); + wait_messages( 0, FALSE ); + + SetCapture( 0 ); - if (msg.message == WM_LBUTTONDOWN) - { - ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); - got_button_down = TRUE; - } - else if (msg.message == WM_LBUTTONUP) - { - ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); - got_button_up = TRUE; - break; - } - } - ok(got_button_down, "expected WM_LBUTTONDOWN message\n"); - ok(got_button_up, "expected WM_LBUTTONUP message\n"); - DestroyWindow(hwnd); - ok(ReleaseCapture(), "ReleaseCapture failed\n"); - wclass.style = 0; - wclass.lpfnWndProc = WndProc; - wclass.cbClsExtra = 0; - wclass.cbWndExtra = 0; - wclass.hInstance = GetModuleHandleA(NULL); - wclass.hIcon = LoadIconA(0, (LPCSTR)IDI_APPLICATION); - wclass.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW); - wclass.hbrBackground = CreateSolidBrush(RGB(128, 128, 128)); - wclass.lpszMenuName = NULL; - wclass.lpszClassName = "InputLayeredTestClass"; - RegisterClassA( &wclass ); /* click through layered window with alpha channel / color key */ - hwnd = CreateWindowA(wclass.lpszClassName, "InputLayeredTest", - WS_VISIBLE | WS_POPUP, 100, 100, 100, 100, button_win, NULL, NULL, NULL); - ok(hwnd != NULL, "CreateWindowEx failed\n"); - static_win = CreateWindowA("static", "Title", WS_VISIBLE | WS_CHILD, - 10, 10, 20, 20, hwnd, NULL, NULL, NULL); - ok(static_win != NULL, "CreateWindowA failed %u\n", GetLastError()); - - SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); - SetWindowLongA(hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED); - ret = SetLayeredWindowAttributes(hwnd, 0, 255, LWA_ALPHA); - ok(ret, "SetLayeredWindowAttributes failed\n"); - while (wait_for_message(&msg)) DispatchMessageA(&msg); - Sleep(100); - - if (pGetWindowRgnBox) + for (i = 0; i < ARRAY_SIZE(layered_tests); i++) { - region_type = pGetWindowRgnBox(hwnd, ®ion); - ok(region_type == ERROR, "expected ERROR, got %d\n", region_type); - } + const struct layered_test *test = layered_tests + i; + BOOL ret; - get_dc_region(®ion, hwnd, DCX_PARENTCLIP); - ok(region.left == 100 && region.top == 100 && region.right == 200 && region.bottom == 200, - "expected region (100,100)-(200,200), got %s\n", wine_dbgstr_rect(®ion)); - get_dc_region(®ion, hwnd, DCX_WINDOW | DCX_USESTYLE); - ok(region.left == 100 && region.top == 100 && region.right == 200 && region.bottom == 200, - "expected region (100,100)-(200,200), got %s\n", wine_dbgstr_rect(®ion)); - get_dc_region(®ion, hwnd, DCX_USESTYLE); - ok(region.left == 100 && region.top == 100 && region.right == 200 && region.bottom == 200, - "expected region (100,100)-(200,200), got %s\n", wine_dbgstr_rect(®ion)); - get_dc_region(®ion, static_win, DCX_PARENTCLIP); - ok(region.left == 100 && region.top == 100 && region.right == 200 && region.bottom == 200, - "expected region (100,100)-(200,200), got %s\n", wine_dbgstr_rect(®ion)); - get_dc_region(®ion, static_win, DCX_WINDOW | DCX_USESTYLE); - ok(region.left == 110 && region.top == 110 && region.right == 130 && region.bottom == 130, - "expected region (110,110)-(130,130), got %s\n", wine_dbgstr_rect(®ion)); - get_dc_region(®ion, static_win, DCX_USESTYLE); - ok(region.left == 100 && region.top == 100 && region.right == 200 && region.bottom == 200, - "expected region (100,100)-(200,200), got %s\n", wine_dbgstr_rect(®ion)); + winetest_push_context( "layered %u", i ); - got_button_down = got_button_up = FALSE; - simulate_click(TRUE, 150, 150); - while (wait_for_message(&msg)) - { - DispatchMessageA(&msg); + other = CreateWindowW( L"static", NULL, WS_VISIBLE | WS_POPUP, 0, 0, 100, 100, NULL, NULL, NULL, NULL ); + ok_ne( NULL, other, HWND, "%p" ); + old_other_proc = SetWindowLongPtrW( other, GWLP_WNDPROC, (LONG_PTR)mouse_layered_wndproc ); + ok_ne( 0, old_other_proc, LONG_PTR, "%#Ix" ); + wait_messages( 100, FALSE ); - if (msg.message == WM_LBUTTONDOWN) + ok_ret( ERROR, GetWindowRgnBox( other, ®ion ) ); + + + SetWindowLongW( other, GWL_EXSTYLE, GetWindowLongW( other, GWL_EXSTYLE ) | WS_EX_LAYERED ); + ret = SetLayeredWindowAttributes( other, test->color, test->alpha, test->flags ); + if (broken(!ret)) /* broken on Win7 probably because of the separate desktop */ { - ok(msg.hwnd == hwnd, "msg.hwnd = %p\n", msg.hwnd); - got_button_down = TRUE; - } - else if (msg.message == WM_LBUTTONUP) - { - ok(msg.hwnd == hwnd, "msg.hwnd = %p\n", msg.hwnd); - got_button_up = TRUE; + win_skip("Skipping broken SetLayeredWindowAttributes tests\n"); + winetest_pop_context(); + DestroyWindow( other ); break; } - } - ok(got_button_down, "expected WM_LBUTTONDOWN message\n"); - ok(got_button_up, "expected WM_LBUTTONUP message\n"); - ret = SetLayeredWindowAttributes(hwnd, 0, 0, LWA_ALPHA); - ok(ret, "SetLayeredWindowAttributes failed\n"); - while (wait_for_message(&msg)) DispatchMessageA(&msg); - Sleep(100); + ok_ret( 1, RedrawWindow( other, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN ) ); + wait_messages( 5, FALSE ); + current_sequence_len = 0; - if (pGetWindowRgnBox) - { - region_type = pGetWindowRgnBox(hwnd, ®ion); - ok(region_type == ERROR, "expected ERROR, got %d\n", region_type); + mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 ); + wait_messages( 5, FALSE ); + button_down_hwnd_todo[1].message.hwnd = test->expect_click ? other : hwnd; + button_down_hwnd_todo[1].todo = !test->expect_click; + button_down_hwnd_todo[2].todo = !test->alpha && (test->flags & LWA_ALPHA); + ok_seq( button_down_hwnd_todo ); + mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 ); + wait_messages( 5, FALSE ); + button_up_hwnd_todo[1].message.hwnd = test->expect_click ? other : hwnd; + button_up_hwnd_todo[1].todo = !test->expect_click; + button_up_hwnd_todo[2].todo = !test->alpha && (test->flags & LWA_ALPHA); + ok_seq( button_up_hwnd_todo ); + + + /* removing the attribute isn't enough to get mouse input again? */ + + SetWindowLongW( other, GWL_EXSTYLE, GetWindowLongW( other, GWL_EXSTYLE ) & ~WS_EX_LAYERED ); + ok_ret( 1, RedrawWindow( other, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN ) ); + wait_messages( 5, FALSE ); + + mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 ); + wait_messages( 5, FALSE ); + button_down_hwnd_todo[1].message.hwnd = test->expect_click ? other : hwnd; + button_down_hwnd_todo[1].todo = !test->expect_click; + button_down_hwnd_todo[2].todo = !test->alpha && (test->flags & LWA_ALPHA); + ok_seq( button_down_hwnd_todo ); + mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 ); + wait_messages( 5, FALSE ); + button_up_hwnd_todo[1].message.hwnd = test->expect_click ? other : hwnd; + button_up_hwnd_todo[1].todo = !test->expect_click; + button_up_hwnd_todo[2].todo = !test->alpha && (test->flags & LWA_ALPHA); + ok_seq( button_up_hwnd_todo ); + + ok_ret( 1, DestroyWindow( other ) ); + + winetest_pop_context(); } - got_button_down = got_button_up = FALSE; - simulate_click(TRUE, 150, 150); - while (wait_for_message(&msg)) - { - DispatchMessageA(&msg); - if (msg.message == WM_LBUTTONDOWN) - { - ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); - got_button_down = TRUE; - } - else if (msg.message == WM_LBUTTONUP) - { - ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); - got_button_up = TRUE; - break; - } - } - ok(got_button_down || broken(!got_button_down), "expected WM_LBUTTONDOWN message\n"); - ok(got_button_up, "expected WM_LBUTTONUP message\n"); + /* click on top-level window with SetWindowRgn called */ - ret = SetLayeredWindowAttributes(hwnd, RGB(0, 255, 0), 255, LWA_ALPHA | LWA_COLORKEY); - ok(ret, "SetLayeredWindowAttributes failed\n"); - while (wait_for_message(&msg)) DispatchMessageA(&msg); - Sleep(100); + other = CreateWindowW( L"static", NULL, WS_VISIBLE | WS_POPUP, 0, 0, 100, 100, NULL, NULL, NULL, NULL ); + ok_ne( NULL, hwnd, HWND, "%p" ); + wait_messages( 100, FALSE ); + current_sequence_len = 0; - if (pGetWindowRgnBox) - { - region_type = pGetWindowRgnBox(hwnd, ®ion); - ok(region_type == ERROR, "expected ERROR, got %d\n", region_type); - } + old_other_proc = SetWindowLongPtrW( other, GWLP_WNDPROC, (LONG_PTR)append_message_wndproc ); + ok_ne( 0, old_other_proc, LONG_PTR, "%#Ix" ); - got_button_down = got_button_up = FALSE; - simulate_click(TRUE, 150, 150); - while (wait_for_message(&msg)) - { - DispatchMessageA(&msg); + hregion = CreateRectRgn( 0, 0, 10, 10 ); + ok_ne( NULL, hregion, HRGN, "%p" ); + ok_ret( 1, SetWindowRgn( other, hregion, TRUE ) ); + DeleteObject( hregion ); + ok_ret( SIMPLEREGION, GetWindowRgnBox( other, ®ion ) ); - if (msg.message == WM_LBUTTONDOWN) - { - ok(msg.hwnd == hwnd, "msg.hwnd = %p\n", msg.hwnd); - got_button_down = TRUE; - } - else if (msg.message == WM_LBUTTONUP) - { - ok(msg.hwnd == hwnd, "msg.hwnd = %p\n", msg.hwnd); - got_button_up = TRUE; - break; - } - } - ok(got_button_down, "expected WM_LBUTTONDOWN message\n"); - ok(got_button_up, "expected WM_LBUTTONUP message\n"); + mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 ); + wait_messages( 5, FALSE ); + button_down_hwnd[1].message.hwnd = hwnd; + ok_seq( button_down_hwnd ); + mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 ); + wait_messages( 5, FALSE ); + button_up_hwnd[1].message.hwnd = hwnd; + ok_seq( button_up_hwnd ); - ret = SetLayeredWindowAttributes(hwnd, RGB(128, 128, 128), 0, LWA_COLORKEY); - ok(ret, "SetLayeredWindowAttributes failed\n"); - while (wait_for_message(&msg)) DispatchMessageA(&msg); - Sleep(100); + ok_ret( 1, DestroyWindow( other ) ); + wait_messages( 0, FALSE ); - if (pGetWindowRgnBox) - { - region_type = pGetWindowRgnBox(hwnd, ®ion); - ok(region_type == ERROR, "expected ERROR, got %d\n", region_type); - } - got_button_down = got_button_up = FALSE; - simulate_click(TRUE, 150, 150); - while (wait_for_message(&msg)) - { - DispatchMessageA(&msg); + /* warm up test case by moving cursor and window a bit first */ + ok_ret( 1, SetCursorPos( 60, 50 ) ); + ok_ret( 1, SetWindowPos( hwnd, NULL, 10, 0, 0, 0, SWP_NOSIZE ) ); + wait_messages( 5, FALSE ); + ok_ret( 1, SetCursorPos( 50, 50 ) ); + ok_ret( 1, SetWindowPos( hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE ) ); + wait_messages( 5, FALSE ); + SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)mouse_move_wndproc ); - if (msg.message == WM_LBUTTONDOWN) - { - todo_wine - ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); - got_button_down = TRUE; - } - else if (msg.message == WM_LBUTTONUP) - { - todo_wine - ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); - got_button_up = TRUE; - break; - } - } - ok(got_button_down, "expected WM_LBUTTONDOWN message\n"); - ok(got_button_up, "expected WM_LBUTTONUP message\n"); + ok_ret( 1, SetCursorPos( 60, 50 ) ); + ok_ret( 1, SetWindowPos( hwnd, NULL, 10, 0, 0, 0, SWP_NOSIZE ) ); + wait_messages( 5, FALSE ); + ok_ret( 1, GetCursorPos( &pt ) ); + ok_point( expect_60x50, pt ); - SetWindowLongA(hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED); - while (wait_for_message(&msg)) DispatchMessageA(&msg); - Sleep(100); + ok_ret( 1, SetCursorPos( 50, 50 ) ); + ok_ret( 1, SetWindowPos( hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE ) ); + wait_messages( 5, FALSE ); + ok_ret( 1, GetCursorPos( &pt ) ); + ok_point( expect_50x50, pt ); - if (pGetWindowRgnBox) - { - region_type = pGetWindowRgnBox(hwnd, ®ion); - ok(region_type == ERROR, "expected ERROR, got %d\n", region_type); - } - got_button_down = got_button_up = FALSE; - simulate_click(TRUE, 150, 150); - while (wait_for_message(&msg)) - { - DispatchMessageA(&msg); + ok_ret( 1, UnhookWindowsHookEx( hook ) ); - if (msg.message == WM_LBUTTONDOWN) - { - ok(msg.hwnd == hwnd, "msg.hwnd = %p\n", msg.hwnd); - got_button_down = TRUE; - } - else if (msg.message == WM_LBUTTONUP) - { - ok(msg.hwnd == hwnd, "msg.hwnd = %p\n", msg.hwnd); - got_button_up = TRUE; - break; - } - } - ok(got_button_down, "expected WM_LBUTTONDOWN message\n"); - ok(got_button_up, "expected WM_LBUTTONUP message\n"); + wait_messages( 100, FALSE ); + todo_wine ok_seq( empty_sequence ); + p_accept_message = NULL; + append_message_hwnd = FALSE; - hregion = CreateRectRgn(0, 0, 10, 10); - ok(hregion != NULL, "CreateRectRgn failed\n"); - ret = SetWindowRgn(hwnd, hregion, TRUE); - ok(ret, "SetWindowRgn failed\n"); - DeleteObject(hregion); - while (wait_for_message(&msg)) DispatchMessageA(&msg); - Sleep(1000); - if (pGetWindowRgnBox) - { - region_type = pGetWindowRgnBox(hwnd, ®ion); - ok(region_type == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", region_type); - } + ok_ret( 1, DestroyWindow( hwnd ) ); - got_button_down = got_button_up = FALSE; - simulate_click(TRUE, 150, 150); - while (wait_for_message(&msg)) - { - DispatchMessageA(&msg); + CloseHandle( params.start_event ); + CloseHandle( params.end_event ); - if (msg.message == WM_LBUTTONDOWN) - { - ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); - got_button_down = TRUE; - } - else if (msg.message == WM_LBUTTONUP) - { - ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); - got_button_up = TRUE; - break; - } - } - ok(got_button_down, "expected WM_LBUTTONDOWN message\n"); - ok(got_button_up, "expected WM_LBUTTONUP message\n"); - DestroyWindow(static_win); - DestroyWindow(hwnd); - SetCursorPos(pt_org.x, pt_org.y); - - CloseHandle(thread_data.start_event); - CloseHandle(thread_data.end_event); - DestroyWindow(button_win); + ok_ret( 1, SetDoubleClickTime( dblclk_time ) ); } @@ -2613,13 +4609,13 @@ static DWORD WINAPI thread_proc(void *param) if (wnd_event->attach_from) { ret = AttachThreadInput(wnd_event->attach_from, GetCurrentThreadId(), TRUE); - ok(ret, "AttachThreadInput error %d\n", GetLastError()); + ok(ret, "AttachThreadInput error %ld\n", GetLastError()); } if (wnd_event->attach_to) { ret = AttachThreadInput(GetCurrentThreadId(), wnd_event->attach_to, TRUE); - ok(ret, "AttachThreadInput error %d\n", GetLastError()); + ok(ret, "AttachThreadInput error %ld\n", GetLastError()); } wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW, @@ -2675,7 +4671,7 @@ static void test_attach_input(void) } hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid); - ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError()); + ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError()); ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); CloseHandle(wnd_event.start_event); @@ -2692,7 +4688,7 @@ static void test_attach_input(void) SetActiveWindow(ourWnd); ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE); - ok(ret, "AttachThreadInput error %d\n", GetLastError()); + ok(ret, "AttachThreadInput error %ld\n", GetLastError()); ok(GetActiveWindow() == ourWnd, "expected active %p, got %p\n", ourWnd, GetActiveWindow()); ok(GetFocus() == ourWnd, "expected focus %p, got %p\n", ourWnd, GetFocus()); @@ -2700,14 +4696,14 @@ static void test_attach_input(void) SendMessageA(wnd_event.hwnd, WM_USER+1, 0, (LPARAM)ourWnd); ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE); - ok(ret, "AttachThreadInput error %d\n", GetLastError()); + ok(ret, "AttachThreadInput error %ld\n", GetLastError()); ok(GetActiveWindow() == ourWnd, "expected active %p, got %p\n", ourWnd, GetActiveWindow()); ok(GetFocus() == ourWnd, "expected focus %p, got %p\n", ourWnd, GetFocus()); SendMessageA(wnd_event.hwnd, WM_USER+1, 0, 0); ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE); - ok(ret, "AttachThreadInput error %d\n", GetLastError()); + ok(ret, "AttachThreadInput error %ld\n", GetLastError()); ok(GetActiveWindow() == ourWnd, "expected active %p, got %p\n", ourWnd, GetActiveWindow()); ok(GetFocus() == ourWnd, "expected focus %p, got %p\n", ourWnd, GetFocus()); @@ -2721,14 +4717,14 @@ static void test_attach_input(void) SendMessageA(wnd_event.hwnd, WM_USER+1, 0, (LPARAM)Wnd2); ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE); - ok(ret, "AttachThreadInput error %d\n", GetLastError()); + ok(ret, "AttachThreadInput error %ld\n", GetLastError()); ok(GetActiveWindow() == Wnd2, "expected active %p, got %p\n", Wnd2, GetActiveWindow()); ok(GetFocus() == Wnd2, "expected focus %p, got %p\n", Wnd2, GetFocus()); SendMessageA(wnd_event.hwnd, WM_USER+1, 0, 0); ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0); - ok(ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError()); + ok(ret, "PostMessageA(WM_QUIT) error %ld\n", GetLastError()); ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); CloseHandle(hThread); @@ -2740,7 +4736,7 @@ static void test_attach_input(void) wnd_event.setWindows = TRUE; hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid); - ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError()); + ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError()); ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); CloseHandle(wnd_event.start_event); @@ -2749,7 +4745,7 @@ static void test_attach_input(void) SetActiveWindow(ourWnd); ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE); - ok(ret, "AttachThreadInput error %d\n", GetLastError()); + ok(ret, "AttachThreadInput error %ld\n", GetLastError()); ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow()); ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus()); @@ -2757,7 +4753,7 @@ static void test_attach_input(void) SendMessageA(wnd_event.hwnd, WM_USER+1, 0, (LPARAM)wnd_event.hwnd); ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE); - ok(ret, "AttachThreadInput error %d\n", GetLastError()); + ok(ret, "AttachThreadInput error %ld\n", GetLastError()); ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow()); ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus()); @@ -2765,7 +4761,7 @@ static void test_attach_input(void) SendMessageA(wnd_event.hwnd, WM_USER+1, 0, (LPARAM)wnd_event.hwnd); ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE); - ok(ret, "AttachThreadInput error %d\n", GetLastError()); + ok(ret, "AttachThreadInput error %ld\n", GetLastError()); ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow()); ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus()); @@ -2780,7 +4776,7 @@ static void test_attach_input(void) SendMessageA(wnd_event.hwnd, WM_USER+1, 0, (LPARAM)Wnd2); ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE); - ok(ret, "AttachThreadInput error %d\n", GetLastError()); + ok(ret, "AttachThreadInput error %ld\n", GetLastError()); ok(GetActiveWindow() == Wnd2, "expected active %p, got %p\n", Wnd2, GetActiveWindow()); ok(GetFocus() == Wnd2, "expected focus %p, got %p\n", Wnd2, GetFocus()); @@ -2788,7 +4784,7 @@ static void test_attach_input(void) SendMessageA(wnd_event.hwnd, WM_USER+1, 0, 0); ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0); - ok(ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError()); + ok(ret, "PostMessageA(WM_QUIT) error %ld\n", GetLastError()); ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); CloseHandle(hThread); @@ -2800,19 +4796,19 @@ static void test_attach_input(void) wnd_event.setWindows = TRUE; hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid); - ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError()); + ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE); ok(!ret, "AttachThreadInput succeeded\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef) /* <= Win XP */, - "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = AttachThreadInput(tid, GetCurrentThreadId(), TRUE); ok(!ret, "AttachThreadInput succeeded\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef) /* <= Win XP */, - "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); SetEvent(wnd_event.wait_event); @@ -2820,7 +4816,7 @@ static void test_attach_input(void) CloseHandle(wnd_event.start_event); ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0); - ok(ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError()); + ok(ret, "PostMessageA(WM_QUIT) error %ld\n", GetLastError()); ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); CloseHandle(hThread); @@ -2835,7 +4831,7 @@ static void test_attach_input(void) SetActiveWindow(ourWnd); hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid); - ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError()); + ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError()); ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); CloseHandle(wnd_event.start_event); @@ -2844,7 +4840,7 @@ static void test_attach_input(void) ok(GetFocus() == ourWnd, "expected focus %p, got %p\n", ourWnd, GetFocus()); ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0); - ok(ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError()); + ok(ret, "PostMessageA(WM_QUIT) error %ld\n", GetLastError()); ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); CloseHandle(hThread); @@ -2859,7 +4855,7 @@ static void test_attach_input(void) SetActiveWindow(ourWnd); hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid); - ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError()); + ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError()); ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); CloseHandle(wnd_event.start_event); @@ -2868,7 +4864,7 @@ static void test_attach_input(void) ok(GetFocus() == ourWnd, "expected focus %p, got %p\n", ourWnd, GetFocus()); ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0); - ok(ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError()); + ok(ret, "PostMessageA(WM_QUIT) error %ld\n", GetLastError()); ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); CloseHandle(hThread); @@ -2876,68 +4872,258 @@ static void test_attach_input(void) DestroyWindow(Wnd2); } +struct get_key_state_test_desc +{ + BOOL peek_message; + BOOL peek_message_main; + BOOL set_keyboard_state_main; + BOOL set_keyboard_state; +}; + +struct get_key_state_test_desc get_key_state_tests[] = +{ + /* 0: not peeking in thread, no msg queue: GetKeyState / GetKeyboardState miss key press */ + {FALSE, TRUE, FALSE, FALSE}, + /* 1: peeking on thread init, not in main: GetKeyState / GetKeyboardState catch key press */ + /* - GetKeyboardState misses key press if called before GetKeyState */ + /* - GetKeyboardState catches key press, if called after GetKeyState */ + { TRUE, FALSE, FALSE, FALSE}, + /* 2: peeking on thread init, and in main: GetKeyState / GetKeyboardState catch key press */ + { TRUE, TRUE, FALSE, FALSE}, + + /* same tests but with SetKeyboardState called in main thread */ + /* 3: not peeking in thread, no msg queue: GetKeyState / GetKeyboardState miss key press */ + {FALSE, TRUE, TRUE, FALSE}, + /* 4: peeking on thread init, not in main: GetKeyState / GetKeyboardState catch key press */ + /* - GetKeyboardState misses key press if called before GetKeyState */ + /* - GetKeyboardState catches key press, if called after GetKeyState */ + { TRUE, FALSE, TRUE, FALSE}, + /* 5: peeking on thread init, and in main: GetKeyState / GetKeyboardState catch key press */ + { TRUE, TRUE, TRUE, FALSE}, + + /* same tests but with SetKeyboardState called in other thread */ + /* 6: not peeking in thread, no msg queue: GetKeyState / GetKeyboardState miss key press */ + {FALSE, TRUE, TRUE, TRUE}, + /* 7: peeking on thread init, not in main: GetKeyState / GetKeyboardState catch key press */ + /* - GetKeyboardState misses key press if called before GetKeyState */ + /* - GetKeyboardState catches key press, if called after GetKeyState */ + { TRUE, FALSE, TRUE, TRUE}, + /* 8: peeking on thread init, and in main: GetKeyState / GetKeyboardState catch key press */ + { TRUE, TRUE, TRUE, TRUE}, +}; + +struct get_key_state_thread_params +{ + HANDLE semaphores[2]; + int index; +}; + +#define check_get_keyboard_state(i, j, c, x) check_get_keyboard_state_(i, j, c, x, __LINE__) +static void check_get_keyboard_state_(int i, int j, int c, int x, int line) +{ + unsigned char keystate[256]; + BOOL ret; + + memset(keystate, 0, sizeof(keystate)); + ret = GetKeyboardState(keystate); + ok_(__FILE__, line)(ret, "GetKeyboardState failed, %lu\n", GetLastError()); + ok_(__FILE__, line)(!(keystate['X'] & 0x80) == !x, "%d:%d: expected that X keystate is %s\n", i, j, x ? "set" : "unset"); + ok_(__FILE__, line)(!(keystate['C'] & 0x80) == !c, "%d:%d: expected that C keystate is %s\n", i, j, c ? "set" : "unset"); + + /* calling it twice shouldn't change */ + memset(keystate, 0, sizeof(keystate)); + ret = GetKeyboardState(keystate); + ok_(__FILE__, line)(ret, "GetKeyboardState failed, %lu\n", GetLastError()); + ok_(__FILE__, line)(!(keystate['X'] & 0x80) == !x, "%d:%d: expected that X keystate is %s\n", i, j, x ? "set" : "unset"); + ok_(__FILE__, line)(!(keystate['C'] & 0x80) == !c, "%d:%d: expected that C keystate is %s\n", i, j, c ? "set" : "unset"); +} + +#define check_get_key_state(i, j, c, x) check_get_key_state_(i, j, c, x, __LINE__) +static void check_get_key_state_(int i, int j, int c, int x, int line) +{ + SHORT state; + + state = GetKeyState('X'); + ok_(__FILE__, line)(!(state & 0x8000) == !x, "%d:%d: expected that X highest bit is %s, got %#x\n", i, j, x ? "set" : "unset", state); + ok_(__FILE__, line)(!(state & 0x007e), "%d:%d: expected that X undefined bits are unset, got %#x\n", i, j, state); + + state = GetKeyState('C'); + ok_(__FILE__, line)(!(state & 0x8000) == !c, "%d:%d: expected that C highest bit is %s, got %#x\n", i, j, c ? "set" : "unset", state); + ok_(__FILE__, line)(!(state & 0x007e), "%d:%d: expected that C undefined bits are unset, got %#x\n", i, j, state); +} + static DWORD WINAPI get_key_state_thread(void *arg) { - HANDLE *semaphores = arg; + struct get_key_state_thread_params *params = arg; + struct get_key_state_test_desc* test; + HANDLE *semaphores = params->semaphores; DWORD result; + BYTE keystate[256] = {0}; + BOOL has_queue; + BOOL expect_x, expect_c; + MSG msg; + int i = params->index, j; - ReleaseSemaphore(semaphores[0], 1, NULL); - result = WaitForSingleObject(semaphores[1], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + test = get_key_state_tests + i; + has_queue = test->peek_message || test->set_keyboard_state; - result = GetKeyState('X'); - ok((result & 0x8000) || broken(!(result & 0x8000)), /* > Win 2003 */ - "expected that highest bit is set, got %x\n", result); + if (test->peek_message) + { + while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) + ok(!is_keyboard_message(msg.message), "%d: PeekMessageA got keyboard message.\n", i); + } - ReleaseSemaphore(semaphores[0], 1, NULL); - result = WaitForSingleObject(semaphores[1], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + for (j = 0; j < 4; ++j) + { + /* initialization */ + ReleaseSemaphore(semaphores[0], 1, NULL); + result = WaitForSingleObject(semaphores[1], 1000); + ok(result == WAIT_OBJECT_0, "%d:%d: WaitForSingleObject returned %lu\n", i, j, result); - result = GetKeyState('X'); - ok(!(result & 0x8000), "expected that highest bit is unset, got %x\n", result); + if (test->set_keyboard_state) + { + keystate['C'] = 0xff; + SetKeyboardState(keystate); + } + + /* key pressed */ + ReleaseSemaphore(semaphores[0], 1, NULL); + result = WaitForSingleObject(semaphores[1], 1000); + ok(result == WAIT_OBJECT_0, "%d:%d: WaitForSingleObject returned %lu\n", i, j, result); + + if (test->set_keyboard_state) expect_x = TRUE; + else if (!has_queue && j == 0) expect_x = FALSE; + else expect_x = TRUE; + + if (test->set_keyboard_state) expect_c = TRUE; + else expect_c = FALSE; + + check_get_keyboard_state(i, j, expect_c, FALSE); + check_get_key_state(i, j, expect_c, expect_x); + check_get_keyboard_state(i, j, expect_c, expect_x); + + /* key released */ + ReleaseSemaphore(semaphores[0], 1, NULL); + result = WaitForSingleObject(semaphores[1], 1000); + ok(result == WAIT_OBJECT_0, "%d: WaitForSingleObject returned %lu\n", i, result); + + check_get_keyboard_state(i, j, expect_c, expect_x); + check_get_key_state(i, j, expect_c, FALSE); + check_get_keyboard_state(i, j, expect_c, FALSE); + } return 0; } static void test_GetKeyState(void) { - HANDLE semaphores[2]; + struct get_key_state_thread_params params; HANDLE thread; DWORD result; + BYTE keystate[256] = {0}; + BOOL expect_x, expect_c; HWND hwnd; + MSG msg; + int i, j; - semaphores[0] = CreateSemaphoreA(NULL, 0, 1, NULL); - ok(semaphores[0] != NULL, "CreateSemaphoreA failed %u\n", GetLastError()); - semaphores[1] = CreateSemaphoreA(NULL, 0, 1, NULL); - ok(semaphores[1] != NULL, "CreateSemaphoreA failed %u\n", GetLastError()); + BOOL us_kbd = (GetKeyboardLayout(0) == (HKL)(ULONG_PTR)0x04090409); + if (!us_kbd) + { + skip("skipping test with inconsistent results on non-us keyboard\n"); + return; + } + + params.semaphores[0] = CreateSemaphoreA(NULL, 0, 1, NULL); + ok(params.semaphores[0] != NULL, "CreateSemaphoreA failed %lu\n", GetLastError()); + params.semaphores[1] = CreateSemaphoreA(NULL, 0, 1, NULL); + ok(params.semaphores[1] != NULL, "CreateSemaphoreA failed %lu\n", GetLastError()); hwnd = CreateWindowA("static", "Title", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 10, 10, 200, 200, NULL, NULL, NULL, NULL); - ok(hwnd != NULL, "CreateWindowA failed %u\n", GetLastError()); + ok(hwnd != NULL, "CreateWindowA failed %lu\n", GetLastError()); + empty_message_queue(); - thread = CreateThread(NULL, 0, get_key_state_thread, semaphores, 0, NULL); - ok(thread != NULL, "CreateThread failed %u\n", GetLastError()); - result = WaitForSingleObject(semaphores[0], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + for (i = 0; i < ARRAY_SIZE(get_key_state_tests); ++i) + { + struct get_key_state_test_desc* test = get_key_state_tests + i; - SetForegroundWindow(hwnd); - SetFocus(hwnd); - keybd_event('X', 0, 0, 0); + params.index = i; + thread = CreateThread(NULL, 0, get_key_state_thread, ¶ms, 0, NULL); + ok(thread != NULL, "CreateThread failed %lu\n", GetLastError()); - ReleaseSemaphore(semaphores[1], 1, NULL); - result = WaitForSingleObject(semaphores[0], 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + for (j = 0; j < 4; ++j) + { + /* initialization */ + result = WaitForSingleObject(params.semaphores[0], 1000); + ok(result == WAIT_OBJECT_0, "%d:%d: WaitForSingleObject returned %lu\n", i, j, result); - keybd_event('X', 0, KEYEVENTF_KEYUP, 0); + SetForegroundWindow(hwnd); + SetFocus(hwnd); + empty_message_queue(); - ReleaseSemaphore(semaphores[1], 1, NULL); - result = WaitForSingleObject(thread, 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); - CloseHandle(thread); + ReleaseSemaphore(params.semaphores[1], 1, NULL); + + /* key pressed */ + result = WaitForSingleObject(params.semaphores[0], 1000); + ok(result == WAIT_OBJECT_0, "%d:%d: WaitForSingleObject returned %lu\n", i, j, result); + + keybd_event('X', 0, 0, 0); + if (test->set_keyboard_state_main) + { + expect_c = TRUE; + keystate['C'] = 0xff; + SetKeyboardState(keystate); + } + else expect_c = FALSE; + + check_get_keyboard_state(i, j, expect_c, FALSE); + check_get_key_state(i, j, expect_c, FALSE); + check_get_keyboard_state(i, j, expect_c, FALSE); + + if (test->peek_message_main) while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + + if (test->peek_message_main) expect_x = TRUE; + else expect_x = FALSE; + + check_get_keyboard_state(i, j, expect_c, expect_x); + check_get_key_state(i, j, expect_c, expect_x); + check_get_keyboard_state(i, j, expect_c, expect_x); + + ReleaseSemaphore(params.semaphores[1], 1, NULL); + + /* key released */ + result = WaitForSingleObject(params.semaphores[0], 1000); + ok(result == WAIT_OBJECT_0, "%d:%d: WaitForSingleObject returned %lu\n", i, j, result); + + keybd_event('X', 0, KEYEVENTF_KEYUP, 0); + if (test->set_keyboard_state_main) + { + expect_x = FALSE; + keystate['C'] = 0x00; + SetKeyboardState(keystate); + } + + check_get_keyboard_state(i, j, FALSE, expect_x); + check_get_key_state(i, j, FALSE, expect_x); + check_get_keyboard_state(i, j, FALSE, expect_x); + + if (test->peek_message_main) while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + + check_get_keyboard_state(i, j, FALSE, FALSE); + check_get_key_state(i, j, FALSE, FALSE); + check_get_keyboard_state(i, j, FALSE, FALSE); + + ReleaseSemaphore(params.semaphores[1], 1, NULL); + } + + result = WaitForSingleObject(thread, 1000); + ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); + CloseHandle(thread); + } DestroyWindow(hwnd); - CloseHandle(semaphores[0]); - CloseHandle(semaphores[1]); + CloseHandle(params.semaphores[0]); + CloseHandle(params.semaphores[1]); } static void test_OemKeyScan(void) @@ -2946,6 +5132,13 @@ static void test_OemKeyScan(void) WCHAR oem, wchr; char oem_char; + BOOL us_kbd = (GetKeyboardLayout(0) == (HKL)(ULONG_PTR)0x04090409); + if (!us_kbd) + { + skip("skipping test with inconsistent results on non-us keyboard\n"); + return; + } + for (oem = 0; oem < 0x200; oem++) { ret = OemKeyScan( oem ); @@ -2970,7 +5163,7 @@ static void test_OemKeyScan(void) expect = vkey | scan; } } - ok( ret == expect, "%04x: got %08x expected %08x\n", oem, ret, expect ); + ok( ret == expect, "%04x: got %08lx expected %08lx\n", oem, ret, expect ); } } @@ -3022,7 +5215,7 @@ static LRESULT WINAPI msg_source_proc( HWND hwnd, UINT message, WPARAM wp, LPARA static void test_input_message_source(void) { WNDCLASSA cls; - TEST_INPUT inputs[2]; + INPUT inputs[2]; HWND hwnd; RECT rc; MSG msg; @@ -3046,20 +5239,20 @@ static void test_input_message_source(void) SetFocus( hwnd ); inputs[0].type = INPUT_KEYBOARD; - inputs[0].u.ki.dwExtraInfo = 0; - inputs[0].u.ki.time = 0; - inputs[0].u.ki.wVk = 0; - inputs[0].u.ki.wScan = 0x3c0; - inputs[0].u.ki.dwFlags = KEYEVENTF_UNICODE; + inputs[0].ki.dwExtraInfo = 0; + inputs[0].ki.time = 0; + inputs[0].ki.wVk = 0; + inputs[0].ki.wScan = 0x3c0; + inputs[0].ki.dwFlags = KEYEVENTF_UNICODE; inputs[1] = inputs[0]; - inputs[1].u.ki.dwFlags |= KEYEVENTF_KEYUP; + inputs[1].ki.dwFlags |= KEYEVENTF_KEYUP; expect_src.deviceType = IMDT_UNAVAILABLE; expect_src.originId = IMO_UNAVAILABLE; SendMessageA( hwnd, WM_KEYDOWN, 0, 0 ); SendMessageA( hwnd, WM_MOUSEMOVE, 0, 0 ); - SendInput( 2, (INPUT *)inputs, sizeof(INPUT) ); + SendInput( 2, inputs, sizeof(INPUT) ); while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE )) { expect_src.deviceType = IMDT_KEYBOARD; @@ -3103,92 +5296,981 @@ static void test_input_message_source(void) UnregisterClassA( cls.lpszClassName, GetModuleHandleA(0) ); } -static void test_GetPointerType(void) +static void test_UnregisterDeviceNotification(void) { - BOOL ret; - POINTER_INPUT_TYPE type = -1; - UINT id = 0; - - SetLastError(0xdeadbeef); - ret = pGetPointerType(id, NULL); - ok(!ret, "GetPointerType should have failed.\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, - "expected error ERROR_INVALID_PARAMETER, got %u.\n", GetLastError()); - - SetLastError(0xdeadbeef); - ret = pGetPointerType(id, &type); - ok(GetLastError() == ERROR_INVALID_PARAMETER, - "expected error ERROR_INVALID_PARAMETER, got %u.\n", GetLastError()); - ok(!ret, "GetPointerType failed, got type %d for %u.\n", type, id ); - ok(type == -1, " type %d\n", type ); - - id = 1; - ret = pGetPointerType(id, &type); - ok(ret, "GetPointerType failed, got type %d for %u.\n", type, id ); - ok(type == PT_MOUSE, " type %d\n", type ); + BOOL ret = UnregisterDeviceNotification(NULL); + ok(ret == FALSE, "Unregistering NULL Device Notification returned: %d\n", ret); } -static void test_GetKeyboardLayoutList(void) +static void test_SendInput( WORD vkey, WCHAR wch, HKL hkl ) { - int cnt, cnt2; - HKL *layouts; - ULONG_PTR baselayout; - LANGID langid; - - baselayout = GetUserDefaultLCID(); - langid = PRIMARYLANGID(LANGIDFROMLCID(baselayout)); - if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN) - baselayout = MAKELONG( baselayout, 0xe001 ); /* IME */ - else - baselayout |= baselayout << 16; - - cnt = GetKeyboardLayoutList(0, NULL); - /* Most users will not have more than a few keyboard layouts installed at a time. */ - ok(cnt > 0 && cnt < 10, "Layout count %d\n", cnt); - if (cnt > 0) + const struct user_call broken_sequence[] = { - layouts = HeapAlloc(GetProcessHeap(), 0, sizeof(*layouts) * cnt ); + {.func = MSG_TEST_WIN, .message = {.msg = WM_KEYDOWN, .wparam = vkey, .lparam = MAKELONG(1, 0)}}, + {.func = MSG_TEST_WIN, .message = {.msg = WM_CHAR, .wparam = wch, .lparam = MAKELONG(1, 0)}}, + {.func = MSG_TEST_WIN, .message = {.msg = WM_KEYUP, .wparam = vkey, .lparam = MAKELONG(1, KF_UP | KF_REPEAT)}}, + {0} + }; - cnt2 = GetKeyboardLayoutList(cnt, layouts); - ok(cnt == cnt2, "wrong value %d!=%d\n", cnt, cnt2); - for(cnt = 0; cnt < cnt2; cnt++) - { - if(layouts[cnt] == (HKL)baselayout) - break; - } - ok(cnt < cnt2, "Didnt find current keyboard\n"); + INPUT input[16]; + UINT res, i; + HWND hwnd; - HeapFree(GetProcessHeap(), 0, layouts); + hwnd = CreateWindowW( L"static", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, NULL, NULL ); + ok_ne( NULL, hwnd, HWND, "%p" ); + wait_messages( 100, FALSE ); + + /* If we have had a spurious layout change, wch may be incorrect. */ + if (GetKeyboardLayout( 0 ) != hkl) + { + win_skip( "Spurious keyboard layout changed detected (expected: %p got: %p)\n", + hkl, GetKeyboardLayout( 0 ) ); + ok_ret( 1, DestroyWindow( hwnd ) ); + wait_messages( 100, FALSE ); + ok_seq( empty_sequence ); + return; + } + + SetLastError( 0xdeadbeef ); + ok_ret( 0, SendInput( 0, NULL, 0 ) ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + SetLastError( 0xdeadbeef ); + ok_ret( 0, SendInput( 1, NULL, 0 ) ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + SetLastError( 0xdeadbeef ); + ok_ret( 0, SendInput( 1, NULL, sizeof(*input) ) ); + ok( GetLastError() == ERROR_NOACCESS || GetLastError() == ERROR_INVALID_PARAMETER, + "GetLastError returned %#lx\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ok_ret( 0, SendInput( 0, input, sizeof(*input) ) ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + SetLastError( 0xdeadbeef ); + ok_ret( 0, SendInput( 0, NULL, sizeof(*input) ) ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + + memset( input, 0, sizeof(input) ); + SetLastError( 0xdeadbeef ); + ok_ret( 1, SendInput( 1, input, sizeof(*input) ) ); + ok_ret( 0xdeadbeef, GetLastError() ); + SetLastError( 0xdeadbeef ); + ok_ret( 16, SendInput( 16, input, sizeof(*input) ) ); + ok_ret( 0xdeadbeef, GetLastError() ); + + SetLastError( 0xdeadbeef ); + ok_ret( 0, SendInput( 1, input, 0 ) ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + SetLastError( 0xdeadbeef ); + ok_ret( 0, SendInput( 1, input, sizeof(*input) + 1 ) ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + SetLastError( 0xdeadbeef ); + ok_ret( 0, SendInput( 1, input, sizeof(*input) - 1 ) ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + + for (i = 0; i < ARRAY_SIZE(input); ++i) input[i].type = INPUT_KEYBOARD; + SetLastError( 0xdeadbeef ); + ok_ret( 0, SendInput( 16, input, offsetof( INPUT, ki ) + sizeof(KEYBDINPUT) ) ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + SetLastError( 0xdeadbeef ); + ok_ret( 16, SendInput( 16, input, sizeof(*input) ) ); + ok_ret( 0xdeadbeef, GetLastError() ); + + for (i = 0; i < ARRAY_SIZE(input); ++i) input[i].type = INPUT_HARDWARE; + SetLastError( 0xdeadbeef ); + ok_ret( 0, SendInput( 16, input, offsetof( INPUT, hi ) + sizeof(HARDWAREINPUT) ) ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + + wait_messages( 100, FALSE ); + ok_seq( empty_sequence ); + p_accept_message = is_keyboard_message; + + input[0].hi.uMsg = WM_KEYDOWN; + input[0].hi.wParamL = 0; + input[0].hi.wParamH = 'A'; + input[1].hi.uMsg = WM_KEYUP; + input[1].hi.wParamL = 0; + input[1].hi.wParamH = 'A' | 0xc000; + SetLastError( 0xdeadbeef ); + res = SendInput( 16, input, sizeof(*input) ); + ok( (res == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) || + broken(res == 16 && GetLastError() == 0xdeadbeef) /* 32bit */, + "SendInput returned %u, error %#lx\n", res, GetLastError() ); + wait_messages( 100, TRUE ); + ok_seq( empty_sequence ); + + memset( input, 0, sizeof(input) ); + input[0].type = INPUT_HARDWARE; + input[1].type = INPUT_KEYBOARD; + input[1].ki.wVk = vkey; + input[1].ki.dwFlags = 0; + input[2].type = INPUT_KEYBOARD; + input[2].ki.wVk = vkey; + input[2].ki.dwFlags = KEYEVENTF_KEYUP; + SetLastError( 0xdeadbeef ); + res = SendInput( 16, input, sizeof(*input) ); + ok( (res == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) || + broken(res == 16 && GetLastError() == 0xdeadbeef), + "SendInput returned %u, error %#lx\n", res, GetLastError() ); + wait_messages( 100, TRUE ); + if (broken(res == 16)) ok_seq( broken_sequence ); + else ok_seq( empty_sequence ); + + for (i = 0; i < ARRAY_SIZE(input); ++i) input[i].type = INPUT_HARDWARE + 1; + SetLastError( 0xdeadbeef ); + ok_ret( 16, SendInput( 16, input, sizeof(*input) ) ); + ok_ret( 0xdeadbeef, GetLastError() ); + wait_messages( 100, TRUE ); + ok_seq( empty_sequence ); + + ok_ret( 1, DestroyWindow( hwnd ) ); + wait_messages( 100, FALSE ); + ok_seq( empty_sequence ); + p_accept_message = NULL; +} + +#define check_pointer_info( a, b ) check_pointer_info_( __LINE__, a, b ) +static void check_pointer_info_( int line, const POINTER_INFO *actual, const POINTER_INFO *expected ) +{ + check_member( *actual, *expected, "%#lx", pointerType ); + check_member( *actual, *expected, "%#x", pointerId ); + check_member( *actual, *expected, "%#x", frameId ); + check_member( *actual, *expected, "%#x", pointerFlags ); + check_member( *actual, *expected, "%p", sourceDevice ); + check_member( *actual, *expected, "%p", hwndTarget ); + check_member( *actual, *expected, "%+ld", ptPixelLocation.x ); + check_member( *actual, *expected, "%+ld", ptPixelLocation.y ); + check_member( *actual, *expected, "%+ld", ptHimetricLocation.x ); + check_member( *actual, *expected, "%+ld", ptHimetricLocation.y ); + check_member( *actual, *expected, "%+ld", ptPixelLocationRaw.x ); + check_member( *actual, *expected, "%+ld", ptPixelLocationRaw.y ); + check_member( *actual, *expected, "%+ld", ptHimetricLocationRaw.x ); + check_member( *actual, *expected, "%+ld", ptHimetricLocationRaw.y ); + check_member( *actual, *expected, "%lu", dwTime ); + check_member( *actual, *expected, "%u", historyCount ); + check_member( *actual, *expected, "%#x", InputData ); + check_member( *actual, *expected, "%#lx", dwKeyStates ); + check_member( *actual, *expected, "%I64u", PerformanceCount ); + check_member( *actual, *expected, "%#x", ButtonChangeType ); +} + +static DWORD CALLBACK test_GetPointerInfo_thread( void *arg ) +{ + POINTER_INFO pointer_info; + HWND hwnd; + BOOL ret; + + hwnd = CreateWindowW( L"test", L"test name", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 200, + 200, 0, 0, NULL, 0 ); + + memset( &pointer_info, 0xcd, sizeof(pointer_info) ); + ret = pGetPointerInfo( 1, &pointer_info ); + ok( !ret, "GetPointerInfo succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + + DestroyWindow( hwnd ); + + return 0; +} + +static void test_GetPointerInfo( BOOL mouse_in_pointer_enabled ) +{ + POINTER_INFO pointer_info[4], expect_pointer; + void *invalid_ptr = (void *)0xdeadbeef; + UINT32 entry_count, pointer_count; + POINTER_INPUT_TYPE type; + WNDCLASSW cls = + { + .lpfnWndProc = DefWindowProcW, + .hInstance = GetModuleHandleW( NULL ), + .hbrBackground = GetStockObject( WHITE_BRUSH ), + .lpszClassName = L"test", + }; + HANDLE thread; + ATOM class; + DWORD res; + HWND hwnd; + BOOL ret; + + if (!pGetPointerType) + { + todo_wine + win_skip( "GetPointerType not found, skipping tests\n" ); + return; + } + + SetLastError( 0xdeadbeef ); + ret = pGetPointerType( 1, NULL ); + ok( !ret, "GetPointerType succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = pGetPointerType( 0xdead, &type ); + todo_wine + ok( !ret, "GetPointerType succeeded\n" ); + todo_wine + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + ret = pGetPointerType( 1, &type ); + ok( ret, "GetPointerType failed, error %lu\n", GetLastError() ); + ok( type == PT_MOUSE, " type %ld\n", type ); + + if (!pGetPointerInfo) + { + todo_wine + win_skip( "GetPointerInfo not found, skipping tests\n" ); + return; + } + + class = RegisterClassW( &cls ); + ok( class, "RegisterClassW failed: %lu\n", GetLastError() ); + + ret = pGetPointerInfo( 1, invalid_ptr ); + ok( !ret, "GetPointerInfo succeeded\n" ); + todo_wine + ok( GetLastError() == ERROR_NOACCESS || broken(GetLastError() == ERROR_INVALID_PARAMETER) /* w10 32bit */, + "got error %lu\n", GetLastError() ); + + memset( pointer_info, 0xcd, sizeof(pointer_info) ); + ret = pGetPointerInfo( 1, pointer_info ); + ok( !ret, "GetPointerInfo succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + + SetCursorPos( 500, 500 ); /* avoid generating mouse message on window creation */ + + hwnd = CreateWindowW( L"test", L"test name", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 200, + 200, 0, 0, NULL, 0 ); + empty_message_queue(); + + memset( pointer_info, 0xcd, sizeof(pointer_info) ); + ret = pGetPointerInfo( 1, pointer_info ); + ok( !ret, "GetPointerInfo succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + + SetCursorPos( 200, 200 ); + empty_message_queue(); + mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 ); + empty_message_queue(); + mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 ); + empty_message_queue(); + mouse_event( MOUSEEVENTF_MOVE, 10, 10, 0, 0 ); + empty_message_queue(); + + memset( pointer_info, 0xcd, sizeof(pointer_info) ); + ret = pGetPointerInfo( 0xdead, pointer_info ); + ok( !ret, "GetPointerInfo succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + + memset( pointer_info, 0xcd, sizeof(pointer_info) ); + ret = pGetPointerInfo( 1, pointer_info ); + todo_wine_if(mouse_in_pointer_enabled) + ok( ret == mouse_in_pointer_enabled, "GetPointerInfo failed, error %lu\n", GetLastError() ); + if (!mouse_in_pointer_enabled) + { + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + return; + } + + todo_wine + ok( pointer_info[0].pointerType == PT_MOUSE, "got pointerType %lu\n", pointer_info[0].pointerType ); + todo_wine + ok( pointer_info[0].pointerId == 1, "got pointerId %u\n", pointer_info[0].pointerId ); + ok( !!pointer_info[0].frameId, "got frameId %u\n", pointer_info[0].frameId ); + todo_wine + ok( pointer_info[0].pointerFlags == (0x20000 | POINTER_MESSAGE_FLAG_INRANGE | POINTER_MESSAGE_FLAG_PRIMARY), + "got pointerFlags %#x\n", pointer_info[0].pointerFlags ); + todo_wine + ok( pointer_info[0].sourceDevice == INVALID_HANDLE_VALUE || broken(!!pointer_info[0].sourceDevice) /* < w10 & 32bit */, + "got sourceDevice %p\n", pointer_info[0].sourceDevice ); + todo_wine + ok( pointer_info[0].hwndTarget == hwnd, "got hwndTarget %p\n", pointer_info[0].hwndTarget ); + ok( !!pointer_info[0].ptPixelLocation.x, "got ptPixelLocation %s\n", wine_dbgstr_point( &pointer_info[0].ptPixelLocation ) ); + ok( !!pointer_info[0].ptPixelLocation.y, "got ptPixelLocation %s\n", wine_dbgstr_point( &pointer_info[0].ptPixelLocation ) ); + ok( !!pointer_info[0].ptHimetricLocation.x, "got ptHimetricLocation %s\n", wine_dbgstr_point( &pointer_info[0].ptHimetricLocation ) ); + ok( !!pointer_info[0].ptHimetricLocation.y, "got ptHimetricLocation %s\n", wine_dbgstr_point( &pointer_info[0].ptHimetricLocation ) ); + ok( !!pointer_info[0].ptPixelLocationRaw.x, "got ptPixelLocationRaw %s\n", wine_dbgstr_point( &pointer_info[0].ptPixelLocationRaw ) ); + ok( !!pointer_info[0].ptPixelLocationRaw.y, "got ptPixelLocationRaw %s\n", wine_dbgstr_point( &pointer_info[0].ptPixelLocationRaw ) ); + ok( !!pointer_info[0].ptHimetricLocationRaw.x, "got ptHimetricLocationRaw %s\n", wine_dbgstr_point( &pointer_info[0].ptHimetricLocationRaw ) ); + ok( !!pointer_info[0].ptHimetricLocationRaw.y, "got ptHimetricLocationRaw %s\n", wine_dbgstr_point( &pointer_info[0].ptHimetricLocationRaw ) ); + ok( !!pointer_info[0].dwTime, "got dwTime %lu\n", pointer_info[0].dwTime ); + todo_wine + ok( pointer_info[0].historyCount == 1, "got historyCount %u\n", pointer_info[0].historyCount ); + todo_wine + ok( pointer_info[0].InputData == 0, "got InputData %u\n", pointer_info[0].InputData ); + todo_wine + ok( pointer_info[0].dwKeyStates == 0, "got dwKeyStates %lu\n", pointer_info[0].dwKeyStates ); + ok( !!pointer_info[0].PerformanceCount, "got PerformanceCount %I64u\n", pointer_info[0].PerformanceCount ); + todo_wine + ok( pointer_info[0].ButtonChangeType == 0, "got ButtonChangeType %u\n", pointer_info[0].ButtonChangeType ); + + thread = CreateThread( NULL, 0, test_GetPointerInfo_thread, NULL, 0, NULL ); + res = WaitForSingleObject( thread, 5000 ); + ok( !res, "WaitForSingleObject returned %#lx, error %lu\n", res, GetLastError() ); + + expect_pointer = pointer_info[0]; + + memset( pointer_info, 0xa5, sizeof(pointer_info) ); + entry_count = pointer_count = 2; + if (!pGetPointerFrameInfo) ret = FALSE; + else ret = pGetPointerFrameInfo( 1, &pointer_count, pointer_info ); + todo_wine_if(!pGetPointerFrameInfo) + ok( ret, "GetPointerFrameInfo failed, error %lu\n", GetLastError() ); + todo_wine_if(!pGetPointerFrameInfo) + ok( pointer_count == 1, "got pointer_count %u\n", pointer_count ); + todo_wine_if(!pGetPointerFrameInfo) + check_pointer_info( &pointer_info[0], &expect_pointer ); + memset( pointer_info, 0xa5, sizeof(pointer_info) ); + entry_count = pointer_count = 2; + if (!pGetPointerInfoHistory) ret = FALSE; + else ret = pGetPointerInfoHistory( 1, &entry_count, pointer_info ); + todo_wine_if(!pGetPointerInfoHistory) + ok( ret, "GetPointerInfoHistory failed, error %lu\n", GetLastError() ); + todo_wine_if(!pGetPointerInfoHistory) + ok( entry_count == 1, "got entry_count %u\n", entry_count ); + todo_wine_if(!pGetPointerInfoHistory) + check_pointer_info( &pointer_info[0], &expect_pointer ); + memset( pointer_info, 0xa5, sizeof(pointer_info) ); + entry_count = pointer_count = 2; + if (!pGetPointerFrameInfoHistory) ret = FALSE; + else ret = pGetPointerFrameInfoHistory( 1, &entry_count, &pointer_count, pointer_info ); + todo_wine_if(!pGetPointerFrameInfoHistory) + ok( ret, "GetPointerFrameInfoHistory failed, error %lu\n", GetLastError() ); + todo_wine_if(!pGetPointerFrameInfoHistory) + ok( entry_count == 1, "got pointer_count %u\n", pointer_count ); + todo_wine_if(!pGetPointerFrameInfoHistory) + ok( pointer_count == 1, "got pointer_count %u\n", pointer_count ); + todo_wine_if(!pGetPointerFrameInfoHistory) + check_pointer_info( &pointer_info[0], &expect_pointer ); + + DestroyWindow( hwnd ); + + ret = UnregisterClassW( L"test", GetModuleHandleW( NULL ) ); + ok( ret, "UnregisterClassW failed: %lu\n", GetLastError() ); +} + +static void test_EnableMouseInPointer( const char *arg ) +{ + DWORD enable = strtoul( arg, 0, 10 ); + BOOL ret; + + winetest_push_context( "enable %lu", enable ); + + ret = pEnableMouseInPointer( enable ); + todo_wine + ok( ret, "EnableMouseInPointer failed, error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + ret = pEnableMouseInPointer( !enable ); + ok( !ret, "EnableMouseInPointer succeeded\n" ); + todo_wine + ok( GetLastError() == ERROR_ACCESS_DENIED, "got error %lu\n", GetLastError() ); + ret = pIsMouseInPointerEnabled(); + todo_wine_if(enable) + ok( ret == enable, "IsMouseInPointerEnabled returned %u, error %lu\n", ret, GetLastError() ); + + ret = pEnableMouseInPointer( enable ); + todo_wine + ok( ret, "EnableMouseInPointer failed, error %lu\n", GetLastError() ); + ret = pIsMouseInPointerEnabled(); + todo_wine_if(enable) + ok( ret == enable, "IsMouseInPointerEnabled returned %u, error %lu\n", ret, GetLastError() ); + + test_GetPointerInfo( enable ); + + winetest_pop_context(); +} + +static BOOL CALLBACK get_virtual_screen_proc( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp ) +{ + RECT *virtual_rect = (RECT *)lp; + UnionRect( virtual_rect, virtual_rect, rect ); + return TRUE; +} + +RECT get_virtual_screen_rect(void) +{ + RECT rect = {0}; + EnumDisplayMonitors( 0, NULL, get_virtual_screen_proc, (LPARAM)&rect ); + return rect; +} + +static void test_ClipCursor_dirty( const char *arg ) +{ + RECT rect, expect_rect = {1, 2, 3, 4}; + + /* check leaked clip rect from another desktop or process */ + ok_ret( 1, GetClipCursor( &rect ) ); + todo_wine_if( !strcmp( arg, "desktop" ) ) + ok_rect( expect_rect, rect ); + + /* intentionally leaking clipping rect */ +} + +static DWORD CALLBACK test_ClipCursor_thread( void *arg ) +{ + RECT rect, clip_rect, virtual_rect = get_virtual_screen_rect(); + HWND hwnd; + + clip_rect.left = clip_rect.right = (virtual_rect.left + virtual_rect.right) / 2; + clip_rect.top = clip_rect.bottom = (virtual_rect.top + virtual_rect.bottom) / 2; + + /* creating a window doesn't reset clipping rect */ + hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, + NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( clip_rect, rect ); + + /* setting a window foreground does, even from the same process */ + ok_ret( 1, SetForegroundWindow( hwnd ) ); + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( virtual_rect, rect ); + + /* destroying the window doesn't reset the clipping rect */ + InflateRect( &clip_rect, +1, +1 ); + ok_ret( 1, ClipCursor( &clip_rect ) ); + ok_ret( 1, DestroyWindow( hwnd ) ); + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( clip_rect, rect ); + + /* intentionally leaking clipping rect */ + return 0; +} + +static void test_ClipCursor_process(void) +{ + RECT rect, clip_rect, virtual_rect = get_virtual_screen_rect(); + HWND hwnd, tmp_hwnd; + HANDLE thread; + + clip_rect.left = clip_rect.right = (virtual_rect.left + virtual_rect.right) / 2; + clip_rect.top = clip_rect.bottom = (virtual_rect.top + virtual_rect.bottom) / 2; + + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( clip_rect, rect ); + + /* creating an invisible window doesn't reset clip cursor */ + hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, + NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + ok_ret( 1, DestroyWindow( hwnd ) ); + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( clip_rect, rect ); + + /* setting a window foreground, even invisible, resets it */ + hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, + NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + ok_ret( 1, SetForegroundWindow( hwnd ) ); + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( virtual_rect, rect ); + + ok_ret( 1, ClipCursor( &clip_rect ) ); + + /* creating and setting another window foreground doesn't reset it */ + tmp_hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, + NULL, NULL, NULL, NULL ); + ok( !!tmp_hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + ok_ret( 1, SetForegroundWindow( tmp_hwnd ) ); + ok_ret( 1, DestroyWindow( tmp_hwnd ) ); + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( clip_rect, rect ); + + /* but changing foreground to another thread in the same process reset it */ + thread = CreateThread( NULL, 0, test_ClipCursor_thread, NULL, 0, NULL ); + ok( !!thread, "CreateThread failed, error %lu\n", GetLastError() ); + msg_wait_for_events( 1, &thread, 5000 ); + + /* thread exit and foreground window destruction doesn't reset the clipping rect */ + InflateRect( &clip_rect, +1, +1 ); + ok_ret( 1, DestroyWindow( hwnd ) ); + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( clip_rect, rect ); + + /* intentionally leaking clipping rect */ +} + +static void test_ClipCursor_desktop( char **argv ) +{ + RECT rect, clip_rect, virtual_rect = get_virtual_screen_rect(); + + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( virtual_rect, rect ); + + /* ClipCursor clips rectangle to the virtual screen rect */ + clip_rect = virtual_rect; + InflateRect( &clip_rect, +1, +1 ); + ok_ret( 1, ClipCursor( &clip_rect ) ); + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( virtual_rect, rect ); + + clip_rect = virtual_rect; + InflateRect( &clip_rect, -1, -1 ); + ok_ret( 1, ClipCursor( &clip_rect ) ); + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( clip_rect, rect ); + + /* ClipCursor(NULL) resets to the virtual screen rect */ + ok_ret( 1, ClipCursor( NULL ) ); + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( virtual_rect, rect ); + + clip_rect.left = clip_rect.right = (virtual_rect.left + virtual_rect.right) / 2; + clip_rect.top = clip_rect.bottom = (virtual_rect.top + virtual_rect.bottom) / 2; + ok_ret( 1, ClipCursor( &clip_rect ) ); + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( clip_rect, rect ); + + /* ClipCursor rejects invalid rectangles */ + clip_rect.right -= 1; + clip_rect.bottom -= 1; + SetLastError( 0xdeadbeef ); + ok_ret( 0, ClipCursor( &clip_rect ) ); + todo_wine + ok_ret( ERROR_ACCESS_DENIED, GetLastError() ); + + /* which doesn't reset the previous clip rect */ + clip_rect.right += 1; + clip_rect.bottom += 1; + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( clip_rect, rect ); + + /* running a process causes it to leak until foreground actually changes */ + run_in_process( argv, "test_ClipCursor_process" ); + + /* as foreground window is now transient, cursor clipping isn't reset */ + InflateRect( &clip_rect, +1, +1 ); + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( clip_rect, rect ); + + /* intentionally leaking clipping rect */ +} + +static void test_ClipCursor( char **argv ) +{ + RECT rect, clip_rect = {1, 2, 3, 4}, virtual_rect = get_virtual_screen_rect(); + + ok_ret( 1, ClipCursor( &clip_rect ) ); + + /* running a new process doesn't reset clipping rectangle */ + run_in_process( argv, "test_ClipCursor_dirty process" ); + + /* running in a separate desktop, without switching desktop as well */ + run_in_desktop( argv, "test_ClipCursor_dirty desktop", 0 ); + + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( clip_rect, rect ); + + /* running in a desktop and switching input resets the clipping rect */ + run_in_desktop( argv, "test_ClipCursor_desktop", 1 ); + + ok_ret( 1, GetClipCursor( &rect ) ); + todo_wine + ok_rect( virtual_rect, rect ); + if (!EqualRect( &rect, &virtual_rect )) ok_ret( 1, ClipCursor( NULL ) ); +} + +static void test_SetCursorPos(void) +{ + RECT clip_rect = {50, 50, 51, 51}; + POINT pos, expect_pos = {50, 50}; + + ok_ret( 0, GetCursorPos( NULL ) ); + todo_wine ok_ret( ERROR_NOACCESS, GetLastError() ); + + /* immediate cursor position updates */ + ok_ret( 1, SetCursorPos( 50, 50 ) ); + ok_ret( 1, GetCursorPos( &pos ) ); + ok_point( expect_pos, pos ); + + /* without MOUSEEVENTF_MOVE cursor doesn't move */ + mouse_event( MOUSEEVENTF_LEFTUP, 123, 456, 0, 0 ); + mouse_event( MOUSEEVENTF_LEFTUP | MOUSEEVENTF_ABSOLUTE, 123, 456, 0, 0 ); + mouse_event( MOUSEEVENTF_RIGHTUP, 456, 123, 0, 0 ); + mouse_event( MOUSEEVENTF_RIGHTUP | MOUSEEVENTF_ABSOLUTE, 456, 123, 0, 0 ); + ok_ret( 1, GetCursorPos( &pos ) ); + ok_point( expect_pos, pos ); + + /* need to move by at least 3 pixels to update, but not consistent */ + mouse_event( MOUSEEVENTF_MOVE, -1, 0, 0, 0 ); + ok_ret( 1, GetCursorPos( &pos ) ); +#ifdef __REACTOS__ + ok( abs( expect_pos.x - pos.x ) <= 2, "got pos %ld\n", pos.x ); + ok( abs( expect_pos.y - pos.y ) <= 2, "got pos %ld\n", pos.y ); +#else + todo_wine ok_point( expect_pos, pos ); +#endif + mouse_event( MOUSEEVENTF_MOVE, +1, 0, 0, 0 ); + ok_ret( 1, GetCursorPos( &pos ) ); +#ifdef __REACTOS__ + ok( abs( expect_pos.x - pos.x ) <= 2, "got pos %ld\n", pos.x ); + ok( abs( expect_pos.y - pos.y ) <= 2, "got pos %ld\n", pos.y ); +#else + ok_point( expect_pos, pos ); +#endif + + /* spuriously moves by 1 or 2 pixels on Windows */ + expect_pos.x -= 2; + mouse_event( MOUSEEVENTF_MOVE, -4, 0, 0, 0 ); + ok_ret( 1, GetCursorPos( &pos ) ); +#ifdef __REACTOS__ + todo_wine ok( abs( expect_pos.x - pos.x ) <= 2, "got pos %ld\n", pos.x ); +#else + todo_wine ok( abs( expect_pos.x - pos.x ) <= 1, "got pos %ld\n", pos.x ); +#endif + expect_pos.x += 2; + mouse_event( MOUSEEVENTF_MOVE, +4, 0, 0, 0 ); + ok_ret( 1, GetCursorPos( &pos ) ); +#ifdef __REACTOS__ + ok( abs( expect_pos.x - pos.x ) <= 2, "got pos %ld\n", pos.x ); +#else + ok( abs( expect_pos.x - pos.x ) <= 1, "got pos %ld\n", pos.x ); +#endif + + /* test ClipCursor holding the cursor in place */ + expect_pos.x = expect_pos.y = 50; + ok_ret( 1, SetCursorPos( 49, 51 ) ); + ok_ret( 1, ClipCursor( &clip_rect ) ); + ok_ret( 1, GetCursorPos( &pos ) ); + ok_point( expect_pos, pos ); + ok_ret( 1, SetCursorPos( 49, 49 ) ); + ok_ret( 1, GetCursorPos( &pos ) ); + ok_point( expect_pos, pos ); + ok_ret( 1, SetCursorPos( 50, 50 ) ); + ok_ret( 1, GetCursorPos( &pos ) ); + ok_point( expect_pos, pos ); + ok_ret( 1, SetCursorPos( 48, 48 ) ); + ok_ret( 1, GetCursorPos( &pos ) ); + ok_point( expect_pos, pos ); + ok_ret( 1, SetCursorPos( 51, 51 ) ); + ok_ret( 1, GetCursorPos( &pos ) ); + ok_point( expect_pos, pos ); + ok_ret( 1, SetCursorPos( 52, 52 ) ); + ok_ret( 1, GetCursorPos( &pos ) ); + ok_point( expect_pos, pos ); + ok_ret( 1, SetCursorPos( 49, 51 ) ); + ok_ret( 1, GetCursorPos( &pos ) ); + ok_point( expect_pos, pos ); + ok_ret( 1, SetCursorPos( 51, 49 ) ); + ok_ret( 1, GetCursorPos( &pos ) ); + ok_point( expect_pos, pos ); + + mouse_event( MOUSEEVENTF_MOVE, -1, 0, 0, 0 ); + ok_ret( 1, GetCursorPos( &pos ) ); + ok_point( expect_pos, pos ); + mouse_event( MOUSEEVENTF_MOVE, 0, +1, 0, 0 ); + ok_ret( 1, GetCursorPos( &pos ) ); + ok_point( expect_pos, pos ); + mouse_event( MOUSEEVENTF_MOVE, +1, 0, 0, 0 ); + ok_ret( 1, GetCursorPos( &pos ) ); + ok_point( expect_pos, pos ); + mouse_event( MOUSEEVENTF_MOVE, 0, -1, 0, 0 ); + ok_ret( 1, GetCursorPos( &pos ) ); + ok_point( expect_pos, pos ); + + /* weird behavior when ClipCursor rect is empty */ + clip_rect.right = clip_rect.bottom = 50; + ok_ret( 1, SetCursorPos( 50, 50 ) ); + expect_pos.x = expect_pos.y = 49; + ok_ret( 1, ClipCursor( &clip_rect ) ); + ok_ret( 1, GetCursorPos( &pos ) ); + todo_wine ok_point( expect_pos, pos ); + expect_pos.x = expect_pos.y = 50; + ok_ret( 1, SetCursorPos( 49, 49 ) ); + ok_ret( 1, GetCursorPos( &pos ) ); + ok_point( expect_pos, pos ); + expect_pos.x = expect_pos.y = 49; + ok_ret( 1, SetCursorPos( 50, 50 ) ); + ok_ret( 1, GetCursorPos( &pos ) ); + todo_wine ok_point( expect_pos, pos ); + expect_pos.x = expect_pos.y = 50; + ok_ret( 1, SetCursorPos( 48, 48 ) ); + ok_ret( 1, GetCursorPos( &pos ) ); + ok_point( expect_pos, pos ); + expect_pos.x = expect_pos.y = 49; + ok_ret( 1, SetCursorPos( 51, 51 ) ); + ok_ret( 1, GetCursorPos( &pos ) ); + todo_wine ok_point( expect_pos, pos ); + ok_ret( 1, SetCursorPos( 52, 52 ) ); + ok_ret( 1, GetCursorPos( &pos ) ); + todo_wine ok_point( expect_pos, pos ); + expect_pos.x = 50; + expect_pos.y = 49; + ok_ret( 1, SetCursorPos( 49, 51 ) ); + ok_ret( 1, GetCursorPos( &pos ) ); + todo_wine ok_point( expect_pos, pos ); + expect_pos.x = 49; + expect_pos.y = 50; + ok_ret( 1, SetCursorPos( 51, 49 ) ); + ok_ret( 1, GetCursorPos( &pos ) ); + todo_wine ok_point( expect_pos, pos ); + + expect_pos.x = 50; + expect_pos.y = 49; + mouse_event( MOUSEEVENTF_MOVE, -10, 0, 0, 0 ); + ok_ret( 1, GetCursorPos( &pos ) ); + todo_wine ok_point( expect_pos, pos ); + expect_pos.x = 49; + expect_pos.y = 49; + mouse_event( MOUSEEVENTF_MOVE, 0, +10, 0, 0 ); + ok_ret( 1, GetCursorPos( &pos ) ); + todo_wine ok_point( expect_pos, pos ); + expect_pos.x = 49; + expect_pos.y = 50; + mouse_event( MOUSEEVENTF_MOVE, +10, 0, 0, 0 ); + ok_ret( 1, GetCursorPos( &pos ) ); + todo_wine ok_point( expect_pos, pos ); + expect_pos.x = 50; + expect_pos.y = 50; + mouse_event( MOUSEEVENTF_MOVE, 0, -10, 0, 0 ); + ok_ret( 1, GetCursorPos( &pos ) ); + ok_point( expect_pos, pos ); + + ok_ret( 1, ClipCursor( NULL ) ); +} + +static HANDLE ll_keyboard_event; + +static LRESULT CALLBACK ll_keyboard_event_wait(int code, WPARAM wparam, LPARAM lparam) +{ + if (code == HC_ACTION) + { + ok_ret( WAIT_TIMEOUT, WaitForSingleObject( ll_keyboard_event, 100 ) ); + return -123; + } + + return CallNextHookEx( 0, code, wparam, lparam ); +} + +static void test_keyboard_ll_hook_blocking(void) +{ + INPUT input = {.type = INPUT_KEYBOARD, .ki = {.wVk = VK_RETURN}}; + HHOOK hook; + HWND hwnd; + + hwnd = CreateWindowW( L"static", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, NULL, NULL ); + ok_ne( NULL, hwnd, HWND, "%p" ); + wait_messages( 100, FALSE ); + hook = SetWindowsHookExW( WH_KEYBOARD_LL, ll_keyboard_event_wait, GetModuleHandleW( NULL ), 0 ); + ok_ne( NULL, hook, HHOOK, "%p" ); + ll_keyboard_event = CreateEventW( NULL, FALSE, FALSE, NULL ); + ok_ne( NULL, ll_keyboard_event, HANDLE, "%p" ); + + ok_ret( 1, SendInput( 1, &input, sizeof(input) ) ); + input.ki.dwFlags = KEYEVENTF_KEYUP; + ok_ret( 1, SendInput( 1, &input, sizeof(input) ) ); + ok_ret( 1, SetEvent( ll_keyboard_event ) ); + + ok_ret( 1, CloseHandle( ll_keyboard_event ) ); + ok_ret( 1, UnhookWindowsHookEx( hook ) ); + ok_ret( 1, DestroyWindow( hwnd ) ); +} + +static void test_LoadKeyboardLayoutEx( HKL orig_hkl ) +{ + static const WCHAR test_layout_name[] = L"00000429"; + static const HKL test_hkl = (HKL)0x04290429; + + HKL *new_layouts, *layouts, old_hkl, hkl; + UINT i, j, len, new_len; + WCHAR layout_name[64]; + + old_hkl = GetKeyboardLayout( 0 ); + ok_ne( 0, old_hkl, HKL, "%p" ); + + /* If we are dealing with a testbot setup that is prone to spurious + * layout changes, layout activations in this test are likely to + * not have the expected effect, invalidating the test assumptions. */ + if (orig_hkl != old_hkl) + { + win_skip( "Spurious keyboard layout changed detected (expected: %p got: %p)\n", + orig_hkl, old_hkl ); + return; + } + + hkl = pLoadKeyboardLayoutEx( NULL, test_layout_name, 0 ); + ok_eq( 0, hkl, HKL, "%p" ); + + layouts = get_keyboard_layouts( &len ); + for (i = 0; i < len; i++) if (layouts[i] == test_hkl) break; + if (i != len) + { + skip( "Test HKL is already loaded, skipping tests\n" ); + free( layouts ); + return; + } + + /* LoadKeyboardLayoutEx replaces loaded layouts, but will lose mixed layout / locale */ + for (i = 0, j = len; i < len; i++) + { + if (HIWORD(layouts[i]) != LOWORD(layouts[i])) continue; + if (j == len) j = i; + else break; + } + if (i == len) i = j; + if (i == len) + { + skip( "Failed to find appropriate layouts, skipping tests\n" ); + free( layouts ); + return; + } + + trace( "using layouts %p / %p\n", layouts[i], layouts[j] ); + + ActivateKeyboardLayout( layouts[i], 0 ); + ok_eq( layouts[i], GetKeyboardLayout( 0 ), HKL, "%p" ); + ok_ret( 1, GetKeyboardLayoutNameW( layout_name ) ); + + /* LoadKeyboardLayoutEx replaces a currently loaded layout */ + hkl = pLoadKeyboardLayoutEx( layouts[i], test_layout_name, 0 ); + todo_wine + ok_eq( test_hkl, hkl, HKL, "%p" ); + new_layouts = get_keyboard_layouts( &new_len ); + ok_eq( len, new_len, UINT, "%u" ); + todo_wine + ok_eq( test_hkl, new_layouts[i], HKL, "%p" ); + new_layouts[i] = layouts[i]; + ok( !memcmp( new_layouts, layouts, len * sizeof(*layouts) ), "keyboard layouts changed\n" ); + free( new_layouts ); + + hkl = pLoadKeyboardLayoutEx( test_hkl, layout_name, 0 ); + ok_eq( layouts[i], hkl, HKL, "%p" ); + new_layouts = get_keyboard_layouts( &new_len ); + ok_eq( len, new_len, UINT, "%u" ); + ok( !memcmp( new_layouts, layouts, len * sizeof(*layouts) ), "keyboard layouts changed\n" ); + free( new_layouts ); + + if (j == i) skip( "Only one layout found, skipping tests\n" ); + else + { + /* it also works if a different layout is active */ + ActivateKeyboardLayout( layouts[j], 0 ); + ok_eq( layouts[j], GetKeyboardLayout( 0 ), HKL, "%p" ); + + hkl = pLoadKeyboardLayoutEx( layouts[i], test_layout_name, 0 ); + todo_wine + ok_eq( test_hkl, hkl, HKL, "%p" ); + new_layouts = get_keyboard_layouts( &new_len ); + ok_eq( len, new_len, UINT, "%u" ); + todo_wine + ok_eq( test_hkl, new_layouts[i], HKL, "%p" ); + new_layouts[i] = layouts[i]; + ok( !memcmp( new_layouts, layouts, len * sizeof(*layouts) ), "keyboard layouts changed\n" ); + free( new_layouts ); + + hkl = pLoadKeyboardLayoutEx( test_hkl, layout_name, 0 ); + ok_eq( layouts[i], hkl, HKL, "%p" ); + new_layouts = get_keyboard_layouts( &new_len ); + ok_eq( len, new_len, UINT, "%u" ); + ok( !memcmp( new_layouts, layouts, len * sizeof(*layouts) ), "keyboard layouts changed\n" ); + free( new_layouts ); + } + + free( layouts ); + ActivateKeyboardLayout( old_hkl, 0 ); + ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); +} + +/* run the tests in a separate desktop to avoid interaction with other + * tests, current desktop state, or user actions. */ +static void test_input_desktop( char **argv ) +{ + HKL hkl = GetKeyboardLayout( 0 ); + WCHAR wch, wch_shift; + POINT pos; + WORD scan; + + trace( "hkl %p\n", hkl ); + ok_ret( 1, GetCursorPos( &pos ) ); + test_SetCursorPos(); + + get_test_scan( 'F', &scan, &wch, &wch_shift ); + test_SendInput( 'F', wch, hkl ); + test_SendInput_keyboard_messages( 'F', scan, wch, wch_shift, '\x06', hkl ); + test_SendInput_mouse_messages(); + + test_keyboard_ll_hook_blocking(); + + test_RegisterRawInputDevices(); + test_GetRawInputData(); + test_GetRawInputBuffer(); + test_SendInput_raw_key_messages( 'F', wch, hkl ); + + test_LoadKeyboardLayoutEx( hkl ); + + ok_ret( 1, SetCursorPos( pos.x, pos.y ) ); +} + +static void test_keyboard_layout(void) +{ + const CHAR *layout_name; + LANGID lang_id; + HKL hkl; + + /* Test that the high word of the keyboard layout in CJK locale is the same as the low word, + * even when IME is on */ + lang_id = PRIMARYLANGID(GetUserDefaultLCID()); + if (lang_id == LANG_CHINESE || lang_id == LANG_JAPANESE || lang_id == LANG_KOREAN) + { + hkl = GetKeyboardLayout(0); + ok(HIWORD(hkl) == LOWORD(hkl), "Got unexpected hkl %p.\n", hkl); + + if (lang_id == LANG_CHINESE) + layout_name = "00000804"; + else if (lang_id == LANG_JAPANESE) + layout_name = "00000411"; + else if (lang_id == LANG_KOREAN) + layout_name = "00000412"; + hkl = LoadKeyboardLayoutA(layout_name, 0); + ok(HIWORD(hkl) == LOWORD(hkl), "Got unexpected hkl %p.\n", hkl); } } START_TEST(input) { + char **argv; + int argc; POINT pos; init_function_pointers(); GetCursorPos( &pos ); - test_Input_blackbox(); - test_Input_whitebox(); - test_Input_unicode(); - test_Input_mouse(); +#ifdef __REACTOS__ + if (GetNTVersion() < _WIN32_WINNT_VISTA && !is_reactos()) { + skip("The user32:input tests causes persistent input issues on WS03!\n"); + return; + } +#endif + argc = winetest_get_mainargs(&argv); + if (argc >= 3 && !strcmp( argv[2], "rawinput_test" )) + return rawinput_test_process(); + if (argc >= 3 && !strcmp( argv[2], "test_GetMouseMovePointsEx_process" )) + return test_GetMouseMovePointsEx_process(); + if (argc >= 4 && !strcmp( argv[2], "test_EnableMouseInPointer" )) + return test_EnableMouseInPointer( argv[3] ); + if (argc >= 4 && !strcmp( argv[2], "test_ClipCursor_dirty" )) + return test_ClipCursor_dirty( argv[3] ); + if (argc >= 3 && !strcmp( argv[2], "test_ClipCursor_process" )) + return test_ClipCursor_process(); + if (argc >= 3 && !strcmp( argv[2], "test_ClipCursor_desktop" )) + return test_ClipCursor_desktop( argv ); + if (argc >= 3 && !strcmp( argv[2], "test_input_desktop" )) + return test_input_desktop( argv ); + + run_in_desktop( argv, "test_input_desktop", 1 ); test_keynames(); - test_mouse_ll_hook(); test_key_map(); test_ToUnicode(); test_ToAscii(); test_get_async_key_state(); + test_keyboard_layout(); test_keyboard_layout_name(); + test_ActivateKeyboardLayout( argv ); test_key_names(); test_attach_input(); test_GetKeyState(); test_OemKeyScan(); - test_GetRawInputData(); - test_GetKeyboardLayoutList(); + test_rawinput(argv[0]); + test_DefRawInputProc(); if(pGetMouseMovePointsEx) - test_GetMouseMovePointsEx(); + test_GetMouseMovePointsEx( argv ); else win_skip("GetMouseMovePointsEx is not available\n"); @@ -3204,8 +6286,20 @@ START_TEST(input) SetCursorPos( pos.x, pos.y ); - if(pGetPointerType) - test_GetPointerType(); + if (pGetPointerType) + test_GetPointerInfo( FALSE ); else - win_skip("GetPointerType is not available\n"); + win_skip( "GetPointerType is not available\n" ); + + test_UnregisterDeviceNotification(); + + if (!pEnableMouseInPointer) + win_skip( "EnableMouseInPointer not found, skipping tests\n" ); + else + { + run_in_process( argv, "test_EnableMouseInPointer 0" ); + run_in_process( argv, "test_EnableMouseInPointer 1" ); + } + + test_ClipCursor( argv ); } diff --git a/modules/rostests/winetests/user32/listbox.c b/modules/rostests/winetests/user32/listbox.c index 3f83b5ac3ef..747e3dae192 100644 --- a/modules/rostests/winetests/user32/listbox.c +++ b/modules/rostests/winetests/user32/listbox.c @@ -128,7 +128,7 @@ keypress (HWND handle, WPARAM keycode, BYTE scancode, BOOL extended) } #define listbox_field_ok(t, s, f, got) \ - ok (t.s.f==got.f, "style %#x, step " #s ", field " #f \ + ok (t.s.f==got.f, "style %#lx, step " #s ", field " #f \ ": expected %d, got %d\n", style, t.s.f, got.f) #define listbox_todo_field_ok(t, s, f, got) \ @@ -178,18 +178,18 @@ check (DWORD style, const struct listbox_test test) WCHAR *txtw; int resA, resW; - txt = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, size+1); + txt = calloc(1, size + 1); resA=SendMessageA(hLB, LB_GETTEXT, i, (LPARAM)txt); ok(!strcmp (txt, strings[i]), "returned string for item %d does not match %s vs %s\n", i, txt, strings[i]); - txtw = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, 2*size+2); + txtw = calloc(1, 2 * size + 2); resW=SendMessageW(hLB, LB_GETTEXT, i, (LPARAM)txtw); ok(resA == resW, "Unexpected text length.\n"); WideCharToMultiByte( CP_ACP, 0, txtw, -1, txt, size, NULL, NULL ); ok(!strcmp (txt, strings[i]), "returned string for item %d does not match %s vs %s\n", i, txt, strings[i]); - HeapFree (GetProcessHeap(), 0, txtw); - HeapFree (GetProcessHeap(), 0, txt); + free(txtw); + free(txt); } /* Confirm the count of items, and that an invalid delete does not remove anything */ @@ -223,7 +223,7 @@ static void check_item_height(void) ok (SendMessageA(hLB, WM_SETFONT, (WPARAM)font, 0) == 0, "Can't set font\n"); itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0); - ok (itemHeight == tm.tmHeight, "Item height wrong, got %d, expecting %d\n", itemHeight, tm.tmHeight); + ok (itemHeight == tm.tmHeight, "Item height wrong, got %d, expecting %ld\n", itemHeight, tm.tmHeight); DestroyWindow (hLB); @@ -238,7 +238,7 @@ static void check_item_height(void) DestroyWindow (hLB); } -static int got_selchange; +static unsigned int got_selchange, got_drawitem; static LRESULT WINAPI main_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { @@ -249,7 +249,7 @@ static LRESULT WINAPI main_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARA DWORD style = GetWindowLongA(GetWindow(hwnd, GW_CHILD), GWL_STYLE); MEASUREITEMSTRUCT *mi = (void*)lparam; - ok(wparam == mi->CtlID, "got wParam=%08lx, expected %08x\n", wparam, mi->CtlID); + ok(wparam == mi->CtlID, "got wParam=%08Ix, expected %08x\n", wparam, mi->CtlID); ok(mi->CtlType == ODT_LISTBOX, "mi->CtlType = %u\n", mi->CtlType); ok(mi->CtlID == 1, "mi->CtlID = %u\n", mi->CtlID); ok(mi->itemHeight, "mi->itemHeight = 0\n"); @@ -265,7 +265,7 @@ static LRESULT WINAPI main_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARA else { ok((void*)mi->itemData == strings[mi->itemID], - "mi->itemData = %08lx, expected %p\n", mi->itemData, strings[mi->itemID]); + "mi->itemData = %08Ix, expected %p\n", mi->itemData, strings[mi->itemID]); } break; } @@ -274,9 +274,9 @@ static LRESULT WINAPI main_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARA RECT rc_item, rc_client, rc_clip; DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lparam; - trace("%p WM_DRAWITEM %08lx %08lx\n", hwnd, wparam, lparam); + trace("%p WM_DRAWITEM %08Ix %08Ix\n", hwnd, wparam, lparam); - ok(wparam == dis->CtlID, "got wParam=%08lx instead of %08x\n", + ok(wparam == dis->CtlID, "got wParam=%08Ix instead of %08x\n", wparam, dis->CtlID); ok(dis->CtlType == ODT_LISTBOX, "wrong CtlType %04x\n", dis->CtlType); @@ -293,6 +293,7 @@ static LRESULT WINAPI main_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARA trace("item rect %s\n", wine_dbgstr_rect(&rc_item)); ok(EqualRect(&dis->rcItem, &rc_item), "item rects are not equal\n"); + got_drawitem++; break; } @@ -343,6 +344,19 @@ static void test_ownerdraw(void) 0, LBS_NODATA }; + static const struct { + UINT message; + WPARAM wparam; + LPARAM lparam; + UINT drawitem; + } testcase[] = { + { WM_NULL, 0, 0, 0 }, + { WM_PAINT, 0, 0, 0 }, + { LB_GETCOUNT, 0, 0, 0 }, + { LB_SETCOUNT, ARRAY_SIZE(strings), 0, ARRAY_SIZE(strings) }, + { LB_ADDSTRING, 0, (LPARAM)"foo", ARRAY_SIZE(strings)+1 }, + { LB_DELETESTRING, 0, 0, ARRAY_SIZE(strings)-1 }, + }; HWND parent, hLB; INT ret; RECT rc; @@ -372,14 +386,14 @@ static void test_ownerdraw(void) SendMessageA(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc); trace("item 0 rect %s\n", wine_dbgstr_rect(&rc)); ok(!IsRectEmpty(&rc), "empty item rect\n"); - ok(rc.top < 0, "rc.top is not negative (%d)\n", rc.top); + ok(rc.top < 0, "rc.top is not negative (%ld)\n", rc.top); DestroyWindow(hLB); /* Both FIXED and VARIABLE, FIXED should override VARIABLE. */ hLB = CreateWindowA("listbox", "TestList", LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE | styles[i], 0, 0, 100, 100, NULL, NULL, NULL, 0); - ok(hLB != NULL, "last error 0x%08x\n", GetLastError()); + ok(hLB != NULL, "last error 0x%08lx\n", GetLastError()); ok(GetWindowLongA(hLB, GWL_STYLE) & LBS_OWNERDRAWVARIABLE, "Unexpected window style.\n"); @@ -405,6 +419,40 @@ static void test_ownerdraw(void) DestroyWindow (hLB); } + + /* test pending redraw state */ + for (i = 0; i < ARRAY_SIZE(testcase); i++) + { + winetest_push_context("%d", i); + hLB = create_listbox(LBS_OWNERDRAWFIXED | LBS_NODATA | WS_CHILD | WS_VISIBLE, parent); + assert(hLB); + + ret = SendMessageA(hLB, WM_SETREDRAW, FALSE, 0); + ok(!ret, "got %d\n", ret); + ret = SendMessageA(hLB, testcase[i].message, testcase[i].wparam, testcase[i].lparam); + if (testcase[i].message >= LB_ADDSTRING && testcase[i].message < LB_MSGMAX && + testcase[i].message != LB_SETCOUNT) + ok(ret > 0, "expected > 0, got %d\n", ret); + else + ok(!ret, "expected 0, got %d\n", ret); + + got_drawitem = 0; + ret = RedrawWindow(hLB, NULL, 0, RDW_UPDATENOW); + ok(ret, "RedrawWindow failed\n"); + ok(!got_drawitem, "got %u\n", got_drawitem); + + ret = SendMessageA(hLB, WM_SETREDRAW, TRUE, 0); + ok(!ret, "got %d\n", ret); + + got_drawitem = 0; + ret = RedrawWindow(hLB, NULL, 0, RDW_UPDATENOW); + ok(ret, "RedrawWindow failed\n"); + ok(got_drawitem == testcase[i].drawitem, "expected %u, got %u\n", testcase[i].drawitem, got_drawitem); + + DestroyWindow(hLB); + winetest_pop_context(); + } + DestroyWindow(parent); } @@ -583,21 +631,29 @@ static void test_LB_SETSEL(void) ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0); ok(ret == -1, "Unexpected anchor index %d.\n", ret); + ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0); + ok(ret == 0, "Unexpected caret index %d.\n", ret); ret = SendMessageA(list, LB_SETSEL, TRUE, 0); ok(ret == 0, "Unexpected return value %d.\n", ret); ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0); ok(ret == 0, "Unexpected anchor index %d.\n", ret); + ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0); + ok(ret == 0, "Unexpected caret index %d.\n", ret); ret = SendMessageA(list, LB_SETSEL, TRUE, 1); ok(ret == 0, "Unexpected return value %d.\n", ret); ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0); ok(ret == 1, "Unexpected anchor index %d.\n", ret); + ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0); + ok(ret == 1, "Unexpected caret index %d.\n", ret); ret = SendMessageA(list, LB_SETSEL, FALSE, 1); ok(ret == 0, "Unexpected return value %d.\n", ret); ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0); ok(ret == 1, "Unexpected anchor index %d.\n", ret); + ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0); + ok(ret == 1, "Unexpected caret index %d.\n", ret); DestroyWindow(list); @@ -607,21 +663,29 @@ static void test_LB_SETSEL(void) ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0); ok(ret == -1, "Unexpected anchor index %d.\n", ret); + ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0); + ok(ret == 0, "Unexpected caret index %d.\n", ret); ret = SendMessageA(list, LB_SETSEL, TRUE, 0); ok(ret == 0, "Unexpected return value %d.\n", ret); ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0); ok(ret == 0, "Unexpected anchor index %d.\n", ret); + ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0); + ok(ret == 0, "Unexpected caret index %d.\n", ret); ret = SendMessageA(list, LB_SETSEL, TRUE, 1); ok(ret == 0, "Unexpected return value %d.\n", ret); ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0); ok(ret == 1, "Unexpected anchor index %d.\n", ret); + ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0); + ok(ret == 1, "Unexpected caret index %d.\n", ret); ret = SendMessageA(list, LB_SETSEL, FALSE, 1); ok(ret == 0, "Unexpected return value %d.\n", ret); ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0); ok(ret == 1, "Unexpected anchor index %d.\n", ret); + ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0); + ok(ret == 1, "Unexpected caret index %d.\n", ret); DestroyWindow(list); } @@ -721,70 +785,70 @@ static void test_changing_selection_styles(void) for (k = 0; k < ARRAY_SIZE(selexpect_multi); k++) { ret = SendMessageA(listbox, LB_INSERTSTRING, -1, (LPARAM)"x"); - ok(ret == k, "%u: Unexpected return value %d, expected %d.\n", j, ret, k); + ok(ret == k, "%u: Unexpected return value %ld, expected %d.\n", j, ret, k); } ret = SendMessageA(listbox, LB_GETCOUNT, 0, 0); - ok(ret == ARRAY_SIZE(selexpect_multi), "%u: Unexpected count %d.\n", j, ret); + ok(ret == ARRAY_SIZE(selexpect_multi), "%u: Unexpected count %ld.\n", j, ret); /* Select items with different methods */ ret = SendMessageA(listbox, LB_SETCURSEL, 2, 0); - ok(ret == setcursel_expect, "%u: Unexpected return value %d.\n", j, ret); + ok(ret == setcursel_expect, "%u: Unexpected return value %ld.\n", j, ret); ret = SendMessageA(listbox, LB_SELITEMRANGE, TRUE, MAKELPARAM(0, 0)); - ok(ret == selitemrange_expect, "%u: Unexpected return value %d.\n", j, ret); + ok(ret == selitemrange_expect, "%u: Unexpected return value %ld.\n", j, ret); ret = SendMessageA(listbox, LB_SELITEMRANGE, TRUE, MAKELPARAM(2, 2)); - ok(ret == selitemrange_expect, "%u: Unexpected return value %d.\n", j, ret); + ok(ret == selitemrange_expect, "%u: Unexpected return value %ld.\n", j, ret); /* Verify that the proper items are selected */ for (k = 0; k < ARRAY_SIZE(selexpect_multi); k++) { ret = SendMessageA(listbox, LB_GETSEL, k, 0); - ok(ret == selexpect[k], "%u: Unexpected selection state %d, expected %d.\n", + ok(ret == selexpect[k], "%u: Unexpected selection state %ld, expected %ld.\n", j, ret, selexpect[k]); } /* Now change the selection style */ style = GetWindowLongA(listbox, GWL_STYLE); ok((style & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) == selstyles[j], - "%u: unexpected window styles %#x.\n", j, style); + "%u: unexpected window styles %#lx.\n", j, style); if (selstyles[j] & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) style &= ~selstyles[j]; else style |= LBS_MULTIPLESEL | LBS_EXTENDEDSEL; SetWindowLongA(listbox, GWL_STYLE, style); style = GetWindowLongA(listbox, GWL_STYLE); - ok(!(style & selstyles[j]), "%u: unexpected window styles %#x.\n", j, style); + ok(!(style & selstyles[j]), "%u: unexpected window styles %#lx.\n", j, style); /* Verify that the same items are selected */ ret = SendMessageA(listbox, LB_GETSELCOUNT, 0, 0); - ok(ret == getselcount_expect, "%u: expected %d from LB_GETSELCOUNT, got %d\n", + ok(ret == getselcount_expect, "%u: expected %ld from LB_GETSELCOUNT, got %ld\n", j, getselcount_expect, ret); for (k = 0; k < ARRAY_SIZE(selexpect_multi); k++) { ret = SendMessageA(listbox, LB_GETSEL, k, 0); - ok(ret == selexpect[k], "%u: Unexpected selection state %d, expected %d.\n", + ok(ret == selexpect[k], "%u: Unexpected selection state %ld, expected %ld.\n", j, ret, selexpect[k]); } /* Lastly see if we can still change the selection as before with old style */ if (setcursel_expect != LB_ERR) setcursel_expect = 0; ret = SendMessageA(listbox, LB_SETCURSEL, 0, 0); - ok(ret == setcursel_expect, "%u: Unexpected return value %d.\n", j, ret); + ok(ret == setcursel_expect, "%u: Unexpected return value %ld.\n", j, ret); ret = SendMessageA(listbox, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 1)); - ok(ret == selitemrange_expect, "%u: Unexpected return value %d.\n", j, ret); + ok(ret == selitemrange_expect, "%u: Unexpected return value %ld.\n", j, ret); ret = SendMessageA(listbox, LB_SELITEMRANGE, FALSE, MAKELPARAM(2, 2)); - ok(ret == selitemrange_expect, "%u: Unexpected return value %d.\n", j, ret); + ok(ret == selitemrange_expect, "%u: Unexpected return value %ld.\n", j, ret); /* And verify the selections */ selexpect = (selstyles[j] & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) ? selexpect_multi2 : selexpect_single2; ret = SendMessageA(listbox, LB_GETSELCOUNT, 0, 0); - ok(ret == getselcount_expect, "%u: expected %d from LB_GETSELCOUNT, got %d\n", + ok(ret == getselcount_expect, "%u: expected %ld from LB_GETSELCOUNT, got %ld\n", j, getselcount_expect, ret); for (k = 0; k < ARRAY_SIZE(selexpect_multi); k++) { ret = SendMessageA(listbox, LB_GETSEL, k, 0); - ok(ret == selexpect[k], "%u: Unexpected selection state %d, expected %d.\n", + ok(ret == selexpect[k], "%u: Unexpected selection state %ld, expected %ld.\n", j, ret, selexpect[k]); } @@ -808,13 +872,13 @@ static void test_itemfrompoint(void) /* For an empty listbox win2k returns 0x1ffff, win98 returns 0x10000, nt4 returns 0xffffffff */ r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 )); - ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r ); + ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %lx\n", r ); r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 700, 30 )); - ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r ); + ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %lx\n", r ); r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 30, 300 )); - ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r ); + ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %lx\n", r ); id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi"); ok( id == 0, "item id wrong\n"); @@ -822,17 +886,17 @@ static void test_itemfrompoint(void) ok( id == 1, "item id wrong\n"); r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 )); - ok( r == 0x1, "ret %x\n", r ); + ok( r == 0x1, "ret %lx\n", r ); r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 601 )); ok( r == 0x10001 || broken(r == 1), /* nt4 */ - "ret %x\n", r ); + "ret %lx\n", r ); /* Resize control so that below assertions about sizes are valid */ r = SendMessageA( hList, LB_GETITEMRECT, 0, (LPARAM)&rc); - ok( r == 1, "ret %x\n", r); + ok( r == 1, "ret %lx\n", r); r = MoveWindow(hList, 1, 1, 600, (rc.bottom - rc.top + 1) * 9 / 2, TRUE); - ok( r != 0, "ret %x\n", r); + ok( r != 0, "ret %lx\n", r); id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi2"); ok( id == 2, "item id wrong\n"); @@ -852,31 +916,31 @@ static void test_itemfrompoint(void) SendMessageA( hList, LB_SETTOPINDEX, 1, 0); r = SendMessageA( hList, LB_GETTOPINDEX, 0, 0); - ok( r == 1, "top %d\n", r); + ok( r == 1, "top %ld\n", r); r = SendMessageA( hList, LB_GETITEMRECT, 5, (LPARAM)&rc); - ok( r == 1, "ret %x\n", r); + ok( r == 1, "ret %lx\n", r); r = SendMessageA( hList, LB_GETITEMRECT, 6, (LPARAM)&rc); - ok( r == 0, "ret %x\n", r); + ok( r == 0, "ret %lx\n", r); r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(/* x */ 10, /* y */ 10) ); - ok( r == 1, "ret %x\n", r); + ok( r == 1, "ret %lx\n", r); r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(1000, 10) ); ok( r == 0x10001 || broken(r == 1), /* nt4 */ - "ret %x\n", r ); + "ret %lx\n", r ); r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, -10) ); ok( r == 0x10001 || broken(r == 1), /* nt4 */ - "ret %x\n", r ); + "ret %lx\n", r ); r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 100) ); ok( r == 0x10005 || broken(r == 5), /* nt4 */ - "item %x\n", r ); + "item %lx\n", r ); r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 200) ); ok( r == 0x10005 || broken(r == 5), /* nt4 */ - "item %x\n", r ); + "item %lx\n", r ); DestroyWindow( hList ); } @@ -929,7 +993,7 @@ static void test_listbox_LB_DIR(void) ok(ret, "Failed to create test directory.\n"); file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL ); - ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %d\n", GetLastError()); + ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %ld\n", GetLastError()); CloseHandle( file ); /* NOTE: for this test to succeed, there must be no subdirectories @@ -953,7 +1017,7 @@ static void test_listbox_LB_DIR(void) strcpy(pathBuffer, wildcard); res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer); } - ok (res >= 0, "SendMessage(LB_DIR, 0, *) failed - 0x%08x\n", GetLastError()); + ok (res >= 0, "SendMessage(LB_DIR, 0, *) failed - 0x%08lx\n", GetLastError()); /* There should be some content in the listbox */ itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0); @@ -980,7 +1044,7 @@ static void test_listbox_LB_DIR(void) strcpy(pathBuffer, "w*.c"); SendMessageA(hList, LB_RESETCONTENT, 0, 0); res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer); - ok (res >= 0, "SendMessage(LB_DIR, 0, w*.c) failed - 0x%08x\n", GetLastError()); + ok (res >= 0, "SendMessage(LB_DIR, 0, w*.c) failed - 0x%08lx\n", GetLastError()); /* Path specification does NOT converted to uppercase */ ok (!strcmp(pathBuffer, "w*.c"), @@ -1008,7 +1072,7 @@ static void test_listbox_LB_DIR(void) strcpy(pathBuffer, wildcard); SendMessageA(hList, LB_RESETCONTENT, 0, 0); res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer); - ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY, *) failed - 0x%08x\n", GetLastError()); + ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY, *) failed - 0x%08lx\n", GetLastError()); /* There should be some content in the listbox. * All files plus "[..]" @@ -1037,7 +1101,7 @@ static void test_listbox_LB_DIR(void) strcpy(pathBuffer, "w*.c"); SendMessageA(hList, LB_RESETCONTENT, 0, 0); res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer); - ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) failed - 0x%08x\n", GetLastError()); + ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) failed - 0x%08lx\n", GetLastError()); /* There should be some content in the listbox. Since the parent directory does not * fit w*.c, there should be exactly the same number of items as without DDL_DIRECTORY @@ -1066,7 +1130,7 @@ static void test_listbox_LB_DIR(void) strcpy(pathBuffer, wildcard); SendMessageA(hList, LB_RESETCONTENT, 0, 0); res = SendMessageA(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer); - ok (res >= 0, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) failed - 0x%08x\n", GetLastError()); + ok (res >= 0, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) failed - 0x%08lx\n", GetLastError()); /* There should be some content in the listbox. In particular, there should * be at least one element before, since the string "[-c-]" should @@ -1113,7 +1177,7 @@ static void test_listbox_LB_DIR(void) strcpy(pathBuffer, wildcard); SendMessageA(hList, LB_RESETCONTENT, 0, 0); res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer); - ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, *) failed - 0x%08x\n", GetLastError()); + ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, *) failed - 0x%08lx\n", GetLastError()); /* There should be some content in the listbox. In particular, there should * be at least one element before, since the string "[-c-]" should @@ -1141,7 +1205,7 @@ static void test_listbox_LB_DIR(void) strcpy(pathBuffer, "w*.c"); SendMessageA(hList, LB_RESETCONTENT, 0, 0); res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer); - ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) failed - 0x%08x\n", GetLastError()); + ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) failed - 0x%08lx\n", GetLastError()); /* There should be some content in the listbox. In particular, there should * be at least one element before, since the string "[-c-]" should @@ -1176,7 +1240,7 @@ static void test_listbox_LB_DIR(void) strcpy(pathBuffer, wildcard); SendMessageA(hList, LB_RESETCONTENT, 0, 0); res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer); - ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, *) failed - 0x%08x\n", GetLastError()); + ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, *) failed - 0x%08lx\n", GetLastError()); /* There should be some content in the listbox. In particular, there should * be exactly the number of plain files, plus the number of mapped drives. @@ -1216,7 +1280,7 @@ static void test_listbox_LB_DIR(void) strcpy(pathBuffer, "w*.c"); SendMessageA(hList, LB_RESETCONTENT, 0, 0); res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer); - ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) failed - 0x%08x\n", GetLastError()); + ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) failed - 0x%08lx\n", GetLastError()); /* There should be some content in the listbox. In particular, there should * be exactly the number of plain files, plus the number of mapped drives. @@ -1250,7 +1314,7 @@ static void test_listbox_LB_DIR(void) strcpy(pathBuffer, wildcard); SendMessageA(hList, LB_RESETCONTENT, 0, 0); res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer); - ok (res != -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) failed err %u\n", GetLastError()); + ok (res != -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) failed err %lu\n", GetLastError()); itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0); ok (itemCount == itemCount_allDirs, @@ -1292,7 +1356,7 @@ static void test_listbox_LB_DIR(void) strcpy(pathBuffer, wildcard); SendMessageA(hList, LB_RESETCONTENT, 0, 0); res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer); - ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError()); + ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08lx\n", GetLastError()); /* There should be no plain files on the listbox */ itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0); @@ -1327,7 +1391,7 @@ static void test_listbox_LB_DIR(void) strcpy(pathBuffer, "w*.c"); SendMessageA(hList, LB_RESETCONTENT, 0, 0); res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer); - ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError()); + ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08lx\n", GetLastError()); /* There should be no plain files on the listbox, and no [..], since it does not fit w*.c */ itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0); @@ -1433,7 +1497,7 @@ static void test_listbox_dlgdir(void) HANDLE file; file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL ); - ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %d\n", GetLastError()); + ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %ld\n", GetLastError()); CloseHandle( file ); /* NOTE: for this test to succeed, there must be no subdirectories @@ -1460,7 +1524,7 @@ static void test_listbox_dlgdir(void) */ strcpy(pathBuffer, "w*.c"); res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0); - ok (res == 1, "DlgDirList(*.c, 0) returned %d - expected 1 - 0x%08x\n", res, GetLastError()); + ok (res == 1, "DlgDirList(*.c, 0) returned %d - expected 1 - 0x%08lx\n", res, GetLastError()); /* Path specification gets converted to uppercase */ ok (!strcmp(pathBuffer, "W*.C"), @@ -1498,7 +1562,7 @@ static void test_listbox_dlgdir(void) strcpy(pathBuffer, "w*.c"); res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY); - ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY) failed - 0x%08x\n", GetLastError()); + ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY) failed - 0x%08lx\n", GetLastError()); /* There should be some content in the listbox. In particular, there should * be exactly more elements than before, since the directories should @@ -1545,7 +1609,7 @@ static void test_listbox_dlgdir(void) strcpy(pathBuffer, "w*.c"); res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DRIVES); - ok (res == 1, "DlgDirList(*.c, DDL_DRIVES) failed - 0x%08x\n", GetLastError()); + ok (res == 1, "DlgDirList(*.c, DDL_DRIVES) failed - 0x%08lx\n", GetLastError()); /* There should be some content in the listbox. In particular, there should * be at least one element before, since the string "[-c-]" should @@ -1587,7 +1651,7 @@ static void test_listbox_dlgdir(void) strcpy(pathBuffer, "w*.c"); res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES); - ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError()); + ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08lx\n", GetLastError()); /* There should be some content in the listbox. In particular, there should * be exactly the number of plain files, plus the number of mapped drives, @@ -1634,7 +1698,7 @@ static void test_listbox_dlgdir(void) strcpy(pathBuffer, "w*.c"); res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_EXCLUSIVE); - ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError()); + ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_EXCLUSIVE) failed - 0x%08lx\n", GetLastError()); /* There should be exactly one element: "[..]" */ itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0); @@ -1663,7 +1727,7 @@ static void test_listbox_dlgdir(void) strcpy(pathBuffer, "w*.c"); res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE); - ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError()); + ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) failed - 0x%08lx\n", GetLastError()); /* There should be no plain files on the listbox */ itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0); @@ -1698,19 +1762,19 @@ static void test_listbox_dlgdir(void) strcpy(pathBuffer, "*"); res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES); - ok (res != 0, "DlgDirList(*, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError()); + ok (res != 0, "DlgDirList(*, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08lx\n", GetLastError()); SendMessageA(g_listBox, LB_SETCURSEL, -1, 0); /* Unselect any current selection */ memset(pathBuffer, 0, MAX_PATH); SetLastError(0xdeadbeef); res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX); ok (GetLastError() == 0xdeadbeef, - "DlgDirSelectEx() with no selection modified last error code from 0xdeadbeef to 0x%08x\n", + "DlgDirSelectEx() with no selection modified last error code from 0xdeadbeef to 0x%08lx\n", GetLastError()); ok (res == 0, "DlgDirSelectEx() with no selection returned %d, expected 0\n", res); /* WinXP-SP2 leaves pathBuffer untouched, but Win98 fills it with garbage. */ /* - ok (strlen(pathBuffer) == 0, "DlgDirSelectEx() with no selection filled buffer with %s\n", pathBuffer); + ok (!*pathBuffer, "DlgDirSelectEx() with no selection filled buffer with %s\n", pathBuffer); */ /* Test proper drive/dir/file recognition */ itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0); @@ -1720,7 +1784,6 @@ static void test_listbox_dlgdir(void) memset(tempBuffer, 0, MAX_PATH); driveletter = '\0'; SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer); - if (!strstr(itemBuffer, ".exe")) continue; // skip downloaded/generated files from other tests res = SendMessageA(g_listBox, LB_SETCURSEL, i, 0); ok (res == i, "SendMessageA(LB_SETCURSEL, %d) failed\n", i); if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1) { @@ -1728,7 +1791,7 @@ static void test_listbox_dlgdir(void) SetLastError(0xdeadbeef); res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX); ok (GetLastError() == 0xdeadbeef, - "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n", + "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08lx\n", i, GetLastError()); ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer); @@ -1740,7 +1803,7 @@ static void test_listbox_dlgdir(void) SetLastError(0xdeadbeef); res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX); ok (GetLastError() == 0xdeadbeef, - "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n", + "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08lx\n", i, GetLastError()); ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer); @@ -1757,7 +1820,7 @@ static void test_listbox_dlgdir(void) SetLastError(0xdeadbeef); res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX); ok (GetLastError() == 0xdeadbeef, - "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n", + "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08lx\n", i, GetLastError()); ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer); @@ -1791,7 +1854,7 @@ static void test_listbox_dlgdir(void) SetLastError(0xdeadbeef); res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX); ok (GetLastError() == 0xdeadbeef, - "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n", + "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08lx\n", i, GetLastError()); ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer); @@ -1803,7 +1866,7 @@ static void test_listbox_dlgdir(void) SetLastError(0xdeadbeef); res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX); ok (GetLastError() == 0xdeadbeef, - "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n", + "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08lx\n", i, GetLastError()); ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer); @@ -1820,7 +1883,7 @@ static void test_listbox_dlgdir(void) SetLastError(0xdeadbeef); res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX); ok (GetLastError() == 0xdeadbeef, - "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n", + "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08lx\n", i, GetLastError()); ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer); @@ -1852,7 +1915,7 @@ static void test_listbox_dlgdir(void) res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE); ok(!res, "DlgDirList should have failed with 0 but %d was returned\n", res); ok(GetLastError() == ERROR_NO_WILDCARD_CHARACTERS, - "GetLastError should return 0x589, got 0x%X\n",GetLastError()); + "GetLastError should return 0x589, got 0x%lX\n",GetLastError()); DestroyWindow(hWnd); } @@ -1876,10 +1939,16 @@ static void test_set_count( void ) GetUpdateRect( listbox, &r, TRUE ); ok( IsRectEmpty( &r ), "got non-empty rect\n"); + ret = GetWindowLongA( listbox, GWL_STYLE ); + ok((ret & (WS_VSCROLL | WS_HSCROLL)) == 0, "Listbox should not have scroll bars\n"); + ret = SendMessageA( listbox, LB_SETCOUNT, 100, 0 ); - ok( ret == 0, "got %d\n", ret ); + ok( ret == 0, "got %ld\n", ret ); ret = SendMessageA( listbox, LB_GETCOUNT, 0, 0 ); - ok( ret == 100, "got %d\n", ret ); + ok( ret == 100, "got %ld\n", ret ); + + ret = GetWindowLongA( listbox, GWL_STYLE ); + ok((ret & (WS_VSCROLL | WS_HSCROLL)) == WS_VSCROLL, "Listbox should have vertical scroll bar\n"); GetUpdateRect( listbox, &r, TRUE ); ok( !IsRectEmpty( &r ), "got empty rect\n"); @@ -1889,15 +1958,15 @@ static void test_set_count( void ) ok( IsRectEmpty( &r ), "got non-empty rect\n"); ret = SendMessageA( listbox, LB_SETCOUNT, 99, 0 ); - ok( ret == 0, "got %d\n", ret ); + ok( ret == 0, "got %ld\n", ret ); GetUpdateRect( listbox, &r, TRUE ); ok( !IsRectEmpty( &r ), "got empty rect\n"); ret = SendMessageA( listbox, LB_SETCOUNT, -5, 0 ); - ok( ret == 0, "got %d\n", ret ); + ok( ret == 0, "got %ld\n", ret ); ret = SendMessageA( listbox, LB_GETCOUNT, 0, 0 ); - ok( ret == -5, "got %d\n", ret ); + ok( ret == -5, "got %ld\n", ret ); DestroyWindow( listbox ); @@ -1907,8 +1976,8 @@ static void test_set_count( void ) SetLastError( 0xdeadbeef ); ret = SendMessageA( listbox, LB_SETCOUNT, 100, 0 ); - ok( ret == LB_ERR, "expected %d, got %d\n", LB_ERR, ret ); - ok( GetLastError() == ERROR_SETCOUNT_ON_BAD_LB, "Unexpected error %d.\n", GetLastError() ); + ok( ret == LB_ERR, "expected %d, got %ld\n", LB_ERR, ret ); + ok( GetLastError() == ERROR_SETCOUNT_ON_BAD_LB, "Unexpected error %ld.\n", GetLastError() ); DestroyWindow( listbox ); } @@ -1951,8 +2020,8 @@ static void test_GetListBoxInfo(void) lb_getlistboxinfo = 0; ret = pGetListBoxInfo(listbox); - ok(ret > 0, "got %d\n", ret); -todo_wine + ok(ret > 0, "got %ld\n", ret); + todo_wine ok(lb_getlistboxinfo == 0, "got %d\n", lb_getlistboxinfo); DestroyWindow(listbox); @@ -1977,45 +2046,45 @@ static void test_init_storage( void ) 0, 0, 100, 100, parent, (HMENU)1, NULL, 0); items_size = SendMessageA(listbox, LB_INITSTORAGE, 100, 0); - ok(items_size >= 100, "expected at least 100, got %d\n", items_size); + ok(items_size >= 100, "expected at least 100, got %ld\n", items_size); ret = SendMessageA(listbox, LB_INITSTORAGE, 0, 0); - ok(ret == items_size, "expected %d, got %d\n", items_size, ret); + ok(ret == items_size, "expected %ld, got %ld\n", items_size, ret); /* it doesn't grow since the space was already reserved */ ret = SendMessageA(listbox, LB_INITSTORAGE, items_size, 0); - ok(ret == items_size, "expected %d, got %d\n", items_size, ret); + ok(ret == items_size, "expected %ld, got %ld\n", items_size, ret); /* it doesn't shrink the reserved space */ ret = SendMessageA(listbox, LB_INITSTORAGE, 42, 0); - ok(ret == items_size, "expected %d, got %d\n", items_size, ret); + ok(ret == items_size, "expected %ld, got %ld\n", items_size, ret); /* now populate almost all of it so it's not reserved anymore */ if (styles[i] & LBS_NODATA) { ret = SendMessageA(listbox, LB_SETCOUNT, items_size - 1, 0); - ok(ret == 0, "unexpected return value %d\n", ret); + ok(ret == 0, "unexpected return value %ld\n", ret); } else { for (j = 0; j < items_size - 1; j++) { ret = SendMessageA(listbox, LB_INSERTSTRING, -1, (LPARAM)""); - ok(ret == j, "expected %d, got %d\n", j, ret); + ok(ret == j, "expected %d, got %ld\n", j, ret); } } /* we still have one more reserved slot, so it doesn't grow yet */ ret = SendMessageA(listbox, LB_INITSTORAGE, 1, 0); - ok(ret == items_size, "expected %d, got %d\n", items_size, ret); + ok(ret == items_size, "expected %ld, got %ld\n", items_size, ret); /* fill the slot and check again, it should grow this time */ ret = SendMessageA(listbox, LB_INSERTSTRING, -1, (LPARAM)""); - ok(ret == items_size - 1, "expected %d, got %d\n", items_size - 1, ret); + ok(ret == items_size - 1, "expected %ld, got %ld\n", items_size - 1, ret); ret = SendMessageA(listbox, LB_INITSTORAGE, 0, 0); - ok(ret == items_size, "expected %d, got %d\n", items_size, ret); + ok(ret == items_size, "expected %ld, got %ld\n", items_size, ret); ret = SendMessageA(listbox, LB_INITSTORAGE, 1, 0); - ok(ret > items_size, "expected it to grow past %d, got %d\n", items_size, ret); + ok(ret > items_size, "expected it to grow past %ld, got %ld\n", items_size, ret); DestroyWindow(listbox); } @@ -2057,7 +2126,7 @@ static void test_extents(void) listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent); res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0); - ok(res == 0, "Got wrong initial horizontal extent: %u\n", res); + ok(res == 0, "Got wrong initial horizontal extent: %lu\n", res); sinfo.cbSize = sizeof(sinfo); sinfo.fMask = SIF_RANGE; @@ -2072,7 +2141,7 @@ static void test_extents(void) SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0); res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0); - ok(res == 64, "Got wrong horizontal extent: %u\n", res); + ok(res == 64, "Got wrong horizontal extent: %lu\n", res); sinfo.cbSize = sizeof(sinfo); sinfo.fMask = SIF_RANGE; @@ -2087,7 +2156,7 @@ static void test_extents(void) SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0); res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0); - ok(res == 184, "Got wrong horizontal extent: %u\n", res); + ok(res == 184, "Got wrong horizontal extent: %lu\n", res); sinfo.cbSize = sizeof(sinfo); sinfo.fMask = SIF_RANGE; @@ -2104,7 +2173,7 @@ static void test_extents(void) listbox = create_listbox(WS_CHILD | WS_VISIBLE | WS_HSCROLL, parent); res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0); - ok(res == 0, "Got wrong initial horizontal extent: %u\n", res); + ok(res == 0, "Got wrong initial horizontal extent: %lu\n", res); sinfo.cbSize = sizeof(sinfo); sinfo.fMask = SIF_RANGE; @@ -2119,7 +2188,7 @@ static void test_extents(void) SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0); res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0); - ok(res == 64, "Got wrong horizontal extent: %u\n", res); + ok(res == 64, "Got wrong horizontal extent: %lu\n", res); sinfo.cbSize = sizeof(sinfo); sinfo.fMask = SIF_RANGE; @@ -2134,7 +2203,7 @@ static void test_extents(void) SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0); res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0); - ok(res == 184, "Got wrong horizontal extent: %u\n", res); + ok(res == 184, "Got wrong horizontal extent: %lu\n", res); sinfo.cbSize = sizeof(sinfo); sinfo.fMask = SIF_RANGE; @@ -2148,7 +2217,7 @@ static void test_extents(void) SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 0, 0); res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0); - ok(res == 0, "Got wrong horizontal extent: %u\n", res); + ok(res == 0, "Got wrong horizontal extent: %lu\n", res); sinfo.cbSize = sizeof(sinfo); sinfo.fMask = SIF_RANGE; @@ -2165,7 +2234,7 @@ static void test_extents(void) listbox = create_listbox(WS_CHILD | WS_VISIBLE | WS_HSCROLL | LBS_DISABLENOSCROLL, parent); res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0); - ok(res == 0, "Got wrong initial horizontal extent: %u\n", res); + ok(res == 0, "Got wrong initial horizontal extent: %lu\n", res); sinfo.cbSize = sizeof(sinfo); sinfo.fMask = SIF_RANGE; @@ -2180,7 +2249,7 @@ static void test_extents(void) SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0); res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0); - ok(res == 64, "Got wrong horizontal extent: %u\n", res); + ok(res == 64, "Got wrong horizontal extent: %lu\n", res); sinfo.cbSize = sizeof(sinfo); sinfo.fMask = SIF_RANGE; @@ -2195,7 +2264,7 @@ static void test_extents(void) SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0); res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0); - ok(res == 184, "Got wrong horizontal extent: %u\n", res); + ok(res == 184, "Got wrong horizontal extent: %lu\n", res); sinfo.cbSize = sizeof(sinfo); sinfo.fMask = SIF_RANGE; @@ -2209,7 +2278,7 @@ static void test_extents(void) SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 0, 0); res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0); - ok(res == 0, "Got wrong horizontal extent: %u\n", res); + ok(res == 0, "Got wrong horizontal extent: %lu\n", res); sinfo.cbSize = sizeof(sinfo); sinfo.fMask = SIF_RANGE; @@ -2234,14 +2303,14 @@ static void test_WM_MEASUREITEM(void) listbox = create_listbox(WS_CHILD | LBS_OWNERDRAWVARIABLE, parent); data = SendMessageA(listbox, LB_GETITEMDATA, 0, 0); - ok(data == (LRESULT)strings[0], "data = %08lx, expected %p\n", data, strings[0]); + ok(data == (LRESULT)strings[0], "data = %08Ix, expected %p\n", data, strings[0]); DestroyWindow(parent); parent = create_parent(); listbox = create_listbox(WS_CHILD | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS, parent); data = SendMessageA(listbox, LB_GETITEMDATA, 0, 0); - ok(!data, "data = %08lx\n", data); + ok(!data, "data = %08Ix\n", data); DestroyWindow(parent); } @@ -2312,27 +2381,27 @@ static void test_LBS_NODATA(void) SetLastError(0xdeadbeef); ret = SendMessageA(listbox, LB_FINDSTRING, 1, 0); ok(ret == LB_ERR, "Unexpected return value %d.\n", ret); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError should return 0x57, got 0x%X\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError should return 0x57, got 0x%lX\n", GetLastError()); SetLastError(0xdeadbeef); ret = SendMessageA(listbox, LB_FINDSTRING, 1, 42); ok(ret == LB_ERR, "Unexpected return value %d.\n", ret); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError should return 0x57, got 0x%X\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError should return 0x57, got 0x%lX\n", GetLastError()); SetLastError(0xdeadbeef); ret = SendMessageA(listbox, LB_FINDSTRINGEXACT, 1, 0); ok(ret == LB_ERR, "Unexpected return value %d.\n", ret); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError should return 0x57, got 0x%X\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError should return 0x57, got 0x%lX\n", GetLastError()); SetLastError(0xdeadbeef); ret = SendMessageA(listbox, LB_FINDSTRINGEXACT, 1, 42); ok(ret == LB_ERR, "Unexpected return value %d.\n", ret); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError should return 0x57, got 0x%X\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError should return 0x57, got 0x%lX\n", GetLastError()); SetLastError(0xdeadbeef); ret = SendMessageA(listbox, LB_SELECTSTRING, 1, 0); ok(ret == LB_ERR, "Unexpected return value %d.\n", ret); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError should return 0x57, got 0x%X\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError should return 0x57, got 0x%lX\n", GetLastError()); SetLastError(0xdeadbeef); ret = SendMessageA(listbox, LB_SELECTSTRING, 1, 42); ok(ret == LB_ERR, "Unexpected return value %d.\n", ret); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError should return 0x57, got 0x%X\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError should return 0x57, got 0x%lX\n", GetLastError()); DestroyWindow(listbox); @@ -2349,7 +2418,7 @@ static void test_LBS_NODATA(void) ok(listbox != NULL, "Failed to create a listbox.\n"); style = GetWindowLongA(listbox, GWL_STYLE); - ok((style & invalid_styles[i]) == invalid_styles[i], "%u: unexpected window styles %#x.\n", i, style); + ok((style & invalid_styles[i]) == invalid_styles[i], "%u: unexpected window styles %#lx.\n", i, style); ret = SendMessageA(listbox, LB_SETCOUNT, 100, 0); ok(ret == LB_ERR, "%u: unexpected return value %d.\n", i, ret); DestroyWindow(listbox); @@ -2358,6 +2427,83 @@ static void test_LBS_NODATA(void) DestroyWindow(parent); } +static void test_LB_FINDSTRING(void) +{ + static const WCHAR *strings[] = + { + L"abci", + L"AbCI", + L"abcI", + L"abc\xcdzz", + L"abc\xedzz", + L"abc\xcd", + L"abc\xed", + L"abcO", + L"abc\xd8", + L"abcP", + }; + static const struct { const WCHAR *str; LRESULT from, res, exact, alt_res, alt_exact; } tests[] = + { + { L"ab", -1, 0, -1, 0, -1 }, + { L"abc", -1, 0, -1, 0, -1 }, + { L"abci", -1, 0, 0, 0, 0 }, + { L"ABCI", -1, 0, 0, 0, 0 }, + { L"ABC\xed", -1, 3, 3, 3, 3 }, + { L"ABC\xcd", 4, 5, 3, 5, 3 }, + { L"abcp", -1, 9, 9, 8, 8 }, + }; + HWND listbox; + unsigned int i; + LRESULT ret; + + listbox = CreateWindowW( L"listbox", L"TestList", LBS_HASSTRINGS | LBS_SORT, + 0, 0, 100, 100, NULL, NULL, NULL, 0 ); + ok( listbox != NULL, "Failed to create listbox\n" ); + SendMessageW( listbox, LB_SETLOCALE, MAKELANGID( LANG_FRENCH, SUBLANG_DEFAULT ), 0 ); + for (i = 0; i < ARRAY_SIZE(strings); i++) SendMessageW( listbox, LB_ADDSTRING, 0, (LPARAM)strings[i] ); + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + ret = SendMessageW( listbox, LB_FINDSTRING, tests[i].from, (LPARAM)tests[i].str ); + ok( ret == tests[i].res, "%u: wrong result %Id / %Id\n", i, ret, tests[i].res ); + ret = SendMessageW( listbox, LB_FINDSTRINGEXACT, tests[i].from, (LPARAM)tests[i].str ); + ok( ret == tests[i].exact, "%u: wrong result %Id / %Id\n", i, ret, tests[i].exact ); + } + + SendMessageW( listbox, LB_RESETCONTENT, 0, 0 ); + SendMessageW( listbox, LB_SETLOCALE, MAKELANGID( LANG_SWEDISH, SUBLANG_DEFAULT ), 0 ); + for (i = 0; i < ARRAY_SIZE(strings); i++) SendMessageW( listbox, LB_ADDSTRING, 0, (LPARAM)strings[i] ); + ret = SendMessageW( listbox, LB_FINDSTRING, -1, (LPARAM)L"abcp" ); + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + ret = SendMessageW( listbox, LB_FINDSTRING, tests[i].from, (LPARAM)tests[i].str ); + ok( ret == tests[i].alt_res, "%u: wrong result %Id / %Id\n", i, ret, tests[i].alt_res ); + ret = SendMessageW( listbox, LB_FINDSTRINGEXACT, tests[i].from, (LPARAM)tests[i].str ); + ok( ret == tests[i].alt_exact, "%u: wrong result %Id / %Id\n", i, ret, tests[i].alt_exact ); + } + + SendMessageW( listbox, LB_RESETCONTENT, 0, 0 ); + SendMessageW( listbox, LB_ADDSTRING, 0, (LPARAM)L"abc" ); + SendMessageW( listbox, LB_ADDSTRING, 0, (LPARAM)L"[abc]" ); + SendMessageW( listbox, LB_ADDSTRING, 0, (LPARAM)L"[-abc-]" ); + ret = SendMessageW( listbox, LB_FINDSTRING, -1, (LPARAM)L"abc" ); + ok( ret == 0, "wrong result %Id\n", ret ); + ret = SendMessageW( listbox, LB_FINDSTRINGEXACT, -1, (LPARAM)L"abc" ); + todo_wine + ok( ret == 0, "wrong result %Id\n", ret ); + ret = SendMessageW( listbox, LB_FINDSTRING, 0, (LPARAM)L"abc" ); + ok( ret == 1, "wrong result %Id\n", ret ); + ret = SendMessageW( listbox, LB_FINDSTRINGEXACT, 0, (LPARAM)L"abc" ); + todo_wine + ok( ret == 0, "wrong result %Id\n", ret ); + ret = SendMessageW( listbox, LB_FINDSTRING, 1, (LPARAM)L"abc" ); + ok( ret == 2, "wrong result %Id\n", ret ); + ret = SendMessageW( listbox, LB_FINDSTRINGEXACT, 1, (LPARAM)L"abc" ); + todo_wine + ok( ret == 0, "wrong result %Id\n", ret ); + DestroyWindow( listbox ); +} + START_TEST(listbox) { const struct listbox_test SS = @@ -2457,4 +2603,5 @@ START_TEST(listbox) test_WM_MEASUREITEM(); test_LB_SETSEL(); test_LBS_NODATA(); + test_LB_FINDSTRING(); } diff --git a/modules/rostests/winetests/user32/menu.c b/modules/rostests/winetests/user32/menu.c index 95a5e21d2c4..6862f13c6b1 100644 --- a/modules/rostests/winetests/user32/menu.c +++ b/modules/rostests/winetests/user32/menu.c @@ -49,19 +49,6 @@ static LRESULT WINAPI menu_check_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LP return DefWindowProcA(hwnd, msg, wparam, lparam); } -/* The MSVC headers ignore our NONAMELESSUNION requests so we have to define - * our own type */ -typedef struct -{ - DWORD type; - union - { - MOUSEINPUT mi; - KEYBDINPUT ki; - HARDWAREINPUT hi; - } u; -} TEST_INPUT; - /* globals to communicate between test and wndproc */ static BOOL bMenuVisible; @@ -120,9 +107,9 @@ static LRESULT WINAPI menu_ownerdraw_wnd_proc(HWND hwnd, UINT msg, { MEASUREITEMSTRUCT* pmis = (MEASUREITEMSTRUCT*)lparam; if (winetest_debug > 1) - trace("WM_MEASUREITEM received data %lx size %dx%d\n", + trace("WM_MEASUREITEM received data %Ix size %dx%d\n", pmis->itemData, pmis->itemWidth, pmis->itemHeight); - ok( !wparam, "wrong wparam %lx\n", wparam ); + ok( !wparam, "wrong wparam %Ix\n", wparam ); ok( pmis->CtlType == ODT_MENU, "wrong type %x\n", pmis->CtlType ); MOD_odheight = pmis->itemHeight; pmis->itemWidth = MODsizes[pmis->itemData].cx; @@ -141,7 +128,7 @@ static LRESULT WINAPI menu_ownerdraw_wnd_proc(HWND hwnd, UINT msg, if (winetest_debug > 1) { RECT rc; GetMenuItemRect( hwnd, (HMENU)pdis->hwndItem, pdis->itemData ,&rc); - trace("WM_DRAWITEM received hwnd %p hmenu %p itemdata %ld item %d rc %s itemrc: %s\n", + trace("WM_DRAWITEM received hwnd %p hmenu %p itemdata %Id item %d rc %s itemrc: %s\n", hwnd, pdis->hwndItem, pdis->itemData, pdis->itemID, wine_dbgstr_rect(&pdis->rcItem), wine_dbgstr_rect(&rc)); oldpen=SelectObject( pdis->hDC, GetStockObject( @@ -150,7 +137,7 @@ static LRESULT WINAPI menu_ownerdraw_wnd_proc(HWND hwnd, UINT msg, pdis->rcItem.right,pdis->rcItem.bottom ); SelectObject( pdis->hDC, oldpen); } - ok( !wparam, "wrong wparam %lx\n", wparam ); + ok( !wparam, "wrong wparam %Ix\n", wparam ); ok( pdis->CtlType == ODT_MENU, "wrong type %x\n", pdis->CtlType ); /* calculate widths of some menu texts */ if( ! MOD_txtsizes[0].size.cx) @@ -236,7 +223,7 @@ static void test_getmenubarinfo(void) hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL, WS_SYSMENU | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, NULL, NULL, NULL, NULL); - ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); + ok(hwnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError()); /* no menu: getmenubarinfo should fail */ SetLastError(0xdeadbeef); @@ -247,10 +234,10 @@ static void test_getmenubarinfo(void) /* create menubar, no items yet */ hmenu = CreateMenu(); - ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); + ok(hmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError()); ret = SetMenu(hwnd, hmenu); - ok(ret, "SetMenu failed with error %d\n", GetLastError()); + ok(ret, "SetMenu failed with error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = GetMenuBarInfo(NULL, OBJID_CLIENT, 0, &mbi); @@ -285,7 +272,7 @@ static void test_getmenubarinfo(void) ok(err == 0xdeadbeef, "err = %d\n", err); ret = GetMenuBarInfo(hwnd, OBJID_MENU, 0, &mbi); - ok(ret, "GetMenuBarInfo failed with error %d\n", GetLastError()); + ok(ret, "GetMenuBarInfo failed with error %ld\n", GetLastError()); ok(mbi.rcBar.left == 0 && mbi.rcBar.top == 0 && mbi.rcBar.bottom == 0 && mbi.rcBar.right == 0, "rcBar: Expected (0,0)-(0,0), got: %s\n", wine_dbgstr_rect(&mbi.rcBar)); @@ -300,7 +287,7 @@ static void test_getmenubarinfo(void) ret = AppendMenuA(hmenu, MF_STRING , 101, "item 2"); ok(ret, "AppendMenu failed.\n"); ret = SetMenu(hwnd, hmenu); - ok(ret, "SetMenu failed with error %d\n", GetLastError()); + ok(ret, "SetMenu failed with error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = GetMenuBarInfo(hwnd, OBJID_MENU, 200, &mbi); @@ -310,7 +297,7 @@ static void test_getmenubarinfo(void) /* get info for the whole menu */ ret = GetMenuBarInfo(hwnd, OBJID_MENU, 0, &mbi); - ok(ret, "GetMenuBarInfo failed with error %d\n", GetLastError()); + ok(ret, "GetMenuBarInfo failed with error %ld\n", GetLastError()); /* calculate menu rectangle, from window rectangle and the position of the first item */ ret = GetWindowRect(hwnd, &rcw); @@ -319,7 +306,7 @@ static void test_getmenubarinfo(void) ok(ret, "GetMenuItemRect failed.\n"); todo_wine ok(mbi.rcBar.left == rci.left && mbi.rcBar.top == rci.top && mbi.rcBar.bottom == rci.bottom && mbi.rcBar.right == rcw.right - rci.left + rcw.left, - "rcBar: Got %s instead of (%d,%d)-(%d,%d)\n", wine_dbgstr_rect(&mbi.rcBar), + "rcBar: Got %s instead of (%ld,%ld)-(%ld,%ld)\n", wine_dbgstr_rect(&mbi.rcBar), rci.left, rci.top, rcw.right - rci.left + rcw.left, rci.bottom); ok(mbi.hMenu == hmenu, "hMenu: Got %p instead of %p\n", mbi.hMenu, hmenu); ok(mbi.fBarFocused == 0, "fBarFocused: got %d instead of 0\n", mbi.fBarFocused); @@ -327,7 +314,7 @@ static void test_getmenubarinfo(void) /* get info for item nr.2 */ ret = GetMenuBarInfo(hwnd, OBJID_MENU, 2, &mbi); - ok(ret, "GetMenuBarInfo failed with error %d\n", GetLastError()); + ok(ret, "GetMenuBarInfo failed with error %ld\n", GetLastError()); ret = GetMenuItemRect(hwnd, hmenu, 1, &rci); ok(ret, "GetMenuItemRect failed.\n"); ok(EqualRect(&mbi.rcBar, &rci), "rcBar: Got %s instead of %s\n", wine_dbgstr_rect(&mbi.rcBar), @@ -352,21 +339,21 @@ static void test_GetMenuItemRect(void) hwnd = CreateWindowW((LPCWSTR)MAKEINTATOM(atomMenuCheckClass), NULL, WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, NULL, NULL, NULL, NULL); - ok(hwnd != NULL, "CreateWindow failed with error %d\n", GetLastError()); + ok(hwnd != NULL, "CreateWindow failed with error %ld\n", GetLastError()); hmenu = CreateMenu(); - ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); + ok(hmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError()); popup_hmenu = CreatePopupMenu(); - ok(popup_hmenu != NULL, "CreatePopupMenu failed with error %d\n", GetLastError()); + ok(popup_hmenu != NULL, "CreatePopupMenu failed with error %ld\n", GetLastError()); ret = AppendMenuA(popup_hmenu, MF_STRING, 0, "Popup"); - ok(ret, "AppendMenu failed with error %d\n", GetLastError()); + ok(ret, "AppendMenu failed with error %ld\n", GetLastError()); ret = AppendMenuA(hmenu, MF_STRING | MF_POPUP, (UINT_PTR)popup_hmenu, "Menu"); - ok(ret, "AppendMenu failed with error %d\n", GetLastError()); + ok(ret, "AppendMenu failed with error %ld\n", GetLastError()); ret = SetMenu(hwnd, hmenu); - ok(ret, "SetMenu failed with error %d\n", GetLastError()); + ok(ret, "SetMenu failed with error %ld\n", GetLastError()); /* Get the menu item rectangle of the displayed sysmenu item */ ret = GetMenuItemRect(hwnd, hmenu, 0, &item_rect); - ok(ret, "GetMenuItemRect failed with error %d\n", GetLastError()); + ok(ret, "GetMenuItemRect failed with error %ld\n", GetLastError()); GetWindowRect(hwnd, &window_rect); /* Get the screen coordinate of the left top corner of the client rectangle */ client_top_left.x = 0; @@ -374,22 +361,22 @@ static void test_GetMenuItemRect(void) MapWindowPoints(hwnd, 0, &client_top_left, 1); caption_height = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION); - ok(item_rect.left == client_top_left.x, "Expect item_rect.left %d == %d\n", item_rect.left, client_top_left.x); - ok(item_rect.right <= window_rect.right, "Expect item_rect.right %d <= %d\n", item_rect.right, window_rect.right); + ok(item_rect.left == client_top_left.x, "Expect item_rect.left %ld == %ld\n", item_rect.left, client_top_left.x); + ok(item_rect.right <= window_rect.right, "Expect item_rect.right %ld <= %ld\n", item_rect.right, window_rect.right); /* A gap of 1 pixel is added deliberately in commit 75f9e64, so using equal operator would fail on Wine. * Check that top and bottom are correct with 1 pixel margin tolerance */ - ok(item_rect.top - (window_rect.top + caption_height) <= 1, "Expect item_rect.top %d - %d <= 1\n", item_rect.top, + ok(item_rect.top - (window_rect.top + caption_height) <= 1, "Expect item_rect.top %ld - %ld <= 1\n", item_rect.top, window_rect.top + caption_height); - ok(item_rect.bottom - (client_top_left.y - 1) <= 1, "Expect item_rect.bottom %d - %d <= 1\n", item_rect.bottom, + ok(item_rect.bottom - (client_top_left.y - 1) <= 1, "Expect item_rect.bottom %ld - %ld <= 1\n", item_rect.bottom, client_top_left.y - 1); /* Get the item rectangle of the not yet displayed popup menu item. */ ret = GetMenuItemRect(hwnd, popup_hmenu, 0, &item_rect); - ok(ret, "GetMenuItemRect failed with error %d\n", GetLastError()); - ok(item_rect.left == client_top_left.x, "Expect item_rect.left %d == %d\n", item_rect.left, client_top_left.x); - ok(item_rect.right == client_top_left.x, "Expect item_rect.right %d == %d\n", item_rect.right, client_top_left.x); - ok(item_rect.top == client_top_left.y, "Expect item_rect.top %d == %d\n", item_rect.top, client_top_left.y); - ok(item_rect.bottom == client_top_left.y, "Expect item_rect.bottom %d == %d\n", item_rect.bottom, + ok(ret, "GetMenuItemRect failed with error %ld\n", GetLastError()); + ok(item_rect.left == client_top_left.x, "Expect item_rect.left %ld == %ld\n", item_rect.left, client_top_left.x); + ok(item_rect.right == client_top_left.x, "Expect item_rect.right %ld == %ld\n", item_rect.right, client_top_left.x); + ok(item_rect.top == client_top_left.y, "Expect item_rect.top %ld == %ld\n", item_rect.top, client_top_left.y); + ok(item_rect.bottom == client_top_left.y, "Expect item_rect.bottom %ld == %ld\n", item_rect.bottom, client_top_left.y); DestroyWindow(hwnd); @@ -410,7 +397,7 @@ static void test_system_menu(void) hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL, WS_SYSMENU | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, NULL, NULL, NULL, NULL); - ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); + ok(hwnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError()); menu = GetSystemMenu( hwnd, FALSE ); ok( menu != NULL, "no system menu\n" ); @@ -533,7 +520,7 @@ static void test_system_menu(void) /* now a normal (non-system) menu */ menu = CreateMenu(); - ok( menu != NULL, "CreateMenu failed with error %d\n", GetLastError() ); + ok( menu != NULL, "CreateMenu failed with error %ld\n", GetLastError() ); res = CheckMenuItem( menu, SC_TASKLIST, 0 ); ok( res == -1, "CheckMenuItem succeeded\n" ); @@ -544,9 +531,9 @@ static void test_system_menu(void) ret = RemoveMenu( menu, SC_TASKLIST, 0 ); ok( !ret, "RemoveMenu succeeded\n" ); ret = ModifyMenuA( menu, SC_TASKLIST, 0, SC_TASKLIST, "test" ); - ok( ret, "ModifyMenuA failed err %d\n", GetLastError() ); + ok( ret, "ModifyMenuA failed err %ld\n", GetLastError() ); ret = ModifyMenuW( menu, SC_TASKLIST, 0, SC_TASKLIST, testW ); - ok( ret, "ModifyMenuW failed err %d\n", GetLastError() ); + ok( ret, "ModifyMenuW failed err %ld\n", GetLastError() ); ret = ModifyMenuA( menu, SC_TASKLIST-1, 0, SC_TASKLIST, "test" ); ok( !ret, "ModifyMenu succeeded on SC_TASKLIST-1\n" ); strcpy( buffer, "test" ); @@ -589,18 +576,18 @@ static void test_menu_locked_by_window(void) HWND hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL, WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, NULL, NULL, NULL, NULL); - ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); + ok(hwnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError()); hmenu = CreateMenu(); - ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); + ok(hmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError()); ret = InsertMenuA(hmenu, 0, MF_STRING, 0, "&Test"); - ok(ret, "InsertMenu failed with error %d\n", GetLastError()); + ok(ret, "InsertMenu failed with error %ld\n", GetLastError()); ret = SetMenu(hwnd, hmenu); - ok(ret, "SetMenu failed with error %d\n", GetLastError()); + ok(ret, "SetMenu failed with error %ld\n", GetLastError()); ret = DestroyMenu(hmenu); - ok(ret, "DestroyMenu failed with error %d\n", GetLastError()); + ok(ret, "DestroyMenu failed with error %ld\n", GetLastError()); ret = DrawMenuBar(hwnd); - ok(ret, "DrawMenuBar failed with error %d\n", GetLastError()); + ok(ret, "DrawMenuBar failed with error %ld\n", GetLastError()); ret = IsMenu(GetMenu(hwnd)); ok(!ret || broken(ret) /* nt4 */, "Menu handle should have been destroyed\n"); @@ -645,38 +632,38 @@ static void test_subpopup_locked_by_menu(void) hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL, WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, NULL, NULL, NULL, NULL); - ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); + ok(hwnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError()); SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR) subpopuplocked_wnd_proc); hmenu = CreatePopupMenu(); - ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); + ok(hmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError()); hsubmenu = CreatePopupMenu(); - ok(hsubmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); + ok(hsubmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError()); ret = InsertMenuA(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hsubmenu, "PopUpLockTest"); - ok(ret, "InsertMenu failed with error %d\n", GetLastError()); + ok(ret, "InsertMenu failed with error %ld\n", GetLastError()); ret = InsertMenuA(hsubmenu, 0, MF_BYPOSITION | MF_STRING, itemid, "PopUpMenu"); - ok(ret, "InsertMenu failed with error %d\n", GetLastError()); + ok(ret, "InsertMenu failed with error %ld\n", GetLastError()); /* first some tests that all this functions properly */ mii.fMask = MIIM_SUBMENU; ret = GetMenuItemInfoA( hmenu, 0, TRUE, &mii); - ok( ret, "GetMenuItemInfo failed error %d\n", GetLastError()); + ok( ret, "GetMenuItemInfo failed error %ld\n", GetLastError()); ok( mii.hSubMenu == hsubmenu, "submenu is %p\n", mii.hSubMenu); mi.fMask |= MIM_STYLE; ret = GetMenuInfo( hsubmenu, &mi); - ok( ret , "GetMenuInfo returned 0 with error %d\n", GetLastError()); + ok( ret , "GetMenuInfo returned 0 with error %ld\n", GetLastError()); ret = IsMenu( hsubmenu); ok( ret , "Menu handle is not valid\n"); ret = TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL); - ok( ret == itemid , "TrackPopupMenu returned %d error is %d\n", ret, GetLastError()); + ok( ret == itemid , "TrackPopupMenu returned %d error is %ld\n", ret, GetLastError()); /* then destroy the sub-popup */ ret = DestroyMenu( hsubmenu); - ok(ret, "DestroyMenu failed with error %d\n", GetLastError()); + ok(ret, "DestroyMenu failed with error %ld\n", GetLastError()); /* and repeat the tests */ mii.fMask = MIIM_SUBMENU; ret = GetMenuItemInfoA( hmenu, 0, TRUE, &mii); - ok( ret, "GetMenuItemInfo failed error %d\n", GetLastError()); + ok( ret, "GetMenuItemInfo failed error %ld\n", GetLastError()); /* GetMenuInfo fails now */ ok( mii.hSubMenu == hsubmenu, "submenu is %p\n", mii.hSubMenu); mi.fMask |= MIM_STYLE; @@ -689,7 +676,7 @@ static void test_subpopup_locked_by_menu(void) /* but TrackPopupMenu still works! */ ret = TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL); todo_wine { - ok( ret == itemid , "TrackPopupMenu returned %d error is %d\n", ret, GetLastError()); + ok( ret == itemid , "TrackPopupMenu returned %d error is %ld\n", ret, GetLastError()); } /* clean up */ @@ -707,11 +694,11 @@ static void test_menu_ownerdraw(void) HWND hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL, WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, NULL, NULL, NULL, NULL); - ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); + ok(hwnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError()); if( !hwnd) return; SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_ownerdraw_wnd_proc); hmenu = CreatePopupMenu(); - ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); + ok(hmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError()); if( !hmenu) { DestroyWindow(hwnd);return;} k=0; for( j=0;j<2;j++) /* create columns */ @@ -731,11 +718,11 @@ static void test_menu_ownerdraw(void) "item rectangles are not separated by 4 pixels space\n"); /* height should be what the MEASUREITEM message has returned */ ok( MOD_rc[0].bottom - MOD_rc[0].top == MOD_SIZE, - "menu item has wrong height: %d should be %d\n", + "menu item has wrong height: %ld should be %d\n", MOD_rc[0].bottom - MOD_rc[0].top, MOD_SIZE); /* no gaps between the rows */ ok( MOD_rc[0].bottom - MOD_rc[1].top == 0, - "There should not be a space between the rows, gap is %d\n", + "There should not be a space between the rows, gap is %ld\n", MOD_rc[0].bottom - MOD_rc[1].top); /* test the correct value of the item height that was sent * by the WM_MEASUREITEM message */ @@ -751,15 +738,15 @@ static void test_menu_ownerdraw(void) TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL); /* left should be 4 pixels less now */ ok( leftcol == MOD_rc[0].left + 4, - "columns should be 4 pixels to the left (actual %d).\n", + "columns should be 4 pixels to the left (actual %ld).\n", leftcol - MOD_rc[0].left); /* test width */ ok( MOD_rc[0].right - MOD_rc[0].left == 2 * MOD_avec + MOD_SIZE, - "width of owner drawn menu item is wrong. Got %d expected %d\n", + "width of owner drawn menu item is wrong. Got %ld expected %d\n", MOD_rc[0].right - MOD_rc[0].left , 2*MOD_avec + MOD_SIZE); /* and height */ ok( MOD_rc[0].bottom - MOD_rc[0].top == MOD_SIZE, - "Height is incorrect. Got %d expected %d\n", + "Height is incorrect. Got %ld expected %d\n", MOD_rc[0].bottom - MOD_rc[0].top, MOD_SIZE); /* test owner-drawn callback bitmap */ @@ -776,9 +763,9 @@ static void test_menu_ownerdraw(void) /* test width/height of an ownerdraw menu bar as well */ ret = DestroyMenu(hmenu); - ok(ret, "DestroyMenu failed with error %d\n", GetLastError()); + ok(ret, "DestroyMenu failed with error %ld\n", GetLastError()); hmenu = CreateMenu(); - ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); + ok(hmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError()); if( !hmenu) { DestroyWindow(hwnd);return;} MOD_maxid=1; for(i=0;i<2;i++) { @@ -787,19 +774,19 @@ static void test_menu_ownerdraw(void) } ret = SetMenu( hwnd, hmenu); UpdateWindow( hwnd); /* hack for wine to draw the window + menu */ - ok(ret, "SetMenu failed with error %d\n", GetLastError()); + ok(ret, "SetMenu failed with error %ld\n", GetLastError()); /* test width */ ok( MOD_rc[0].right - MOD_rc[0].left == 2 * MOD_avec + MOD_SIZE, - "width of owner drawn menu item is wrong. Got %d expected %d\n", + "width of owner drawn menu item is wrong. Got %ld expected %d\n", MOD_rc[0].right - MOD_rc[0].left , 2*MOD_avec + MOD_SIZE); /* test height */ ok( MOD_rc[0].bottom - MOD_rc[0].top == GetSystemMetrics( SM_CYMENU) - 1, - "Height of owner drawn menu item is wrong. Got %d expected %d\n", + "Height of owner drawn menu item is wrong. Got %ld expected %d\n", MOD_rc[0].bottom - MOD_rc[0].top, GetSystemMetrics( SM_CYMENU) - 1); /* clean up */ ret = DestroyMenu(hmenu); - ok(ret, "DestroyMenu failed with error %d\n", GetLastError()); + ok(ret, "DestroyMenu failed with error %ld\n", GetLastError()); DestroyWindow(hwnd); } @@ -841,12 +828,12 @@ static void test_mbs_help( int ispop, int hassub, int mnuopt, mii.hbmpItem = hbmp; } submenu = CreateMenu(); - ok( submenu != 0, "CreateMenu failed with error %d\n", GetLastError()); + ok( submenu != 0, "CreateMenu failed with error %ld\n", GetLastError()); if( ispop) hmenu = CreatePopupMenu(); else hmenu = CreateMenu(); - ok( hmenu != 0, "Create{Popup}Menu failed with error %d\n", GetLastError()); + ok( hmenu != 0, "Create{Popup}Menu failed with error %ld\n", GetLastError()); if( hassub) { mii.fMask |= MIIM_SUBMENU; mii.hSubMenu = submenu; @@ -857,10 +844,10 @@ static void test_mbs_help( int ispop, int hassub, int mnuopt, GetMenuInfo( hmenu, &mi); if( mnuopt) mi.dwStyle |= mnuopt == 1 ? MNS_NOCHECK : MNS_CHECKORBMP; ret = SetMenuInfo( hmenu, &mi); - ok( ret, "SetMenuInfo failed with error %d\n", GetLastError()); + ok( ret, "SetMenuInfo failed with error %ld\n", GetLastError()); } ret = InsertMenuItemA( hmenu, 0, FALSE, &mii); - ok( ret, "InsertMenuItem failed with error %d\n", GetLastError()); + ok( ret, "InsertMenuItem failed with error %ld\n", GetLastError()); failed = !ret; if( winetest_debug) { HDC hdc=GetDC(hwnd); @@ -876,11 +863,11 @@ static void test_mbs_help( int ispop, int hassub, int mnuopt, TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL); else { ret = SetMenu( hwnd, hmenu); - ok(ret, "SetMenu failed with error %d\n", GetLastError()); + ok(ret, "SetMenu failed with error %ld\n", GetLastError()); DrawMenuBar( hwnd); } ret = GetMenuItemRect( hwnd, hmenu, 0, &rc); - ok(ret, "GetMenuItemRect failed with error %d\n", GetLastError()); + ok(ret, "GetMenuItemRect failed with error %ld\n", GetLastError()); if (0) /* comment out menu size checks, behavior is different in almost every Windows version */ /* the tests should however succeed on win2000, XP and Wine (at least up to 1.1.15) */ @@ -902,7 +889,7 @@ static void test_mbs_help( int ispop, int hassub, int mnuopt, ( hbmp ? (text ? 2:0) + bmpsize.cx : 0 ) + (text ? 2 * MOD_avec + (text[0] ? size.cx :0): 0) ; ok( rc.right - rc.left == expect, - "menu width wrong, got %d expected %d\n", rc.right - rc.left, expect); + "menu width wrong, got %ld expected %d\n", rc.right - rc.left, expect); failed = failed || !(rc.right - rc.left == expect); /* check menu height */ if( ispop) @@ -917,7 +904,7 @@ static void test_mbs_help( int ispop, int hassub, int mnuopt, expect = ( !(text || hbmp) ? GetSystemMetrics( SM_CYMENUSIZE)/2 : max( GetSystemMetrics( SM_CYMENU) - 1, (hbmp ? bmpsize.cy : 0))); ok( rc.bottom - rc.top == expect, - "menu height wrong, got %d expected %d (%d)\n", + "menu height wrong, got %ld expected %d (%d)\n", rc.bottom - rc.top, expect, GetSystemMetrics( SM_CYMENU)); failed = failed || !(rc.bottom - rc.top == expect); if( hbmp == HBMMENU_CALLBACK && MOD_GotDrawItemMsg) { @@ -932,18 +919,18 @@ static void test_mbs_help( int ispop, int hassub, int mnuopt, else /* mnuopt == 2 */ expect = 2; ok( expect == MOD_rc[0].left, - "bitmap left is %d expected %d\n", MOD_rc[0].left, expect); + "bitmap left is %ld expected %d\n", MOD_rc[0].left, expect); failed = failed || !(expect == MOD_rc[0].left); /* vertical */ expect = (rc.bottom - rc.top - MOD_rc[0].bottom + MOD_rc[0].top) / 2; ok( expect == MOD_rc[0].top, - "bitmap top is %d expected %d\n", MOD_rc[0].top, expect); + "bitmap top is %ld expected %d\n", MOD_rc[0].top, expect); failed = failed || !(expect == MOD_rc[0].top); } } /* if there was a failure, report details */ if( failed) { - trace("*** count %d %s text \"%s\" bitmap %p bmsize %d,%d textsize %d+%d,%d mnuopt %d hastab %d\n", + trace("*** count %d %s text \"%s\" bitmap %p bmsize %ld,%ld textsize %ld+%ld,%ld mnuopt %d hastab %d\n", count, (ispop? "POPUP": "MENUBAR"),text ? text: "(nil)", hbmp, bmpsize.cx, bmpsize.cy, size.cx, size.cy, sc_size.cx, mnuopt, hastab); trace(" check %d,%d arrow %d avechar %d\n", @@ -954,9 +941,9 @@ static void test_mbs_help( int ispop, int hassub, int mnuopt, } /* clean up */ ret = DestroyMenu(submenu); - ok(ret, "DestroyMenu failed with error %d\n", GetLastError()); + ok(ret, "DestroyMenu failed with error %ld\n", GetLastError()); ret = DestroyMenu(hmenu); - ok(ret, "DestroyMenu failed with error %d\n", GetLastError()); + ok(ret, "DestroyMenu failed with error %ld\n", GetLastError()); } @@ -980,21 +967,21 @@ static void test_menu_bmp_and_string(void) hbm_arrow = LoadBitmapA( 0, (LPCSTR)OBM_MNARROW); GetObjectA( hbm_arrow, sizeof(bm), &bm); arrowwidth = bm.bmWidth; - ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); + ok(hwnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError()); if( !hwnd) return; /* test system menu */ hsysmenu = GetSystemMenu( hwnd, FALSE); - ok( hsysmenu != NULL, "GetSystemMenu failed with error %d\n", GetLastError()); + ok( hsysmenu != NULL, "GetSystemMenu failed with error %ld\n", GetLastError()); mi.fMask = MIM_STYLE; mi.dwStyle = 0; got = GetMenuInfo( hsysmenu, &mi); - ok( got, "GetMenuInfo failed gle=%d\n", GetLastError()); - ok( MNS_CHECKORBMP == mi.dwStyle, "System Menu Style is %08x, without the bit %08x\n", + ok( got, "GetMenuInfo failed gle=%ld\n", GetLastError()); + ok( MNS_CHECKORBMP == mi.dwStyle, "System Menu Style is %08lx, without the bit %08x\n", mi.dwStyle, MNS_CHECKORBMP); mii.fMask = MIIM_BITMAP; mii.hbmpItem = NULL; got = GetMenuItemInfoA( hsysmenu, SC_CLOSE, FALSE, &mii); - ok( got, "GetMenuItemInfoA failed gle=%d\n", GetLastError()); + ok( got, "GetMenuItemInfoA failed gle=%ld\n", GetLastError()); ok( HBMMENU_POPUP_CLOSE == mii.hbmpItem, "Item info did not get the right hbitmap: got %p expected %p\n", mii.hbmpItem, HBMMENU_POPUP_CLOSE); @@ -1010,7 +997,7 @@ static void test_menu_bmp_and_string(void) ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState); ok(mii.wID == SC_RESTORE, "expected SC_RESTORE, got %#x\n", mii.wID); ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); - ok(mii.dwItemData == 0, "expected 0, got %#lx\n", mii.dwItemData); + ok(mii.dwItemData == 0, "expected 0, got %#Ix\n", mii.dwItemData); ok(mii.dwTypeData == (LPSTR)bmfill, "expected %p, got %p\n", bmfill, mii.dwTypeData); ok(mii.cch != 0, "cch should not be 0\n"); ok(mii.hbmpItem == HBMMENU_POPUP_RESTORE, "expected HBMMENU_POPUP_RESTORE, got %p\n", mii.hbmpItem); @@ -1024,7 +1011,7 @@ static void test_menu_bmp_and_string(void) ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState); ok(mii.wID == SC_RESTORE, "expected SC_RESTORE, got %#x\n", mii.wID); ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); - ok(mii.dwItemData == 0, "expected 0, got %#lx\n", mii.dwItemData); + ok(mii.dwItemData == 0, "expected 0, got %#Ix\n", mii.dwItemData); ok(mii.dwTypeData == (LPSTR)bmfill, "expected %p, got %p\n", bmfill, mii.dwTypeData); ok(mii.cch != 0, "cch should not be 0\n"); ok(mii.hbmpItem == HBMMENU_POPUP_CLOSE, "expected HBMMENU_POPUP_CLOSE, got %p\n", mii.hbmpItem); @@ -1043,7 +1030,7 @@ static void test_menu_bmp_and_string(void) for( szidx=0; szidx < ARRAY_SIZE(bmsizes); szidx++) { HBITMAP hbm = CreateBitmap( bmsizes[szidx].cx, bmsizes[szidx].cy,1,1,bmfill); HBITMAP bitmaps[] = { HBMMENU_CALLBACK, hbm, HBMMENU_POPUP_CLOSE, NULL }; - ok( hbm != 0, "CreateBitmap failed err %d\n", GetLastError()); + ok( hbm != 0, "CreateBitmap failed err %ld\n", GetLastError()); for( txtidx = 0; txtidx < ARRAY_SIZE(MOD_txtsizes); txtidx++) { for( hassub = 0; hassub < 2 ; hassub++) { /* add submenu item */ for( mnuopt = 0; mnuopt < 3 ; mnuopt++){ /* test MNS_NOCHECK/MNS_CHECKORBMP */ @@ -1200,21 +1187,6 @@ static void test_menu_add_string( void ) DestroyMenu( hmenu ); } -/* define building blocks for the menu item info tests */ -static 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 WCHAR *strcpyW( WCHAR *dst, const WCHAR *src ) -{ - WCHAR *p = dst; - while ((*p++ = *src++)); - return dst; -} - static void insert_menu_item( int line, HMENU hmenu, BOOL ansi, UINT mask, UINT type, UINT state, UINT id, HMENU submenu, HBITMAP checked, HBITMAP unchecked, ULONG_PTR data, void *type_data, UINT len, HBITMAP item, BOOL expect ) @@ -1242,7 +1214,7 @@ static void insert_menu_item( int line, HMENU hmenu, BOOL ansi, UINT mask, UINT if (ansi) ret = InsertMenuItemA( hmenu, 0, TRUE, &info ); else ret = InsertMenuItemW( hmenu, 0, TRUE, (MENUITEMINFOW*)&info ); if (!expect) ok_(__FILE__, line)( !ret, "InsertMenuItem should have failed.\n" ); - else ok_(__FILE__, line)( ret, "InsertMenuItem failed, err %u\n", GetLastError()); + else ok_(__FILE__, line)( ret, "InsertMenuItem failed, err %lu\n", GetLastError()); } static void check_menu_item_info( int line, HMENU hmenu, BOOL ansi, UINT mask, UINT type, UINT state, @@ -1268,7 +1240,7 @@ static void check_menu_item_info( int line, HMENU hmenu, BOOL ansi, UINT mask, U ok_(__FILE__, line)( !ret, "GetMenuItemInfo should have failed.\n" ); return; } - ok_(__FILE__, line)( ret, "GetMenuItemInfo failed, err %u\n", GetLastError()); + ok_(__FILE__, line)( ret, "GetMenuItemInfo failed, err %lu\n", GetLastError()); if (mask & MIIM_TYPE) ok_(__FILE__, line)( info.fType == type || info.fType == LOWORD(type), "wrong type %x/%x\n", info.fType, type ); @@ -1290,7 +1262,7 @@ static void check_menu_item_info( int line, HMENU hmenu, BOOL ansi, UINT mask, U } if (mask & MIIM_DATA) ok_(__FILE__, line)( info.dwItemData == data || info.dwItemData == LOWORD(data), - "wrong item data %lx/%lx\n", info.dwItemData, data ); + "wrong item data %Ix/%Ix\n", info.dwItemData, data ); if (mask & MIIM_BITMAP) ok_(__FILE__, line)( info.hbmpItem == item || (ULONG_PTR)info.hbmpItem == LOWORD(item), "wrong bmpitem %p/%p\n", info.hbmpItem, item ); @@ -1305,14 +1277,14 @@ static void check_menu_item_info( int line, HMENU hmenu, BOOL ansi, UINT mask, U ok_(__FILE__, line)( !strncmp( expname, info.dwTypeData, out_len ), "menu item name differed from '%s' '%s'\n", expname, info.dwTypeData ); else - ok_(__FILE__, line)( !strncmpW( (WCHAR *)expname, (WCHAR *)info.dwTypeData, out_len ), + ok_(__FILE__, line)( !wcsncmp( (WCHAR *)expname, (WCHAR *)info.dwTypeData, out_len ), "menu item name wrong\n" ); SetLastError( 0xdeadbeef ); ret = ansi ? GetMenuStringA( hmenu, 0, (char *)buffer, 80, MF_BYPOSITION ) : GetMenuStringW( hmenu, 0, buffer, 80, MF_BYPOSITION ); if (expstring) - ok_(__FILE__, line)( ret, "GetMenuString failed, err %u\n", GetLastError()); + ok_(__FILE__, line)( ret, "GetMenuString failed, err %lu\n", GetLastError()); else ok_(__FILE__, line)( !ret, "GetMenuString should have failed\n" ); } @@ -1325,7 +1297,7 @@ static void modify_menu( int line, HMENU hmenu, BOOL ansi, UINT flags, UINT_PTR SetLastError( 0xdeadbeef ); if (ansi) ret = ModifyMenuA( hmenu, 0, flags, id, data ); else ret = ModifyMenuW( hmenu, 0, flags, id, data ); - ok_(__FILE__,line)( ret, "ModifyMenuA failed, err %u\n", GetLastError()); + ok_(__FILE__,line)( ret, "ModifyMenuA failed, err %lu\n", GetLastError()); } static void set_menu_item_info( int line, HMENU hmenu, BOOL ansi, UINT mask, UINT type, UINT state, @@ -1355,14 +1327,14 @@ static void set_menu_item_info( int line, HMENU hmenu, BOOL ansi, UINT mask, UIN SetLastError( 0xdeadbeef ); if (ansi) ret = SetMenuItemInfoA( hmenu, 0, TRUE, &info ); else ret = SetMenuItemInfoW( hmenu, 0, TRUE, (MENUITEMINFOW*)&info ); - ok_(__FILE__, line)( ret, "SetMenuItemInfo failed, err %u\n", GetLastError()); + ok_(__FILE__, line)( ret, "SetMenuItemInfo failed, err %lu\n", GetLastError()); } #define TMII_INSMI( c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,eret1 )\ hmenu = CreateMenu();\ submenu = CreateMenu();\ if(ansi)strcpy( string, init );\ - else strcpyW( string, init );\ + else wcscpy( string, init );\ insert_menu_item( __LINE__, hmenu, ansi, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, eret1 ) /* GetMenuItemInfo + GetMenuString */ @@ -2258,18 +2230,18 @@ static struct menu_mouse_tests_s { static void send_key(WORD wVk) { - TEST_INPUT i[2]; + INPUT i[2]; memset(i, 0, sizeof(i)); i[0].type = i[1].type = INPUT_KEYBOARD; - i[0].u.ki.wVk = i[1].u.ki.wVk = wVk; - i[1].u.ki.dwFlags = KEYEVENTF_KEYUP; - SendInput(2, (INPUT *) i, sizeof(INPUT)); + i[0].ki.wVk = i[1].ki.wVk = wVk; + i[1].ki.dwFlags = KEYEVENTF_KEYUP; + SendInput(2, i, sizeof(INPUT)); } static BOOL click_menu(HANDLE hWnd, struct menu_item_pair_s *mi) { HMENU hMenu = hMenus[mi->uMenu]; - TEST_INPUT i[3]; + INPUT i[3]; MSG msg; RECT r; int screen_w = GetSystemMetrics(SM_CXSCREEN); @@ -2279,16 +2251,16 @@ static BOOL click_menu(HANDLE hWnd, struct menu_item_pair_s *mi) memset(i, 0, sizeof(i)); i[0].type = i[1].type = i[2].type = INPUT_MOUSE; - i[0].u.mi.dx = i[1].u.mi.dx = i[2].u.mi.dx + i[0].mi.dx = i[1].mi.dx = i[2].mi.dx = ((r.left + 5) * 65535) / screen_w; - i[0].u.mi.dy = i[1].u.mi.dy = i[2].u.mi.dy + i[0].mi.dy = i[1].mi.dy = i[2].mi.dy = ((r.top + 5) * 65535) / screen_h; - i[0].u.mi.dwFlags = i[1].u.mi.dwFlags = i[2].u.mi.dwFlags + i[0].mi.dwFlags = i[1].mi.dwFlags = i[2].mi.dwFlags = MOUSEEVENTF_ABSOLUTE; - i[0].u.mi.dwFlags |= MOUSEEVENTF_MOVE; - i[1].u.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN; - i[2].u.mi.dwFlags |= MOUSEEVENTF_LEFTUP; - ret = SendInput(3, (INPUT *) i, sizeof(INPUT)); + i[0].mi.dwFlags |= MOUSEEVENTF_MOVE; + i[1].mi.dwFlags |= MOUSEEVENTF_LEFTDOWN; + i[2].mi.dwFlags |= MOUSEEVENTF_LEFTUP; + ret = SendInput(3, i, sizeof(INPUT)); /* hack to prevent mouse message buildup in Wine */ while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg ); @@ -2566,14 +2538,14 @@ static void test_menu_hilitemenuitem( void ) } ok(GetLastError() == 0xdeadbeef || /* 9x */ GetLastError() == ERROR_INVALID_WINDOW_HANDLE /* NT */, - "HiliteMenuItem: expected error ERROR_INVALID_WINDOW_HANDLE, got: %d\n", GetLastError()); + "HiliteMenuItem: expected error ERROR_INVALID_WINDOW_HANDLE, got: %ld\n", GetLastError()); SetLastError(0xdeadbeef); ok(!HiliteMenuItem(hWnd, NULL, 1, MF_HILITE | MF_BYPOSITION), "HiliteMenuItem: call should have failed.\n"); ok(GetLastError() == 0xdeadbeef || /* 9x */ GetLastError() == ERROR_INVALID_MENU_HANDLE /* NT */, - "HiliteMenuItem: expected error ERROR_INVALID_MENU_HANDLE, got: %d\n", GetLastError()); + "HiliteMenuItem: expected error ERROR_INVALID_MENU_HANDLE, got: %ld\n", GetLastError()); ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE), "HiliteMenuItem: Item 2 is hilited\n"); @@ -2584,7 +2556,7 @@ static void test_menu_hilitemenuitem( void ) ok(HiliteMenuItem(hWnd, hPopupMenu, 1, MF_BYPOSITION), "HiliteMenuItem: call should have succeeded.\n"); ok(GetLastError() == 0xdeadbeef, - "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError()); + "HiliteMenuItem: expected error 0xdeadbeef, got: %ld\n", GetLastError()); ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE), "HiliteMenuItem: Item 2 is hilited\n"); @@ -2596,7 +2568,7 @@ static void test_menu_hilitemenuitem( void ) "HiliteMenuItem: call should have succeeded.\n"); } ok(GetLastError() == 0xdeadbeef, - "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError()); + "HiliteMenuItem: expected error 0xdeadbeef, got: %ld\n", GetLastError()); ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE), "HiliteMenuItem: Item 2 is hilited\n"); @@ -2607,7 +2579,7 @@ static void test_menu_hilitemenuitem( void ) ok(HiliteMenuItem(hWnd, hPopupMenu, 1, MF_HILITE | MF_BYPOSITION), "HiliteMenuItem: call should not have failed.\n"); ok(GetLastError() == 0xdeadbeef, - "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError()); + "HiliteMenuItem: expected error 0xdeadbeef, got: %ld\n", GetLastError()); todo_wine { @@ -2621,7 +2593,7 @@ static void test_menu_hilitemenuitem( void ) ok(HiliteMenuItem(hWnd, hPopupMenu, 1, MF_UNHILITE | MF_BYPOSITION), "HiliteMenuItem: call should not have failed.\n"); ok(GetLastError() == 0xdeadbeef, - "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError()); + "HiliteMenuItem: expected error 0xdeadbeef, got: %ld\n", GetLastError()); ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE), "HiliteMenuItem: Item 2 is hilited\n"); @@ -2632,7 +2604,7 @@ static void test_menu_hilitemenuitem( void ) ok(HiliteMenuItem(hWnd, hPopupMenu, 103, MF_HILITE | MF_BYCOMMAND), "HiliteMenuItem: call should not have failed.\n"); ok(GetLastError() == 0xdeadbeef, - "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError()); + "HiliteMenuItem: expected error 0xdeadbeef, got: %ld\n", GetLastError()); todo_wine { @@ -2646,7 +2618,7 @@ static void test_menu_hilitemenuitem( void ) ok(HiliteMenuItem(hWnd, hPopupMenu, 103, MF_UNHILITE | MF_BYCOMMAND), "HiliteMenuItem: call should not have failed.\n"); ok(GetLastError() == 0xdeadbeef, - "HiliteMenuItem: expected error 0xdeadbeef, got: %d\n", GetLastError()); + "HiliteMenuItem: expected error 0xdeadbeef, got: %ld\n", GetLastError()); ok(!(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE), "HiliteMenuItem: Item 3 is hilited\n"); @@ -2812,7 +2784,7 @@ static void test_menu_resource_layout(void) BOOL ret; hmenu = LoadMenuIndirectA(&menu_template); - ok(hmenu != 0, "LoadMenuIndirect error %u\n", GetLastError()); + ok(hmenu != 0, "LoadMenuIndirect error %lu\n", GetLastError()); ret = AppendMenuA(hmenu, MF_STRING, 6, NULL); ok(ret, "AppendMenu failed\n"); @@ -2875,7 +2847,7 @@ static HMENU create_menu_from_data(const struct menu_data *item, INT item_count) { SetLastError(0xdeadbeef); ret = AppendMenuA(hmenu, item[i].type, item[i].id, item[i].str); - ok(ret, "%d: AppendMenu(%04x, %04x, %p) error %u\n", + ok(ret, "%d: AppendMenu(%04x, %04x, %p) error %lu\n", i, item[i].type, item[i].id, item[i].str, GetLastError()); } return hmenu; @@ -2917,7 +2889,7 @@ static HMENU create_menuitem_from_data(const struct menu_data *item, INT item_co if( item[i].type & MF_HELP) mii.fType |= MF_HELP; mii.wID = item[i].id; ret = InsertMenuItemA( hmenu, -1, TRUE, &mii); - ok(ret, "%d: InsertMenuItem(%04x, %04x, %p) error %u\n", + ok(ret, "%d: InsertMenuItem(%04x, %04x, %p) error %lu\n", i, item[i].type, item[i].id, item[i].str, GetLastError()); } return hmenu; @@ -3041,6 +3013,7 @@ static void test_InsertMenu(void) { MF_HELP, 1, MAKEINTRESOURCEA(1) } }; HMENU hmenu; + BOOL ret; #define create_menu(a) create_menu_from_data((a), ARRAY_SIZE(a)) #define create_menuitem(a) create_menuitem_from_data((a), ARRAY_SIZE(a)) @@ -3082,6 +3055,16 @@ static void test_InsertMenu(void) #undef create_menu #undef create_menuitem #undef compare_menu + + hmenu = CreateMenu(); + + SetLastError(0xdeadbeef); + ret = InsertMenuW(hmenu, -1, MF_BYPOSITION | MF_POPUP, 0xdeadbeef, L"test"); + ok(ret && GetLastError() == ERROR_INVALID_MENU_HANDLE, + "InsertMenuW returned %x %lu\n", ret, GetLastError()); + ok(GetMenuItemCount(hmenu) == 1, "GetMenuItemCount() = %d\n", GetMenuItemCount(hmenu)); + + DestroyMenu(hmenu); } static void test_menu_getmenuinfo(void) @@ -3101,7 +3084,7 @@ static void test_menu_getmenuinfo(void) ok( !ret, "GetMenuInfo() should have failed\n"); ok( gle == ERROR_INVALID_PARAMETER || broken(gle == 0xdeadbeef), /* Win98, WinME */ - "GetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER); + "GetMenuInfo() error got %lu expected %u\n", gle, ERROR_INVALID_PARAMETER); SetLastError(0xdeadbeef); mi.cbSize = 0; ret = GetMenuInfo( hmenu, &mi); @@ -3109,13 +3092,13 @@ static void test_menu_getmenuinfo(void) ok( !ret, "GetMenuInfo() should have failed\n"); ok( gle == ERROR_INVALID_PARAMETER || broken(gle == 0xdeadbeef), /* Win98, WinME */ - "GetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER); + "GetMenuInfo() error got %lu expected %u\n", gle, ERROR_INVALID_PARAMETER); SetLastError(0xdeadbeef); mi.cbSize = sizeof( MENUINFO); ret = GetMenuInfo( hmenu, &mi); gle= GetLastError(); ok( ret, "GetMenuInfo() should have succeeded\n"); - ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); + ok( gle == 0xdeadbeef, "GetMenuInfo() error got %lu\n", gle); SetLastError(0xdeadbeef); mi.cbSize = 0; ret = GetMenuInfo( NULL, &mi); @@ -3123,7 +3106,7 @@ static void test_menu_getmenuinfo(void) ok( !ret, "GetMenuInfo() should have failed\n"); ok( gle == ERROR_INVALID_PARAMETER || broken(gle == 0xdeadbeef), /* Win98, WinME */ - "GetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER); + "GetMenuInfo() error got %lu expected %u\n", gle, ERROR_INVALID_PARAMETER); /* clean up */ DestroyMenu( hmenu); return; @@ -3145,7 +3128,7 @@ static void test_menu_setmenuinfo(void) mii.fMask = MIIM_SUBMENU; mii.hSubMenu = hsubmenu; ret = InsertMenuItemA( hmenu, 0, FALSE, &mii); - ok( ret, "InsertMenuItem failed with error %d\n", GetLastError()); + ok( ret, "InsertMenuItem failed with error %ld\n", GetLastError()); /* test some parameter errors */ SetLastError(0xdeadbeef); ret = SetMenuInfo( hmenu, NULL); @@ -3153,7 +3136,7 @@ static void test_menu_setmenuinfo(void) ok( !ret, "SetMenuInfo() should have failed\n"); ok( gle == ERROR_INVALID_PARAMETER || broken(gle == 0xdeadbeef), /* Win98, WinME */ - "SetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER); + "SetMenuInfo() error got %lu expected %u\n", gle, ERROR_INVALID_PARAMETER); SetLastError(0xdeadbeef); mi.cbSize = 0; ret = SetMenuInfo( hmenu, &mi); @@ -3161,13 +3144,13 @@ static void test_menu_setmenuinfo(void) ok( !ret, "SetMenuInfo() should have failed\n"); ok( gle == ERROR_INVALID_PARAMETER || broken(gle == 0xdeadbeef), /* Win98, WinME */ - "SetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER); + "SetMenuInfo() error got %lu expected %u\n", gle, ERROR_INVALID_PARAMETER); SetLastError(0xdeadbeef); mi.cbSize = sizeof( MENUINFO); ret = SetMenuInfo( hmenu, &mi); gle= GetLastError(); ok( ret, "SetMenuInfo() should have succeeded\n"); - ok( gle == 0xdeadbeef, "SetMenuInfo() error got %u\n", gle); + ok( gle == 0xdeadbeef, "SetMenuInfo() error got %lu\n", gle); SetLastError(0xdeadbeef); mi.cbSize = 0; ret = SetMenuInfo( NULL, &mi); @@ -3175,7 +3158,7 @@ static void test_menu_setmenuinfo(void) ok( !ret, "SetMenuInfo() should have failed\n"); ok( gle == ERROR_INVALID_PARAMETER || broken(gle == 0xdeadbeef), /* Win98, WinME */ - "SetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER); + "SetMenuInfo() error got %lu expected %u\n", gle, ERROR_INVALID_PARAMETER); /* functional tests */ /* menu and submenu should have the CHECKORBMP style bit cleared */ SetLastError(0xdeadbeef); @@ -3184,7 +3167,7 @@ static void test_menu_setmenuinfo(void) ret = GetMenuInfo( hmenu, &mi); gle= GetLastError(); ok( ret, "GetMenuInfo() should have succeeded\n"); - ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); + ok( gle == 0xdeadbeef, "GetMenuInfo() error got %lu\n", gle); ok( !(mi.dwStyle & MNS_CHECKORBMP), "menustyle was not expected to have the MNS_CHECKORBMP flag\n"); SetLastError(0xdeadbeef); mi.cbSize = sizeof( MENUINFO); @@ -3192,7 +3175,7 @@ static void test_menu_setmenuinfo(void) ret = GetMenuInfo( hsubmenu, &mi); gle= GetLastError(); ok( ret, "GetMenuInfo() should have succeeded\n"); - ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); + ok( gle == 0xdeadbeef, "GetMenuInfo() error got %lu\n", gle); ok( !(mi.dwStyle & MNS_CHECKORBMP), "menustyle was not expected to have the MNS_CHECKORBMP flag\n"); /* SetMenuInfo() */ SetLastError(0xdeadbeef); @@ -3202,7 +3185,7 @@ static void test_menu_setmenuinfo(void) ret = SetMenuInfo( hmenu, &mi); gle= GetLastError(); ok( ret, "SetMenuInfo() should have succeeded\n"); - ok( gle == 0xdeadbeef, "SetMenuInfo() error got %u\n", gle); + ok( gle == 0xdeadbeef, "SetMenuInfo() error got %lu\n", gle); /* Now both menus should have the MNS_CHECKORBMP style bit set */ SetLastError(0xdeadbeef); mi.cbSize = sizeof( MENUINFO); @@ -3210,7 +3193,7 @@ static void test_menu_setmenuinfo(void) ret = GetMenuInfo( hmenu, &mi); gle= GetLastError(); ok( ret, "GetMenuInfo() should have succeeded\n"); - ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); + ok( gle == 0xdeadbeef, "GetMenuInfo() error got %lu\n", gle); ok( mi.dwStyle & MNS_CHECKORBMP, "menustyle was expected to have the MNS_CHECKORBMP flag\n"); SetLastError(0xdeadbeef); mi.cbSize = sizeof( MENUINFO); @@ -3218,7 +3201,7 @@ static void test_menu_setmenuinfo(void) ret = GetMenuInfo( hsubmenu, &mi); gle= GetLastError(); ok( ret, "GetMenuInfo() should have succeeded\n"); - ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); + ok( gle == 0xdeadbeef, "GetMenuInfo() error got %lu\n", gle); ok( mi.dwStyle & MNS_CHECKORBMP, "menustyle was expected to have the MNS_CHECKORBMP flag\n"); /* now repeat that without the APPLYTOSUBMENUS flag and another style bit */ SetLastError(0xdeadbeef); @@ -3228,7 +3211,7 @@ static void test_menu_setmenuinfo(void) ret = SetMenuInfo( hmenu, &mi); gle= GetLastError(); ok( ret, "SetMenuInfo() should have succeeded\n"); - ok( gle == 0xdeadbeef, "SetMenuInfo() error got %u\n", gle); + ok( gle == 0xdeadbeef, "SetMenuInfo() error got %lu\n", gle); /* Now only the top menu should have the MNS_NOCHECK style bit set */ SetLastError(0xdeadbeef); mi.cbSize = sizeof( MENUINFO); @@ -3236,7 +3219,7 @@ static void test_menu_setmenuinfo(void) ret = GetMenuInfo( hmenu, &mi); gle= GetLastError(); ok( ret, "GetMenuInfo() should have succeeded\n"); - ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); + ok( gle == 0xdeadbeef, "GetMenuInfo() error got %lu\n", gle); ok( mi.dwStyle & MNS_NOCHECK, "menustyle was expected to have the MNS_NOCHECK flag\n"); SetLastError(0xdeadbeef); mi.cbSize = sizeof( MENUINFO); @@ -3244,7 +3227,7 @@ static void test_menu_setmenuinfo(void) ret = GetMenuInfo( hsubmenu, &mi); gle= GetLastError(); ok( ret, "GetMenuInfo() should have succeeded\n"); - ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); + ok( gle == 0xdeadbeef, "GetMenuInfo() error got %lu\n", gle); ok( !(mi.dwStyle & MNS_NOCHECK), "menustyle was not expected to have the MNS_NOCHECK flag\n"); /* test background brush */ @@ -3299,13 +3282,13 @@ static void test_menu_trackpopupmenu(void) HWND hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL, WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, NULL, NULL, NULL, NULL); - ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); + ok(hwnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError()); if (!hwnd) return; SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_ownerdraw_wnd_proc); for( Ex = 0; Ex < 2; Ex++) { hmenu = CreatePopupMenu(); - ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); + ok(hmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError()); if (!hmenu) { DestroyWindow(hwnd); @@ -3322,7 +3305,7 @@ static void test_menu_trackpopupmenu(void) ok( gle == ERROR_INVALID_MENU_HANDLE || broken (gle == 0xdeadbeef) /* win95 */ || broken (gle == NO_ERROR) /* win98/ME */ - ,"TrackPopupMenu%s error got %u expected %u\n", + ,"TrackPopupMenu%s error got %lu expected %u\n", Ex ? "Ex" : "", gle, ERROR_INVALID_MENU_HANDLE); ok( !(gflag_initmenupopup || gflag_entermenuloop || gflag_initmenu), "got unexpected message(s)%s%s%s\n", @@ -3338,7 +3321,7 @@ static void test_menu_trackpopupmenu(void) ok( gle == ERROR_INVALID_MENU_HANDLE || broken (gle == 0xdeadbeef) /* win95 */ || broken (gle == NO_ERROR) /* win98/ME */ - ,"TrackPopupMenu%s error got %u expected %u\n", + ,"TrackPopupMenu%s error got %lu expected %u\n", Ex ? "Ex" : "", gle, ERROR_INVALID_MENU_HANDLE); ok( !(gflag_initmenupopup || gflag_entermenuloop || gflag_initmenu), "got unexpected message(s)%s%s%s\n", @@ -3352,7 +3335,7 @@ static void test_menu_trackpopupmenu(void) ret = MyTrackPopupMenu( Ex, hmenu, TPM_RETURNCMD, 100,100, 0, NULL); gle = GetLastError(); ok( !ret, "TrackPopupMenu%s should have failed\n", Ex ? "Ex" : ""); - ok( gle == ERROR_INVALID_WINDOW_HANDLE, "TrackPopupMenu%s error got %u\n", Ex ? "Ex" : "", gle ); + ok( gle == ERROR_INVALID_WINDOW_HANDLE, "TrackPopupMenu%s error got %lu\n", Ex ? "Ex" : "", gle ); ok( !(gflag_initmenupopup || gflag_entermenuloop || gflag_initmenu), "got unexpected message(s)%s%s%s\n", gflag_initmenupopup ? " WM_INITMENUPOPUP ": " ", @@ -3368,7 +3351,7 @@ static void test_menu_trackpopupmenu(void) ok( gle == NO_ERROR || gle == ERROR_INVALID_MENU_HANDLE /* NT4, win2k */ || broken (gle == 0xdeadbeef) /* win95 */ - ,"TrackPopupMenu%s error got %u expected %u or %u\n", + ,"TrackPopupMenu%s error got %lu expected %u or %u\n", Ex ? "Ex" : "", gle, NO_ERROR, ERROR_INVALID_MENU_HANDLE); ok( gflag_initmenupopup && gflag_entermenuloop && gflag_initmenu, "missed expected message(s)%s%s%s\n", @@ -3386,7 +3369,7 @@ static void test_menu_trackpopupmenu(void) ok( gle == NO_ERROR || gle == ERROR_INVALID_MENU_HANDLE /* NT4, win2k and Vista in the TrackPopupMenuEx case */ || broken (gle == 0xdeadbeef) /* win95 */ - ,"TrackPopupMenu%s error got %u expected %u or %u\n", + ,"TrackPopupMenu%s error got %lu expected %u or %u\n", Ex ? "Ex" : "", gle, NO_ERROR, ERROR_INVALID_MENU_HANDLE); ok( gflag_initmenupopup && gflag_entermenuloop && gflag_initmenu, "missed expected message(s)%s%s%s\n", @@ -3414,7 +3397,7 @@ static LRESULT WINAPI menu_track_again_wnd_proc(HWND hwnd, UINT msg, WPARAM wpar ret = TrackPopupMenu(g_hmenu, 0, 100, 100, 0, hwnd, NULL); ok(ret == FALSE, "got %d\n", ret); ok(GetLastError() == ERROR_POPUP_ALREADY_ACTIVE || - broken(GetLastError() == 0xdeadbeef) /* W9x */, "got %d\n", GetLastError()); + broken(GetLastError() == 0xdeadbeef) /* W9x */, "got %ld\n", GetLastError()); /* exit menu modal loop * ( A SendMessage does not work on NT3.51 here ) */ @@ -3432,12 +3415,12 @@ static void test_menu_trackagain(void) hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL, WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, NULL, NULL, NULL, NULL); - ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); + ok(hwnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError()); if (!hwnd) return; SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_track_again_wnd_proc); g_hmenu = CreatePopupMenu(); - ok(g_hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); + ok(g_hmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError()); ret = AppendMenuA(g_hmenu, MF_STRING , 100, "item 1"); ok(ret, "AppendMenu failed.\n"); @@ -3490,14 +3473,14 @@ static void test_menu_cancelmode(void) WS_VISIBLE | WS_CHILD, 10, 10, 20, 20, hwnd, NULL, NULL, NULL); ok( hwnd != NULL && hwndchild != NULL, - "CreateWindowEx failed with error %d\n", GetLastError()); + "CreateWindowEx failed with error %ld\n", GetLastError()); g_hwndtosend = hwnd; SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_cancelmode_wnd_proc); SetWindowLongPtrA( hwndchild, GWLP_WNDPROC, (LONG_PTR)menu_cancelmode_wnd_proc); menu = CreatePopupMenu(); - ok( menu != NULL, "CreatePopupMenu failed with error %d\n", GetLastError()); + ok( menu != NULL, "CreatePopupMenu failed with error %ld\n", GetLastError()); ret = AppendMenuA( menu, MF_STRING, 1, "winetest"); - ok( ret, "Functie failed lasterror is %u\n", GetLastError()); + ok( ret, "Functie failed lasterror is %lu\n", GetLastError()); /* seems to be needed only on wine :( */ while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); @@ -3524,15 +3507,15 @@ static void test_menu_cancelmode(void) /* test canceling tracking in a window's menu bar */ menubar = CreateMenu(); - ok( menubar != NULL, "CreateMenu failed with error %d\n", GetLastError()); + ok( menubar != NULL, "CreateMenu failed with error %ld\n", GetLastError()); ret = AppendMenuA( menubar, MF_POPUP|MF_STRING, (UINT_PTR)menu, "winetest"); - ok( ret, "AppendMenuA failed lasterror is %u\n", GetLastError()); + ok( ret, "AppendMenuA failed lasterror is %lu\n", GetLastError()); ret = SetMenu( hwnd, menubar ); - ok( ret, "SetMenu failed lasterror is %u\n", GetLastError()); + ok( ret, "SetMenu failed lasterror is %lu\n", GetLastError()); /* initiate tracking */ g_hwndtosend = hwnd; ret = SendMessageA( hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0 ); - ok( ret == 0, "Sending WM_SYSCOMMAND/SC_KEYMENU failed lasterror is %u\n", GetLastError()); + ok( ret == 0, "Sending WM_SYSCOMMAND/SC_KEYMENU failed lasterror is %lu\n", GetLastError()); while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); ok(g_got_enteridle == 0, "received %d WM_ENTERIDLE messages, none expected\n", g_got_enteridle); @@ -3563,7 +3546,7 @@ static void test_menu_maxdepth(void) if( !ret) break; } trace("Maximum depth is %d\n", i); - ok( GetLastError() == 12345678, "unexpected error %d\n", GetLastError()); + ok( GetLastError() == 12345678, "unexpected error %ld\n", GetLastError()); ok( i < NR_MENUS || broken( i == NR_MENUS), /* win98, NT */ "no ( or very large) limit on menu depth!\n"); @@ -3582,12 +3565,12 @@ static void test_menu_circref(void) menu2 = CreatePopupMenu(); ok( menu1 && menu2, "error creating menus.\n"); ret = AppendMenuA( menu1, MF_POPUP, (UINT_PTR)menu2, "winetest"); - ok( ret, "AppendMenu failed, error is %d\n", GetLastError()); + ok( ret, "AppendMenu failed, error is %ld\n", GetLastError()); ret = AppendMenuA( menu1, MF_STRING | MF_HILITE, 123, "winetest"); - ok( ret, "AppendMenu failed, error is %d\n", GetLastError()); + ok( ret, "AppendMenu failed, error is %ld\n", GetLastError()); /* app chooses an id that happens to clash with its own hmenu */ ret = AppendMenuA( menu2, MF_STRING, (UINT_PTR)menu2, "winetest"); - ok( ret, "AppendMenu failed, error is %d\n", GetLastError()); + ok( ret, "AppendMenu failed, error is %ld\n", GetLastError()); /* now attempt to change the string of the first item of menu1 */ ret = ModifyMenuA( menu1, (UINT_PTR)menu2, MF_POPUP, (UINT_PTR)menu2, "menu 2"); ok( !ret || @@ -3595,7 +3578,7 @@ static void test_menu_circref(void) "ModifyMenu should have failed.\n"); if( !ret) { /* will probably stack fault if the ModifyMenu succeeded */ ret = GetMenuState( menu1, 123, 0); - ok( ret == MF_HILITE, "GetMenuState returned %x\n",ret); + ok( ret == MF_HILITE, "GetMenuState returned %lx\n",ret); } DestroyMenu( menu2); DestroyMenu( menu1); @@ -3636,9 +3619,9 @@ static void test_menualign(void) mi.fMask = MIM_STYLE; ret = GetMenuInfo( menu, &mi); - ok( ret, "GetMenuInfo failed: %d\n", GetLastError()); + ok( ret, "GetMenuInfo failed: %ld\n", GetLastError()); ok( menu != NULL, "GetMenuInfo() failed\n"); - ok( 0 == mi.dwStyle, "menuinfo style is %x\n", mi.dwStyle); + ok( 0 == mi.dwStyle, "menuinfo style is %lx\n", mi.dwStyle); /* test 1 */ mii.fMask = MIIM_BITMAP | MIIM_STRING | MIIM_ID; @@ -3654,7 +3637,7 @@ static void test_menualign(void) ret = InsertMenuItemA( menu, -1, TRUE, &mii); ok( ret, "InsertMenuItem() failed\n"); ret = TrackPopupMenu( menu, TPM_RETURNCMD, 110, 200, 0, hwnd, NULL); - ok( ret != 2, "User indicated that menu text alignment test 1 failed %d\n", ret); + ok( ret != 2, "User indicated that menu text alignment test 1 failed %ld\n", ret); /* test 2*/ mii.fMask = MIIM_BITMAP | MIIM_STRING | MIIM_ID; mii.wID = 3; @@ -3676,7 +3659,7 @@ static void test_menualign(void) ret = SetMenuItemInfoA( menu, 2, TRUE, &mii); ok( ret, "SetMenuItemInfo() failed\n"); ret = TrackPopupMenu( menu, TPM_RETURNCMD, 110, 200, 0, hwnd, NULL); - ok( ret != 2, "User indicated that menu text alignment test 2 failed %d\n", ret); + ok( ret != 2, "User indicated that menu text alignment test 2 failed %ld\n", ret); /* test 3 */ mii.fMask = MIIM_TYPE | MIIM_ID; mii.wID = 3; @@ -3696,7 +3679,7 @@ static void test_menualign(void) ret = SetMenuItemInfoA( menu, 2, TRUE, &mii); ok( ret, "SetMenuItemInfo() failed\n"); ret = TrackPopupMenu( menu, TPM_RETURNCMD, 110, 200, 0, hwnd, NULL); - ok( ret != 2, "User indicated that menu text alignment test 3 failed %d\n", ret); + ok( ret != 2, "User indicated that menu text alignment test 3 failed %ld\n", ret); /* cleanup */ DeleteObject( hbm1); DeleteObject( hbm2); @@ -3746,11 +3729,11 @@ static void test_emptypopup(void) HWND hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL, WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, NULL, NULL, NULL, NULL); - ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); + ok(hwnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError()); SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_ownerdraw_wnd_proc); hmenu = CreatePopupMenu(); - ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); + ok(hmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError()); gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = gflag_enteridle = 0; selectitem_wp = 0xdeadbeef; @@ -3764,8 +3747,8 @@ static void test_emptypopup(void) ok(gflag_initmenu == 1, "got %i\n", gflag_initmenu); ok(gflag_enteridle == 0, "got %i\n", gflag_initmenu); - ok(selectitem_wp == 0xdeadbeef, "got %lx\n", selectitem_wp); - ok(selectitem_lp == 0xdeadbeef, "got %lx\n", selectitem_lp); + ok(selectitem_wp == 0xdeadbeef, "got %Ix\n", selectitem_wp); + ok(selectitem_lp == 0xdeadbeef, "got %Ix\n", selectitem_lp); gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = gflag_enteridle = 0; selectitem_wp = 0xdeadbeef; @@ -3779,8 +3762,8 @@ static void test_emptypopup(void) ok(gflag_initmenu == 1, "got %i\n", gflag_initmenu); ok(gflag_enteridle == 0, "got %i\n", gflag_initmenu); - ok(selectitem_wp == 0xdeadbeef, "got %lx\n", selectitem_wp); - ok(selectitem_lp == 0xdeadbeef, "got %lx\n", selectitem_lp); + ok(selectitem_wp == 0xdeadbeef, "got %Ix\n", selectitem_wp); + ok(selectitem_lp == 0xdeadbeef, "got %Ix\n", selectitem_lp); SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_fill_in_init); @@ -3796,13 +3779,13 @@ static void test_emptypopup(void) ok(gflag_initmenu == 1, "got %i\n", gflag_initmenu); ok(gflag_enteridle == 1, "got %i\n", gflag_initmenu); - ok(selectitem_wp == 0xffff0000, "got %lx\n", selectitem_wp); - ok(selectitem_lp == 0, "got %lx\n", selectitem_lp); + ok(selectitem_wp == 0xffff0000, "got %Ix\n", selectitem_wp); + ok(selectitem_lp == 0, "got %Ix\n", selectitem_lp); DestroyWindow(hwnd); ret = DestroyMenu(hmenu); - ok(ret, "DestroyMenu failed with error %d\n", GetLastError()); + ok(ret, "DestroyMenu failed with error %ld\n", GetLastError()); } static HMENU get_bad_hmenu( UINT_PTR id ) @@ -3961,7 +3944,7 @@ if (0) /* FIXME: uncomment once Wine is fixed */ { ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState); ok(mii.wID == 0, "expected 0, got %#x\n", mii.wID); ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); - ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData); + ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#Ix\n", mii.dwItemData); ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData); ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf); @@ -3977,7 +3960,7 @@ if (0) /* FIXME: uncomment once Wine is fixed */ { ok(mii.fState == 0x81818181, "expected 0x81818181, got %#x\n", mii.fState); ok(mii.wID == 0x81818181, "expected 0x81818181, got %#x\n", mii.wID); ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); - ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData); + ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#Ix\n", mii.dwItemData); ok(mii.dwTypeData == (LPSTR)hbmp, "expected %p, got %p\n", hbmp, mii.dwTypeData); ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); ok(mii.hbmpItem == hbmp, "expected %p, got %p\n", hbmp, mii.hbmpItem); @@ -3995,7 +3978,7 @@ if (0) /* FIXME: uncomment once Wine is fixed */ { ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState); ok(mii.wID == 0, "expected 0, got %#x\n", mii.wID); ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); - ok(mii.dwItemData == 0, "expected 0, got %#lx\n", mii.dwItemData); + ok(mii.dwItemData == 0, "expected 0, got %#Ix\n", mii.dwItemData); ok(mii.dwTypeData == (LPSTR)hbmp, "expected %p, got %p\n", hbmp, mii.dwTypeData); ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); ok(mii.hbmpItem == hbmp, "expected %p, got %p\n", hbmp, mii.hbmpItem); @@ -4028,7 +4011,7 @@ if (0) /* FIXME: uncomment once Wine is fixed */ { ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState); ok(mii.wID == 0, "expected 0, got %#x\n", mii.wID); ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); - ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData); + ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#Ix\n", mii.dwItemData); ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData); ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf); @@ -4046,7 +4029,7 @@ if (0) /* FIXME: uncomment once Wine is fixed */ { ok(mii.fState == 0x81818181, "expected 0x81818181, got %#x\n", mii.fState); ok(mii.wID == 0x81818181, "expected 0x81818181, got %#x\n", mii.wID); ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); - ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData); + ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#Ix\n", mii.dwItemData); ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData); ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf); @@ -4065,7 +4048,7 @@ if (0) /* FIXME: uncomment once Wine is fixed */ { ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState); ok(mii.wID == 0, "expected 0, got %#x\n", mii.wID); ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); - ok(mii.dwItemData == 0, "expected 0, got %#lx\n", mii.dwItemData); + ok(mii.dwItemData == 0, "expected 0, got %#Ix\n", mii.dwItemData); ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData); ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf); @@ -4100,7 +4083,7 @@ if (0) /* FIXME: uncomment once Wine is fixed */ { ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState); ok(mii.wID == 0, "expected 0, got %#x\n", mii.wID); ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); - ok(mii.dwItemData == (ULONG_PTR)hbmp, "expected %p, got %#lx\n", hbmp, mii.dwItemData); + ok(mii.dwItemData == (ULONG_PTR)hbmp, "expected %p, got %#Ix\n", hbmp, mii.dwItemData); ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData); ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf); @@ -4119,7 +4102,7 @@ if (0) /* FIXME: uncomment once Wine is fixed */ { ok(mii.fState == 0x81818181, "expected 0x81818181, got %#x\n", mii.fState); ok(mii.wID == 0x81818181, "expected 0x81818181, got %#x\n", mii.wID); ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); - ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData); + ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#Ix\n", mii.dwItemData); ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData); ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf); @@ -4152,7 +4135,7 @@ if (0) /* FIXME: uncomment once Wine is fixed */ { ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState); ok(mii.wID == 0, "expected 0, got %#x\n", mii.wID); ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); - ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData); + ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#Ix\n", mii.dwItemData); ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData); ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf); @@ -4176,7 +4159,7 @@ if (0) /* FIXME: uncomment once Wine is fixed */ { ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState); ok(mii.wID == 0, "expected 0, got %#x\n", mii.wID); ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); - ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData); + ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#Ix\n", mii.dwItemData); ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData); ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf); @@ -4195,7 +4178,7 @@ if (0) /* FIXME: uncomment once Wine is fixed */ { ok(mii.fState == 0x81818181, "expected 0x81818181, got %#x\n", mii.fState); ok(mii.wID == 0x81818181, "expected 0x81818181, got %#x\n", mii.wID); ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); - ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData); + ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#Ix\n", mii.dwItemData); ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData); ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf); @@ -4219,7 +4202,7 @@ if (0) /* FIXME: uncomment once Wine is fixed */ { ok(mii.fState == MF_ENABLED, "expected MF_ENABLED, got %#x\n", mii.fState); ok(mii.wID == 0, "expected 0, got %#x\n", mii.wID); ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); - ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData); + ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#Ix\n", mii.dwItemData); ok(mii.dwTypeData == buf, "expected %p, got %p\n", buf, mii.dwTypeData); ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); ok(!strcmp(buf, string), "expected %s, got %s\n", string, buf); @@ -4238,7 +4221,7 @@ if (0) /* FIXME: uncomment once Wine is fixed */ { ok(mii.fState == 0x81818181, "expected 0x81818181, got %#x\n", mii.fState); ok(mii.wID == 0x81818181, "expected 0x81818181, got %#x\n", mii.wID); ok(mii.hSubMenu == 0, "expected 0, got %p\n", mii.hSubMenu); - ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#lx\n", mii.dwItemData); + ok(mii.dwItemData == 0x81818181, "expected 0x81818181, got %#Ix\n", mii.dwItemData); ok(mii.dwTypeData == (LPSTR)hbmp, "expected %p, got %p\n", hbmp, mii.dwTypeData); ok(mii.cch == 6, "expected 6, got %u\n", mii.cch); ok(mii.hbmpItem == hbmp, "expected %p, got %p\n", hbmp, mii.hbmpItem); diff --git a/modules/rostests/winetests/user32/monitor.c b/modules/rostests/winetests/user32/monitor.c index 26ee28a122d..f58f35b66d9 100644 --- a/modules/rostests/winetests/user32/monitor.c +++ b/modules/rostests/winetests/user32/monitor.c @@ -3,6 +3,7 @@ * * Copyright 2005 Huw Davies * Copyright 2008 Dmitry Timoshkov + * Copyright 2019-2022 Zhiyi Zhang for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,61 +20,129 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "ntstatus.h" +#define WIN32_NO_STATUS + +#include "initguid.h" + #include "wine/test.h" #include "winbase.h" #include "wingdi.h" #include "winuser.h" #include "winreg.h" +#ifndef __REACTOS__ +#include "winternl.h" +#endif +#include "ddk/d3dkmthk.h" +#include "setupapi.h" +#include "shellscalingapi.h" +#include "ntddvdeo.h" #include +#include + +#ifdef __REACTOS__ +#include "devpropdef.h" + +typedef struct DISPLAYCONFIG_GET_SOURCE_DPI_SCALE +{ + DISPLAYCONFIG_DEVICE_INFO_HEADER header; + int minRelativeScaleStep; /* Minimum scale step relative to the recommended scale */ + int curRelativeScaleStep; /* Current scale step relative to the recommended scale */ + int maxRelativeScaleStep; /* Maximum scale step relative to the recommended scale */ +} DISPLAYCONFIG_GET_SOURCE_DPI_SCALE; +typedef struct DISPLAYCONFIG_SET_SOURCE_DPI_SCALE +{ + DISPLAYCONFIG_DEVICE_INFO_HEADER header; + int relativeScaleStep; /* Target scale step relative to the recommended scale */ +} DISPLAYCONFIG_SET_SOURCE_DPI_SCALE; +#endif + +DEFINE_DEVPROPKEY(DEVPROPKEY_MONITOR_GPU_LUID, 0xca085853, 0x16ce, 0x48aa, 0xb1, 0x14, 0xde, 0x9c, 0x72, 0x33, 0x42, 0x23, 1); +DEFINE_DEVPROPKEY(DEVPROPKEY_MONITOR_OUTPUT_ID, 0xca085853, 0x16ce, 0x48aa, 0xb1, 0x14, 0xde, 0x9c, 0x72, 0x33, 0x42, 0x23, 2); -static HMODULE hdll; -static LONG (WINAPI *pChangeDisplaySettingsExA)(LPCSTR, LPDEVMODEA, HWND, DWORD, LPVOID); -static LONG (WINAPI *pChangeDisplaySettingsExW)(LPCWSTR, LPDEVMODEW, HWND, DWORD, LPVOID); -static BOOL (WINAPI *pEnumDisplayDevicesA)(LPCSTR,DWORD,LPDISPLAY_DEVICEA,DWORD); -static BOOL (WINAPI *pEnumDisplayMonitors)(HDC,LPRECT,MONITORENUMPROC,LPARAM); -static BOOL (WINAPI *pGetMonitorInfoA)(HMONITOR,LPMONITORINFO); -static BOOL (WINAPI *pGetMonitorInfoW)(HMONITOR,LPMONITORINFO); -static HMONITOR (WINAPI *pMonitorFromPoint)(POINT,DWORD); -static HMONITOR (WINAPI *pMonitorFromRect)(LPCRECT,DWORD); -static HMONITOR (WINAPI *pMonitorFromWindow)(HWND,DWORD); static LONG (WINAPI *pGetDisplayConfigBufferSizes)(UINT32,UINT32*,UINT32*); +static BOOL (WINAPI *pGetDpiForMonitorInternal)(HMONITOR,UINT,UINT*,UINT*); +static LONG (WINAPI *pQueryDisplayConfig)(UINT32,UINT32*,DISPLAYCONFIG_PATH_INFO*,UINT32*, + DISPLAYCONFIG_MODE_INFO*,DISPLAYCONFIG_TOPOLOGY_ID*); +static LONG (WINAPI *pDisplayConfigGetDeviceInfo)(DISPLAYCONFIG_DEVICE_INFO_HEADER*); +static LONG (WINAPI *pDisplayConfigSetDeviceInfo)(DISPLAYCONFIG_DEVICE_INFO_HEADER*); +static DPI_AWARENESS_CONTEXT (WINAPI *pSetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); +static DPI_AWARENESS_CONTEXT (WINAPI *pGetThreadDpiAwarenessContext)(void); +static DPI_AWARENESS_CONTEXT (WINAPI *pGetWindowDpiAwarenessContext)(HWND); +static UINT (WINAPI *pGetDpiForSystem)(void); +static UINT (WINAPI *pGetDpiForWindow)(HWND); +static BOOL (WINAPI *pLogicalToPhysicalPointForPerMonitorDPI)(HWND,POINT*); +static BOOL (WINAPI *pPhysicalToLogicalPointForPerMonitorDPI)(HWND,POINT*); + +static NTSTATUS (WINAPI *pD3DKMTCloseAdapter)(const D3DKMT_CLOSEADAPTER*); +static NTSTATUS (WINAPI *pD3DKMTOpenAdapterFromGdiDisplayName)(D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME*); static void init_function_pointers(void) { - hdll = GetModuleHandleA("user32.dll"); + HMODULE user32 = GetModuleHandleA("user32.dll"); + HMODULE gdi32 = GetModuleHandleA("gdi32.dll"); -#define GET_PROC(func) \ - p ## func = (void*)GetProcAddress(hdll, #func); \ - if(!p ## func) \ - trace("GetProcAddress(%s) failed\n", #func); +#define GET_PROC(module, func) \ + p##func = (void *)GetProcAddress(module, #func); \ + if (!p##func) \ + trace("GetProcAddress(%s, %s) failed.\n", #module, #func); - GET_PROC(ChangeDisplaySettingsExA) - GET_PROC(ChangeDisplaySettingsExW) - GET_PROC(EnumDisplayDevicesA) - GET_PROC(EnumDisplayMonitors) - GET_PROC(GetDisplayConfigBufferSizes) - GET_PROC(GetMonitorInfoA) - GET_PROC(GetMonitorInfoW) - GET_PROC(MonitorFromPoint) - GET_PROC(MonitorFromRect) - GET_PROC(MonitorFromWindow) + GET_PROC(user32, GetDisplayConfigBufferSizes) + GET_PROC(user32, GetDpiForMonitorInternal) + GET_PROC(user32, QueryDisplayConfig) + GET_PROC(user32, DisplayConfigGetDeviceInfo) + GET_PROC(user32, DisplayConfigSetDeviceInfo) + GET_PROC(user32, SetThreadDpiAwarenessContext) + GET_PROC(user32, GetThreadDpiAwarenessContext) + GET_PROC(user32, GetWindowDpiAwarenessContext) + GET_PROC(user32, GetDpiForSystem) + GET_PROC(user32, GetDpiForWindow) + GET_PROC(user32, LogicalToPhysicalPointForPerMonitorDPI) + GET_PROC(user32, PhysicalToLogicalPointForPerMonitorDPI) + + GET_PROC(gdi32, D3DKMTCloseAdapter) + GET_PROC(gdi32, D3DKMTOpenAdapterFromGdiDisplayName) #undef GET_PROC } -static BOOL CALLBACK monitor_enum_proc(HMONITOR hmon, HDC hdc, LPRECT lprc, - LPARAM lparam) +static void flush_events(void) { - MONITORINFOEXA mi; - char *primary = (char *)lparam; + int diff = 1000; + DWORD time; + MSG msg; - mi.cbSize = sizeof(mi); + time = GetTickCount() + diff; + while (diff > 0) + { + if (MsgWaitForMultipleObjects(0, NULL, FALSE, 200, QS_ALLINPUT) == WAIT_TIMEOUT) + break; + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) + DispatchMessageA(&msg); + diff = time - GetTickCount(); + } +} - ok(pGetMonitorInfoA(hmon, (MONITORINFO*)&mi), "GetMonitorInfo failed\n"); - if (mi.dwFlags & MONITORINFOF_PRIMARY) - strcpy(primary, mi.szDevice); +static unsigned int get_primary_dpi(void) +{ + DPI_AWARENESS_CONTEXT old_context; + UINT dpi_x = 0, dpi_y = 0; + POINT point = {0, 0}; + HMONITOR monitor; - return TRUE; + if (!pSetThreadDpiAwarenessContext || !pGetDpiForMonitorInternal) + return 0; + + old_context = pSetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE); + monitor = MonitorFromPoint(point, MONITOR_DEFAULTTOPRIMARY); + pGetDpiForMonitorInternal(monitor, 0, &dpi_x, &dpi_y); + pSetThreadDpiAwarenessContext(old_context); + return dpi_y; +} + +static int get_bitmap_stride(int width, int bpp) +{ + return ((width * bpp + 15) >> 3) & ~1; } static int adapter_count = 0; @@ -81,19 +150,13 @@ static int monitor_count = 0; static void test_enumdisplaydevices_adapter(int index, const DISPLAY_DEVICEA *device, DWORD flags) { - char video_name[32]; - char video_value[128]; char buffer[128]; int number; int vendor_id; int device_id; int subsys_id; int revision_id; - size_t length; - HKEY hkey; HDC hdc; - DWORD size; - LSTATUS ls; adapter_count++; @@ -102,42 +165,21 @@ static void test_enumdisplaydevices_adapter(int index, const DISPLAY_DEVICEA *de device->DeviceName); /* DeviceKey */ - /* win7 is the only OS version where \Device\Video? value in HLKM\HARDWARE\DEVICEMAP\VIDEO are not in order with adapter index. */ - if (GetVersion() != 0x1db10106 || !strcmp(winetest_platform, "wine")) - { - sprintf(video_name, "\\Device\\Video%d", index); - ls = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\VIDEO", 0, KEY_READ, &hkey); - ok(!ls, "#%d: failed to open registry, error: %#x\n", index, ls); - if (!ls) - { - memset(video_value, 0, sizeof(video_value)); - size = sizeof(video_value); - ls = RegQueryValueExA(hkey, video_name, NULL, NULL, (unsigned char *)video_value, &size); - ok(!ls, "#%d: failed to get registry value, error: %#x\n", index, ls); - RegCloseKey(hkey); - ok(!strcmp(video_value, device->DeviceKey), "#%d: wrong DeviceKey: %s\n", index, device->DeviceKey); - } - } - else - ok(sscanf(device->DeviceKey, "\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Video\\%[^\\]\\%04d", buffer, &number) == 2, - "#%d: wrong DeviceKey %s\n", index, device->DeviceKey); + /* \Device\Video? value in HLKM\HARDWARE\DEVICEMAP\VIDEO are not necessarily in order with adapter index. + * Check format only */ + ok(sscanf(device->DeviceKey, "\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Video\\%[^\\]\\%04d", buffer, &number) == 2, + "#%d: wrong DeviceKey %s\n", index, device->DeviceKey); /* DeviceString */ - length = strlen(device->DeviceString); - ok(broken(length == 0) || /* XP on Testbot will return an empty string, whereas XP on real machine doesn't. Probably a bug in virtual adapter driver */ - length > 0, "#%d: expect DeviceString not empty\n", index); + ok(broken(!*device->DeviceString) || /* XP on Testbot will return an empty string, whereas XP on real machine doesn't. Probably a bug in virtual adapter driver */ + *device->DeviceString, "#%d: expect DeviceString not empty\n", index); /* StateFlags */ - if (index == 0) - ok(device->StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE, "#%d: adapter should be primary\n", index); - else - ok(!(device->StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE), "#%d: adapter should not be primary\n", index); - if (device->StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) { /* Test creating DC */ hdc = CreateDCA(device->DeviceName, NULL, NULL, NULL); - ok(hdc != NULL, "#%d: failed to CreateDC(\"%s\") err=%d\n", index, device->DeviceName, GetLastError()); + ok(hdc != NULL, "#%d: failed to CreateDC(\"%s\") err=%ld\n", index, device->DeviceName, GetLastError()); DeleteDC(hdc); } @@ -158,10 +200,9 @@ static void test_enumdisplaydevices_adapter(int index, const DISPLAY_DEVICEA *de } } -static void test_enumdisplaydevices_monitor(int adapter_index, int monitor_index, const char *adapter_name, - const DISPLAY_DEVICEA *device, DWORD flags) +static void test_enumdisplaydevices_monitor(int monitor_index, const char *adapter_name, + DISPLAY_DEVICEA *device, DWORD flags) { - static const char device_id_prefix[] = "MONITOR\\Default_Monitor\\{4d36e96e-e325-11ce-bfc1-08002be10318}\\"; static const char device_key_prefix[] = "\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class" "\\{4d36e96e-e325-11ce-bfc1-08002be10318}\\"; char monitor_name[32]; @@ -176,34 +217,29 @@ static void test_enumdisplaydevices_monitor(int adapter_index, int monitor_index ok(!strcmp(monitor_name, device->DeviceName), "#%d: expect %s, got %s\n", monitor_index, monitor_name, device->DeviceName); /* DeviceString */ - ok(strlen(device->DeviceString) > 0, "#%d: expect DeviceString not empty\n", monitor_index); + ok(*device->DeviceString, "#%d: expect DeviceString not empty\n", monitor_index); /* StateFlags */ - if (adapter_index == 0 && monitor_index == 0) - ok(device->StateFlags & DISPLAY_DEVICE_ATTACHED, "#%d expect to have a primary monitor attached\n", monitor_index); - else - ok(device->StateFlags <= (DISPLAY_DEVICE_ATTACHED | DISPLAY_DEVICE_ACTIVE), "#%d wrong state %#x\n", monitor_index, - device->StateFlags); + ok(device->StateFlags <= (DISPLAY_DEVICE_ATTACHED | DISPLAY_DEVICE_ACTIVE), + "#%d wrong state %#lx\n", monitor_index, device->StateFlags); /* DeviceID */ - lstrcpynA(buffer, device->DeviceID, sizeof(device_id_prefix)); + CharLowerA(device->DeviceID); if (flags & EDD_GET_DEVICE_INTERFACE_NAME) - { /* HKLM\SYSTEM\CurrentControlSet\Enum\DISPLAY\Default_Monitor\4&2abfaa30&0&UID0 GUID_DEVINTERFACE_MONITOR - * ^ ^ ^ - * Expect format \\?\DISPLAY#Default_Monitor#4&2abfaa30&0&UID0#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7} */ + { /* HKLM\SYSTEM\CurrentControlSet\Enum\DISPLAY\[monitor name]\[instance id] GUID_DEVINTERFACE_MONITOR + * ^ ^ ^ + * Expect format \\?\DISPLAY#[monitor name]#[instance id]#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7} */ ok(strlen(device->DeviceID) == 0 || /* vista ~ win7 */ - sscanf(device->DeviceID, "\\\\?\\DISPLAY#Default_Monitor#%[^#]#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}", buffer) == 1 || /* win8+ */ - (!lstrcmpiA(buffer, device_id_prefix) && - sscanf(device->DeviceID + sizeof(device_id_prefix) - 1, "%04d", &number) == 1), /* XP/2003 ignores EDD_GET_DEVICE_INTERFACE_NAME */ - "#%d: wrong DeviceID : %s\n", monitor_index, device->DeviceID); + sscanf(device->DeviceID, "\\\\?\\display#%[^#]#%[^#]#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}", buffer, buffer) == 2 || /* win8+ */ + sscanf(device->DeviceID, "monitor\\%[^\\]\\{4d36e96e-e325-11ce-bfc1-08002be10318}\\%04d", buffer, &number) == 2, /* XP/2003 ignores EDD_GET_DEVICE_INTERFACE_NAME */ + "#%d: wrong DeviceID : %s\n", monitor_index, device->DeviceID); } else { - /* Expect HarewareID value data + Driver value data in HKLM\SYSTEM\CurrentControlSet\Enum\DISPLAY\Default_Monitor\{Instance} */ + /* Expect HarewareID value data + Driver value data in HKLM\SYSTEM\CurrentControlSet\Enum\DISPLAY\[monitor name]\{instance} */ /* But we don't know which monitor instance this belongs to, so check format instead */ - ok(!lstrcmpiA(buffer, device_id_prefix), "#%d wrong DeviceID : %s\n", monitor_index, device->DeviceID); - ok(sscanf(device->DeviceID + sizeof(device_id_prefix) - 1, "%04d", &number) == 1, - "#%d wrong DeviceID : %s\n", monitor_index, device->DeviceID); + ok(sscanf(device->DeviceID, "monitor\\%[^\\]\\{4d36e96e-e325-11ce-bfc1-08002be10318}\\%04d", buffer, &number) == 2, + "#%d: wrong DeviceID : %s\n", monitor_index, device->DeviceID); } /* DeviceKey */ @@ -217,8 +253,6 @@ static void test_enumdisplaydevices(void) { static const DWORD flags[] = {0, EDD_GET_DEVICE_INTERFACE_NAME}; DISPLAY_DEVICEA dd; - char primary_device_name[32]; - char primary_monitor_device_name[32]; char adapter_name[32]; int number; int flag_index; @@ -226,20 +260,14 @@ static void test_enumdisplaydevices(void) int monitor_index; BOOL ret; - if (!pEnumDisplayDevicesA) - { - win_skip("EnumDisplayDevicesA is not available\n"); - return; - } - /* Doesn't accept \\.\DISPLAY */ dd.cb = sizeof(dd); - ret = pEnumDisplayDevicesA("\\\\.\\DISPLAY", 0, &dd, 0); + ret = EnumDisplayDevicesA("\\\\.\\DISPLAY", 0, &dd, 0); ok(!ret, "Expect failure\n"); /* Enumeration */ for (flag_index = 0; flag_index < ARRAY_SIZE(flags); flag_index++) - for (adapter_index = 0; pEnumDisplayDevicesA(NULL, adapter_index, &dd, flags[flag_index]); adapter_index++) + for (adapter_index = 0; EnumDisplayDevicesA(NULL, adapter_index, &dd, flags[flag_index]); adapter_index++) { lstrcpyA(adapter_name, dd.DeviceName); @@ -251,31 +279,14 @@ static void test_enumdisplaydevices(void) test_enumdisplaydevices_adapter(adapter_index, &dd, flags[flag_index]); - for (monitor_index = 0; pEnumDisplayDevicesA(adapter_name, monitor_index, &dd, flags[flag_index]); + for (monitor_index = 0; EnumDisplayDevicesA(adapter_name, monitor_index, &dd, flags[flag_index]); monitor_index++) - test_enumdisplaydevices_monitor(adapter_index, monitor_index, adapter_name, &dd, flags[flag_index]); + test_enumdisplaydevices_monitor(monitor_index, adapter_name, &dd, flags[flag_index]); } ok(adapter_count > 0, "Expect at least one adapter found\n"); /* XP on Testbot doesn't report a monitor, whereas XP on real machine does */ ok(broken(monitor_count == 0) || monitor_count > 0, "Expect at least one monitor found\n"); - - if (!pEnumDisplayMonitors || !pGetMonitorInfoA) - { - win_skip("EnumDisplayMonitors or GetMonitorInfoA are not available\n"); - return; - } - - ret = pEnumDisplayDevicesA(NULL, 0, &dd, 0); - ok(ret, "Expect success\n"); - lstrcpyA(primary_device_name, dd.DeviceName); - - primary_monitor_device_name[0] = 0; - ret = pEnumDisplayMonitors(NULL, NULL, monitor_enum_proc, (LPARAM)primary_monitor_device_name); - ok(ret, "EnumDisplayMonitors failed\n"); - ok(!strcmp(primary_monitor_device_name, primary_device_name), - "monitor device name %s, device name %s\n", primary_monitor_device_name, - primary_device_name); } struct vid_mode @@ -285,108 +296,237 @@ struct vid_mode }; static const struct vid_mode vid_modes_test[] = { - {640, 480, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY, 0}, - {640, 480, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY, 1}, - {640, 480, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL , 0}, - {640, 480, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT , 1}, - {640, 480, 0, 0, DM_BITSPERPEL , 0}, - {640, 480, 0, 0, DM_DISPLAYFREQUENCY, 0}, + {1024, 768, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY, 0}, + {1024, 768, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY, 1}, + {1024, 768, 0, 1, DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY, 0}, + {1024, 768, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL , 0}, + {1024, 768, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT , 1}, + {1024, 768, 0, 0, DM_BITSPERPEL , 0}, + {1024, 768, 0, 0, DM_DISPLAYFREQUENCY, 0}, {0, 0, 0, 0, DM_PELSWIDTH, 0}, {0, 0, 0, 0, DM_PELSHEIGHT, 0}, - {640, 480, 0, 0, DM_PELSWIDTH, 0}, - {640, 480, 0, 0, DM_PELSHEIGHT, 0}, - { 0, 480, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT, 0}, - {640, 0, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT, 0}, + {1024, 768, 0, 0, DM_PELSWIDTH, 0}, + {1024, 768, 0, 0, DM_PELSHEIGHT, 0}, + { 0, 768, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT, 0}, + {1024, 0, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT, 0}, /* the following test succeeds under XP SP3 {0, 0, 0, 0, DM_DISPLAYFREQUENCY, 0} */ }; -static void test_ChangeDisplaySettingsEx(void) +struct device_info +{ + DWORD index; + CHAR name[CCHDEVICENAME]; + DEVMODEA original_mode; +}; + +#define expect_dm(a, b, c) _expect_dm(__LINE__, a, b, c) +static void _expect_dm(INT line, const DEVMODEA *expected, const CHAR *device, DWORD test) { DEVMODEA dm; + BOOL ret; + + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + SetLastError(0xdeadbeef); + ret = EnumDisplaySettingsA(device, ENUM_CURRENT_SETTINGS, &dm); + ok_(__FILE__, line)(ret, "Device %s test %ld EnumDisplaySettingsA failed, error %#lx\n", device, test, GetLastError()); + + ok_(__FILE__, line)((dm.dmFields & expected->dmFields) == expected->dmFields, + "Device %s test %ld expect dmFields to contain %#lx, got %#lx\n", device, test, expected->dmFields, dm.dmFields); + ok_(__FILE__, line)(!(expected->dmFields & DM_BITSPERPEL) || dm.dmBitsPerPel == expected->dmBitsPerPel, + "Device %s test %ld expect dmBitsPerPel %lu, got %lu\n", device, test, expected->dmBitsPerPel, dm.dmBitsPerPel); + ok_(__FILE__, line)(!(expected->dmFields & DM_PELSWIDTH) || dm.dmPelsWidth == expected->dmPelsWidth, + "Device %s test %ld expect dmPelsWidth %lu, got %lu\n", device, test, expected->dmPelsWidth, dm.dmPelsWidth); + ok_(__FILE__, line)(!(expected->dmFields & DM_PELSHEIGHT) || dm.dmPelsHeight == expected->dmPelsHeight, + "Device %s test %ld expect dmPelsHeight %lu, got %lu\n", device, test, expected->dmPelsHeight, dm.dmPelsHeight); + ok_(__FILE__, line)(!(expected->dmFields & DM_POSITION) || dm.dmPosition.x == expected->dmPosition.x, + "Device %s test %ld expect dmPosition.x %ld, got %ld\n", device, test, expected->dmPosition.x, dm.dmPosition.x); + ok_(__FILE__, line)(!(expected->dmFields & DM_POSITION) || dm.dmPosition.y == expected->dmPosition.y, + "Device %s test %ld expect dmPosition.y %ld, got %ld\n", device, test, expected->dmPosition.y, dm.dmPosition.y); + ok_(__FILE__, line)(!(expected->dmFields & DM_DISPLAYFREQUENCY) || + dm.dmDisplayFrequency == expected->dmDisplayFrequency, + "Device %s test %ld expect dmDisplayFrequency %lu, got %lu\n", device, test, expected->dmDisplayFrequency, + dm.dmDisplayFrequency); + ok_(__FILE__, line)(!(expected->dmFields & DM_DISPLAYORIENTATION) || + dm.dmDisplayOrientation == expected->dmDisplayOrientation, + "Device %s test %ld expect dmDisplayOrientation %ld, got %ld\n", device, test, expected->dmDisplayOrientation, + dm.dmDisplayOrientation); +} + +#define wait_for_dm(a, b, c) wait_for_dm_(__LINE__, a, b, c) +static void wait_for_dm_(int line, const char *device, DWORD expected_width, DWORD expected_height) +{ + DEVMODEA dm; + BOOL ret; + int i; + + for (i = 0; i < 50; ++i) + { + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + SetLastError(0xdeadbeef); + ret = EnumDisplaySettingsA(device, ENUM_CURRENT_SETTINGS, &dm); + ok_(__FILE__, line)(ret, "Device %s EnumDisplaySettingsA failed, error %#lx\n", device, GetLastError()); + + if (dm.dmPelsWidth == expected_width && dm.dmPelsHeight == expected_height) + break; + + Sleep(100); + } + + ok_(__FILE__, line)(dm.dmPelsWidth == expected_width, + "Device %s expect dmPelsWidth %lu, got %lu\n", device, expected_width, dm.dmPelsWidth); + ok_(__FILE__, line)(dm.dmPelsHeight == expected_height, + "Device %s expect dmPelsHeight %lu, got %lu\n", device, expected_height, dm.dmPelsHeight); +} + +static HANDLE test_child_process_ChangeDisplaySettingsEx(const char *argv0, const char *device, DWORD flags, const char *exit_event_name) +{ + static const char *cds_event_name = "test_child_process_cds_event"; + PROCESS_INFORMATION info; + char buffer[MAX_PATH]; + STARTUPINFOA startup; + DWORD wait_result; + HANDLE cds_event; + LONG res; + + cds_event = CreateEventA(NULL, FALSE, FALSE, cds_event_name); + ok(!!cds_event, "CreateEventA failed, error %#lx\n", GetLastError()); + + memset(&startup, 0, sizeof(startup)); + startup.cb = sizeof(startup); + + snprintf(buffer, sizeof(buffer), "%s monitor fullscreen %s %#lx %s %s", argv0, device, flags, + cds_event_name, exit_event_name); + res = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info); + ok(res, "CreateProcessA returned unexpected %ld\n", res); + wait_result = WaitForSingleObject(cds_event, 5000); + ok(wait_result == WAIT_OBJECT_0, "WaitForSingleObject returned %lx.\n", wait_result); + + CloseHandle(cds_event); + CloseHandle(info.hThread); + + return info.hProcess; +} + +static void test_ChangeDisplaySettingsEx(int argc, char **argv) +{ + static const DWORD registry_fields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | + DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION; + static const char *exit_event0_name = "test_cds_exit_event0"; + static const char *exit_event1_name = "test_cds_exit_event1"; + static const DWORD depths[] = {8, 16, 32}; + DPI_AWARENESS_CONTEXT context = NULL; + UINT primary, device, test, mode; + HANDLE exit_event0, exit_event1; + UINT device_size, device_count; + struct device_info *devices; + HANDLE process0, process1; + DEVMODEA dm, dm2, dm3; + INT count, old_count; + DISPLAY_DEVICEA dd; + DWORD wait_result; + POINTL position; DEVMODEW dmW; - DWORD width; + BOOL found; LONG res; int i; - if (!pChangeDisplaySettingsExA) - { - win_skip("ChangeDisplaySettingsExA is not available\n"); - return; - } - - SetLastError(0xdeadbeef); + /* Test invalid device names */ + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); res = EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &dm); - ok(res, "EnumDisplaySettings error %u\n", GetLastError()); + ok(res, "EnumDisplaySettingsA failed, error %#lx\n", GetLastError()); - width = dm.dmPelsWidth; + res = ChangeDisplaySettingsExA("invalid", &dm, NULL, CDS_TEST, NULL); + ok(res == DISP_CHANGE_BADPARAM, "ChangeDisplaySettingsA returned unexpected %ld\n", res); - dm.dmDriverExtra = 1; - res = ChangeDisplaySettingsA(&dm, CDS_TEST); - ok(res == DISP_CHANGE_SUCCESSFUL, - "ChangeDisplaySettingsA returned %d, expected DISP_CHANGE_SUCCESSFUL\n", res); - ok(dm.dmDriverExtra == 0 || broken(dm.dmDriverExtra == 1) /* win9x */, - "ChangeDisplaySettingsA didn't reset dmDriverExtra to 0\n"); + res = ChangeDisplaySettingsExA("\\\\.\\DISPLAY0", &dm, NULL, CDS_TEST, NULL); + ok(res == DISP_CHANGE_BADPARAM, "ChangeDisplaySettingsA returned unexpected %ld\n", res); - /* crashes under XP SP3 for large dmDriverExtra values */ - dm.dmDriverExtra = 1; - res = pChangeDisplaySettingsExA(NULL, &dm, NULL, CDS_TEST, NULL); - ok(res == DISP_CHANGE_SUCCESSFUL, - "ChangeDisplaySettingsExW returned %d, expected DISP_CHANGE_SUCCESSFUL\n", res); - ok(dm.dmDriverExtra == 1, "ChangeDisplaySettingsExA shouldn't reset dmDriverExtra to 0\n"); + res = ChangeDisplaySettingsExA("\\\\.\\DISPLAY1\\Monitor0", &dm, NULL, CDS_TEST, NULL); + ok(res == DISP_CHANGE_BADPARAM, "ChangeDisplaySettingsA returned unexpected %ld\n", res); + + /* Test dmDriverExtra */ + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + res = EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &dm); + ok(res, "EnumDisplaySettingsA failed, error %#lx\n", GetLastError()); memset(&dmW, 0, sizeof(dmW)); dmW.dmSize = sizeof(dmW); - dmW.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; - dmW.dmPelsWidth = dm.dmPelsWidth; - dmW.dmPelsHeight = dm.dmPelsHeight; + res = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &dmW); + ok(res, "EnumDisplaySettingsW failed, error %#lx\n", GetLastError()); + + /* ChangeDisplaySettingsA/W reset dmDriverExtra to 0 */ + dm.dmDriverExtra = 1; + res = ChangeDisplaySettingsA(&dm, CDS_TEST); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsA returned unexpected %ld\n", res); + ok(dm.dmDriverExtra == 0, "ChangeDisplaySettingsA didn't reset dmDriverExtra to 0\n"); + dmW.dmDriverExtra = 1; - SetLastError(0xdeadbeef); res = ChangeDisplaySettingsW(&dmW, CDS_TEST); - if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) - { - ok(res == DISP_CHANGE_SUCCESSFUL, - "ChangeDisplaySettingsW returned %d, expected DISP_CHANGE_SUCCESSFUL\n", res); - ok(dmW.dmDriverExtra == 0, "ChangeDisplaySettingsW didn't reset dmDriverExtra to 0\n"); - } + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW returned unexpected %ld\n", res); + ok(dmW.dmDriverExtra == 0, "ChangeDisplaySettingsW didn't reset dmDriverExtra to 0\n"); + + /* ChangeDisplaySettingsExA/W do not modify dmDriverExtra */ + dm.dmDriverExtra = 1; + res = ChangeDisplaySettingsExA(NULL, &dm, NULL, CDS_TEST, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA returned unexpected %ld\n", res); + ok(dm.dmDriverExtra == 1, "ChangeDisplaySettingsExA shouldn't change dmDriverExtra\n"); - /* Apparently XP treats dmDriverExtra being != 0 as an error */ dmW.dmDriverExtra = 1; - res = pChangeDisplaySettingsExW(NULL, &dmW, NULL, CDS_TEST, NULL); - if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) - { - ok(res == DISP_CHANGE_SUCCESSFUL, - "ChangeDisplaySettingsExW returned %d, expected DISP_CHANGE_SUCCESSFUL\n", res); - ok(dmW.dmDriverExtra == 1, "ChangeDisplaySettingsExW shouldn't reset dmDriverExtra to 0\n"); - } + res = ChangeDisplaySettingsExW(NULL, &dmW, NULL, CDS_TEST, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW returned unexpected %ld\n", res); + ok(dmW.dmDriverExtra == 1, "ChangeDisplaySettingsExW shouldn't change dmDriverExtra\n"); - /* the following 2 tests show that dm.dmSize being 0 is invalid, but - * ChangeDisplaySettingsExA still reports success. - */ + /* Test dmSize */ + /* ChangeDisplaySettingsA/ExA report success even if dmSize is 0 */ memset(&dm, 0, sizeof(dm)); - dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; - dm.dmPelsWidth = width; - res = pChangeDisplaySettingsExA(NULL, &dm, NULL, CDS_TEST, NULL); - ok(res == DISP_CHANGE_SUCCESSFUL || - res == DISP_CHANGE_BADMODE || /* Win98, WinMe */ - res == DISP_CHANGE_FAILED, /* NT4 */ - "ChangeDisplaySettingsExA returned unexpected %d\n", res); + dm.dmSize = sizeof(dm); + res = EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &dm); + ok(res, "EnumDisplaySettingsA failed, error %#lx\n", GetLastError()); + dm.dmSize = 0; + res = ChangeDisplaySettingsA(&dm, CDS_TEST); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsA returned unexpected %ld\n", res); + + dm.dmSize = 0; + res = ChangeDisplaySettingsExA(NULL, &dm, NULL, CDS_TEST, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA returned unexpected %ld\n", res); + + /* dmSize for ChangeDisplaySettingsW/ExW needs to be at least FIELD_OFFSET(DEVMODEW, dmICMMethod) */ memset(&dmW, 0, sizeof(dmW)); - dmW.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; - dmW.dmPelsWidth = width; - SetLastError(0xdeadbeef); - res = pChangeDisplaySettingsExW(NULL, &dmW, NULL, CDS_TEST, NULL); - if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) - ok(res == DISP_CHANGE_FAILED || - res == DISP_CHANGE_BADPARAM || /* NT4 */ - res == DISP_CHANGE_BADMODE /* XP SP3 */, - "ChangeDisplaySettingsExW returned %d\n", res); + dmW.dmSize = sizeof(dmW); + res = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &dmW); + ok(res, "EnumDisplaySettingsW failed, error %#lx\n", GetLastError()); + dmW.dmSize = FIELD_OFFSET(DEVMODEW, dmICMMethod) - 1; + res = ChangeDisplaySettingsW(&dmW, CDS_TEST); + ok(res == DISP_CHANGE_BADMODE, "ChangeDisplaySettingsW returned %ld, expect DISP_CHANGE_BADMODE\n", res); + + dmW.dmSize = FIELD_OFFSET(DEVMODEW, dmICMMethod) - 1; + res = ChangeDisplaySettingsExW(NULL, &dmW, NULL, CDS_TEST, NULL); + ok(res == DISP_CHANGE_BADMODE, "ChangeDisplaySettingsExW returned %ld, expect DISP_CHANGE_BADMODE\n", res); + + dmW.dmSize = FIELD_OFFSET(DEVMODEW, dmICMMethod); + res = ChangeDisplaySettingsW(&dmW, CDS_TEST); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW returned unexpected %ld\n", res); + + dmW.dmSize = FIELD_OFFSET(DEVMODEW, dmICMMethod); + res = ChangeDisplaySettingsExW(NULL, &dmW, NULL, CDS_TEST, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW returned unexpected %ld\n", res); + + /* Test clip rectangle after resolution changes */ + /* GetClipCursor always returns result in physical pixels but GetSystemMetrics(SM_CX/CYVIRTUALSCREEN) are not. + * Set per-monitor aware context so that virtual screen rectangles are in physical pixels */ + if (pSetThreadDpiAwarenessContext) + context = pSetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE); memset(&dm, 0, sizeof(dm)); dm.dmSize = sizeof(dm); @@ -397,12 +537,12 @@ static void test_ChangeDisplaySettingsEx(void) dm.dmBitsPerPel = vid_modes_test[i].bpp; dm.dmDisplayFrequency = vid_modes_test[i].freq; dm.dmFields = vid_modes_test[i].fields; - res = pChangeDisplaySettingsExA(NULL, &dm, NULL, CDS_TEST, NULL); + res = ChangeDisplaySettingsExA(NULL, &dm, NULL, CDS_TEST, NULL); ok(vid_modes_test[i].must_succeed ? (res == DISP_CHANGE_SUCCESSFUL || res == DISP_CHANGE_RESTART) : (res == DISP_CHANGE_SUCCESSFUL || res == DISP_CHANGE_RESTART || res == DISP_CHANGE_BADMODE || res == DISP_CHANGE_BADPARAM), - "Unexpected ChangeDisplaySettingsEx() return code for resolution[%d]: %d\n", i, res); + "Unexpected ChangeDisplaySettingsExA() return code for vid_modes_test[%d]: %ld\n", i, res); if (res == DISP_CHANGE_SUCCESSFUL) { @@ -443,8 +583,846 @@ static void test_ChangeDisplaySettingsEx(void) ClipCursor(&virt); } } - res = pChangeDisplaySettingsExA(NULL, NULL, NULL, CDS_RESET, NULL); - ok(res == DISP_CHANGE_SUCCESSFUL, "Failed to reset default resolution: %d\n", res); + if (pSetThreadDpiAwarenessContext && context) + pSetThreadDpiAwarenessContext(context); + + /* Save the original mode for all devices so that they can be restored at the end of tests */ + device_count = 0; + device_size = 2; + devices = calloc(device_size, sizeof(*devices)); + ok(devices != NULL, "Failed to allocate memory.\n"); + + primary = 0; + memset(&dd, 0, sizeof(dd)); + dd.cb = sizeof(dd); + for (device = 0; EnumDisplayDevicesA(NULL, device, &dd, 0); ++device) + { + INT number; + + /* Skip software devices */ + if (sscanf(dd.DeviceName, "\\\\.\\DISPLAY%d", &number) != 1) + continue; + + if (!(dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) + continue; + + if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) + primary = device_count; + + if (device_count >= device_size) + { + device_size *= 2; + devices = realloc(devices, device_size * sizeof(*devices)); + ok(devices != NULL, "Failed to reallocate memory.\n"); + } + + devices[device_count].index = device; + lstrcpyA(devices[device_count].name, dd.DeviceName); + memset(&devices[device_count].original_mode, 0, sizeof(devices[device_count].original_mode)); + devices[device_count].original_mode.dmSize = sizeof(devices[device_count].original_mode); + res = EnumDisplaySettingsA(dd.DeviceName, ENUM_CURRENT_SETTINGS, &devices[device_count].original_mode); + ok(res, "EnumDisplaySettingsA %s failed, error %#lx\n", dd.DeviceName, GetLastError()); + ++device_count; + } + + /* Make the primary adapter first */ + if (primary) + { + struct device_info tmp; + tmp = devices[0]; + devices[0] = devices[primary]; + devices[primary] = tmp; + } + + /* Test detaching adapters */ + /* Test that when there is only one adapter, it can't be detached */ + if (device_count == 1) + { + old_count = GetSystemMetrics(SM_CMONITORS); + + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + dm.dmFields = DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT; + dm.dmPosition = devices[0].original_mode.dmPosition; + res = ChangeDisplaySettingsExA(devices[0].name, &dm, NULL, CDS_UPDATEREGISTRY | CDS_NORESET, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned unexpected %ld\n", devices[0].name, res); + res = ChangeDisplaySettingsExA(NULL, NULL, NULL, 0, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL || + broken(res == DISP_CHANGE_FAILED), /* win8 TestBot */ + "ChangeDisplaySettingsExA %s returned unexpected %ld\n", devices[0].name, res); + + /* Check that the adapter is still attached */ + dd.cb = sizeof(dd); + res = EnumDisplayDevicesA(NULL, devices[0].index, &dd, 0); + ok(res, "EnumDisplayDevicesA %s failed, error %#lx\n", devices[0].name, GetLastError()); + ok(dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP, "Expect device %s still attached.\n", devices[0].name); + + count = GetSystemMetrics(SM_CMONITORS); + ok(count == old_count, "Expect monitor count %d, got %d\n", old_count, count); + + /* Restore registry settings */ + res = ChangeDisplaySettingsExA(devices[0].name, &devices[0].original_mode, NULL, + CDS_UPDATEREGISTRY | CDS_NORESET, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL || + broken(res == DISP_CHANGE_BADPARAM) || /* win10 */ + broken(res == DISP_CHANGE_FAILED), /* win8 TestBot */ + "ChangeDisplaySettingsExA %s returned unexpected %ld\n", devices[0].name, res); + } + + /* Test that only specifying DM_POSITION in dmFields is not enough to detach an adapter */ + if (device_count >= 2) + { + old_count = GetSystemMetrics(SM_CMONITORS); + + /* MSDN says set dmFields to DM_POSITION to detach, but DM_PELSWIDTH and DM_PELSHEIGHT are needed actually. + * To successfully detach adapters, settings have to be saved to the registry first, and then call + * ChangeDisplaySettingsExA(device, NULL, NULL, 0, NULL) to update settings. Otherwise on some older versions + * of Windows, e.g., XP and Win7, the adapter doesn't get detached */ + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + dm.dmFields = DM_POSITION; + dm.dmPosition = devices[1].original_mode.dmPosition; + res = ChangeDisplaySettingsExA(devices[1].name, &dm, NULL, CDS_UPDATEREGISTRY | CDS_NORESET, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned unexpected %ld\n", devices[1].name, res); + res = ChangeDisplaySettingsExA(devices[1].name, NULL, NULL, 0, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned unexpected %ld\n", devices[1].name, res); + + dd.cb = sizeof(dd); + res = EnumDisplayDevicesA(NULL, devices[1].index, &dd, 0); + ok(res, "EnumDisplayDevicesA %s failed, error %#lx\n", devices[1].name, GetLastError()); + ok(dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP, "Expect device %s still attached.\n", devices[1].name); + + count = GetSystemMetrics(SM_CMONITORS); + ok(count == old_count, "Expect monitor count %d, got %d\n", old_count, count); + } + + /* Test changing to a mode with depth set but with zero width and height */ + for (device = 0; device < device_count; ++device) + { + for (test = 0; test < ARRAY_SIZE(depths); ++test) + { + /* Find the native resolution */ + memset(&dm, 0, sizeof(dm)); + memset(&dm2, 0, sizeof(dm2)); + dm2.dmSize = sizeof(dm2); + for (mode = 0; EnumDisplaySettingsExA(devices[device].name, mode, &dm2, 0); ++mode) + { + if (dm2.dmBitsPerPel == depths[test] + && dm2.dmPelsWidth > dm.dmPelsWidth && dm2.dmPelsHeight > dm.dmPelsHeight) + dm = dm2; + } + if (dm.dmBitsPerPel != depths[test]) + { + skip("Depth %lu is unsupported for %s.\n", depths[test], devices[device].name); + continue; + } + + /* Find the second resolution */ + memset(&dm2, 0, sizeof(dm2)); + dm2.dmSize = sizeof(dm2); + for (mode = 0; EnumDisplaySettingsExA(devices[device].name, mode, &dm2, 0); ++mode) + { + if (dm2.dmBitsPerPel == depths[test] + && dm2.dmPelsWidth != dm.dmPelsWidth && dm2.dmPelsHeight != dm.dmPelsHeight) + break; + } + if (dm2.dmBitsPerPel != depths[test] + || dm2.dmPelsWidth == dm.dmPelsWidth || dm2.dmPelsHeight == dm.dmPelsHeight) + { + skip("Failed to find the second mode for %s.\n", devices[device].name); + continue; + } + + /* Find the third resolution */ + memset(&dm3, 0, sizeof(dm3)); + dm3.dmSize = sizeof(dm3); + for (mode = 0; EnumDisplaySettingsExA(devices[device].name, mode, &dm3, 0); ++mode) + { + if (dm3.dmBitsPerPel == depths[test] + && dm3.dmPelsWidth != dm.dmPelsWidth && dm3.dmPelsHeight != dm.dmPelsHeight + && dm3.dmPelsWidth != dm2.dmPelsWidth && dm3.dmPelsHeight != dm2.dmPelsHeight) + break; + } + if (dm3.dmBitsPerPel != depths[test] + || dm3.dmPelsWidth == dm.dmPelsWidth || dm3.dmPelsHeight == dm.dmPelsHeight + || dm3.dmPelsWidth == dm2.dmPelsWidth || dm3.dmPelsHeight == dm2.dmPelsHeight) + { + skip("Failed to find the third mode for %s.\n", devices[device].name); + continue; + } + + /* Change the current mode to the third mode first */ + res = ChangeDisplaySettingsExA(devices[device].name, &dm3, NULL, CDS_RESET, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL + || broken(res == DISP_CHANGE_FAILED), /* Win8 TestBots */ + "ChangeDisplaySettingsExA %s returned unexpected %ld.\n", devices[device].name, res); + if (res != DISP_CHANGE_SUCCESSFUL) + { + win_skip("Failed to change display mode for %s.\n", devices[device].name); + continue; + } + flush_events(); + expect_dm(&dm3, devices[device].name, test); + + /* Change the registry mode to the second mode */ + res = ChangeDisplaySettingsExA(devices[device].name, &dm2, NULL, CDS_UPDATEREGISTRY | CDS_NORESET, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL + || broken(res == DISP_CHANGE_BADFLAGS), /* Win10 32bit */ + "ChangeDisplaySettingsExA %s returned unexpected %ld.\n", devices[device].name, res); + + /* Change to a mode with depth set but with zero width and height */ + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; + dm.dmBitsPerPel = depths[test]; + res = ChangeDisplaySettingsExA(devices[device].name, &dm, NULL, CDS_RESET, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned unexpected %ld.\n", + devices[device].name, res); + flush_events(); + + dd.cb = sizeof(dd); + res = EnumDisplayDevicesA(NULL, devices[device].index, &dd, 0); + ok(res, "EnumDisplayDevicesA %s failed, error %#lx.\n", devices[device].name, GetLastError()); + ok(dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP, "Expect %s attached.\n", + devices[device].name); + + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + res = EnumDisplaySettingsA(devices[device].name, ENUM_CURRENT_SETTINGS, &dm); + ok(res, "Device %s EnumDisplaySettingsA failed, error %#lx.\n", devices[device].name, GetLastError()); + ok(dm.dmBitsPerPel == depths[test], "Device %s expect dmBitsPerPel %lu, got %lu.\n", + devices[device].name, depths[test], dm.dmBitsPerPel); + /* 2008 resets to the resolution in the registry. Newer versions of Windows doesn't + * change the current resolution */ + ok(dm.dmPelsWidth == dm3.dmPelsWidth || broken(dm.dmPelsWidth == dm2.dmPelsWidth), + "Device %s expect dmPelsWidth %lu, got %lu.\n", + devices[device].name, dm3.dmPelsWidth, dm.dmPelsWidth); + ok(dm.dmPelsHeight == dm3.dmPelsHeight || broken(dm.dmPelsHeight == dm2.dmPelsHeight), + "Device %s expect dmPelsHeight %lu, got %lu.\n", + devices[device].name, dm3.dmPelsHeight, dm.dmPelsHeight); + } + } + + /* Detach all non-primary adapters to avoid position conflicts */ + for (device = 1; device < device_count; ++device) + { + old_count = GetSystemMetrics(SM_CMONITORS); + + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + dm.dmFields = DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT; + dm.dmPosition = devices[device].original_mode.dmPosition; + res = ChangeDisplaySettingsExA(devices[device].name, &dm, NULL, CDS_UPDATEREGISTRY | CDS_NORESET, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned unexpected %ld\n", devices[device].name, res); + res = ChangeDisplaySettingsExA(devices[device].name, NULL, NULL, 0, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned unexpected %ld\n", devices[device].name, res); + + dd.cb = sizeof(dd); + res = EnumDisplayDevicesA(NULL, devices[device].index, &dd, 0); + ok(res, "EnumDisplayDevicesA %s failed, error %#lx\n", devices[device].name, GetLastError()); + ok(!(dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP), "Expect device %s detached.\n", devices[device].name); + + count = GetSystemMetrics(SM_CMONITORS); + ok(count == old_count - 1, "Expect monitor count %d, got %d\n", old_count - 1, count); + } + + /* Test changing each adapter to different width, height, frequency and depth */ + position.x = 0; + position.y = 0; + for (device = 0; device < device_count; ++device) + { + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + for (mode = 0; EnumDisplaySettingsExA(devices[device].name, mode, &dm, 0); ++mode) + { + if (mode == 0) + { + dm2 = dm; + } + else + { + found = FALSE; + if (dm2.dmPelsWidth && dm.dmPelsWidth != dm2.dmPelsWidth) + { + dm2.dmPelsWidth = 0; + found = TRUE; + } + if (dm2.dmPelsHeight && dm.dmPelsHeight != dm2.dmPelsHeight) + { + dm2.dmPelsHeight = 0; + found = TRUE; + } + if (dm2.dmDisplayFrequency && dm.dmDisplayFrequency != dm2.dmDisplayFrequency) + { + dm2.dmDisplayFrequency = 0; + found = TRUE; + } + if (dm2.dmBitsPerPel && dm.dmBitsPerPel != dm2.dmBitsPerPel) + { + dm2.dmBitsPerPel = 0; + found = TRUE; + } + + if (!dm2.dmPelsWidth && !dm2.dmPelsHeight && !dm2.dmDisplayFrequency + && !dm2.dmBitsPerPel) + break; + + if (!found) + continue; + } + + dm.dmPosition = position; + dm.dmFields |= DM_POSITION; + /* Reattach detached non-primary adapters, otherwise ChangeDisplaySettingsExA with only CDS_RESET fails */ + if (mode == 0 && device) + { + res = ChangeDisplaySettingsExA(devices[device].name, &dm, NULL, CDS_UPDATEREGISTRY | CDS_NORESET, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s mode %d returned unexpected %ld\n", + devices[device].name, mode, res); + res = ChangeDisplaySettingsExA(NULL, NULL, NULL, 0, NULL); + } + else + { + res = ChangeDisplaySettingsExA(devices[device].name, &dm, NULL, CDS_RESET, NULL); + } + + ok(res == DISP_CHANGE_SUCCESSFUL || + broken(res == DISP_CHANGE_FAILED), /* TestBots using VGA driver can't change to some modes */ + "ChangeDisplaySettingsExA %s mode %d returned unexpected %ld\n", devices[device].name, mode, res); + if (res != DISP_CHANGE_SUCCESSFUL) + { + win_skip("Failed to change %s to mode %d.\n", devices[device].name, mode); + continue; + } + + flush_events(); + expect_dm(&dm, devices[device].name, mode); + } + + /* Restore settings */ + res = ChangeDisplaySettingsExA(devices[device].name, NULL, NULL, 0, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL || + broken(res == DISP_CHANGE_FAILED), /* win8 TestBot */ + "ChangeDisplaySettingsExA %s returned unexpected %ld\n", devices[device].name, res); + + /* Place the next adapter to the right so that there is no position conflict */ + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + res = EnumDisplaySettingsA(devices[device].name, ENUM_CURRENT_SETTINGS, &dm); + ok(res, "EnumDisplaySettingsA %s failed, error %#lx\n", devices[device].name, GetLastError()); + position.x = dm.dmPosition.x + dm.dmPelsWidth; + } + + /* Test changing modes by saving settings to the registry first */ + for (device = 0; device < device_count; ++device) + { + /* Place adapter to the right */ + if (device == 0) + { + position.x = 0; + position.y = 0; + } + else + { + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + res = EnumDisplaySettingsA(devices[device - 1].name, ENUM_CURRENT_SETTINGS, &dm); + ok(res, "EnumDisplaySettingsA %s failed, error %#lx.\n", devices[device - 1].name, GetLastError()); + position.x = dm.dmPosition.x + dm.dmPelsWidth; + } + + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + res = EnumDisplaySettingsA(devices[device].name, ENUM_CURRENT_SETTINGS, &dm); + ok(res, "EnumDisplaySettingsA %s failed, error %#lx\n", devices[device].name, GetLastError()); + dm3 = dm; + + /* Find a mode that's different from the current mode */ + memset(&dm2, 0, sizeof(dm2)); + dm2.dmSize = sizeof(dm2); + for (mode = 0; EnumDisplaySettingsA(devices[device].name, mode, &dm2); ++mode) + { + /* Use the same color depth because the win2008 TestBots are unable to change it */ + if (dm2.dmPelsWidth != dm.dmPelsWidth && dm2.dmPelsHeight != dm.dmPelsHeight && + dm2.dmBitsPerPel == dm.dmBitsPerPel) + break; + } + ok(dm2.dmPelsWidth != dm.dmPelsWidth && dm2.dmPelsHeight != dm.dmPelsHeight && + dm2.dmBitsPerPel == dm.dmBitsPerPel, "Failed to find a different mode.\n"); + + /* Test normal operation */ + dm = dm2; + dm.dmFields |= DM_POSITION; + dm.dmPosition = position; + res = ChangeDisplaySettingsExA(devices[device].name, &dm, NULL, CDS_UPDATEREGISTRY | CDS_NORESET, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL || + broken(res == DISP_CHANGE_FAILED), /* win8 TestBot */ + "ChangeDisplaySettingsExA %s returned unexpected %ld\n", devices[device].name, res); + res = ChangeDisplaySettingsExA(devices[device].name, NULL, NULL, 0, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL || + broken(res == DISP_CHANGE_FAILED), /* win8 TestBot */ + "ChangeDisplaySettingsExA %s returned unexpected %ld\n", devices[device].name, res); + if (res != DISP_CHANGE_SUCCESSFUL) + { + win_skip("Failed to change mode for %s.\n", devices[device].name); + continue; + } + + flush_events(); + expect_dm(&dm, devices[device].name, 0); + + /* Test specifying only position, width and height */ + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + dm.dmFields = DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT; + dm.dmPosition = position; + dm.dmPelsWidth = dm3.dmPelsWidth; + dm.dmPelsHeight = dm3.dmPelsHeight; + res = ChangeDisplaySettingsExA(devices[device].name, &dm, NULL, CDS_UPDATEREGISTRY | CDS_NORESET, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned %ld.\n", devices[device].name, res); + res = EnumDisplaySettingsA(devices[device].name, ENUM_REGISTRY_SETTINGS, &dm); + /* Win10 either returns failure here or retrieves outdated display settings until they're applied */ + if (res) + { + ok((dm.dmFields & registry_fields) == registry_fields, "Got unexpected dmFields %#lx.\n", dm.dmFields); + ok(dm.dmPosition.x == position.x, "Expected dmPosition.x %ld, got %ld.\n", position.x, dm.dmPosition.x); + ok(dm.dmPosition.y == position.y, "Expected dmPosition.y %ld, got %ld.\n", position.y, dm.dmPosition.y); + ok(dm.dmPelsWidth == dm3.dmPelsWidth || broken(dm.dmPelsWidth == dm2.dmPelsWidth), /* Win10 */ + "Expected dmPelsWidth %lu, got %lu.\n", dm3.dmPelsWidth, dm.dmPelsWidth); + ok(dm.dmPelsHeight == dm3.dmPelsHeight || broken(dm.dmPelsHeight == dm2.dmPelsHeight), /* Win10 */ + "Expected dmPelsHeight %lu, got %lu.\n", dm3.dmPelsHeight, dm.dmPelsHeight); + ok(dm.dmBitsPerPel, "Expected dmBitsPerPel not zero.\n"); + ok(dm.dmDisplayFrequency, "Expected dmDisplayFrequency not zero.\n"); + } + else + { + win_skip("EnumDisplaySettingsA %s failed, error %#lx.\n", devices[device].name, GetLastError()); + } + + res = ChangeDisplaySettingsExA(devices[device].name, NULL, NULL, 0, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned %ld.\n", devices[device].name, res); + flush_events(); + + res = EnumDisplaySettingsA(devices[device].name, ENUM_REGISTRY_SETTINGS, &dm); + ok(res, "EnumDisplaySettingsA %s failed, error %#lx.\n", devices[device].name, GetLastError()); + ok((dm.dmFields & registry_fields) == registry_fields, "Got unexpected dmFields %#lx.\n", dm.dmFields); + ok(dm.dmPosition.x == position.x, "Expected dmPosition.x %ld, got %ld.\n", position.x, dm.dmPosition.x); + ok(dm.dmPosition.y == position.y, "Expected dmPosition.y %ld, got %ld.\n", position.y, dm.dmPosition.y); + ok(dm.dmPelsWidth == dm3.dmPelsWidth, "Expected dmPelsWidth %lu, got %lu.\n", dm3.dmPelsWidth, dm.dmPelsWidth); + ok(dm.dmPelsHeight == dm3.dmPelsHeight, "Expected dmPelsHeight %lu, got %lu.\n", dm3.dmPelsHeight, + dm.dmPelsHeight); + ok(dm.dmBitsPerPel, "Expected dmBitsPerPel not zero.\n"); + ok(dm.dmDisplayFrequency, "Expected dmDisplayFrequency not zero.\n"); + + expect_dm(&dm, devices[device].name, 0); + } + + /* Test dmPosition */ + /* First detach all adapters except for the primary and secondary adapters to avoid position conflicts */ + if (device_count >= 3) + { + for (device = 2; device < device_count; ++device) + { + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + res = EnumDisplaySettingsA(devices[device].name, ENUM_CURRENT_SETTINGS, &dm); + ok(res, "EnumDisplaySettingsA %s failed, error %#lx\n", devices[device].name, GetLastError()); + + dm.dmPelsWidth = 0; + dm.dmPelsHeight = 0; + dm.dmFields = DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT; + res = ChangeDisplaySettingsExA(devices[device].name, &dm, NULL, CDS_UPDATEREGISTRY | CDS_NORESET, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned unexpected %ld\n", devices[device].name, res); + } + res = ChangeDisplaySettingsExA(NULL, NULL, NULL, 0, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA returned unexpected %ld\n", res); + } + + if (device_count >= 2) + { + /* Query the primary adapter settings */ + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + res = EnumDisplaySettingsA(devices[0].name, ENUM_CURRENT_SETTINGS, &dm); + ok(res, "EnumDisplaySettingsA %s failed, error %#lx\n", devices[0].name, GetLastError()); + + if (res) + { + /* Query the secondary adapter settings */ + memset(&dm2, 0, sizeof(dm2)); + dm2.dmSize = sizeof(dm2); + res = EnumDisplaySettingsA(devices[1].name, ENUM_CURRENT_SETTINGS, &dm2); + ok(res, "EnumDisplaySettingsA %s failed, error %#lx\n", devices[1].name, GetLastError()); + } + + if (res) + { + /* The secondary adapter should be to the right of the primary adapter */ + ok(dm2.dmPosition.x == dm.dmPosition.x + dm.dmPelsWidth, + "Expected dm2.dmPosition.x %ld, got %ld.\n", dm.dmPosition.x + dm.dmPelsWidth, + dm2.dmPosition.x); + ok(dm2.dmPosition.y == dm.dmPosition.y, "Expected dm2.dmPosition.y %ld, got %ld.\n", + dm.dmPosition.y, dm2.dmPosition.y); + + /* Test position conflict */ + dm2.dmPosition.x = dm.dmPosition.x - dm2.dmPelsWidth + 1; + dm2.dmPosition.y = dm.dmPosition.y; + res = ChangeDisplaySettingsExA(devices[1].name, &dm2, NULL, CDS_RESET, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned unexpected %ld\n", devices[1].name, res); + + /* Position is changed and automatically moved */ + memset(&dm2, 0, sizeof(dm2)); + dm2.dmSize = sizeof(dm2); + res = EnumDisplaySettingsA(devices[1].name, ENUM_CURRENT_SETTINGS, &dm2); + ok(res, "EnumDisplaySettingsA %s failed, error %#lx\n", devices[1].name, GetLastError()); + ok(dm2.dmPosition.x == dm.dmPosition.x - dm2.dmPelsWidth, + "Expected dmPosition.x %ld, got %ld.\n", dm.dmPosition.x - dm2.dmPelsWidth, + dm2.dmPosition.x); + + /* Test position with extra space. The extra space will be removed */ + dm2.dmPosition.x = dm.dmPosition.x + dm.dmPelsWidth + 1; + dm2.dmPosition.y = dm.dmPosition.y; + res = ChangeDisplaySettingsExA(devices[1].name, &dm2, NULL, CDS_RESET, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned unexpected %ld\n", devices[1].name, res); + + dm2.dmPosition.x = dm.dmPosition.x + dm.dmPelsWidth; + expect_dm(&dm2, devices[1].name, 0); + + /* Test placing the secondary adapter to all sides of the primary adapter */ + for (test = 0; test < 8; ++test) + { + switch (test) + { + /* Bottom side with x offset */ + case 0: + dm2.dmPosition.x = dm.dmPosition.x + dm.dmPelsWidth / 2; + dm2.dmPosition.y = dm.dmPosition.y + dm.dmPelsHeight; + break; + /* Left side with y offset */ + case 1: + dm2.dmPosition.x = dm.dmPosition.x - dm2.dmPelsWidth; + dm2.dmPosition.y = dm.dmPosition.y + dm.dmPelsHeight / 2; + break; + /* Top side with x offset */ + case 2: + dm2.dmPosition.x = dm.dmPosition.x + dm.dmPelsWidth / 2; + dm2.dmPosition.y = dm.dmPosition.y - dm2.dmPelsHeight; + break; + /* Right side with y offset */ + case 3: + dm2.dmPosition.x = dm.dmPosition.x + dm.dmPelsWidth; + dm2.dmPosition.y = dm.dmPosition.y + dm.dmPelsHeight / 2; + break; + /* Bottom side with the same x */ + case 4: + dm2.dmPosition.x = dm.dmPosition.x; + dm2.dmPosition.y = dm.dmPosition.y + dm.dmPelsHeight; + break; + /* Left side with the same y */ + case 5: + dm2.dmPosition.x = dm.dmPosition.x - dm2.dmPelsWidth; + dm2.dmPosition.y = dm.dmPosition.y; + break; + /* Top side with the same x */ + case 6: + dm2.dmPosition.x = dm.dmPosition.x; + dm2.dmPosition.y = dm.dmPosition.y - dm2.dmPelsHeight; + break; + /* Right side with the same y */ + case 7: + dm2.dmPosition.x = dm.dmPosition.x + dm.dmPelsWidth; + dm2.dmPosition.y = dm.dmPosition.y; + break; + } + + res = ChangeDisplaySettingsExA(devices[1].name, &dm2, NULL, CDS_RESET, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s test %d returned unexpected %ld\n", + devices[1].name, test, res); + if (res != DISP_CHANGE_SUCCESSFUL) + { + win_skip("ChangeDisplaySettingsExA %s test %d returned unexpected %ld.\n", devices[1].name, test, res); + continue; + } + + flush_events(); + expect_dm(&dm2, devices[1].name, test); + } + + /* Test automatic position update when other adapters change resolution */ + /* Find a mode that's different from the current mode */ + memset(&dm2, 0, sizeof(dm2)); + dm2.dmSize = sizeof(dm2); + for (mode = 0; EnumDisplaySettingsA(devices[0].name, mode, &dm2); ++mode) + { + if (dm2.dmPelsWidth != dm.dmPelsWidth && dm2.dmPelsHeight != dm.dmPelsHeight) + break; + } + ok(dm2.dmPelsWidth != dm.dmPelsWidth && dm2.dmPelsHeight != dm.dmPelsHeight, "Failed to find a different mode.\n"); + + /* Change the primary adapter to a different mode */ + dm = dm2; + res = ChangeDisplaySettingsExA(devices[0].name, &dm, NULL, CDS_RESET, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned unexpected %ld\n", devices[0].name, res); + + /* Now the position of the second adapter should be changed */ + memset(&dm2, 0, sizeof(dm2)); + dm2.dmSize = sizeof(dm2); + res = EnumDisplaySettingsA(devices[1].name, ENUM_CURRENT_SETTINGS, &dm2); + ok(res, "EnumDisplaySettingsA %s failed, error %#lx\n", devices[1].name, GetLastError()); + ok(dm2.dmPosition.x == dm.dmPelsWidth, "Expect dmPosition.x %ld, got %ld\n", + dm.dmPelsWidth, dm2.dmPosition.x); + } + else + { + win_skip("EnumDisplaySettingsA failed\n"); + } + } + + /* Test changing each adapter to every supported display orientation */ + for (device = 0; device < device_count; ++device) + { + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + res = EnumDisplaySettingsA(devices[device].name, ENUM_CURRENT_SETTINGS, &dm); + ok(res, "EnumDisplaySettingsA %s failed, error %#lx.\n", devices[device].name, GetLastError()); + + memset(&dm2, 0, sizeof(dm2)); + dm2.dmSize = sizeof(dm2); + for (mode = 0; EnumDisplaySettingsExA(devices[device].name, mode, &dm2, EDS_ROTATEDMODE); ++mode) + { + if (dm2.dmBitsPerPel != dm.dmBitsPerPel || dm2.dmDisplayFrequency != dm.dmDisplayFrequency) + continue; + + if ((dm2.dmDisplayOrientation == DMDO_DEFAULT || dm2.dmDisplayOrientation == DMDO_180) + && (dm2.dmPelsWidth != dm.dmPelsWidth || dm2.dmPelsHeight != dm.dmPelsHeight)) + continue; + + if ((dm2.dmDisplayOrientation == DMDO_90 || dm2.dmDisplayOrientation == DMDO_270) + && (dm2.dmPelsWidth != dm.dmPelsHeight || dm2.dmPelsHeight != dm.dmPelsWidth)) + continue; + + res = ChangeDisplaySettingsExA(devices[device].name, &dm2, NULL, CDS_RESET, NULL); + if (res != DISP_CHANGE_SUCCESSFUL) + { + win_skip("Failed to change %s to mode %d.\n", devices[device].name, mode); + continue; + } + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s mode %d returned unexpected %ld.\n", + devices[device].name, mode, res); + flush_events(); + expect_dm(&dm2, devices[device].name, mode); + + /* EnumDisplaySettingsEx without EDS_ROTATEDMODE reports modes with current orientation */ + memset(&dm3, 0, sizeof(dm3)); + dm3.dmSize = sizeof(dm3); + for (i = 0; EnumDisplaySettingsExA(devices[device].name, i, &dm3, 0); ++i) + { + ok(dm3.dmDisplayOrientation == dm2.dmDisplayOrientation, + "Expected %s display mode %d orientation %ld, got %ld.\n", + devices[device].name, i, dm2.dmDisplayOrientation, dm3.dmDisplayOrientation); + } + ok(i > 0, "Expected at least one display mode found.\n"); + + if (device == 0) + { + ok(GetSystemMetrics(SM_CXSCREEN) == dm2.dmPelsWidth, "Expected %ld, got %d.\n", + dm2.dmPelsWidth, GetSystemMetrics(SM_CXSCREEN)); + ok(GetSystemMetrics(SM_CYSCREEN) == dm2.dmPelsHeight, "Expected %ld, got %d.\n", + dm2.dmPelsHeight, GetSystemMetrics(SM_CYSCREEN)); + } + + if (device_count == 1) + { + ok(GetSystemMetrics(SM_CXVIRTUALSCREEN) == dm2.dmPelsWidth, "Expected %ld, got %d.\n", + dm2.dmPelsWidth, GetSystemMetrics(SM_CXVIRTUALSCREEN)); + ok(GetSystemMetrics(SM_CYVIRTUALSCREEN) == dm2.dmPelsHeight, "Expected %ld, got %d.\n", + dm2.dmPelsHeight, GetSystemMetrics(SM_CYVIRTUALSCREEN)); + } + } + ok(mode > 0, "Expected at least one display mode found.\n"); + } + + /* Restore all adapters to the current registry settings */ + res = ChangeDisplaySettingsExA(NULL, NULL, NULL, 0, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL || + broken(res == DISP_CHANGE_FAILED), /* win8 TestBot */ + "ChangeDisplaySettingsExA returned unexpected %ld\n", res); + + if (res == DISP_CHANGE_FAILED) + { + win_skip("Failed to restore dispay mode.\n"); + } + else if (!device_count) + { + win_skip("No suitable devices found.\n"); + } + else + { + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; + + exit_event0 = CreateEventA(NULL, FALSE, FALSE, exit_event0_name); + ok(!!exit_event0, "CreateEventA failed, error %#lx\n", GetLastError()); + exit_event1 = CreateEventA(NULL, FALSE, FALSE, exit_event1_name); + ok(!!exit_event1, "CreateEventA failed, error %#lx\n", GetLastError()); + + /* Test that if the most recent ChangeDisplaySettingsEx call had + * CDS_FULLSCREEN set, then the settings are restored when the caller + * process exits */ + + process0 = test_child_process_ChangeDisplaySettingsEx(argv[0], devices[0].name, CDS_FULLSCREEN, exit_event0_name); + process1 = test_child_process_ChangeDisplaySettingsEx(argv[0], devices[0].name, CDS_FULLSCREEN, exit_event1_name); + + /* Verify that the settings are restored to the current registry settings */ + for (device = 0; device < device_count; ++device) + { + dm.dmPelsWidth = 800; + dm.dmPelsHeight = 600; + res = ChangeDisplaySettingsExA(devices[device].name, &dm, NULL, CDS_UPDATEREGISTRY | CDS_NORESET, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned %ld.\n", devices[device].name, res); + } + + SetEvent(exit_event0); + wait_result = WaitForSingleObject(process0, 5000); + ok(wait_result == WAIT_OBJECT_0, "WaitForSingleObject returned %lx.\n", wait_result); + + Sleep(100); + + dm.dmPelsWidth = 640; + dm.dmPelsHeight = 480; + expect_dm(&dm, devices[0].name, 0); + + SetEvent(exit_event1); + wait_result = WaitForSingleObject(process1, 5000); + ok(wait_result == WAIT_OBJECT_0, "WaitForSingleObject returned %lx.\n", wait_result); + + wait_for_dm(devices[0].name, 800, 600); + + CloseHandle(process1); + CloseHandle(process0); + + /* Test processes exiting in reverse order */ + + process0 = test_child_process_ChangeDisplaySettingsEx(argv[0], devices[0].name, CDS_FULLSCREEN, exit_event0_name); + process1 = test_child_process_ChangeDisplaySettingsEx(argv[0], devices[0].name, CDS_FULLSCREEN, exit_event1_name); + + SetEvent(exit_event1); + wait_result = WaitForSingleObject(process1, 5000); + ok(wait_result == WAIT_OBJECT_0, "WaitForSingleObject returned %lx.\n", wait_result); + + wait_for_dm(devices[0].name, 800, 600); + + SetEvent(exit_event0); + wait_result = WaitForSingleObject(process0, 5000); + ok(wait_result == WAIT_OBJECT_0, "WaitForSingleObject returned %lx.\n", wait_result); + + CloseHandle(process1); + CloseHandle(process0); + + /* Test that ChangeDisplaySettingsEx without CDS_FULLSCREEN cancels the restoration */ + + process0 = test_child_process_ChangeDisplaySettingsEx(argv[0], devices[0].name, CDS_FULLSCREEN, exit_event0_name); + process1 = test_child_process_ChangeDisplaySettingsEx(argv[0], devices[0].name, 0, exit_event1_name); + + SetEvent(exit_event0); + wait_result = WaitForSingleObject(process0, 5000); + ok(wait_result == WAIT_OBJECT_0, "WaitForSingleObject returned %lx.\n", wait_result); + + Sleep(100); + + dm.dmPelsWidth = 640; + dm.dmPelsHeight = 480; + expect_dm(&dm, devices[0].name, 0); + + SetEvent(exit_event1); + wait_result = WaitForSingleObject(process1, 5000); + ok(wait_result == WAIT_OBJECT_0, "WaitForSingleObject returned %lx.\n", wait_result); + + Sleep(100); + + dm.dmPelsWidth = 640; + dm.dmPelsHeight = 480; + expect_dm(&dm, devices[0].name, 0); + + CloseHandle(process1); + CloseHandle(process0); + + /* Test processes exiting in reverse order */ + + process0 = test_child_process_ChangeDisplaySettingsEx(argv[0], devices[0].name, CDS_FULLSCREEN, exit_event0_name); + process1 = test_child_process_ChangeDisplaySettingsEx(argv[0], devices[0].name, 0, exit_event1_name); + + SetEvent(exit_event1); + wait_result = WaitForSingleObject(process1, 5000); + ok(wait_result == WAIT_OBJECT_0, "WaitForSingleObject returned %lx.\n", wait_result); + + Sleep(100); + + dm.dmPelsWidth = 640; + dm.dmPelsHeight = 480; + expect_dm(&dm, devices[0].name, 0); + + SetEvent(exit_event0); + wait_result = WaitForSingleObject(process0, 5000); + ok(wait_result == WAIT_OBJECT_0, "WaitForSingleObject returned %lx.\n", wait_result); + + Sleep(100); + + dm.dmPelsWidth = 640; + dm.dmPelsHeight = 480; + expect_dm(&dm, devices[0].name, 0); + + CloseHandle(process1); + CloseHandle(process0); + + if (device_count < 2) + { + skip("Only one device found.\n"); + } + else + { + /* Test that the settings are restored for all devices, regardless of + * the process that changed them */ + + dm.dmPelsWidth = 640; + dm.dmPelsHeight = 480; + res = ChangeDisplaySettingsExA(devices[1].name, &dm, NULL, CDS_FULLSCREEN, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned %ld.\n", devices[1].name, res); + + process0 = test_child_process_ChangeDisplaySettingsEx(argv[0], devices[0].name, CDS_FULLSCREEN, exit_event0_name); + + SetEvent(exit_event0); + wait_result = WaitForSingleObject(process0, 5000); + ok(wait_result == WAIT_OBJECT_0, "WaitForSingleObject returned %lx.\n", wait_result); + + wait_for_dm(devices[0].name, 800, 600); + wait_for_dm(devices[1].name, 800, 600); + + CloseHandle(process0); + } + + CloseHandle(exit_event1); + CloseHandle(exit_event0); + } + + /* Restore all adapters to their original settings */ + for (device = 0; device < device_count; ++device) + { + res = ChangeDisplaySettingsExA(devices[device].name, &devices[device].original_mode, NULL, + CDS_UPDATEREGISTRY | CDS_NORESET, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL || + broken(res == DISP_CHANGE_FAILED), /* win8 TestBot */ + "ChangeDisplaySettingsExA %s returned unexpected %ld\n", devices[device].name, res); + } + res = ChangeDisplaySettingsExA(NULL, NULL, NULL, 0, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL || + broken(res == DISP_CHANGE_FAILED), /* win8 TestBot */ + "ChangeDisplaySettingsExA returned unexpected %ld\n", res); + for (device = 0; device < device_count; ++device) + expect_dm(&devices[device].original_mode, devices[device].name, 0); + + free(devices); } static void test_monitors(void) @@ -487,76 +1465,64 @@ static void test_monitors(void) {0xdeadbeef, FALSE}, }; - if (!pMonitorFromPoint || !pMonitorFromWindow || !pMonitorFromRect) - { - win_skip("MonitorFromPoint, MonitorFromWindow, or MonitorFromRect is not available\n"); - return; - } - pt.x = pt.y = 0; - primary = pMonitorFromPoint( pt, MONITOR_DEFAULTTOPRIMARY ); + primary = MonitorFromPoint( pt, MONITOR_DEFAULTTOPRIMARY ); ok( primary != 0, "couldn't get primary monitor\n" ); - monitor = pMonitorFromWindow( 0, MONITOR_DEFAULTTONULL ); + monitor = MonitorFromWindow( 0, MONITOR_DEFAULTTONULL ); ok( !monitor, "got %p, should not get a monitor for an invalid window\n", monitor ); - monitor = pMonitorFromWindow( 0, MONITOR_DEFAULTTOPRIMARY ); + monitor = MonitorFromWindow( 0, MONITOR_DEFAULTTOPRIMARY ); ok( monitor == primary, "got %p, should get primary %p for MONITOR_DEFAULTTOPRIMARY\n", monitor, primary ); - monitor = pMonitorFromWindow( 0, MONITOR_DEFAULTTONEAREST ); + monitor = MonitorFromWindow( 0, MONITOR_DEFAULTTONEAREST ); ok( monitor == primary, "got %p, should get primary %p for MONITOR_DEFAULTTONEAREST\n", monitor, primary ); SetRect( &rc, 0, 0, 1, 1 ); - monitor = pMonitorFromRect( &rc, MONITOR_DEFAULTTONULL ); + monitor = MonitorFromRect( &rc, MONITOR_DEFAULTTONULL ); ok( monitor == primary, "got %p, should get primary %p\n", monitor, primary ); - monitor = pMonitorFromRect( &rc, MONITOR_DEFAULTTOPRIMARY ); + monitor = MonitorFromRect( &rc, MONITOR_DEFAULTTOPRIMARY ); ok( monitor == primary, "got %p, should get primary %p\n", monitor, primary ); - monitor = pMonitorFromRect( &rc, MONITOR_DEFAULTTONEAREST ); + monitor = MonitorFromRect( &rc, MONITOR_DEFAULTTONEAREST ); ok( monitor == primary, "got %p, should get primary %p\n", monitor, primary ); /* Empty rect at 0,0 is considered inside the primary monitor */ SetRect( &rc, 0, 0, -1, -1 ); - monitor = pMonitorFromRect( &rc, MONITOR_DEFAULTTONULL ); + monitor = MonitorFromRect( &rc, MONITOR_DEFAULTTONULL ); ok( monitor == primary, "got %p, should get primary %p\n", monitor, primary ); /* Even if there is a monitor left of the primary, the primary will have the most overlapping area */ SetRect( &rc, -1, 0, 2, 1 ); - monitor = pMonitorFromRect( &rc, MONITOR_DEFAULTTONULL ); + monitor = MonitorFromRect( &rc, MONITOR_DEFAULTTONULL ); ok( monitor == primary, "got %p, should get primary %p\n", monitor, primary ); /* But the width of the rect doesn't matter if it's empty. */ SetRect( &rc, -1, 0, 2, -1 ); - monitor = pMonitorFromRect( &rc, MONITOR_DEFAULTTONULL ); + monitor = MonitorFromRect( &rc, MONITOR_DEFAULTTONULL ); ok( monitor != primary, "got primary %p\n", monitor ); - if (!pGetMonitorInfoA) - { - win_skip("GetMonitorInfoA is not available\n"); - return; - } - /* Search for a monitor that has no others equally near to (left, top-1) */ SetRect( &rc, -1, -2, 2, 0 ); - monitor = pMonitorFromRect( &rc, MONITOR_DEFAULTTONULL ); + monitor = MonitorFromRect( &rc, MONITOR_DEFAULTTONULL ); nearest = primary; while (monitor != NULL) { ok( monitor != primary, "got primary %p\n", monitor ); nearest = monitor; mi.cbSize = sizeof(mi); - ret = pGetMonitorInfoA( monitor, &mi ); + ret = GetMonitorInfoA( monitor, &mi ); ok( ret, "GetMonitorInfo failed\n" ); SetRect( &rc, mi.rcMonitor.left-1, mi.rcMonitor.top-2, mi.rcMonitor.left+2, mi.rcMonitor.top ); - monitor = pMonitorFromRect( &rc, MONITOR_DEFAULTTONULL ); + monitor = MonitorFromRect( &rc, MONITOR_DEFAULTTONULL ); } /* tests for cbSize in MONITORINFO */ - monitor = pMonitorFromWindow( 0, MONITOR_DEFAULTTOPRIMARY ); + monitor = MonitorFromWindow( 0, MONITOR_DEFAULTTOPRIMARY ); for (i = 0; i < ARRAY_SIZE(testdatami); i++) { memset( &mi, 0, sizeof(mi) ); mi.cbSize = testdatami[i].cbSize; - ret = pGetMonitorInfoA( monitor, &mi ); + ret = GetMonitorInfoA( monitor, &mi ); ok( ret == testdatami[i].ret, "GetMonitorInfo returned wrong value\n" ); if (ret) ok( (mi.dwFlags & MONITORINFOF_PRIMARY), "MONITORINFOF_PRIMARY flag isn't set\n" ); @@ -565,7 +1531,7 @@ static void test_monitors(void) memset( &miexw, 0, sizeof(miexw) ); miexw.cbSize = testdatamiexw[i].cbSize; - ret = pGetMonitorInfoW( monitor, (LPMONITORINFO)&miexw ); + ret = GetMonitorInfoW( monitor, (LPMONITORINFO)&miexw ); ok( ret == testdatamiexw[i].ret, "GetMonitorInfo returned wrong value\n" ); if (ret) ok( (miexw.dwFlags & MONITORINFOF_PRIMARY), "MONITORINFOF_PRIMARY flag isn't set\n" ); @@ -578,7 +1544,7 @@ static void test_monitors(void) { memset( &miexa, 0, sizeof(miexa) ); miexa.cbSize = testdatamiexa[i].cbSize; - ret = pGetMonitorInfoA( monitor, (LPMONITORINFO)&miexa ); + ret = GetMonitorInfoA( monitor, (LPMONITORINFO)&miexa ); ok( ret == testdatamiexa[i].ret, "GetMonitorInfo returned wrong value\n" ); if (ret) ok( (miexa.dwFlags & MONITORINFOF_PRIMARY), "MONITORINFOF_PRIMARY flag isn't set\n" ); @@ -591,7 +1557,7 @@ static void test_monitors(void) { memset( &miexw, 0, sizeof(miexw) ); miexw.cbSize = testdatamiexw[i].cbSize; - ret = pGetMonitorInfoW( monitor, (LPMONITORINFO)&miexw ); + ret = GetMonitorInfoW( monitor, (LPMONITORINFO)&miexw ); ok( ret == testdatamiexw[i].ret, "GetMonitorInfo returned wrong value\n" ); if (ret) ok( (miexw.dwFlags & MONITORINFOF_PRIMARY), "MONITORINFOF_PRIMARY flag isn't set\n" ); @@ -601,13 +1567,13 @@ static void test_monitors(void) SetRect( &rc, rc.left+1, rc.top+1, rc.left+2, rc.top+2 ); - monitor = pMonitorFromRect( &rc, MONITOR_DEFAULTTONULL ); + monitor = MonitorFromRect( &rc, MONITOR_DEFAULTTONULL ); ok( monitor == NULL, "got %p\n", monitor ); - monitor = pMonitorFromRect( &rc, MONITOR_DEFAULTTOPRIMARY ); + monitor = MonitorFromRect( &rc, MONITOR_DEFAULTTOPRIMARY ); ok( monitor == primary, "got %p, should get primary %p\n", monitor, primary ); - monitor = pMonitorFromRect( &rc, MONITOR_DEFAULTTONEAREST ); + monitor = MonitorFromRect( &rc, MONITOR_DEFAULTTONEAREST ); ok( monitor == nearest, "got %p, should get nearest %p\n", monitor, nearest ); } @@ -617,7 +1583,7 @@ static BOOL CALLBACK find_primary_mon(HMONITOR hmon, HDC hdc, LPRECT rc, LPARAM BOOL ret; mi.cbSize = sizeof(mi); - ret = pGetMonitorInfoA(hmon, &mi); + ret = GetMonitorInfoA(hmon, &mi); ok(ret, "GetMonitorInfo failed\n"); if (mi.dwFlags & MONITORINFOF_PRIMARY) { @@ -636,26 +1602,20 @@ static void test_work_area(void) WINDOWPLACEMENT wp; BOOL ret; - if (!pEnumDisplayMonitors || !pGetMonitorInfoA) - { - win_skip("EnumDisplayMonitors or GetMonitorInfoA are not available\n"); - return; - } - hmon = 0; - ret = pEnumDisplayMonitors(NULL, NULL, find_primary_mon, (LPARAM)&hmon); + ret = EnumDisplayMonitors(NULL, NULL, find_primary_mon, (LPARAM)&hmon); ok(!ret && hmon != 0, "Failed to find primary monitor\n"); mi.cbSize = sizeof(mi); SetLastError(0xdeadbeef); - ret = pGetMonitorInfoA(hmon, &mi); - ok(ret, "GetMonitorInfo error %u\n", GetLastError()); + ret = GetMonitorInfoA(hmon, &mi); + ok(ret, "GetMonitorInfo error %lu\n", GetLastError()); ok(mi.dwFlags & MONITORINFOF_PRIMARY, "not a primary monitor\n"); trace("primary monitor %s\n", wine_dbgstr_rect(&mi.rcMonitor)); SetLastError(0xdeadbeef); ret = SystemParametersInfoA(SPI_GETWORKAREA, 0, &rc_work, 0); - ok(ret, "SystemParametersInfo error %u\n", GetLastError()); + ok(ret, "SystemParametersInfo error %lu\n", GetLastError()); trace("work area %s\n", wine_dbgstr_rect(&rc_work)); ok(EqualRect(&rc_work, &mi.rcWork), "work area is different\n"); @@ -669,7 +1629,7 @@ static void test_work_area(void) wp.length = sizeof(wp); ret = GetWindowPlacement(hwnd, &wp); ok(ret, "GetWindowPlacement failed\n"); - trace("min: %d,%d max %d,%d normal %s\n", wp.ptMinPosition.x, wp.ptMinPosition.y, + trace("min: %ld,%ld max %ld,%ld normal %s\n", wp.ptMinPosition.x, wp.ptMinPosition.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y, wine_dbgstr_rect(&wp.rcNormalPosition)); OffsetRect(&wp.rcNormalPosition, rc_work.left, rc_work.top); todo_wine_if (mi.rcMonitor.left != mi.rcWork.left || @@ -683,71 +1643,2256 @@ static void test_work_area(void) wp.length = sizeof(wp); ret = GetWindowPlacement(hwnd, &wp); ok(ret, "GetWindowPlacement failed\n"); - trace("min: %d,%d max %d,%d normal %s\n", wp.ptMinPosition.x, wp.ptMinPosition.y, + trace("min: %ld,%ld max %ld,%ld normal %s\n", wp.ptMinPosition.x, wp.ptMinPosition.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y, wine_dbgstr_rect(&wp.rcNormalPosition)); ok(EqualRect(&rc_normal, &wp.rcNormalPosition), "normal pos is different\n"); DestroyWindow(hwnd); } -static void test_display_config(void) +static void test_GetDisplayConfigBufferSizes(void) { UINT32 paths, modes; LONG ret; - if (!pGetDisplayConfigBufferSizes) - { - win_skip("GetDisplayConfigBufferSizes is not supported\n"); - return; - } - ret = pGetDisplayConfigBufferSizes(QDC_ALL_PATHS, NULL, NULL); - ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret); + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); paths = 100; ret = pGetDisplayConfigBufferSizes(QDC_ALL_PATHS, &paths, NULL); - ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret); + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); ok(paths == 100, "got %u\n", paths); modes = 100; ret = pGetDisplayConfigBufferSizes(QDC_ALL_PATHS, NULL, &modes); - ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret); + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); ok(modes == 100, "got %u\n", modes); + ret = pGetDisplayConfigBufferSizes(0, NULL, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); + + paths = 100; + ret = pGetDisplayConfigBufferSizes(0, &paths, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); + ok(paths == 100, "got %u\n", paths); + + modes = 100; + ret = pGetDisplayConfigBufferSizes(0, NULL, &modes); + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); + ok(modes == 100, "got %u\n", modes); + + /* Flag validation on Windows is driver-dependent */ + paths = modes = 100; + ret = pGetDisplayConfigBufferSizes(0, &paths, &modes); + ok(ret == ERROR_INVALID_PARAMETER || ret == ERROR_NOT_SUPPORTED, "got %ld\n", ret); + ok((modes == 0 || modes == 100) && paths == 0, "got %u, %u\n", modes, paths); + + paths = modes = 100; + ret = pGetDisplayConfigBufferSizes(0xFF, &paths, &modes); + ok(ret == ERROR_INVALID_PARAMETER || ret == ERROR_NOT_SUPPORTED, "got %ld\n", ret); + ok((modes == 0 || modes == 100) && paths == 0, "got %u, %u\n", modes, paths); + + /* Test success */ paths = modes = 0; ret = pGetDisplayConfigBufferSizes(QDC_ALL_PATHS, &paths, &modes); if (!ret) ok(paths > 0 && modes > 0, "got %u, %u\n", paths, modes); else - ok(ret == ERROR_NOT_SUPPORTED, "got %d\n", ret); + ok(ret == ERROR_NOT_SUPPORTED, "got %ld\n", ret); - /* Invalid flags, non-zero invalid flags validation is version (or driver?) dependent, - it's unreliable to use in tests. */ - ret = pGetDisplayConfigBufferSizes(0, NULL, NULL); - ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret); + paths = modes = 0; + ret = pGetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &paths, &modes); + if (!ret) + ok(paths > 0 && modes > 0, "got %u, %u\n", paths, modes); + else + ok(ret == ERROR_NOT_SUPPORTED, "got %ld\n", ret); - paths = 100; - ret = pGetDisplayConfigBufferSizes(0, &paths, NULL); - ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret); - ok(paths == 100, "got %u\n", paths); + paths = modes = 0; + ret = pGetDisplayConfigBufferSizes(QDC_DATABASE_CURRENT, &paths, &modes); + if (!ret) + ok(paths > 0 && modes > 0, "got %u, %u\n", paths, modes); + else + ok(ret == ERROR_NOT_SUPPORTED, "got %ld\n", ret); - modes = 100; - ret = pGetDisplayConfigBufferSizes(0, NULL, &modes); - ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret); - ok(modes == 100, "got %u\n", modes); + paths = modes = 0; + ret = pGetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS | QDC_VIRTUAL_MODE_AWARE, &paths, &modes); + ok(!ret || broken(ret == ERROR_INVALID_PARAMETER || ret == ERROR_NOT_SUPPORTED) /* before Win10 */, "got %ld\n", ret); + if (!ret) + ok(paths > 0 && modes > 0, "got %u, %u\n", paths, modes); +} - paths = modes = 100; - ret = pGetDisplayConfigBufferSizes(0, &paths, &modes); - ok(ret == ERROR_INVALID_PARAMETER || ret == ERROR_NOT_SUPPORTED, "got %d\n", ret); - ok((modes == 0 || modes == 100) && paths == 0, "got %u, %u\n", modes, paths); +static BOOL CALLBACK test_EnumDisplayMonitors_normal_cb(HMONITOR monitor, HDC hdc, LPRECT rect, + LPARAM lparam) +{ + MONITORINFO mi; + LONG ret; + + mi.cbSize = sizeof(mi); + ret = GetMonitorInfoA(monitor, &mi); + ok(ret, "GetMonitorInfoA failed, error %#lx.\n", GetLastError()); + ok(EqualRect(rect, &mi.rcMonitor), "Expected rect %s, got %s.\n", + wine_dbgstr_rect(&mi.rcMonitor), wine_dbgstr_rect(rect)); + + return TRUE; +} + +static BOOL CALLBACK test_EnumDisplayMonitors_return_false_cb(HMONITOR monitor, HDC hdc, + LPRECT rect, LPARAM lparam) +{ + return FALSE; +} + +static BOOL CALLBACK test_EnumDisplayMonitors_invalid_handle_cb(HMONITOR monitor, HDC hdc, + LPRECT rect, LPARAM lparam) +{ + MONITORINFOEXA mi, mi2; + DEVMODEA old_dm, dm; + DWORD error; + INT count; + LONG ret; + + mi.cbSize = sizeof(mi); + ret = GetMonitorInfoA(monitor, (MONITORINFO *)&mi); + ok(ret, "GetMonitorInfoA failed, error %#lx.\n", GetLastError()); + + /* Test that monitor handle is invalid after the monitor is detached */ + if (!(mi.dwFlags & MONITORINFOF_PRIMARY)) + { + count = GetSystemMetrics(SM_CMONITORS); + + /* Save current display settings */ + memset(&old_dm, 0, sizeof(old_dm)); + old_dm.dmSize = sizeof(old_dm); + ret = EnumDisplaySettingsA(mi.szDevice, ENUM_CURRENT_SETTINGS, &old_dm); + ok(ret, "EnumDisplaySettingsA %s failed, error %#lx.\n", mi.szDevice, GetLastError()); + + /* Detach monitor */ + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + dm.dmFields = DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT; + dm.dmPosition.x = mi.rcMonitor.left; + dm.dmPosition.y = mi.rcMonitor.top; + ret = ChangeDisplaySettingsExA(mi.szDevice, &dm, NULL, CDS_UPDATEREGISTRY | CDS_NORESET, + NULL); + ok(ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned unexpected %ld.\n", + mi.szDevice, ret); + ret = ChangeDisplaySettingsExA(mi.szDevice, NULL, NULL, 0, NULL); + ok(ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned unexpected %ld.\n", + mi.szDevice, ret); + + /* Check if it's really detached */ + if (GetSystemMetrics(SM_CMONITORS) != count - 1) + { + skip("Failed to detach %s.\n", mi.szDevice); + SetLastError(0xdeadbeef); + return TRUE; + } + + /* The monitor handle should be invalid now */ + mi2.cbSize = sizeof(mi2); + SetLastError(0xdeadbeef); + ret = GetMonitorInfoA(monitor, (MONITORINFO *)&mi2); + ok(!ret, "GetMonitorInfoA succeeded.\n"); + error = GetLastError(); + ok(error == ERROR_INVALID_MONITOR_HANDLE || error == ERROR_INVALID_HANDLE, + "Expected error %#x, got %#lx.\n", ERROR_INVALID_MONITOR_HANDLE, error); + + /* Restore the original display settings */ + ret = ChangeDisplaySettingsExA(mi.szDevice, &old_dm, NULL, CDS_UPDATEREGISTRY | CDS_NORESET, + NULL); + ok(ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned unexpected %ld.\n", + mi.szDevice, ret); + ret = ChangeDisplaySettingsExA(mi.szDevice, NULL, NULL, 0, NULL); + ok(ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned unexpected %ld.\n", + mi.szDevice, ret); + } + + SetLastError(0xdeadbeef); + return TRUE; +} + +static BOOL CALLBACK test_EnumDisplayMonitors_count(HMONITOR monitor, HDC hdc, LPRECT rect, + LPARAM lparam) +{ + INT *count = (INT *)lparam; + ++(*count); + return TRUE; +} + +static void test_EnumDisplayMonitors(void) +{ + static const DWORD DESKTOP_ALL_ACCESS = 0x01ff; + HWINSTA winstation, old_winstation; + HDESK desktop, old_desktop; + USEROBJECTFLAGS flags; + INT count, old_count; + DWORD error; + BOOL ret; + + ret = EnumDisplayMonitors(NULL, NULL, test_EnumDisplayMonitors_normal_cb, 0); + ok(ret, "EnumDisplayMonitors failed, error %#lx.\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = EnumDisplayMonitors(NULL, NULL, test_EnumDisplayMonitors_return_false_cb, 0); + error = GetLastError(); + ok(!ret, "EnumDisplayMonitors succeeded.\n"); + ok(error == 0xdeadbeef, "Expected error %#x, got %#lx.\n", 0xdeadbeef, error); + + count = GetSystemMetrics(SM_CMONITORS); + SetLastError(0xdeadbeef); + ret = EnumDisplayMonitors(NULL, NULL, test_EnumDisplayMonitors_invalid_handle_cb, 0); + error = GetLastError(); + if (count >= 2) + todo_wine ok(!ret, "EnumDisplayMonitors succeeded.\n"); + else + ok(ret, "EnumDisplayMonitors failed.\n"); + ok(error == 0xdeadbeef, "Expected error %#x, got %#lx.\n", 0xdeadbeef, error); + + /* Test that monitor enumeration is not affected by window stations and desktops */ + old_winstation = GetProcessWindowStation(); + old_desktop = GetThreadDesktop(GetCurrentThreadId()); + old_count = GetSystemMetrics(SM_CMONITORS); + + count = 0; + ret = EnumDisplayMonitors(NULL, NULL, test_EnumDisplayMonitors_count, (LPARAM)&count); + ok(ret, "EnumDisplayMonitors failed, error %#lx.\n", GetLastError()); + ok(count == old_count, "Expected %d, got %d.\n", old_count, count); + + winstation = CreateWindowStationW(NULL, 0, WINSTA_ALL_ACCESS, NULL); + ok(!!winstation && winstation != old_winstation, "CreateWindowStationW failed, error %#lx.\n", GetLastError()); + ret = SetProcessWindowStation(winstation); + ok(ret, "SetProcessWindowStation failed, error %#lx.\n", GetLastError()); + ok(winstation == GetProcessWindowStation(), "Expected %p, got %p.\n", GetProcessWindowStation(), winstation); + + flags.fInherit = FALSE; + flags.fReserved = FALSE; + flags.dwFlags = WSF_VISIBLE; + ret = SetUserObjectInformationW(winstation, UOI_FLAGS, &flags, sizeof(flags)); + ok(ret, "SetUserObjectInformationW failed, error %#lx.\n", GetLastError()); + + desktop = CreateDesktopW(L"test_desktop", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL); + ok(!!desktop && desktop != old_desktop, "CreateDesktopW failed, error %#lx.\n", GetLastError()); + ret = SetThreadDesktop(desktop); + ok(ret, "SetThreadDesktop failed, error %#lx.\n", GetLastError()); + ok(desktop == GetThreadDesktop(GetCurrentThreadId()), "Expected %p, got %p.\n", + GetThreadDesktop(GetCurrentThreadId()), desktop); + + count = GetSystemMetrics(SM_CMONITORS); + ok(count == old_count, "Expected %d, got %d.\n", old_count, count); + count = 0; + ret = EnumDisplayMonitors(NULL, NULL, test_EnumDisplayMonitors_count, (LPARAM)&count); + ok(ret, "EnumDisplayMonitors failed, error %#lx.\n", GetLastError()); + ok(count == old_count, "Expected %d, got %d.\n", old_count, count); + + ret = SetProcessWindowStation(old_winstation); + ok(ret, "SetProcessWindowStation failed, error %#lx.\n", GetLastError()); + ret = SetThreadDesktop(old_desktop); + ok(ret, "SetThreadDesktop failed, error %#lx.\n", GetLastError()); + ret = CloseDesktop(desktop); + ok(ret, "CloseDesktop failed, error %#lx.\n", GetLastError()); + ret = CloseWindowStation(winstation); + ok(ret, "CloseWindowStation failed, error %#lx.\n", GetLastError()); +} + +static void check_device_path(const WCHAR *device_path, const LUID *adapter_id, DWORD id) +{ +#ifdef __REACTOS__ + skip("FIXME: check_device_path() cannot be built until we add new functions to setupapi\n"); +#else + BYTE iface_detail_buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + 256 * sizeof(WCHAR)]; + SP_DEVINFO_DATA device_data = {sizeof(device_data)}; + SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)}; + SP_DEVICE_INTERFACE_DETAIL_DATA_W *iface_data; + BOOL ret, found = FALSE; + DEVPROPTYPE type; + DWORD output_id; + unsigned int i; + HDEVINFO set; + LUID luid; + + iface_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_W *)iface_detail_buffer; + iface_data->cbSize = sizeof(*iface_data); + + set = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_MONITOR, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); + ok(set != INVALID_HANDLE_VALUE, "Got error %lu.\n", GetLastError()); + + i = 0; + while (SetupDiEnumDeviceInterfaces(set, NULL, &GUID_DEVINTERFACE_MONITOR, i, &iface)) + { + ret = SetupDiGetDeviceInterfaceDetailW(set, &iface, iface_data, + sizeof(iface_detail_buffer), NULL, &device_data); + ok(ret, "Got unexpected ret %d, GetLastError() %lu.\n", ret, GetLastError()); + + ret = SetupDiGetDevicePropertyW(set, &device_data, &DEVPROPKEY_MONITOR_GPU_LUID, &type, + (BYTE *)&luid, sizeof(luid), NULL, 0); + ok(ret || broken(GetLastError() == ERROR_NOT_FOUND) /* before Win10 1809 */, + "Got error %lu.\n", GetLastError()); + if (!ret) + { + win_skip("DEVPROPKEY_MONITOR_GPU_LUID is not found, skipping device path check.\n"); + SetupDiDestroyDeviceInfoList(set); + return; + } + ret = SetupDiGetDevicePropertyW(set, &device_data, &DEVPROPKEY_MONITOR_OUTPUT_ID, + &type, (BYTE *)&output_id, sizeof(output_id), NULL, 0); + ok(ret, "Got error %lu.\n", GetLastError()); + + if (output_id == id && RtlEqualLuid(&luid, adapter_id) && !wcsicmp(device_path, iface_data->DevicePath)) + { + found = TRUE; + break; + } + ++i; + } + ok(found, "device_path %s not found, luid %04lx:%04lx.\n", debugstr_w(device_path), adapter_id->HighPart, + adapter_id->LowPart); + SetupDiDestroyDeviceInfoList(set); +#endif +} + +static void check_preferred_mode(const DISPLAYCONFIG_TARGET_PREFERRED_MODE *mode, const WCHAR *gdi_device_name) +{ + DISPLAYCONFIG_TARGET_PREFERRED_MODE mode2; + DEVMODEW dm, dm2; + LONG lret; + BOOL bret; + + dm.dmSize = sizeof(dm); + bret = EnumDisplaySettingsW(gdi_device_name, ENUM_CURRENT_SETTINGS, &dm); +#ifdef __REACTOS__ + ok(bret || broken(GetLastError() == ERROR_INVALID_PARAMETER) /* Win8 */, "got error %lu.\n", GetLastError()); +#else + ok(bret, "got error %lu.\n", GetLastError()); +#endif + + if (dm.dmPelsWidth == 1024 && dm.dmPelsHeight == 768) + { + skip("Current display mode is already 1024x768, skipping test.\n"); + return; + } + if (mode->width == 1024 && mode->height == 768) + { + skip("Preferred display mode is 1024x768, skipping test.\n"); + return; + } + + memset(&dm2, 0, sizeof(dm2)); + dm2.dmSize = sizeof(dm2); + dm2.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; + dm2.dmPelsWidth = 1024; + dm2.dmPelsHeight = 768; + lret = ChangeDisplaySettingsExW(gdi_device_name, &dm2, NULL, 0, 0); + if (lret != DISP_CHANGE_SUCCESSFUL) + { + skip("Can't change display settings, skipping test.\n"); + return; + } + + memset(&mode2, 0, sizeof(mode2)); + mode2.header = mode->header; + + lret = pDisplayConfigGetDeviceInfo(&mode2.header); + ok(!lret, "got %ld\n", lret); + ok(mode2.width == mode->width, "got %u, expected %u.\n", mode2.width, mode->width); + ok(mode2.height == mode->height, "got %u, expected %u.\n", mode2.height, mode->height); + + lret = ChangeDisplaySettingsExW(gdi_device_name, &dm, NULL, 0, 0); + ok(lret == DISP_CHANGE_SUCCESSFUL, "got %ld.\n", lret); +} + +static void test_QueryDisplayConfig_result(UINT32 flags, + UINT32 paths, const DISPLAYCONFIG_PATH_INFO *pi, UINT32 modes, const DISPLAYCONFIG_MODE_INFO *mi) +{ + UINT32 i, src_mode_idx, tgt_mode_idx; + LONG ret; + DISPLAYCONFIG_SOURCE_DEVICE_NAME source_name; + DISPLAYCONFIG_TARGET_DEVICE_NAME target_name; + DISPLAYCONFIG_TARGET_PREFERRED_MODE preferred_mode; + DISPLAYCONFIG_ADAPTER_NAME adapter_name; + const DISPLAYCONFIG_DESKTOP_IMAGE_INFO *di; + + for (i = 0; i < paths; i++) + { + source_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; + source_name.header.size = sizeof(source_name); + source_name.header.adapterId = pi[i].sourceInfo.adapterId; + source_name.header.id = pi[i].sourceInfo.id; + source_name.viewGdiDeviceName[0] = '\0'; + ret = pDisplayConfigGetDeviceInfo(&source_name.header); +#ifdef __REACTOS__ + ok(!ret || broken(ret == ERROR_GEN_FAILURE) /* Win8 */, "Expected 0, got %ld\n", ret); + if (ret != ERROR_GEN_FAILURE) + ok(source_name.viewGdiDeviceName[0] != '\0', "Expected GDI device name, got empty string\n"); +#else + ok(!ret, "Expected 0, got %ld\n", ret); + ok(source_name.viewGdiDeviceName[0] != '\0', "Expected GDI device name, got empty string\n"); +#endif + + /* Test with an invalid adapter LUID */ + source_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; + source_name.header.size = sizeof(source_name); + source_name.header.adapterId.LowPart = 0xFFFF; + source_name.header.adapterId.HighPart = 0xFFFF; + source_name.header.id = pi[i].sourceInfo.id; + ret = pDisplayConfigGetDeviceInfo(&source_name.header); + ok(ret == ERROR_GEN_FAILURE, "Expected GEN_FAILURE, got %ld\n", ret); + + target_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME; + target_name.header.size = sizeof(target_name); + target_name.header.adapterId = pi[i].targetInfo.adapterId; + target_name.header.id = pi[i].targetInfo.id; + target_name.monitorDevicePath[0] = '\0'; + ret = pDisplayConfigGetDeviceInfo(&target_name.header); +#ifdef __REACTOS__ + ok(!ret || broken(ret == ERROR_GEN_FAILURE) /* Win8 */, "Expected 0, got %ld\n", ret); +#else + ok(!ret, "Expected 0, got %ld\n", ret); +#endif + check_device_path(target_name.monitorDevicePath, &target_name.header.adapterId, target_name.header.id); + + preferred_mode.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE; + preferred_mode.header.size = sizeof(preferred_mode); + preferred_mode.header.adapterId = pi[i].targetInfo.adapterId; + preferred_mode.header.id = pi[i].targetInfo.id; + preferred_mode.width = preferred_mode.height = 0; + ret = pDisplayConfigGetDeviceInfo(&preferred_mode.header); +#ifdef __REACTOS__ + ok(!ret || broken(ret == ERROR_GEN_FAILURE) /* Win8 */, "Expected 0, got %ld\n", ret); + if (!ret) + ok(preferred_mode.width > 0 && preferred_mode.height > 0, "Expected non-zero height/width, got %ux%u\n", + preferred_mode.width, preferred_mode.height); +#else + ok(!ret, "Expected 0, got %ld\n", ret); + ok(preferred_mode.width > 0 && preferred_mode.height > 0, "Expected non-zero height/width, got %ux%u\n", + preferred_mode.width, preferred_mode.height); +#endif + check_preferred_mode(&preferred_mode, source_name.viewGdiDeviceName); + + todo_wine { + adapter_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME; + adapter_name.header.size = sizeof(adapter_name); + adapter_name.header.adapterId = pi[i].sourceInfo.adapterId; + adapter_name.adapterDevicePath[0] = '\0'; + ret = pDisplayConfigGetDeviceInfo(&adapter_name.header); +#ifdef __REACTOS__ + ok(!ret || broken(ret == ERROR_GEN_FAILURE) /* Win8 */, "Expected 0, got %ld\n", ret); + if (!ret) + ok(adapter_name.adapterDevicePath[0] != '\0', "Expected adapter device path, got empty string\n"); +#else + ok(!ret, "Expected 0, got %ld\n", ret); + ok(adapter_name.adapterDevicePath[0] != '\0', "Expected adapter device path, got empty string\n"); +#endif + } + + /* Check corresponding modes */ + if (flags & QDC_VIRTUAL_MODE_AWARE) + { + src_mode_idx = pi[i].sourceInfo.sourceModeInfoIdx; + if (src_mode_idx == DISPLAYCONFIG_PATH_SOURCE_MODE_IDX_INVALID) + { + ok(pi[i].sourceInfo.cloneGroupId != DISPLAYCONFIG_PATH_CLONE_GROUP_INVALID, "got cloneGroupId %#x.\n", + pi[i].sourceInfo.cloneGroupId); + skip("Path doesn't contain source modeInfoIdx\n"); + continue; + } + ok(pi[i].sourceInfo.cloneGroupId == DISPLAYCONFIG_PATH_CLONE_GROUP_INVALID, "got cloneGroupId %#x.\n", + pi[i].sourceInfo.cloneGroupId); + } + else + { + src_mode_idx = pi[i].sourceInfo.modeInfoIdx; + if (src_mode_idx == DISPLAYCONFIG_PATH_MODE_IDX_INVALID) + { + skip("Path doesn't contain source modeInfoIdx\n"); + continue; + } + } + ok(src_mode_idx < modes, "Expected index <%d, got %d\n", modes, src_mode_idx); + if (src_mode_idx >= modes) + continue; + + ok(mi[src_mode_idx].infoType == DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE, "Expected infoType %d, got %d\n", + DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE, mi[src_mode_idx].infoType); + ok(pi[i].sourceInfo.id == mi[src_mode_idx].id, "Expected id %u, got %u\n", + pi[i].sourceInfo.id, mi[src_mode_idx].id); + ok(pi[i].sourceInfo.adapterId.HighPart == mi[src_mode_idx].adapterId.HighPart && + pi[i].sourceInfo.adapterId.LowPart == mi[src_mode_idx].adapterId.LowPart, + "Expected LUID %08lx:%08lx, got %08lx:%08lx\n", + pi[i].sourceInfo.adapterId.HighPart, pi[i].sourceInfo.adapterId.LowPart, + mi[src_mode_idx].adapterId.HighPart, mi[src_mode_idx].adapterId.LowPart); + ok(mi[src_mode_idx].sourceMode.width > 0 && mi[src_mode_idx].sourceMode.height > 0, + "Expected non-zero height/width, got %ux%u\n", + mi[src_mode_idx].sourceMode.width, mi[src_mode_idx].sourceMode.height); + + + if (flags & QDC_VIRTUAL_MODE_AWARE) + { + tgt_mode_idx = pi[i].targetInfo.targetModeInfoIdx; + if (tgt_mode_idx == DISPLAYCONFIG_PATH_TARGET_MODE_IDX_INVALID) + { + skip("Path doesn't contain target modeInfoIdx\n"); + continue; + } + } + else + { + tgt_mode_idx = pi[i].targetInfo.modeInfoIdx; + if (tgt_mode_idx == DISPLAYCONFIG_PATH_MODE_IDX_INVALID) + { + skip("Path doesn't contain target modeInfoIdx\n"); + continue; + } + } + ok(tgt_mode_idx < modes, "Expected index <%d, got %d\n", modes, tgt_mode_idx); + if (tgt_mode_idx >= modes) + continue; + + ok(mi[tgt_mode_idx].infoType == DISPLAYCONFIG_MODE_INFO_TYPE_TARGET, "Expected infoType %d, got %d\n", + DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE, mi[tgt_mode_idx].infoType); + ok(pi[i].targetInfo.id == mi[tgt_mode_idx].id, "Expected id %u, got %u\n", + pi[i].targetInfo.id, mi[tgt_mode_idx].id); + ok(pi[i].targetInfo.adapterId.HighPart == mi[tgt_mode_idx].adapterId.HighPart && + pi[i].targetInfo.adapterId.LowPart == mi[tgt_mode_idx].adapterId.LowPart, + "Expected LUID %08lx:%08lx, got %08lx:%08lx\n", + pi[i].targetInfo.adapterId.HighPart, pi[i].targetInfo.adapterId.LowPart, + mi[tgt_mode_idx].adapterId.HighPart, mi[tgt_mode_idx].adapterId.LowPart); + ok(mi[tgt_mode_idx].targetMode.targetVideoSignalInfo.activeSize.cx > 0 && + mi[tgt_mode_idx].targetMode.targetVideoSignalInfo.activeSize.cy > 0, + "Expected non-zero height/width, got %ux%u\n", + mi[tgt_mode_idx].targetMode.targetVideoSignalInfo.activeSize.cx, + mi[tgt_mode_idx].targetMode.targetVideoSignalInfo.activeSize.cy); + + if (flags == QDC_DATABASE_CURRENT) + ok(mi[tgt_mode_idx].targetMode.targetVideoSignalInfo.totalSize.cx == 0 && + mi[tgt_mode_idx].targetMode.targetVideoSignalInfo.totalSize.cy == 0, + "Expected zero height/width, got %ux%u\n", + mi[tgt_mode_idx].targetMode.targetVideoSignalInfo.totalSize.cx, + mi[tgt_mode_idx].targetMode.targetVideoSignalInfo.totalSize.cy); + else + ok(mi[tgt_mode_idx].targetMode.targetVideoSignalInfo.totalSize.cx > 0 && + mi[tgt_mode_idx].targetMode.targetVideoSignalInfo.totalSize.cy > 0, + "Expected non-zero height/width, got %ux%u\n", + mi[tgt_mode_idx].targetMode.targetVideoSignalInfo.totalSize.cx, + mi[tgt_mode_idx].targetMode.targetVideoSignalInfo.totalSize.cy); + if (flags & QDC_VIRTUAL_MODE_AWARE) + { + tgt_mode_idx = pi[i].targetInfo.desktopModeInfoIdx; + if (tgt_mode_idx == DISPLAYCONFIG_PATH_DESKTOP_IMAGE_IDX_INVALID) + { + ok(!(pi[i].flags & DISPLAYCONFIG_PATH_SUPPORT_VIRTUAL_MODE), "got path flags %#x.\n", pi[i].flags); + skip("Path doesn't contain target desktopModeInfoIdx.\n"); + continue; + } + ok(pi[i].flags & DISPLAYCONFIG_PATH_SUPPORT_VIRTUAL_MODE, "got path flags %#x.\n", pi[i].flags); + } + else + { + continue; + } + + ok(mi[tgt_mode_idx].infoType == DISPLAYCONFIG_MODE_INFO_TYPE_DESKTOP_IMAGE, "Expected infoType %d, got %d\n", + DISPLAYCONFIG_MODE_INFO_TYPE_DESKTOP_IMAGE, mi[tgt_mode_idx].infoType); + ok(pi[i].targetInfo.id == mi[tgt_mode_idx].id, "Expected id %u, got %u\n", + pi[i].targetInfo.id, mi[tgt_mode_idx].id); + ok(pi[i].targetInfo.adapterId.HighPart == mi[tgt_mode_idx].adapterId.HighPart && + pi[i].targetInfo.adapterId.LowPart == mi[tgt_mode_idx].adapterId.LowPart, + "Expected LUID %08lx:%08lx, got %08lx:%08lx\n", + pi[i].targetInfo.adapterId.HighPart, pi[i].targetInfo.adapterId.LowPart, + mi[tgt_mode_idx].adapterId.HighPart, mi[tgt_mode_idx].adapterId.LowPart); + di = &mi[tgt_mode_idx].desktopImageInfo; + ok(!di->DesktopImageRegion.left && !di->DesktopImageRegion.top, + "Expected zero left/top, got %lux%lu\n", + di->DesktopImageRegion.left, + di->DesktopImageRegion.top); + ok(di->DesktopImageRegion.right > 0 && di->DesktopImageRegion.bottom > 0, + "Expected non-zero height/width, got %lux%lu\n", + di->DesktopImageRegion.right, + di->DesktopImageRegion.bottom); + ok(!di->DesktopImageClip.left && !di->DesktopImageClip.top, + "Expected zero left/top, got %lux%lu\n", + di->DesktopImageClip.left, + di->DesktopImageClip.top); + ok(di->DesktopImageClip.right > 0 && di->DesktopImageClip.bottom > 0, + "Expected non-zero height/width, got %lux%lu\n", + di->DesktopImageClip.right, + di->DesktopImageClip.bottom); + ok(di->PathSourceSize.x > 0 && di->PathSourceSize.y > 0, + "Expected non-zero x/y, got %lux%lu\n", + di->PathSourceSize.x, + di->PathSourceSize.y); + } +} + +static void test_QueryDisplayConfig(void) +{ + UINT32 paths, modes; + DISPLAYCONFIG_PATH_INFO pi[10]; + DISPLAYCONFIG_MODE_INFO mi[20]; + DISPLAYCONFIG_TOPOLOGY_ID topologyid; + LONG ret; + + ret = pQueryDisplayConfig(QDC_ALL_PATHS, NULL, NULL, NULL, NULL, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); + + paths = modes = 0; + ret = pQueryDisplayConfig(QDC_ALL_PATHS, &paths, NULL, &modes, NULL, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); + + paths = modes = 0; + ret = pQueryDisplayConfig(QDC_ALL_PATHS, &paths, pi, &modes, NULL, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); + + paths = modes = 0; + ret = pQueryDisplayConfig(QDC_ALL_PATHS, &paths, NULL, &modes, mi, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); + + paths = modes = 0; + ret = pQueryDisplayConfig(QDC_ALL_PATHS, &paths, pi, &modes, mi, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); + + paths = 0; + modes = 1; + ret = pQueryDisplayConfig(QDC_ALL_PATHS, &paths, pi, &modes, mi, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); + ok (paths == 0, "got %u\n", paths); + ok (modes == 1, "got %u\n", modes); + + /* Crashes on Windows 10 */ + if (0) + { + ret = pQueryDisplayConfig(QDC_ALL_PATHS, NULL, pi, NULL, mi, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); + + ret = pQueryDisplayConfig(QDC_ALL_PATHS, NULL, pi, &modes, mi, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); + } + + paths = modes = 1; + ret = pQueryDisplayConfig(0, &paths, pi, &modes, mi, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); + + paths = modes = 1; + ret = pQueryDisplayConfig(0xFF, &paths, pi, &modes, mi, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); + + paths = modes = 1; + ret = pQueryDisplayConfig(QDC_DATABASE_CURRENT, &paths, pi, &modes, mi, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); + + paths = modes = 1; + ret = pQueryDisplayConfig(QDC_ALL_PATHS, &paths, pi, &modes, mi, &topologyid); + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); + + /* Below this point, test functionality that requires a WDDM driver on Windows */ + paths = modes = 1; + memset(pi, 0xFF, sizeof(pi[0])); + memset(mi, 0xFF, sizeof(mi[0])); + ret = pQueryDisplayConfig(QDC_ALL_PATHS, &paths, pi, &modes, mi, NULL); + if (ret == ERROR_NOT_SUPPORTED) + { + todo_wine + win_skip("QueryDisplayConfig() functionality is unsupported\n"); + return; + } + ok(ret == ERROR_INSUFFICIENT_BUFFER, "got %ld\n", ret); + ok (paths == 1, "got %u\n", paths); + ok (modes == 1, "got %u\n", modes); + + paths = ARRAY_SIZE(pi); + modes = ARRAY_SIZE(mi); + memset(pi, 0xFF, sizeof(pi)); + memset(mi, 0xFF, sizeof(mi)); + ret = pQueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &paths, pi, &modes, mi, NULL); + ok(!ret, "got %ld\n", ret); + ok(paths > 0 && modes > 0, "got %u, %u\n", paths, modes); + if (!ret && paths > 0 && modes > 0) + test_QueryDisplayConfig_result(QDC_ONLY_ACTIVE_PATHS, paths, pi, modes, mi); + + paths = ARRAY_SIZE(pi); + modes = ARRAY_SIZE(mi); + memset(pi, 0xFF, sizeof(pi)); + memset(mi, 0xFF, sizeof(mi)); + topologyid = 0xFF; + ret = pQueryDisplayConfig(QDC_DATABASE_CURRENT, &paths, pi, &modes, mi, &topologyid); + ok(!ret, "got %ld\n", ret); + ok(topologyid != 0xFF, "expected topologyid to be set, got %d\n", topologyid); + if (!ret && paths > 0 && modes > 0) + test_QueryDisplayConfig_result(QDC_DATABASE_CURRENT, paths, pi, modes, mi); + + paths = ARRAY_SIZE(pi); + modes = ARRAY_SIZE(mi); + memset(pi, 0xFF, sizeof(pi)); + memset(mi, 0xFF, sizeof(mi)); + ret = pQueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS | QDC_VIRTUAL_MODE_AWARE, &paths, pi, &modes, mi, NULL); + ok(!ret || broken(ret == ERROR_INVALID_PARAMETER) /* before Win10 */, "got %ld\n", ret); + if (!ret) + ok(paths > 0 && modes > 0, "got %u, %u\n", paths, modes); + if (!ret && paths > 0 && modes > 0) + test_QueryDisplayConfig_result(QDC_ONLY_ACTIVE_PATHS | QDC_VIRTUAL_MODE_AWARE, paths, pi, modes, mi); +} + +static void test_DisplayConfigGetDeviceInfo(void) +{ + LONG ret; + DISPLAYCONFIG_SOURCE_DEVICE_NAME source_name; + DISPLAYCONFIG_TARGET_DEVICE_NAME target_name; + DISPLAYCONFIG_TARGET_PREFERRED_MODE preferred_mode; + DISPLAYCONFIG_ADAPTER_NAME adapter_name; + + ret = pDisplayConfigGetDeviceInfo(NULL); + ok(ret == ERROR_GEN_FAILURE, "got %ld\n", ret); + + source_name.header.type = 0xFFFF; + source_name.header.size = 0; + ret = pDisplayConfigGetDeviceInfo(&source_name.header); + ok(ret == ERROR_GEN_FAILURE, "got %ld\n", ret); + + source_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; + source_name.header.size = 0; + ret = pDisplayConfigGetDeviceInfo(&source_name.header); + ok(ret == ERROR_GEN_FAILURE, "got %ld\n", ret); + + source_name.header.type = 0xFFFF; + source_name.header.size = sizeof(source_name.header); + ret = pDisplayConfigGetDeviceInfo(&source_name.header); +#ifdef __REACTOS__ + ok(ret == ERROR_INVALID_PARAMETER || ret == ERROR_GEN_FAILURE /* Win7 */, "got %ld\n", ret); +#else + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); +#endif + + source_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; + source_name.header.size = sizeof(source_name.header); + ret = pDisplayConfigGetDeviceInfo(&source_name.header); +#ifdef __REACTOS__ + ok(ret == ERROR_INVALID_PARAMETER || ret == ERROR_GEN_FAILURE /* Win7 */, "got %ld\n", ret); +#else + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); +#endif + + source_name.header.type = 0xFFFF; + source_name.header.size = sizeof(source_name); + ret = pDisplayConfigGetDeviceInfo(&source_name.header); +#ifdef __REACTOS__ + ok(ret == ERROR_INVALID_PARAMETER || ret == ERROR_GEN_FAILURE /* Win7 */, "got %ld\n", ret); +#else + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); +#endif + + source_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; + source_name.header.size = sizeof(source_name) - 1; + ret = pDisplayConfigGetDeviceInfo(&source_name.header); +#ifdef __REACTOS__ + ok(ret == ERROR_INVALID_PARAMETER || ret == ERROR_GEN_FAILURE /* Win7 */, "got %ld\n", ret); +#else + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); +#endif + + source_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; + source_name.header.size = sizeof(source_name); + source_name.header.adapterId.LowPart = 0xFFFF; + source_name.header.adapterId.HighPart = 0xFFFF; + source_name.header.id = 0; + ret = pDisplayConfigGetDeviceInfo(&source_name.header); + ok(ret == ERROR_GEN_FAILURE || ret == ERROR_NOT_SUPPORTED, "got %ld\n", ret); + + target_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME; + target_name.header.size = sizeof(target_name) - 1; + ret = pDisplayConfigGetDeviceInfo(&target_name.header); +#ifdef __REACTOS__ + ok(ret == ERROR_INVALID_PARAMETER || ret == ERROR_GEN_FAILURE /* Win7 */, "got %ld\n", ret); +#else + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); +#endif + + target_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME; + target_name.header.size = sizeof(target_name); + target_name.header.adapterId.LowPart = 0xFFFF; + target_name.header.adapterId.HighPart = 0xFFFF; + target_name.header.id = 0; + ret = pDisplayConfigGetDeviceInfo(&target_name.header); + ok(ret == ERROR_GEN_FAILURE || ret == ERROR_NOT_SUPPORTED, "got %ld\n", ret); + + preferred_mode.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE; + preferred_mode.header.size = sizeof(preferred_mode) - 1; + ret = pDisplayConfigGetDeviceInfo(&preferred_mode.header); +#ifdef __REACTOS__ + ok(ret == ERROR_INVALID_PARAMETER || ret == ERROR_GEN_FAILURE /* Win7 */, "got %ld\n", ret); +#else + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); +#endif + + preferred_mode.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE; + preferred_mode.header.size = sizeof(preferred_mode); + preferred_mode.header.adapterId.LowPart = 0xFFFF; + preferred_mode.header.adapterId.HighPart = 0xFFFF; + preferred_mode.header.id = 0; + ret = pDisplayConfigGetDeviceInfo(&preferred_mode.header); + ok(ret == ERROR_GEN_FAILURE || ret == ERROR_INVALID_PARAMETER || ret == ERROR_NOT_SUPPORTED, "got %ld\n", ret); + + adapter_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME; + adapter_name.header.size = sizeof(adapter_name) - 1; + ret = pDisplayConfigGetDeviceInfo(&adapter_name.header); +#ifdef __REACTOS__ + ok(ret == ERROR_INVALID_PARAMETER || ret == ERROR_GEN_FAILURE /* Win7 */, "got %ld\n", ret); +#else + ok(ret == ERROR_INVALID_PARAMETER, "got %ld\n", ret); +#endif + + adapter_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME; + adapter_name.header.size = sizeof(adapter_name); + adapter_name.header.adapterId.LowPart = 0xFFFF; + adapter_name.header.adapterId.HighPart = 0xFFFF; + ret = pDisplayConfigGetDeviceInfo(&adapter_name.header); + ok(ret == ERROR_GEN_FAILURE || ret == ERROR_INVALID_PARAMETER || ret == ERROR_NOT_SUPPORTED, "got %ld\n", ret); +} + +static void test_display_config(void) +{ + if (!pGetDisplayConfigBufferSizes || + !pQueryDisplayConfig || + !pDisplayConfigGetDeviceInfo) + { + win_skip("DisplayConfig APIs are not supported\n"); + return; + } + + test_GetDisplayConfigBufferSizes(); + test_QueryDisplayConfig(); + test_DisplayConfigGetDeviceInfo(); +} + +static void test_DisplayConfigSetDeviceInfo(void) +{ + static const unsigned int scales[] = {100, 125, 150, 175, 200, 225, 250, 300, 350, 400, 450, 500}; + static const DWORD enabled = 1; + int current_scale, current_scale_idx, recommended_scale_idx, step, dpi, old_dpi; + D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME open_adapter_gdi_desc; + DISPLAYCONFIG_GET_SOURCE_DPI_SCALE get_scale_req; + DISPLAYCONFIG_SET_SOURCE_DPI_SCALE set_scale_req; + D3DKMT_CLOSEADAPTER close_adapter_desc; + NTSTATUS status; + HKEY key; + LONG ret; + +#define CHECK_FUNC(func) \ + if (!p##func) \ + { \ + win_skip("%s() is unavailable.\n", #func); \ + ret = TRUE; \ + } + + ret = FALSE; + CHECK_FUNC(D3DKMTCloseAdapter) + CHECK_FUNC(D3DKMTOpenAdapterFromGdiDisplayName) + CHECK_FUNC(DisplayConfigGetDeviceInfo) + todo_wine CHECK_FUNC(DisplayConfigSetDeviceInfo) + CHECK_FUNC(GetDpiForMonitorInternal) + CHECK_FUNC(SetThreadDpiAwarenessContext) + if (ret) return; + +#undef CHECK_FUNC + + lstrcpyW(open_adapter_gdi_desc.DeviceName, L"\\\\.\\DISPLAY1"); + status = pD3DKMTOpenAdapterFromGdiDisplayName(&open_adapter_gdi_desc); + ok(status == STATUS_SUCCESS, "D3DKMTOpenAdapterFromGdiDisplayName failed, status %#lx.\n", status); + + get_scale_req.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_DPI_SCALE; + get_scale_req.header.size = sizeof(get_scale_req); + get_scale_req.header.adapterId = open_adapter_gdi_desc.AdapterLuid; + get_scale_req.header.id = open_adapter_gdi_desc.VidPnSourceId; + ret = pDisplayConfigGetDeviceInfo(&get_scale_req.header); + if (ret != NO_ERROR) + { + skip("DisplayConfigGetDeviceInfo failed, returned %ld.\n", ret); + goto failed; + } + + /* Set IgnorePerProcessSystemDPIToast to 1 to disable "fix blurry apps popup" on Windows 10, + * which may interfere other tests because it steals focus */ + RegOpenKeyA(HKEY_CURRENT_USER, "Control Panel\\Desktop", &key); + RegSetValueExA(key, "IgnorePerProcessSystemDPIToast", 0, REG_DWORD, (const BYTE *)&enabled, + sizeof(enabled)); + + dpi = get_primary_dpi(); + old_dpi = dpi; + current_scale = dpi * 100 / 96; + for (current_scale_idx = 0; current_scale_idx < ARRAY_SIZE(scales); ++current_scale_idx) + { + if (scales[current_scale_idx] == current_scale) + break; + } + ok(scales[current_scale_idx] == current_scale, "Failed to find current scale.\n"); + recommended_scale_idx = current_scale_idx - get_scale_req.curRelativeScaleStep; + + set_scale_req.header.type = DISPLAYCONFIG_DEVICE_INFO_SET_SOURCE_DPI_SCALE; + set_scale_req.header.size = sizeof(set_scale_req); + set_scale_req.header.adapterId = open_adapter_gdi_desc.AdapterLuid; + set_scale_req.header.id = open_adapter_gdi_desc.VidPnSourceId; + for (step = get_scale_req.minRelativeScaleStep; step <= get_scale_req.maxRelativeScaleStep; ++step) + { + set_scale_req.relativeScaleStep = step; + ret = pDisplayConfigSetDeviceInfo(&set_scale_req.header); + ok(ret == NO_ERROR, "DisplayConfigSetDeviceInfo failed, returned %ld.\n", ret); + + dpi = scales[step + recommended_scale_idx] * 96 / 100; + ok(dpi == get_primary_dpi(), "Expected %d, got %d.\n", get_primary_dpi(), dpi); + } + + /* Restore to the original scale */ + set_scale_req.relativeScaleStep = get_scale_req.curRelativeScaleStep; + ret = pDisplayConfigSetDeviceInfo(&set_scale_req.header); + ok(ret == NO_ERROR, "DisplayConfigSetDeviceInfo failed, returned %ld.\n", ret); + ok(old_dpi == get_primary_dpi(), "Expected %d, got %d.\n", get_primary_dpi(), old_dpi); + + /* Remove IgnorePerProcessSystemDPIToast registry value */ + RegDeleteValueA(key, "IgnorePerProcessSystemDPIToast"); + RegCloseKey(key); + +failed: + close_adapter_desc.hAdapter = open_adapter_gdi_desc.hAdapter; + status = pD3DKMTCloseAdapter(&close_adapter_desc); + ok(status == STATUS_SUCCESS, "Got unexpected return code %#lx.\n", status); +} + +static BOOL CALLBACK test_handle_proc(HMONITOR full_monitor, HDC hdc, LPRECT rect, LPARAM lparam) +{ + MONITORINFO monitor_info = {sizeof(monitor_info)}; + HMONITOR monitor; + BOOL ret; + +#ifdef _WIN64 + if ((ULONG_PTR)full_monitor >> 32) + monitor = full_monitor; + else + monitor = (HMONITOR)((ULONG_PTR)full_monitor | ((ULONG_PTR)~0u << 32)); + SetLastError(0xdeadbeef); + ret = GetMonitorInfoW(monitor, &monitor_info); + ok(ret, "GetMonitorInfoW failed, error %#lx.\n", GetLastError()); + + monitor = (HMONITOR)((ULONG_PTR)full_monitor & 0xffffffff); + SetLastError(0xdeadbeef); + ret = GetMonitorInfoW(monitor, &monitor_info); + ok(ret, "GetMonitorInfoW failed, error %#lx.\n", GetLastError()); + + monitor = (HMONITOR)(((ULONG_PTR)full_monitor & 0xffffffff) | ((ULONG_PTR)0x1234 << 32)); + SetLastError(0xdeadbeef); + ret = GetMonitorInfoW(monitor, &monitor_info); + ok(ret, "GetMonitorInfoW failed, error %#lx.\n", GetLastError()); + + monitor = (HMONITOR)((ULONG_PTR)full_monitor & 0xffff); + SetLastError(0xdeadbeef); + ret = GetMonitorInfoW(monitor, &monitor_info); + todo_wine ok(!ret, "GetMonitorInfoW succeeded.\n"); + todo_wine ok(GetLastError() == ERROR_INVALID_MONITOR_HANDLE, "Expected error code %#x, got %#lx.\n", + ERROR_INVALID_MONITOR_HANDLE, GetLastError()); + + monitor = (HMONITOR)(((ULONG_PTR)full_monitor & 0xffff) | ((ULONG_PTR)0x9876 << 16)); + SetLastError(0xdeadbeef); + ret = GetMonitorInfoW(monitor, &monitor_info); + ok(!ret, "GetMonitorInfoW succeeded.\n"); + ok(GetLastError() == ERROR_INVALID_MONITOR_HANDLE, "Expected error code %#x, got %#lx.\n", + ERROR_INVALID_MONITOR_HANDLE, GetLastError()); + + monitor = (HMONITOR)(((ULONG_PTR)full_monitor & 0xffff) | ((ULONG_PTR)0x12345678 << 16)); + SetLastError(0xdeadbeef); + ret = GetMonitorInfoW(monitor, &monitor_info); + ok(!ret, "GetMonitorInfoW succeeded.\n"); + ok(GetLastError() == ERROR_INVALID_MONITOR_HANDLE, "Expected error code %#x, got %#lx.\n", + ERROR_INVALID_MONITOR_HANDLE, GetLastError()); +#else + if ((ULONG_PTR)full_monitor >> 16) + monitor = full_monitor; + else + monitor = (HMONITOR)((ULONG_PTR)full_monitor | ((ULONG_PTR)~0u << 16)); + SetLastError(0xdeadbeef); + ret = GetMonitorInfoW(monitor, &monitor_info); + todo_wine_if(((ULONG_PTR)full_monitor >> 16) == 0) + ok(ret, "GetMonitorInfoW failed, error %#lx.\n", GetLastError()); + + monitor = (HMONITOR)((ULONG_PTR)full_monitor & 0xffff); + SetLastError(0xdeadbeef); + ret = GetMonitorInfoW(monitor, &monitor_info); + ok(ret, "GetMonitorInfoW failed, error %#lx.\n", GetLastError()); + + monitor = (HMONITOR)(((ULONG_PTR)full_monitor & 0xffff) | ((ULONG_PTR)0x1234 << 16)); + SetLastError(0xdeadbeef); + ret = GetMonitorInfoW(monitor, &monitor_info); + ok(!ret, "GetMonitorInfoW succeeded.\n"); + ok(GetLastError() == ERROR_INVALID_MONITOR_HANDLE, "Expected error code %#x, got %#lx.\n", + ERROR_INVALID_MONITOR_HANDLE, GetLastError()); +#endif + + return TRUE; +} + +static void test_handles(void) +{ + BOOL ret; + + /* Test that monitor handles are user32 handles */ + ret = EnumDisplayMonitors(NULL, NULL, test_handle_proc, 0); + ok(ret, "EnumDisplayMonitors failed, error %#lx.\n", GetLastError()); +} + +#define check_display_dc(a, b, c) _check_display_dc(__LINE__, a, b, c) +static void _check_display_dc(INT line, HDC hdc, const DEVMODEA *dm, BOOL allow_todo) +{ +#if defined(__REACTOS__) && defined(_MSC_VER) + unsigned char buffer[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256] = {0}; +#else + unsigned char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])] = {0}; +#endif + BITMAPINFO *bmi = (BITMAPINFO *)buffer; + DIBSECTION dib; + BITMAP bitmap; + HBITMAP hbmp; + INT value; + BOOL ret; + + value = GetDeviceCaps(hdc, HORZRES); + todo_wine_if(allow_todo && dm->dmPelsWidth != GetSystemMetrics(SM_CXSCREEN)) + ok_(__FILE__, line)(value == dm->dmPelsWidth, "Expected HORZRES %ld, got %d.\n", + dm->dmPelsWidth, value); + + value = GetDeviceCaps(hdc, VERTRES); + todo_wine_if(allow_todo && dm->dmPelsHeight != GetSystemMetrics(SM_CYSCREEN)) + ok_(__FILE__, line)(value == dm->dmPelsHeight, "Expected VERTRES %ld, got %d.\n", + dm->dmPelsHeight, value); + + value = GetDeviceCaps(hdc, DESKTOPHORZRES); + todo_wine_if(dm->dmPelsWidth != GetSystemMetrics(SM_CXVIRTUALSCREEN) + && value == GetSystemMetrics(SM_CXVIRTUALSCREEN)) + ok_(__FILE__, line)(value == dm->dmPelsWidth, "Expected DESKTOPHORZRES %ld, got %d.\n", + dm->dmPelsWidth, value); + + value = GetDeviceCaps(hdc, DESKTOPVERTRES); + todo_wine_if(dm->dmPelsHeight != GetSystemMetrics(SM_CYVIRTUALSCREEN) + && value == GetSystemMetrics(SM_CYVIRTUALSCREEN)) + ok_(__FILE__, line)(value == dm->dmPelsHeight, "Expected DESKTOPVERTRES %ld, got %d.\n", + dm->dmPelsHeight, value); + + value = GetDeviceCaps(hdc, VREFRESH); + todo_wine_if(allow_todo) + ok_(__FILE__, line)(value == dm->dmDisplayFrequency, "Expected VREFRESH %ld, got %d.\n", + dm->dmDisplayFrequency, value); + + value = GetDeviceCaps(hdc, BITSPIXEL); + ok_(__FILE__, line)(value == dm->dmBitsPerPel, "Expected BITSPIXEL %ld, got %d.\n", + dm->dmBitsPerPel, value); + + hbmp = GetCurrentObject(hdc, OBJ_BITMAP); + ok_(__FILE__, line)(!!hbmp, "GetCurrentObject failed, error %#lx.\n", GetLastError()); + + /* Expect hbmp to be a bitmap, not a DIB when GetObjectA() succeeds */ + value = GetObjectA(hbmp, sizeof(dib), &dib); + ok(!value || value == sizeof(BITMAP), "GetObjectA failed, value %d.\n", value); + + /* Expect GetDIBits() to succeed */ + bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + value = GetDIBits(hdc, hbmp, 0, 0, NULL, (LPBITMAPINFO)bmi, DIB_RGB_COLORS); + ok(value, "GetDIBits failed, error %#lx.\n", GetLastError()); +#ifdef __REACTOS__ + ok(bmi->bmiHeader.biCompression == BI_BITFIELDS || broken(bmi->bmiHeader.biCompression == BI_RGB) /* WS03 */, "Got unexpected biCompression %lu.\n", bmi->bmiHeader.biCompression); +#else + ok(bmi->bmiHeader.biCompression == BI_BITFIELDS, "Got unexpected biCompression %lu.\n", bmi->bmiHeader.biCompression); +#endif + + ret = GetObjectA(hbmp, sizeof(bitmap), &bitmap); + /* GetObjectA fails on Win7 and older */ + if (ret) + { + ok_(__FILE__, line)(bitmap.bmType == 0, "Expected bmType %d, got %d.\n", 0, bitmap.bmType); + ok_(__FILE__, line)(bitmap.bmWidth == GetSystemMetrics(SM_CXVIRTUALSCREEN), + "Expected bmWidth %d, got %d.\n", GetSystemMetrics(SM_CXVIRTUALSCREEN), bitmap.bmWidth); + ok_(__FILE__, line)(bitmap.bmHeight == GetSystemMetrics(SM_CYVIRTUALSCREEN), + "Expected bmHeight %d, got %d.\n", GetSystemMetrics(SM_CYVIRTUALSCREEN), bitmap.bmHeight); + ok_(__FILE__, line)(bitmap.bmBitsPixel == 32, "Expected bmBitsPixel %d, got %d.\n", 32, + bitmap.bmBitsPixel); + ok_(__FILE__, line)(bitmap.bmWidthBytes == get_bitmap_stride(bitmap.bmWidth, bitmap.bmBitsPixel), + "Expected bmWidthBytes %d, got %d.\n", get_bitmap_stride(bitmap.bmWidth, bitmap.bmBitsPixel), + bitmap.bmWidthBytes); + ok_(__FILE__, line)(bitmap.bmPlanes == 1, "Expected bmPlanes %d, got %d.\n", 1, bitmap.bmPlanes); + ok_(__FILE__, line)(bitmap.bmBits == NULL, "Expected bmBits %p, got %p.\n", NULL, bitmap.bmBits); + } +} + +static void test_display_dc(void) +{ + static const INT bpps[] = {1, 4, 8, 16, 24, 32}; + unsigned char buffer[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)]; + HBITMAP hbitmap, hbitmap2, old_hbitmap; + BITMAPINFO *bmi = (BITMAPINFO *)buffer; + INT count, old_count, i, bpp, value; + DWORD device_idx, mode_idx; + DEVMODEA dm, dm2, dm3; + HDC hdc, hdc2, mem_dc; + DISPLAY_DEVICEA dd; + DIBSECTION dib; + BITMAP bitmap; + BOOL ret; + LONG res; +#ifdef __REACTOS__ + UINT display_bpp; + + hdc = GetDC(0); + display_bpp = GetDeviceCaps(hdc, BITSPIXEL); + ReleaseDC(0, hdc); +#endif + + /* Test DCs covering the entire virtual screen */ + hdc = CreateDCA("DISPLAY", NULL, NULL, NULL); + ok(!!hdc, "CreateDCA failed.\n"); + + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + ret = EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &dm); + ok(ret, "EnumDisplaySettingsA failed.\n"); + + check_display_dc(hdc, &dm, FALSE); + + /* Test that CreateCompatibleBitmap() for display DCs creates DDBs */ + hbitmap = CreateCompatibleBitmap(hdc, dm.dmPelsWidth, dm.dmPelsHeight); + ok(!!hbitmap, "CreateCompatibleBitmap failed, error %ld.\n", GetLastError()); + count = GetObjectW(hbitmap, sizeof(dib), &dib); + ok(count == sizeof(BITMAP), "GetObject failed, count %d.\n", count); + count = GetObjectW(hbitmap, sizeof(bitmap), &bitmap); + ok(count == sizeof(BITMAP), "GetObject failed, count %d.\n", count); + ok(bitmap.bmBitsPixel == dm.dmBitsPerPel, "Expected %ld, got %d.\n", dm.dmBitsPerPel, + bitmap.bmBitsPixel); + DeleteObject(hbitmap); + + /* Test selecting a DDB of a different depth into a display compatible DC */ + for (i = 0; i < ARRAY_SIZE(bpps); ++i) + { + winetest_push_context("bpp %d", bpps[i]); + + mem_dc = CreateCompatibleDC(hdc); + hbitmap = CreateBitmap(dm.dmPelsWidth, dm.dmPelsHeight, 1, bpps[i], NULL); + ok(!!hbitmap, "CreateBitmap failed, error %ld.\n", GetLastError()); + old_hbitmap = SelectObject(mem_dc, hbitmap); +#ifdef __REACTOS__ + if (bpps[i] != 1 && bpps[i] != display_bpp) +#else + if (bpps[i] != 1 && bpps[i] != 32) +#endif + ok(!old_hbitmap, "Selecting bitmap succeeded.\n"); + else + ok(!!old_hbitmap, "Failed to select bitmap.\n"); + + SelectObject(mem_dc, old_hbitmap); + DeleteObject(hbitmap); + DeleteDC(mem_dc); + + winetest_pop_context(); + } + + /* Test selecting a DIB of a different depth into a display compatible DC */ + for (i = 0; i < ARRAY_SIZE(bpps); ++i) + { + winetest_push_context("bpp %d", bpps[i]); + + mem_dc = CreateCompatibleDC(hdc); + memset(buffer, 0, sizeof(buffer)); + bmi->bmiHeader.biSize = sizeof(bmi->bmiHeader); + bmi->bmiHeader.biWidth = dm.dmPelsWidth; + bmi->bmiHeader.biHeight = dm.dmPelsHeight; + bmi->bmiHeader.biBitCount = bpps[i]; + bmi->bmiHeader.biPlanes = 1; + bmi->bmiHeader.biCompression = BI_RGB; + hbitmap = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, NULL, NULL, 0); + ok(!!hbitmap, "CreateDIBSection failed, error %ld.\n", GetLastError()); + old_hbitmap = SelectObject(mem_dc, hbitmap); + ok(!!old_hbitmap, "Failed to select bitmap.\n"); + + value = GetDeviceCaps(mem_dc, BITSPIXEL); +#ifdef __REACTOS__ + ok(value == display_bpp, "Expected %d, got %d.\n", display_bpp, value); +#else + ok(value == 32, "Expected 32, got %d.\n", value); +#endif + value = GetDeviceCaps(mem_dc, NUMCOLORS); + ok(value == -1, "Expected -1, got %d.\n", value); + + SelectObject(mem_dc, old_hbitmap); + DeleteObject(hbitmap); + DeleteDC(mem_dc); + + winetest_pop_context(); + } + + /* Test NUMCOLORS for display DCs */ + for (i = ARRAY_SIZE(bpps) - 1; i >= 0; --i) + { + winetest_push_context("bpp %d", bpps[i]); + + ret = EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &dm); + ok(ret, "EnumDisplaySettingsA failed.\n"); + if (bpps[i] == dm.dmBitsPerPel) + { + res = DISP_CHANGE_SUCCESSFUL; + } + else + { + memset(&dm2, 0, sizeof(dm2)); + dm2.dmSize = sizeof(dm2); + for (mode_idx = 0; EnumDisplaySettingsA(NULL, mode_idx, &dm2); ++mode_idx) + { + if (dm2.dmBitsPerPel == bpps[i]) + break; + } + if (dm2.dmBitsPerPel != bpps[i]) + { + skip("%d-bit display mode not found.\n", bpps[i]); + winetest_pop_context(); + continue; + } + + res = ChangeDisplaySettingsExA(NULL, &dm2, NULL, CDS_RESET, NULL); + /* Win8 TestBots */ + ok(res == DISP_CHANGE_SUCCESSFUL || broken(res == DISP_CHANGE_FAILED), + "ChangeDisplaySettingsExA returned unexpected %ld.\n", res); + } + + if (res == DISP_CHANGE_SUCCESSFUL) + { + value = GetDeviceCaps(hdc, BITSPIXEL); + ok(value == (bpps[i] == 4 ? 1 : bpps[i]), "Expected %d, got %d.\n", + (bpps[i] == 4 ? 1 : bpps[i]), value); + + value = GetDeviceCaps(hdc, NUMCOLORS); + if (bpps[i] > 8 || (bpps[i] == 8 && LOBYTE(LOWORD(GetVersion())) >= 6)) +#ifdef __REACTOS__ + ok(value == -1 || broken(value == 20) /* Vista */, "Expected -1, got %d.\n", value); +#else + ok(value == -1, "Expected -1, got %d.\n", value); +#endif + else if (bpps[i] == 8 && LOBYTE(LOWORD(GetVersion())) < 6) + ok(value > 16 && value <= 256, "Got %d.\n", value); + else + ok(value == 1 << bpps[i], "Expected %d, got %d.\n", 1 << bpps[i], value); + } + winetest_pop_context(); + } + res = ChangeDisplaySettingsExA(NULL, NULL, NULL, 0, NULL); + /* Win8 TestBots */ + ok(res == DISP_CHANGE_SUCCESSFUL || broken(res == DISP_CHANGE_FAILED), + "ChangeDisplaySettingsExA returned unexpected %ld.\n", res); + + /* Test selecting a DDB of the same color depth into a display compatible DC */ + ret = EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &dm); + ok(ret, "EnumDisplaySettingsA failed.\n"); + + mem_dc = CreateCompatibleDC(hdc); + bpp = GetDeviceCaps(mem_dc, BITSPIXEL); + ok(bpp == dm.dmBitsPerPel, "Expected bpp %ld, got %d.\n", dm.dmBitsPerPel, bpp); + hbitmap = CreateCompatibleBitmap(hdc, dm.dmPelsWidth, dm.dmPelsHeight); + count = GetObjectW(hbitmap, sizeof(bitmap), &bitmap); + ok(count == sizeof(BITMAP), "GetObject failed, count %d.\n", count); + ok(bitmap.bmBitsPixel == dm.dmBitsPerPel, "Expected %ld, got %d.\n", dm.dmBitsPerPel, bitmap.bmBitsPixel); + old_hbitmap = SelectObject(mem_dc, hbitmap); + ok(!!old_hbitmap, "Failed to select bitmap.\n"); + SelectObject(mem_dc, old_hbitmap); + DeleteDC(mem_dc); + + /* Test that the same bitmap handle is used for different display DCs */ + old_hbitmap = GetCurrentObject(hdc, OBJ_BITMAP); + + hdc2 = CreateDCA("DISPLAY", NULL, NULL, NULL); + ok(!!hdc2, "CreateDCA failed.\n"); + hbitmap2 = GetCurrentObject(hdc2, OBJ_BITMAP); + ok(hbitmap2 == old_hbitmap, "Expected the same bitmap handle.\n"); + + /* Tests after mode changes to a mode with different resolution */ + memset(&dm2, 0, sizeof(dm2)); + dm2.dmSize = sizeof(dm2); + for (mode_idx = 0; EnumDisplaySettingsA(NULL, mode_idx, &dm2); ++mode_idx) + { + if (dm2.dmPelsWidth != dm.dmPelsWidth || dm2.dmPelsHeight != dm.dmPelsHeight) + break; + } + if (dm2.dmPelsWidth != dm.dmPelsWidth || dm2.dmPelsHeight != dm.dmPelsHeight) + { + res = ChangeDisplaySettingsExA(NULL, &dm2, NULL, CDS_RESET, NULL); + /* Win8 TestBots */ + ok(res == DISP_CHANGE_SUCCESSFUL || broken(res == DISP_CHANGE_FAILED), + "ChangeDisplaySettingsExA returned unexpected %ld.\n", res); + if (res == DISP_CHANGE_SUCCESSFUL) + { + check_display_dc(hdc, &dm2, FALSE); + + /* Test that a different bitmap handle is used for the display DC after resolution changes */ + hbitmap2 = GetCurrentObject(hdc, OBJ_BITMAP); + ok(hbitmap2 != old_hbitmap, "Expected a different bitmap handle.\n"); + + /* Test that the old display bitmap is invalid after waiting for a bit. This suggests + * that the bitmap got released. And note that hdc2 has not been deleted yet and hdc2 + * has the same bitmap handle so the display bitmap is not being reference counted */ + Sleep(500); + count = GetObjectW(old_hbitmap, sizeof(bitmap), &bitmap); + ok(!count, "GetObject failed, count %d.\n", count); + } + } + else + { + win_skip("Failed to find a different resolution.\n"); + } + DeleteDC(hdc2); + + /* Tests after mode changes to a mode with different resolution and color depth */ + memset(&dm2, 0, sizeof(dm2)); + dm2.dmSize = sizeof(dm2); + for (mode_idx = 0; EnumDisplaySettingsA(NULL, mode_idx, &dm2); ++mode_idx) + { + if (dm2.dmPelsWidth != dm.dmPelsWidth && dm2.dmPelsHeight != dm.dmPelsHeight && + dm2.dmBitsPerPel != dm.dmBitsPerPel && dm2.dmBitsPerPel != 1) + break; + } + if (dm2.dmBitsPerPel && dm2.dmBitsPerPel != dm.dmBitsPerPel) + { + res = ChangeDisplaySettingsExA(NULL, &dm2, NULL, CDS_RESET, NULL); + /* Win8 TestBots */ + ok(res == DISP_CHANGE_SUCCESSFUL || broken(res == DISP_CHANGE_FAILED), + "ChangeDisplaySettingsExA returned unexpected %ld.\n", res); + if (res == DISP_CHANGE_SUCCESSFUL) + { + check_display_dc(hdc, &dm2, FALSE); + + /* Test selecting a compatible bitmap of a different color depth previously created for + * a display DC into a new compatible DC */ + count = GetObjectW(hbitmap, sizeof(bitmap), &bitmap); + ok(count == sizeof(BITMAP), "GetObject failed, count %d.\n", count); + ok(bitmap.bmBitsPixel == dm.dmBitsPerPel, "Expected %ld, got %d.\n", dm.dmBitsPerPel, + bitmap.bmBitsPixel); + + /* Note that hbitmap is of a different color depth and it can be successfully selected + * into the new compatible DC */ + mem_dc = CreateCompatibleDC(hdc); + bpp = GetDeviceCaps(mem_dc, BITSPIXEL); + ok(bpp == dm2.dmBitsPerPel, "Expected bpp %ld, got %d.\n", dm2.dmBitsPerPel, bpp); + old_hbitmap = SelectObject(mem_dc, hbitmap); + ok(!!old_hbitmap, "Failed to select bitmap.\n"); + bpp = GetDeviceCaps(mem_dc, BITSPIXEL); + ok(bpp == dm2.dmBitsPerPel, "Expected bpp %ld, got %d.\n", dm2.dmBitsPerPel, bpp); + SelectObject(mem_dc, old_hbitmap); + DeleteDC(mem_dc); + DeleteObject(hbitmap); + + /* Test selecting a DDB of a different color depth into a display compatible DC */ + for (i = 0; i < ARRAY_SIZE(bpps); ++i) + { + winetest_push_context("bpp %d", bpps[i]); + + mem_dc = CreateCompatibleDC(hdc); + hbitmap = CreateBitmap(dm2.dmPelsWidth, dm2.dmPelsHeight, 1, bpps[i], NULL); + ok(!!hbitmap, "CreateBitmap failed, error %ld.\n", GetLastError()); + old_hbitmap = SelectObject(mem_dc, hbitmap); + /* On Win7 dual-QXL test bot and XP, only 1-bit DDBs and DDBs with the same color + * depth can be selected to the compatible DC. On newer versions of Windows, only + * 1-bit and 32-bit DDBs can be selected into the compatible DC even if + * GetDeviceCaps(BITSPIXEL) reports a different color depth, for example, 16-bit. + * It's most likely due to the fact that lower color depth are emulated on newer + * versions of Windows as the real color depth is still 32-bit */ + if (bpps[i] != 1 && bpps[i] != 32) + todo_wine_if(bpps[i] == dm2.dmBitsPerPel) + ok(!old_hbitmap || broken(!!old_hbitmap) /* Win7 dual-QXL test bot and XP */, + "Selecting bitmap succeeded.\n"); + else + ok(!!old_hbitmap || broken(!old_hbitmap) /* Win7 dual-QXL test bot and XP */, + "Failed to select bitmap.\n"); + + SelectObject(mem_dc, old_hbitmap); + DeleteObject(hbitmap); + DeleteDC(mem_dc); + + winetest_pop_context(); + } + hbitmap = NULL; + + res = ChangeDisplaySettingsExA(NULL, NULL, NULL, 0, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA returned unexpected %ld.\n", res); + } + } + else + { + win_skip("Failed to find a required display mode.\n"); + } + + if (hbitmap) + DeleteObject(hbitmap); + DeleteDC(hdc); + + /* Test DCs covering a specific monitor */ + dd.cb = sizeof(dd); + for (device_idx = 0; EnumDisplayDevicesA(NULL, device_idx, &dd, 0); ++device_idx) + { + if (!(dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) + continue; + + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + ret = EnumDisplaySettingsA(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm); + ok(ret, "EnumDisplaySettingsA %s failed.\n", dd.DeviceName); + + hdc = CreateDCA(dd.DeviceName, NULL, NULL, NULL); + ok(!!hdc, "CreateDCA %s failed.\n", dd.DeviceName); + + check_display_dc(hdc, &dm, FALSE); + + /* Tests after mode changes to a different resolution */ + memset(&dm2, 0, sizeof(dm2)); + dm2.dmSize = sizeof(dm2); + for (mode_idx = 0; EnumDisplaySettingsA(dd.DeviceName, mode_idx, &dm2); ++mode_idx) + { + if (dm2.dmPelsWidth != dm.dmPelsWidth && dm2.dmPelsHeight != dm.dmPelsHeight) + break; + } + ok(dm2.dmPelsWidth && dm2.dmPelsWidth != dm.dmPelsWidth && dm2.dmPelsHeight != dm.dmPelsHeight, + "Failed to find a different resolution for %s.\n", dd.DeviceName); + + res = ChangeDisplaySettingsExA(dd.DeviceName, &dm2, NULL, CDS_RESET, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL || broken(res == DISP_CHANGE_FAILED), /* Win8 TestBots */ + "ChangeDisplaySettingsExA %s returned unexpected %ld.\n", dd.DeviceName, res); + if (res != DISP_CHANGE_SUCCESSFUL) + { + win_skip("Failed to change display mode for %s.\n", dd.DeviceName); + DeleteDC(hdc); + continue; + } + + check_display_dc(hdc, &dm2, FALSE); + + /* Tests after mode changes to a different color depth */ + memset(&dm2, 0, sizeof(dm2)); + dm2.dmSize = sizeof(dm2); + for (mode_idx = 0; EnumDisplaySettingsA(dd.DeviceName, mode_idx, &dm2); ++mode_idx) + { + if (dm2.dmBitsPerPel != dm.dmBitsPerPel) + break; + } + if (dm2.dmBitsPerPel && dm2.dmBitsPerPel != dm.dmBitsPerPel) + { + res = ChangeDisplaySettingsExA(dd.DeviceName, &dm2, NULL, CDS_RESET, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA returned unexpected %ld.\n", res); + + check_display_dc(hdc, &dm2, FALSE); + + res = ChangeDisplaySettingsExA(NULL, NULL, NULL, 0, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA returned unexpected %ld.\n", res); + } + else + { + win_skip("Failed to find a different color depth other than %lu.\n", dm.dmBitsPerPel); + } + + /* Tests after monitor detach */ + ret = EnumDisplaySettingsA(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm2); + ok(ret, "EnumDisplaySettingsA %s failed.\n", dd.DeviceName); + + if (!(dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)) + { + old_count = GetSystemMetrics(SM_CMONITORS); + + memset(&dm3, 0, sizeof(dm3)); + dm3.dmSize = sizeof(dm3); + ret = EnumDisplaySettingsA(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm3); + ok(ret, "EnumDisplaySettingsA %s failed.\n", dd.DeviceName); + + dm3.dmFields = DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT; + dm3.dmPelsWidth = 0; + dm3.dmPelsHeight = 0; + res = ChangeDisplaySettingsExA(dd.DeviceName, &dm3, NULL, CDS_UPDATEREGISTRY | CDS_NORESET, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned unexpected %ld.\n", + dd.DeviceName, res); + res = ChangeDisplaySettingsExA(dd.DeviceName, NULL, NULL, 0, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned unexpected %ld.\n", + dd.DeviceName, res); + + count = GetSystemMetrics(SM_CMONITORS); + ok(count == old_count - 1, "Expected monitor count %d, got %d.\n", old_count - 1, count); + + /* Should report the same values before detach */ + check_display_dc(hdc, &dm2, TRUE); + } + + res = ChangeDisplaySettingsExA(dd.DeviceName, &dm, NULL, CDS_UPDATEREGISTRY | CDS_NORESET, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned unexpected %ld.\n", + dd.DeviceName, res); + res = ChangeDisplaySettingsExA(NULL, NULL, NULL, 0, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned unexpected %ld.\n", + dd.DeviceName, res); + DeleteDC(hdc); + } +} + +BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, + LPRECT lprcMonitor, LPARAM dwData) +{ + MONITORINFOEXW info; + static int index; + + info.cbSize = sizeof(info); + if (GetMonitorInfoW(hMonitor, (MONITORINFO*)&info)) + { + printf("Monitor %d %7s [%02lx] %s %s\n", index, + (info.dwFlags & MONITORINFOF_PRIMARY) ? "primary" : "", + info.dwFlags, wine_dbgstr_rect(&info.rcMonitor), + wine_dbgstr_w(info.szDevice)); + } + index++; + return TRUE; +} + +static void test_fullscreen(int argc, char **argv) +{ + HANDLE event0, event1; + DWORD wait_result; + DWORD flags = 0; + DEVMODEA dm; + LONG res; + + if (argc < 7) + { + ok(0, "too few arguments.\n"); + return; + } + + res = sscanf(argv[4], "%lx", &flags); + ok(res == 1, "sscanf returned unexpected %ld.\n", res); + + event0 = OpenEventA(EVENT_MODIFY_STATE, FALSE, argv[5]); + ok(!!event0, "OpenEventA failed, error %#lx\n", GetLastError()); + event1 = OpenEventA(SYNCHRONIZE, FALSE, argv[6]); + ok(!!event1, "OpenEventA failed, error %#lx\n", GetLastError()); + + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; + dm.dmPelsWidth = 640; + dm.dmPelsHeight = 480; + res = ChangeDisplaySettingsExA(argv[3], &dm, NULL, flags, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, + "ChangeDisplaySettingsExA %s returned unexpected %ld.\n", argv[3], res); + + SetEvent(event0); + CloseHandle(event0); + + wait_result = WaitForSingleObject(event1, 7000); + ok(wait_result == WAIT_OBJECT_0, "WaitForSingleObject returned %lx.\n", wait_result); + CloseHandle(event1); +} + +#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600 +static void get_monitor_dpi_scale( HMONITOR monitor, int *min, int *cur, int *max ) +{ + DISPLAYCONFIG_GET_SOURCE_DPI_SCALE req = {.header = {.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_DPI_SCALE, .size = sizeof(req)}}; + MONITORINFOEXW info = {.cbSize = sizeof(MONITORINFOEXW)}; + D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME open_desc = {{0}}; + D3DKMT_CLOSEADAPTER close_desc = {0}; + NTSTATUS status; + UINT ret; + + ret = GetMonitorInfoW( monitor, (MONITORINFO *)&info ); + ok( ret, "GetMonitorInfoW failed, error %lu\n", GetLastError() ); + + wcscpy( open_desc.DeviceName, info.szDevice ); + status = D3DKMTOpenAdapterFromGdiDisplayName( &open_desc ); + ok( !status, "D3DKMTOpenAdapterFromGdiDisplayName returned %#lx\n", status ); + + req.header.adapterId = open_desc.AdapterLuid; + req.header.id = open_desc.VidPnSourceId; + ret = pDisplayConfigGetDeviceInfo( &req.header ); + todo_wine ok( !ret, "DisplayConfigGetDeviceInfo returned %u\n", ret ); + *min = req.minRelativeScaleStep; + *cur = req.curRelativeScaleStep; + *max = req.maxRelativeScaleStep; + + close_desc.hAdapter = open_desc.hAdapter; + status = D3DKMTCloseAdapter( &close_desc ); + ok( !status, "D3DKMTCloseAdapter returned %#lx\n", status ); +} + +static void set_monitor_dpi_scale( HMONITOR monitor, int scale ) +{ + DISPLAYCONFIG_SET_SOURCE_DPI_SCALE req = {.header = {.type = DISPLAYCONFIG_DEVICE_INFO_SET_SOURCE_DPI_SCALE, .size = sizeof(req)}}; + MONITORINFOEXW info = {.cbSize = sizeof(MONITORINFOEXW)}; + D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME open_desc = {{0}}; + D3DKMT_CLOSEADAPTER close_desc = {0}; + NTSTATUS status; + UINT ret; + + if (!pDisplayConfigSetDeviceInfo) return; + + ret = GetMonitorInfoW( monitor, (MONITORINFO *)&info ); + ok( ret, "GetMonitorInfoW failed, error %lu\n", GetLastError() ); + + wcscpy( open_desc.DeviceName, info.szDevice ); + status = D3DKMTOpenAdapterFromGdiDisplayName( &open_desc ); + ok( !status, "D3DKMTOpenAdapterFromGdiDisplayName returned %#lx\n", status ); + + req.header.adapterId = open_desc.AdapterLuid; + req.header.id = open_desc.VidPnSourceId; + req.relativeScaleStep = scale; + ret = pDisplayConfigSetDeviceInfo( &req.header ); + todo_wine ok( !ret, "DisplayConfigSetDeviceInfo returned %u\n", ret ); + + close_desc.hAdapter = open_desc.hAdapter; + status = D3DKMTCloseAdapter( &close_desc ); + ok( !status, "D3DKMTCloseAdapter returned %#lx\n", status ); +} +#endif // __REACTOS__ || DLL_EXPORT_VERSION >= 0x600 + +struct monitor_info +{ + UINT eff_x, eff_y, ang_x, ang_y, raw_x, raw_y; /* default monitor DPIs */ + HMONITOR handle; + RECT rect; +}; + +#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600 +static BOOL CALLBACK enum_monitor_rect( HMONITOR handle, HDC hdc, RECT *rect, LPARAM lparam ) +{ + struct monitor_info *info = (struct monitor_info *)lparam; + if (info->handle == handle) info->rect = *rect; + return TRUE; +} + +#define check_physical_dpi(a,b,c,d,e,f) check_physical_dpi_(__LINE__,a,b,c,d,e,f,FALSE) +static void check_physical_dpi_( int line, HWND hwnd, UINT log_x, UINT log_y, UINT phy_x, UINT phy_y, BOOL expect_ret, BOOL todo_ret ) +{ + POINT log = {log_x, log_y}, phy = {phy_x, phy_y}, pt; + UINT ret; + + pt = log; + ret = pLogicalToPhysicalPointForPerMonitorDPI( hwnd, &pt ); + todo_wine_if(todo_ret) + ok_(__FILE__, line)( ret == expect_ret, "LogicalToPhysicalPointForPerMonitorDPI returned %u\n", ret ); + ok_(__FILE__, line)( pt.x == phy.x && pt.y == phy.y, "got physical %s\n", wine_dbgstr_point(&pt) ); +} + +#define check_logical_dpi(a,b,c,d,e,f) check_logical_dpi_(__LINE__,a,b,c,d,e,f,FALSE) +static void check_logical_dpi_( int line, HWND hwnd, UINT phy_x, UINT phy_y, UINT log_x, UINT log_y, BOOL expect_ret, BOOL todo_ret ) +{ + POINT log = {log_x, log_y}, phy = {phy_x, phy_y}, pt; + UINT ret; + + pt = phy; + ret = pPhysicalToLogicalPointForPerMonitorDPI( hwnd, &pt ); + todo_wine_if(todo_ret) + ok_(__FILE__, line)( ret == expect_ret, "PhysicalToLogicalPointForPerMonitorDPI returned %u\n", ret ); + ok_(__FILE__, line)( pt.x == log.x && pt.y == log.y, "got logical %s\n", wine_dbgstr_point(&pt) ); +} + +#define check_logical_physical_dpi(a,b,c,d,e,f) check_logical_physical_dpi_(__LINE__,a,b,c,d,e,f,FALSE) +static void check_logical_physical_dpi_( int line, HWND hwnd, UINT log_x, UINT log_y, UINT phy_x, UINT phy_y, BOOL expect_ret, BOOL todo_ret ) +{ + check_logical_dpi_( line, hwnd, phy_x, phy_y, log_x, log_y, expect_ret, todo_ret ); + check_physical_dpi_( line, hwnd, log_x, log_y, phy_x, phy_y, expect_ret, todo_ret ); +} + +static void test_monitor_dpi_awareness( const struct monitor_info *infos, UINT count, int step, UINT system_dpi, + const struct monitor_info *info, struct monitor_info *phys, BOOL is_virtual ) +{ + static const unsigned int scales[] = {100, 125, 150, 175, 200, 225, 250, 300, 350, 400, 450, 500}; + static const DPI_AWARENESS_CONTEXT tests[] = + { + 0, + DPI_AWARENESS_CONTEXT_UNAWARE, + DPI_AWARENESS_CONTEXT_SYSTEM_AWARE, + DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE, + DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2, + DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED, + (DPI_AWARENESS_CONTEXT)0x7811, + }; + RECT virtual = {0}, scaled_virtual = {0}, monitor = {0}, scaled = {0}, primary = {0}, rect, expect_rect; + struct monitor_info tmp_info = {.handle = info->handle}; + UINT ret, i, x, y, expect_width, expect_height; + HWND unaware_hwnd, aware_hwnd, primary_hwnd; + MONITORINFO mi = {.cbSize = sizeof(mi)}; + DPI_AWARENESS_CONTEXT old_ctx = 0, cur_ctx, ctx; + float scale = scales[step], scale_x, scale_y; + HDC hdc; + + scale_x = (info->rect.right - info->rect.left) / (float)(phys->rect.right - phys->rect.left); + scale_y = (info->rect.bottom - info->rect.top) / (float)(phys->rect.bottom - phys->rect.top); + + for (i = 0; i < count; i++) + { + if (infos[i].rect.left == 0 && infos[i].rect.top == 0) primary = infos[i].rect; + + if (info - infos + i) UnionRect( &scaled_virtual, &scaled_virtual, &infos[i].rect ); + else + { + scaled = monitor = infos[i].rect; + scaled.right = scaled.left + MulDiv( scaled.right - scaled.left, 100, scale ); + scaled.bottom = scaled.top + MulDiv( scaled.bottom - scaled.top, 100, scale ); + UnionRect( &scaled_virtual, &scaled_virtual, &scaled ); + } + + UnionRect( &virtual, &virtual, &infos[i].rect ); + } + + unaware_hwnd = CreateWindowW( L"static", NULL, WS_POPUP | WS_VISIBLE, monitor.left + 100, + monitor.top + 100, 100, 100, NULL, NULL, NULL, NULL ); + ok( unaware_hwnd != NULL, "CreateWindowW failed, error %lu\n", GetLastError() ); + ctx = pGetWindowDpiAwarenessContext( unaware_hwnd ); + ok( ctx == (DPI_AWARENESS_CONTEXT)0x6010, "GetWindowDpiAwarenessContext returned %#Ix\n", (UINT_PTR)ctx ); + ret = pGetDpiForWindow( unaware_hwnd ); + ok( ret == 96, "GetDpiForWindow returned %u\n", ret ); + + SetRect( &expect_rect, 0, 0, 100, 100 ); + ret = GetClientRect( unaware_hwnd, &rect ); + ok( ret, "GetClientRect failed, error %lu\n", GetLastError() ); + ok( EqualRect( &rect, &expect_rect ), "GetClientRect returned %s\n", wine_dbgstr_rect(&rect) ); + + SetRect( &expect_rect, monitor.left + 100, monitor.top + 100, monitor.left + 200, monitor.top + 200 ); + ret = GetWindowRect( unaware_hwnd, &rect ); + ok( ret, "GetWindowRect failed, error %lu\n", GetLastError() ); + ok( EqualRect( &rect, &expect_rect ), "GetWindowRect returned %s\n", wine_dbgstr_rect(&rect) ); + + check_logical_physical_dpi( unaware_hwnd, monitor.left + 99, monitor.top + 99, + monitor.left + 99, monitor.top + 99, FALSE ); + check_logical_physical_dpi( unaware_hwnd, monitor.left + 100, monitor.top + 100, + monitor.left + 1 * scale, monitor.top + 1 * scale, TRUE ); + check_logical_physical_dpi( unaware_hwnd, monitor.left + 200, monitor.top + 200, + monitor.left + 2 * scale, monitor.top + 2 * scale, TRUE ); + + /* physical to logical conversion is lossy in the area of the screen where coordinate systems overlap but don't match */ + check_physical_dpi( unaware_hwnd, monitor.left + 201, monitor.top + 201, + monitor.left + 201, monitor.top + 201, FALSE ); + check_logical_dpi_( __LINE__, unaware_hwnd, monitor.left + 201, monitor.top + 201, + monitor.left + MulDiv( 201, 100, scale ), monitor.top + MulDiv( 201, 100, scale ), TRUE, TRUE ); + + check_logical_physical_dpi( unaware_hwnd, monitor.left + 2 * scale + 1, monitor.top + 2 * scale + 1, + monitor.left + 2 * scale + 1, monitor.top + 2 * scale + 1, FALSE ); + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + BOOL monitor_aware = tests[i] == DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE || + tests[i] == DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2; + if (tests[i]) old_ctx = pSetThreadDpiAwarenessContext( tests[i] ); + cur_ctx = pGetThreadDpiAwarenessContext(); + + winetest_push_context( "ctx %p", tests[i] ); + + ret = GetSystemMetrics( SM_XVIRTUALSCREEN ); + ok( ret == virtual.left, "got SM_XVIRTUALSCREEN %d\n", ret ); + ret = GetSystemMetrics( SM_YVIRTUALSCREEN ); + ok( ret == virtual.top, "got SM_YVIRTUALSCREEN %d\n", ret ); + + if (monitor_aware) + { + expect_width = virtual.right - virtual.left; + expect_height = virtual.bottom - virtual.top; + } + else + { + expect_width = scaled_virtual.right - scaled_virtual.left; + expect_height = scaled_virtual.bottom - scaled_virtual.top; + } + ret = GetSystemMetrics( SM_CXVIRTUALSCREEN ); + ok( ret == expect_width, "got SM_CXVIRTUALSCREEN %d\n", ret ); + ret = GetSystemMetrics( SM_CYVIRTUALSCREEN ); + ok( ret == expect_height, "got SM_CYVIRTUALSCREEN %d\n", ret ); + + if (monitor.left || monitor.top) + { + expect_width = primary.right - primary.left; + expect_height = primary.bottom - primary.top; + } + else if (monitor_aware) + { + expect_width = monitor.right - monitor.left; + expect_height = monitor.bottom - monitor.top; + } + else + { + expect_width = scaled.right - scaled.left; + expect_height = scaled.bottom - scaled.top; + } + ret = GetSystemMetrics( SM_CXSCREEN ); + ok( ret == expect_width, "got SM_CXSCREEN %d\n", ret ); + ret = GetSystemMetrics( SM_CYSCREEN ); + ok( ret == expect_height, "got SM_CYSCREEN %d\n", ret ); + + hdc = GetDC( NULL ); + ok( !!hdc, "GetDC failed\n" ); + ret = GetDeviceCaps( hdc, LOGPIXELSX ); + ok( ret == system_dpi, "got LOGPIXELSX %d\n", ret ); + ret = GetDeviceCaps( hdc, LOGPIXELSY ); + ok( ret == system_dpi, "got LOGPIXELSY %d\n", ret ); + ret = GetDeviceCaps( hdc, HORZRES ); + ok( ret == expect_width, "got HORZRES %u\n", ret ); + ret = GetDeviceCaps( hdc, VERTRES ); + ok( ret == expect_height, "got VERTRES %u\n", ret ); + DeleteDC( hdc ); + + ret = GetMonitorInfoW( info->handle, &mi ); + ok( ret, "GetMonitorInfoW failed, error %lu\n", GetLastError() ); + ok( mi.dwFlags == (monitor.left || monitor.top ? 0 : MONITORINFOF_PRIMARY), "got dwFlags %#lx\n", mi.dwFlags ); + if (monitor_aware) ok( EqualRect( &monitor, &mi.rcMonitor ), "got rect %s\n", wine_dbgstr_rect(&mi.rcMonitor) ); + else ok( EqualRect( &scaled, &mi.rcMonitor ), "got rect %s\n", wine_dbgstr_rect(&mi.rcMonitor) ); + ok( mi.rcWork.top >= mi.rcMonitor.top, "got rect %s\n", wine_dbgstr_rect(&mi.rcWork) ); + ok( mi.rcWork.left >= mi.rcMonitor.left, "got rect %s\n", wine_dbgstr_rect(&mi.rcWork) ); + ok( mi.rcWork.right <= mi.rcMonitor.right, "got rect %s\n", wine_dbgstr_rect(&mi.rcWork) ); + ok( mi.rcWork.bottom <= mi.rcMonitor.bottom, "got rect %s\n", wine_dbgstr_rect(&mi.rcWork) ); + + EnumDisplayMonitors( 0, NULL, enum_monitor_rect, (LPARAM)&tmp_info ); + ok( EqualRect( &tmp_info.rect, &mi.rcMonitor ), "got rect %s\n", wine_dbgstr_rect(&tmp_info.rect) ); + + ret = pGetDpiForMonitorInternal( info->handle, MDT_EFFECTIVE_DPI, &x, &y ); + ok( ret, "GetDpiForMonitorInternal failed, error %lu\n", GetLastError() ); + if (monitor_aware) + { + ok( x == MulDiv( system_dpi, scale, 100 ), "got MDT_EFFECTIVE_DPI x %d\n", x ); + ok( y == MulDiv( system_dpi, scale, 100 ), "got MDT_EFFECTIVE_DPI y %d\n", y ); + } + else + { + ok( x == system_dpi, "got MDT_EFFECTIVE_DPI x %d\n", x ); + ok( y == system_dpi, "got MDT_EFFECTIVE_DPI y %d\n", y ); + } + + ret = pGetDpiForMonitorInternal( info->handle, MDT_ANGULAR_DPI, &x, &y ); + ok( ret, "GetDpiForMonitorInternal failed, error %lu\n", GetLastError() ); + if (monitor_aware && !is_virtual) + { + ok( x == phys->ang_x, "got MDT_ANGULAR_DPI x %u\n", x ); + ok( y == phys->ang_y, "got MDT_ANGULAR_DPI y %u\n", y ); + } + else if (monitor_aware) + { + todo_wine ok( fabs( x - system_dpi * scale_x ) < system_dpi * 0.05, "got MDT_ANGULAR_DPI x %u\n", x ); + todo_wine ok( fabs( y - system_dpi * scale_y ) < system_dpi * 0.05, "got MDT_ANGULAR_DPI y %u\n", y ); + } + else if (!is_virtual) + { + ok( x == MulDiv( phys->ang_x, 100, scale ), "got MDT_ANGULAR_DPI x %d\n", x ); + ok( y == MulDiv( phys->ang_y, 100, scale ), "got MDT_ANGULAR_DPI y %d\n", y ); + } + else + { + todo_wine ok( fabs( x - system_dpi * scale_x * 100 / scale ) < system_dpi * 0.05, "got MDT_ANGULAR_DPI x %d\n", x ); + todo_wine ok( fabs( y - system_dpi * scale_y * 100 / scale ) < system_dpi * 0.05, "got MDT_ANGULAR_DPI y %d\n", y ); + } + + ret = pGetDpiForMonitorInternal( info->handle, MDT_RAW_DPI, &x, &y ); + ok( ret || GetLastError() == ERROR_NOT_SUPPORTED, "GetDpiForMonitorInternal failed, error %lu\n", GetLastError() ); + if (!ret) + { + ok( x == 0, "got MDT_RAW_DPI x %u\n", x ); + ok( y == 0, "got MDT_RAW_DPI y %u\n", y ); + } + else if (monitor_aware && !is_virtual) + { + ok( x == phys->raw_x, "got MDT_RAW_DPI x %u\n", x ); + ok( y == phys->raw_y, "got MDT_RAW_DPI y %u\n", y ); + } + else if (monitor_aware) + { + todo_wine ok( fabs( x - system_dpi * scale_x ) < system_dpi * 0.05, "got MDT_RAW_DPI x %u\n", x ); + todo_wine ok( fabs( y - system_dpi * scale_y ) < system_dpi * 0.05, "got MDT_RAW_DPI y %u\n", y ); + } + else if (!is_virtual) + { + ok( x == MulDiv( phys->raw_x, 100, scale ), "got MDT_RAW_DPI x %d\n", x ); + ok( y == MulDiv( phys->raw_y, 100, scale ), "got MDT_RAW_DPI y %d\n", y ); + } + else + { + todo_wine ok( fabs( x - system_dpi * scale_x * 100 / scale ) < system_dpi * 0.05, "got MDT_RAW_DPI x %d\n", x ); + todo_wine ok( fabs( y - system_dpi * scale_y * 100 / scale ) < system_dpi * 0.05, "got MDT_RAW_DPI y %d\n", y ); + } + + + ctx = pGetWindowDpiAwarenessContext( unaware_hwnd ); + ok( ctx == (DPI_AWARENESS_CONTEXT)0x6010, "GetWindowDpiAwarenessContext returned %#Ix\n", (UINT_PTR)ctx ); + ret = pGetDpiForWindow( unaware_hwnd ); + ok( ret == 96, "GetDpiForWindow returned %u\n", ret ); + + if (monitor_aware) SetRect( &expect_rect, 0, 0, scale, scale ); + else SetRect( &expect_rect, 0, 0, 100, 100 ); + ret = GetClientRect( unaware_hwnd, &rect ); + ok( ret, "GetClientRect failed, error %lu\n", GetLastError() ); + ok( EqualRect( &rect, &expect_rect ), "GetClientRect returned %s\n", wine_dbgstr_rect(&rect) ); + + if (monitor_aware) SetRect( &expect_rect, monitor.left + scale, monitor.top + scale, monitor.left + 2 * scale, monitor.top + 2 * scale ); + else SetRect( &expect_rect, monitor.left + 100, monitor.top + 100, monitor.left + 200, monitor.top + 200 ); + ret = GetWindowRect( unaware_hwnd, &rect ); + ok( ret, "GetWindowRect failed, error %lu\n", GetLastError() ); + ok( EqualRect( &rect, &expect_rect ), "GetWindowRect returned %s\n", wine_dbgstr_rect(&rect) ); + + + aware_hwnd = CreateWindowW( L"static", NULL, WS_POPUP | WS_VISIBLE, mi.rcWork.left + 200, + mi.rcWork.top + 200, 100, 100, NULL, NULL, NULL, NULL ); + ok( aware_hwnd != NULL, "CreateWindowW failed, error %lu\n", GetLastError() ); + + ctx = pGetWindowDpiAwarenessContext( aware_hwnd ); + todo_wine_if(tests[i] == DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) + ok( ctx == cur_ctx, "GetWindowDpiAwarenessContext returned %p vs %p\n", ctx, cur_ctx ); + ret = pGetDpiForWindow( aware_hwnd ); + if (monitor_aware) ok( ret == MulDiv( 96, scale, 100 ), "GetDpiForWindow returned %u\n", ret ); + else ok( ret == 96, "GetDpiForWindow returned %u\n", ret ); + + SetRect( &expect_rect, 0, 0, 100, 100 ); + ret = GetClientRect( aware_hwnd, &rect ); + ok( ret, "GetClientRect failed, error %lu\n", GetLastError() ); + ok( EqualRect( &rect, &expect_rect ), "GetClientRect returned %s\n", wine_dbgstr_rect(&rect) ); + + SetRect( &expect_rect, mi.rcWork.left + 200, mi.rcWork.top + 200, mi.rcWork.left + 300, mi.rcWork.top + 300 ); + ret = GetWindowRect( aware_hwnd, &rect ); + ok( ret, "GetWindowRect failed, error %lu\n", GetLastError() ); + ok( EqualRect( &rect, &expect_rect ), "GetWindowRect returned %s\n", wine_dbgstr_rect(&rect) ); + + + primary_hwnd = CreateWindowW( L"static", NULL, WS_POPUP | WS_VISIBLE, primary.left + 300, + primary.top + 300, 100, 100, NULL, NULL, NULL, NULL ); + ok( primary_hwnd != NULL, "CreateWindowW failed, error %lu\n", GetLastError() ); + + ctx = pGetWindowDpiAwarenessContext( primary_hwnd ); + todo_wine_if(tests[i] == DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) + ok( ctx == cur_ctx, "GetWindowDpiAwarenessContext returned %#Ix\n", (UINT_PTR)ctx ); + ret = pGetDpiForWindow( primary_hwnd ); + if (!monitor_aware) ok( ret == 96, "GetDpiForWindow returned %u\n", ret ); + else if (EqualRect( &primary, &monitor )) ok( ret == MulDiv( 96, scale, 100 ), "GetDpiForWindow returned %u\n", ret ); + else ok( ret == 96, "GetDpiForWindow returned %u\n", ret ); + + SetRect( &expect_rect, 0, 0, 100, 100 ); + ret = GetClientRect( primary_hwnd, &rect ); + ok( ret, "GetClientRect failed, error %lu\n", GetLastError() ); + ok( EqualRect( &rect, &expect_rect ), "GetClientRect returned %s\n", wine_dbgstr_rect(&rect) ); + + SetRect( &expect_rect, primary.left + 300, primary.top + 300, primary.left + 400, primary.top + 400 ); + ret = GetWindowRect( primary_hwnd, &rect ); + ok( ret, "GetWindowRect failed, error %lu\n", GetLastError() ); + ok( EqualRect( &rect, &expect_rect ), "GetWindowRect returned %s\n", wine_dbgstr_rect(&rect) ); + + + check_logical_physical_dpi( unaware_hwnd, monitor.left + 99, monitor.top + 99, + monitor.left + 99, monitor.top + 99, FALSE ); + if (monitor_aware) + { + check_logical_physical_dpi_( __LINE__, unaware_hwnd, monitor.left + 100, monitor.top + 100, + monitor.left + 100, monitor.top + 100, FALSE, TRUE ); + check_logical_physical_dpi( unaware_hwnd, monitor.left + 200, monitor.top + 200, + monitor.left + 2 * scale, monitor.top + 2 * scale, TRUE ); + /* physical to logical conversion is lossy in the area of the screen where coordinate systems overlap but don't match */ + check_physical_dpi_( __LINE__, unaware_hwnd, monitor.left + 201, monitor.top + 201, + monitor.left + MulDiv( 201, scale, 100 ), monitor.top + MulDiv( 201, scale, 100 ), TRUE, TRUE ); + check_logical_dpi_( __LINE__, unaware_hwnd, monitor.left + 201, monitor.top + 201, + monitor.left + MulDiv( 201, 100, scale ), monitor.top + MulDiv( 201, 100, scale ), TRUE, TRUE ); + } + else + { + check_logical_physical_dpi( unaware_hwnd, monitor.left + 100, monitor.top + 100, + monitor.left + 1 * scale, monitor.top + 1 * scale, TRUE ); + check_logical_physical_dpi( unaware_hwnd, monitor.left + 200, monitor.top + 200, + monitor.left + 2 * scale, monitor.top + 2 * scale, TRUE ); + /* physical to logical conversion is lossy in the area of the screen where coordinate systems overlap but don't match */ + check_physical_dpi( unaware_hwnd, monitor.left + 201, monitor.top + 201, + monitor.left + 201, monitor.top + 201, FALSE ); + check_logical_dpi_( __LINE__, unaware_hwnd, monitor.left + 201, monitor.top + 201, + monitor.left + MulDiv( 201, 100, scale ), monitor.top + MulDiv( 201, 100, scale ), TRUE, TRUE ); + } + + check_logical_physical_dpi( unaware_hwnd, monitor.left + 2 * scale + 1, monitor.top + 2 * scale + 1, + monitor.left + 2 * scale + 1, monitor.top + 2 * scale + 1, FALSE ); + + + check_logical_physical_dpi( aware_hwnd, mi.rcWork.left + 199, mi.rcWork.top + 199, + mi.rcWork.left + 199, mi.rcWork.top + 199, FALSE ); + if (monitor_aware) + { + check_logical_physical_dpi( aware_hwnd, mi.rcWork.left + 200, mi.rcWork.top + 200, + mi.rcWork.left + 200, mi.rcWork.top + 200, TRUE ); + check_logical_physical_dpi( aware_hwnd, mi.rcWork.left + 300, mi.rcWork.top + 300, + mi.rcWork.left + 300, mi.rcWork.top + 300, TRUE ); + check_logical_physical_dpi( aware_hwnd, mi.rcWork.left + 301, mi.rcWork.top + 301, + mi.rcWork.left + 301, mi.rcWork.top + 301, FALSE ); + } + else + { + check_logical_physical_dpi( aware_hwnd, mi.rcWork.left + 200, mi.rcWork.top + 200, + mi.rcWork.left + 2 * scale, mi.rcWork.top + 2 * scale, TRUE ); + check_logical_physical_dpi( aware_hwnd, mi.rcWork.left + 300, mi.rcWork.top + 300, + mi.rcWork.left + 3 * scale, mi.rcWork.top + 3 * scale, TRUE ); + /* physical to logical conversion is lossy in the area of the screen where coordinate systems overlap but don't match */ + check_physical_dpi( aware_hwnd, mi.rcWork.left + 301, mi.rcWork.top + 301, mi.rcWork.left + 301, mi.rcWork.top + 301, FALSE ); + check_logical_dpi_( __LINE__, aware_hwnd, mi.rcWork.left + 301, mi.rcWork.top + 301, mi.rcWork.left + MulDiv( 301, 100, scale ), + mi.rcWork.top + MulDiv( 301, 100, scale ), TRUE, TRUE ); + } + + check_logical_physical_dpi( aware_hwnd, mi.rcWork.left + 3 * scale + 1, mi.rcWork.top + 3 * scale + 1, + mi.rcWork.left + 3 * scale + 1, mi.rcWork.top + 3 * scale + 1, FALSE ); + + + check_logical_physical_dpi( primary_hwnd, primary.left + 299, primary.top + 299, + primary.left + 299, primary.top + 299, FALSE ); + if (monitor_aware || !EqualRect( &monitor, &primary )) + { + check_logical_physical_dpi( primary_hwnd, primary.left + 300, primary.top + 300, + primary.left + 300, primary.top + 300, TRUE ); + check_logical_physical_dpi( primary_hwnd, primary.left + 400, primary.top + 400, + primary.left + 400, primary.top + 400, TRUE ); + check_logical_physical_dpi( primary_hwnd, primary.left + 401, primary.top + 401, + primary.left + 401, primary.top + 401, FALSE ); + } + else + { + check_logical_physical_dpi( primary_hwnd, primary.left + 300, primary.top + 300, + primary.left + 3 * scale, primary.top + 3 * scale, TRUE ); + check_logical_physical_dpi( primary_hwnd, primary.left + 400, primary.top + 400, + primary.left + 4 * scale, primary.top + 4 * scale, TRUE ); + /* physical to logical conversion is lossy in the area of the screen where coordinate systems overlap but don't match */ + check_physical_dpi( primary_hwnd, primary.left + 401, primary.top + 401, primary.left + 401, primary.top + 401, FALSE ); + check_logical_dpi_( __LINE__, primary_hwnd, primary.left + 401, primary.top + 401, primary.left + MulDiv( 401, 100, scale ), + primary.top + MulDiv( 401, 100, scale ), TRUE, TRUE ); + } + + check_logical_physical_dpi( primary_hwnd, primary.left + 4 * scale + 1, primary.top + 4 * scale + 1, + primary.left + 4 * scale + 1, primary.top + 4 * scale + 1, FALSE ); + + DestroyWindow( primary_hwnd ); + DestroyWindow( aware_hwnd ); + + if (tests[i]) pSetThreadDpiAwarenessContext( old_ctx ); + + winetest_pop_context(); + } + + DestroyWindow( unaware_hwnd ); + flush_events(); +} +#endif // __REACTOS__ || DLL_EXPORT_VERSION >= 0x600 + +static BOOL CALLBACK enum_monitor_infos( HMONITOR handle, HDC hdc, RECT *rect, LPARAM lparam ) +{ + struct monitor_info *info, **iter = (struct monitor_info **)lparam; + + info = *iter; + info->handle = handle; + info->rect = *rect; + pGetDpiForMonitorInternal( handle, MDT_EFFECTIVE_DPI, &info->eff_x, &info->eff_y ); + pGetDpiForMonitorInternal( handle, MDT_ANGULAR_DPI, &info->ang_x, &info->ang_y ); + pGetDpiForMonitorInternal( handle, MDT_RAW_DPI, &info->raw_x, &info->raw_y ); + + *iter = info + 1; + + return TRUE; +} + +static void get_monitor_infos( struct monitor_info *infos ) +{ + struct monitor_info *iter = infos; + BOOL ret; + ret = EnumDisplayMonitors( 0, NULL, enum_monitor_infos, (LPARAM)&iter ); + ok( ret, "EnumDisplayMonitors failed\n" ); +} + +static BOOL set_display_settings( HMONITOR monitor, UINT width, UINT height ) +{ + MONITORINFOEXW info = {.cbSize = sizeof(MONITORINFOEXW)}; + DEVMODEW mode = {.dmSize = sizeof(DEVMODEW)}; + UINT ret; + + ret = GetMonitorInfoW( monitor, (MONITORINFO *)&info ); + ok( ret, "GetMonitorInfoW failed, error %lu\n", GetLastError() ); + + mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; + mode.dmBitsPerPel = 32; + mode.dmPelsWidth = width; + mode.dmPelsHeight = height; + + ret = ChangeDisplaySettingsExW( info.szDevice, &mode, 0, CDS_FULLSCREEN, NULL ); + return !ret; +} + +static void test_monitor_dpi(void) +{ + struct monitor_info infos[64] = {{0}}, phys_infos[ARRAY_SIZE(infos)] = {{0}}; + struct { UINT width; UINT height; } tests[] = + { + {0, 0}, + {940, 560}, + {1600, 900}, + {1024, 768}, + }; + UINT i, j, count, system_dpi, dpi_x, dpi_y; + DPI_AWARENESS_CONTEXT old_ctx; + float scale_x, scale_y; + BOOL ret, is_virtual; + + if (!pGetDpiForMonitorInternal || !pSetThreadDpiAwarenessContext) + { + win_skip( "GetDpiForMonitorInternal / SetThreadDpiAwarenessContext not found, skipping tests\n" ); + return; + } + + old_ctx = pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_UNAWARE ); + system_dpi = pGetDpiForSystem(); + + count = GetSystemMetrics( SM_CMONITORS ); + ok( count > 0, "Found zero monitors\n" ); + ok( count <= ARRAY_SIZE(infos), "Too many monitors\n" ); + + get_monitor_infos( infos ); + memcpy( phys_infos, infos, sizeof(infos) ); + + /* check whether display driver (likely) supports display mode virtualization */ + is_virtual = abs( (int)infos[0].ang_x - (int)system_dpi ) < system_dpi * 0.05 && + abs( (int)infos[0].ang_y - (int)system_dpi ) < system_dpi * 0.05 && + abs( (int)infos[0].raw_x - (int)system_dpi ) < system_dpi * 0.05 && + abs( (int)infos[0].raw_y - (int)system_dpi ) < system_dpi * 0.05; + + for (i = 0; i < count; i++) + { + for (j = 0; j < ARRAY_SIZE(tests); j++) + { + if (tests[j].width && tests[j].height && !set_display_settings( infos[i].handle, tests[j].width, tests[j].height )) continue; + + get_monitor_infos( infos ); /* refresh infos as changing display settings may invalidate HMONITOR */ + scale_x = (infos[i].rect.right - infos[i].rect.left) / (float)(phys_infos[i].rect.right - phys_infos[i].rect.left); + scale_y = (infos[i].rect.bottom - infos[i].rect.top) / (float)(phys_infos[i].rect.bottom - phys_infos[i].rect.top); + + ret = pGetDpiForMonitorInternal( infos[i].handle, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y ); + ok( ret, "GetDpiForMonitorInternal failed, error %lu\n", GetLastError() ); + ok( dpi_x == system_dpi, "got MDT_EFFECTIVE_DPI x %u\n", dpi_x ); + ok( dpi_y == system_dpi, "got MDT_EFFECTIVE_DPI y %u\n", dpi_y ); + ret = pGetDpiForMonitorInternal( infos[i].handle, MDT_ANGULAR_DPI, &dpi_x, &dpi_y ); + ok( ret, "GetDpiForMonitorInternal failed, error %lu\n", GetLastError() ); + if (!is_virtual) + { + ok( dpi_x == phys_infos[i].ang_x, "got MDT_ANGULAR_DPI x %u\n", dpi_x ); + ok( dpi_y == phys_infos[i].ang_y, "got MDT_ANGULAR_DPI y %u\n", dpi_y ); + } + else + { + todo_wine_if(scale_x != 1.0) + ok( fabs( dpi_x - system_dpi * scale_x ) < system_dpi * 0.05, "got MDT_ANGULAR_DPI x %u\n", dpi_x ); + todo_wine_if(scale_y != 1.0) + ok( fabs( dpi_y - system_dpi * scale_y ) < system_dpi * 0.05, "got MDT_ANGULAR_DPI y %u\n", dpi_y ); + } + ret = pGetDpiForMonitorInternal( infos[i].handle, MDT_RAW_DPI, &dpi_x, &dpi_y ); + ok( ret || GetLastError() == ERROR_NOT_SUPPORTED, "GetDpiForMonitorInternal failed, error %lu\n", GetLastError() ); + if (!ret) + { + ok( dpi_x == 0, "got MDT_RAW_DPI x %u\n", dpi_x ); + ok( dpi_y == 0, "got MDT_RAW_DPI y %u\n", dpi_y ); + } + else if (!is_virtual) + { + ok( dpi_x == phys_infos[i].raw_x, "got MDT_RAW_DPI x %u\n", dpi_x ); + ok( dpi_y == phys_infos[i].raw_y, "got MDT_RAW_DPI y %u\n", dpi_y ); + } + else + { + todo_wine_if(scale_x != 1.0) + ok( fabs( dpi_x - system_dpi * scale_x ) < system_dpi * 0.05, "got MDT_RAW_DPI x %u\n", dpi_x ); + todo_wine_if(scale_y != 1.0) + ok( fabs( dpi_y - system_dpi * scale_y ) < system_dpi * 0.05, "got MDT_RAW_DPI y %u\n", dpi_y ); + } + + pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ); + + ret = pGetDpiForMonitorInternal( infos[i].handle, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y ); + ok( ret, "GetDpiForMonitorInternal failed, error %lu\n", GetLastError() ); + ok( dpi_x == system_dpi, "got MDT_EFFECTIVE_DPI x %u\n", dpi_x ); + ok( dpi_y == system_dpi, "got MDT_EFFECTIVE_DPI y %u\n", dpi_y ); + ret = pGetDpiForMonitorInternal( infos[i].handle, MDT_ANGULAR_DPI, &dpi_x, &dpi_y ); + ok( ret, "GetDpiForMonitorInternal failed, error %lu\n", GetLastError() ); + if (!is_virtual) + { + ok( dpi_x == phys_infos[i].ang_x, "got MDT_ANGULAR_DPI x %u\n", dpi_x ); + ok( dpi_y == phys_infos[i].ang_y, "got MDT_ANGULAR_DPI y %u\n", dpi_y ); + } + else + { + todo_wine_if(scale_x != 1.0) + ok( fabs( dpi_x - system_dpi * scale_x ) < system_dpi * 0.05, "got MDT_ANGULAR_DPI x %u\n", dpi_x ); + todo_wine_if(scale_y != 1.0) + ok( fabs( dpi_y - system_dpi * scale_y ) < system_dpi * 0.05, "got MDT_ANGULAR_DPI y %u\n", dpi_y ); + } + ret = pGetDpiForMonitorInternal( infos[i].handle, MDT_RAW_DPI, &dpi_x, &dpi_y ); + ok( ret || GetLastError() == ERROR_NOT_SUPPORTED, "GetDpiForMonitorInternal failed, error %lu\n", GetLastError() ); + if (!ret) + { + ok( dpi_x == 0, "got MDT_RAW_DPI x %u\n", dpi_x ); + ok( dpi_y == 0, "got MDT_RAW_DPI y %u\n", dpi_y ); + } + else if (!is_virtual) + { + ok( dpi_x == phys_infos[i].raw_x, "got MDT_RAW_DPI x %u\n", dpi_x ); + ok( dpi_y == phys_infos[i].raw_y, "got MDT_RAW_DPI y %u\n", dpi_y ); + } + else + { + todo_wine_if(scale_x != 1.0) + ok( fabs( dpi_x - system_dpi * scale_x ) < system_dpi * 0.05, "got MDT_RAW_DPI x %u\n", dpi_x ); + todo_wine_if(scale_y != 1.0) + ok( fabs( dpi_y - system_dpi * scale_y ) < system_dpi * 0.05, "got MDT_RAW_DPI y %u\n", dpi_y ); + } + + pSetThreadDpiAwarenessContext( old_ctx ); + } + } + + ChangeDisplaySettingsExW( NULL, NULL, 0, 0, NULL ); + pSetThreadDpiAwarenessContext( old_ctx ); + +#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600 + for (i = 0; i < count; i++) + { + int min = 0, max = 0, cur = 0; + + set_display_settings( infos[i].handle, 800, 600 ); + get_monitor_infos( infos ); /* refresh infos as changing display settings may invalidate HMONITOR */ + + get_monitor_dpi_scale( infos[i].handle, &min, &cur, &max ); + if (min == max && !winetest_platform_is_wine) + { + skip( "Cannot change monitor %p dpi, skipping tests\n", infos[i].handle ); + continue; + } + + set_monitor_dpi_scale( infos[i].handle, max ); + test_monitor_dpi_awareness( infos, count, max, system_dpi, infos + i, phys_infos + i, is_virtual ); + set_monitor_dpi_scale( infos[i].handle, cur ); + } +#endif // __REACTOS__ || DLL_EXPORT_VERSION >= 0x600 + + ChangeDisplaySettingsExW( NULL, NULL, 0, 0, NULL ); } START_TEST(monitor) { + char** myARGV; + int myARGC = winetest_get_mainargs(&myARGV); + init_function_pointers(); + + if (myARGC >= 3) + { + if (strcmp(myARGV[2], "info") == 0) + { + printf("Monitor information:\n"); + EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, 0); + return; + } + else if (strcmp(myARGV[2], "fullscreen") == 0) + { + test_fullscreen(myARGC, myARGV); + return; + } + } + test_enumdisplaydevices(); - test_ChangeDisplaySettingsEx(); + test_ChangeDisplaySettingsEx(myARGC, myARGV); + test_DisplayConfigSetDeviceInfo(); + test_EnumDisplayMonitors(); + test_monitor_dpi(); test_monitors(); test_work_area(); test_display_config(); + test_handles(); + test_display_dc(); } diff --git a/modules/rostests/winetests/user32/msg.c b/modules/rostests/winetests/user32/msg.c index 6249c6f178d..a8f4cff7852 100644 --- a/modules/rostests/winetests/user32/msg.c +++ b/modules/rostests/winetests/user32/msg.c @@ -20,9 +20,9 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include #include #include +#include #include #include "windef.h" @@ -31,6 +31,8 @@ #include "winuser.h" #include "winnls.h" #include "dbt.h" +#include "commctrl.h" +#include "imm.h" #include "wine/test.h" @@ -61,22 +63,21 @@ #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 +#ifdef __REACTOS__ +// Temp for now to see where this is crashing on WS03 testbot +extern int winetest_debug; +#endif -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 BOOL (WINAPI *pQueryActCtxW)(DWORD,HANDLE,void*,ULONG,void*,SIZE_T,SIZE_T*); -static void (WINAPI *pReleaseActCtx)(HANDLE); +static void pump_msg_loop(HWND hwnd, HACCEL hAccel); /* encoded DRAWITEMSTRUCT into an LPARAM */ typedef struct @@ -113,16 +114,25 @@ typedef struct static BOOL test_DestroyWindow_flag; static BOOL test_context_menu; +static BOOL ignore_mouse_messages = TRUE; static HWINEVENTHOOK hEvent_hook; static HHOOK hKBD_hook; static HHOOK hCBT_hook; static DWORD cbt_hook_thread_id; +static DWORD winevent_hook_thread_id; static const WCHAR testWindowClassW[] = { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 }; static LRESULT WINAPI ParentMsgCheckProcA(HWND, UINT, WPARAM, LPARAM); +static void register_class(const WNDCLASSA *class) +{ + BOOL ret = RegisterClassA(class); + ok(ret, "Failed to register class %s, error %lu.\n", + debugstr_a(class->lpszClassName), GetLastError()); +} + /* FIXME: add tests for these Window Edge Styles (Win31/Win95/98 look), in order of precedence: @@ -144,7 +154,9 @@ typedef enum { optional=0x80, hook=0x100, winevent_hook=0x200, - kbd_hook=0x400 + kbd_hook=0x400, + msg_todo=0x800, + wine_only=0x1000 } msg_flags_t; struct message { @@ -180,7 +192,7 @@ static const struct message WmCreateOverlappedSeq[] = { { WM_NCCALCSIZE, sent|wparam, 0 }, { 0x0093, sent|defwinproc|optional }, { 0x0094, sent|defwinproc|optional }, - { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on win10. */ { WM_CREATE, sent }, { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, { 0 } @@ -219,7 +231,7 @@ static const struct message WmSWP_ShowOverlappedSeq[] = { { WM_NCCALCSIZE, sent|wparam|optional, 1 }, { WM_NCPAINT, sent|wparam|optional, 1 }, { WM_ERASEBKGND, sent|optional }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on win10 */ { WM_SYNCPAINT, sent|optional }, { WM_GETTITLEBARINFOEX, sent|optional }, { WM_PAINT, sent|optional }, @@ -317,7 +329,7 @@ static const struct message WmSWP_ResizeNoZOrder[] = { { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */ { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on win10. */ { 0 } }; @@ -381,7 +393,7 @@ static const struct message WmSwitchNotMaximizedChild[] = { /* Switch not maximized MDI child */ { WM_MDIACTIVATE, sent },/* in the MDI client */ { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */ - { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { WM_CHILDACTIVATE, sent },/* in the 2nd MDI child */ /* Deactivate 1st MDI child */ { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */ @@ -393,11 +405,13 @@ static const struct message WmSwitchNotMaximizedChild[] = { { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */ { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */ { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */ + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent, 0 }, /* in the MDI client */ { HCBT_SETFOCUS, hook }, { WM_KILLFOCUS, sent }, /* in the MDI client */ { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */ { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */ + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|defwinproc }, /* in the 2nd MDI child */ { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in the 2nd MDI child */ @@ -414,7 +428,7 @@ static const struct message WmSWP_FrameChanged_clip[] = { { WM_NCCALCSIZE, sent|wparam|parent, 1 }, { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */ { WM_GETTEXT, sent|parent|defwinproc|optional }, - { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */ + { WM_ERASEBKGND, sent|parent|msg_todo }, { WM_NCPAINT, sent }, /* wparam != 1 */ { WM_ERASEBKGND, sent }, { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, @@ -468,7 +482,7 @@ static const struct message WmShowOverlappedSeq[] = { { WM_GETTEXT, sent|defwinproc|optional }, { WM_ERASEBKGND, sent|optional }, { HCBT_ACTIVATE, hook|optional }, - { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 }, { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, { WM_NCPAINT, sent|wparam|optional, 1 }, @@ -479,7 +493,7 @@ static const struct message WmShowOverlappedSeq[] = { { HCBT_SETFOCUS, hook|optional }, { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, - { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 }, { WM_GETTEXT, sent|optional }, { WM_NCPAINT, sent|wparam|optional, 1 }, @@ -512,7 +526,7 @@ static const struct message WmShowMaxOverlappedSeq[] = { { WM_NCCALCSIZE, sent|wparam, TRUE }, { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_ACTIVATE, hook|optional }, - { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 }, { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, @@ -522,7 +536,7 @@ static const struct message WmShowMaxOverlappedSeq[] = { { HCBT_SETFOCUS, hook|optional }, { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, - { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 }, { WM_GETTEXT, sent|optional }, { WM_NCPAINT, sent|wparam|optional, 1 }, @@ -536,8 +550,8 @@ static const struct message WmShowMaxOverlappedSeq[] = { { WM_NCCALCSIZE, sent|optional }, { WM_NCPAINT, sent|optional }, { WM_ERASEBKGND, sent|optional }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on win10. */ { WM_SYNCPAINT, sent|optional }, { WM_GETTITLEBARINFOEX, sent|optional }, { WM_PAINT, sent|optional }, @@ -565,6 +579,8 @@ static const struct message WmShowRestoreMaxOverlappedSeq[] = { { WM_GETTITLEBARINFOEX, sent|optional }, { WM_NCPAINT, sent|beginpaint|optional }, { WM_ERASEBKGND, sent|beginpaint|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ { WM_SYNCPAINT, sent|optional }, { 0 } }; @@ -577,13 +593,17 @@ static const struct message WmShowRestoreMinOverlappedSeq[] = { { WM_WINDOWPOSCHANGING, sent|optional }, /* SWP_NOSIZE|SWP_NOMOVE */ { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { WM_NCCALCSIZE, sent|wparam|optional, TRUE }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sent on Win7. */ { WM_MOVE, sent|optional }, { WM_SIZE, sent|wparam|optional, SIZE_RESTORED }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sent on Win7. */ { WM_GETTEXT, sent|optional }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS }, { WM_GETMINMAXINFO, sent|defwinproc|optional }, { WM_NCCALCSIZE, sent|wparam|optional, TRUE }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sent on Win10. */ { HCBT_ACTIVATE, hook|optional }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 }, { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, @@ -593,6 +613,7 @@ static const struct message WmShowRestoreMinOverlappedSeq[] = { { HCBT_SETFOCUS, hook|optional }, { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 }, { WM_GETTEXT, sent|optional }, { WM_NCPAINT, sent|wparam|optional, 1 }, @@ -606,7 +627,11 @@ static const struct message WmShowRestoreMinOverlappedSeq[] = { { WM_NCCALCSIZE, sent|wparam|optional, TRUE }, { WM_NCPAINT, sent|wparam|optional, 1 }, { WM_ERASEBKGND, sent|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ + { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_SETFOCUS, hook|optional }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|wparam|optional, 0 }, { WM_ACTIVATE, sent|wparam, 1 }, { WM_GETTEXT, sent|optional }, @@ -620,7 +645,7 @@ static const struct message WmShowRestoreMinOverlappedSeq[] = { static const struct message WmShowMinOverlappedSeq[] = { { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE }, { HCBT_SETFOCUS, hook|optional }, - { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, { WM_KILLFOCUS, sent|optional }, { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 }, @@ -628,7 +653,7 @@ static const struct message WmShowMinOverlappedSeq[] = { { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED }, { WM_GETMINMAXINFO, sent|defwinproc }, { WM_NCCALCSIZE, sent|wparam, TRUE }, - { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_NCPAINT, sent|optional }, { WM_GETTEXT, sent|defwinproc|optional }, { WM_WINDOWPOSCHANGED, sent }, @@ -636,7 +661,7 @@ static const struct message WmShowMinOverlappedSeq[] = { { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 }, { WM_NCCALCSIZE, sent|optional }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on win10. */ { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, { WM_NCACTIVATE, sent|wparam|optional, 0 }, { WM_GETTEXT, sent|defwinproc|optional }, @@ -687,6 +712,7 @@ static const struct message WmHideOverlappedSeq[] = { { WM_ACTIVATE, sent|wparam|optional, 0 }, { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, { HCBT_SETFOCUS, hook|optional }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, { WM_KILLFOCUS, sent|wparam|optional, 0 }, { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 }, @@ -778,7 +804,7 @@ static const struct message WmCreateInvisibleMaxPopupSeq[] = { static const struct message WmShowMaxPopupResizedSeq[] = { { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE }, { WM_GETMINMAXINFO, sent }, - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED, 0, SWP_STATECHANGED /* w1064v1809 */ }, { WM_NCCALCSIZE, sent|wparam, TRUE }, { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_ACTIVATE, hook }, @@ -810,7 +836,7 @@ static const struct message WmShowMaxPopupResizedSeq[] = { static const struct message WmShowMaxPopupSeq[] = { { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE }, { WM_GETMINMAXINFO, sent }, - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED, 0, SWP_STATECHANGED /* w1064v1809 */ }, { WM_NCCALCSIZE, sent|wparam, TRUE }, { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_ACTIVATE, hook }, @@ -834,9 +860,9 @@ static const struct message WmShowMaxPopupSeq[] = { { WM_ERASEBKGND, sent|optional }, { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 }, { WM_ERASEBKGND, sent|defwinproc|optional }, - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE, 0, SWP_STATECHANGED /* w1064v1809 */ }, { WM_SIZE, sent|defwinproc|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, { 0 } }; /* CreateWindow(WS_VISIBLE) for popup window */ @@ -890,6 +916,168 @@ static const struct message WmShowVisMaxPopupSeq[] = { { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, { 0 } }; +/* ShowWindow(hwnd, SW_RESTORE) to a minimized window */ +static const struct message WmShowRestoreMinimizedOverlappedSeq[] = +{ + { HCBT_MINMAX, hook }, + { WM_QUERYOPEN, sent }, + { WM_GETTEXT, sent|optional }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { WM_GETMINMAXINFO, sent|defwinproc }, + { WM_NCCALCSIZE, sent }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { HCBT_ACTIVATE, hook }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, + { WM_NCACTIVATE, sent }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ACTIVATE, sent|wparam, WA_ACTIVE }, + { HCBT_SETFOCUS, hook }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { WM_SETFOCUS, sent|defwinproc }, + { WM_NCPAINT, sent }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ERASEBKGND, sent }, + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { WM_MOVE, sent|defwinproc }, + { WM_SIZE, sent|defwinproc }, + { WM_NCCALCSIZE, sent|optional }, + { WM_NCPAINT, sent|optional }, + { WM_ERASEBKGND, sent|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ + { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + /* Note this WM_ACTIVATE message even if the window is already active and focused */ + { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, 0 }, + { WM_SYNCPAINT, sent|optional }, + { WM_PAINT, sent }, + { WM_GETMINMAXINFO, sent|optional }, + { 0 } +}; +/* ShowWindow(hwnd, SW_SHOWNOACTIVATE) to a minimized window */ +static const struct message WmShowNoActivateMinimizedOverlappedSeq[] = +{ + { HCBT_MINMAX, hook }, + { WM_QUERYOPEN, sent }, + { WM_GETTEXT, sent|optional }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { WM_GETMINMAXINFO, sent|defwinproc }, + { WM_NCCALCSIZE, sent }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { WM_NCPAINT, sent }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ERASEBKGND, sent }, + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { WM_MOVE, sent|defwinproc }, + { WM_SIZE, sent|defwinproc }, + /* Following optional messages are on XP/2003 */ + { WM_NCCALCSIZE, sent|optional }, + { WM_NCPAINT, sent|optional }, + { WM_ERASEBKGND, sent|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ + { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { HCBT_SETFOCUS, hook|optional }, + { WM_SETFOCUS, sent|optional }, + { HCBT_ACTIVATE, hook|optional }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, + { WM_NCACTIVATE, sent|optional }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ACTIVATE, sent|wparam|optional, WA_ACTIVE }, + { HCBT_SETFOCUS, hook|optional }, + { WM_SETFOCUS, sent|defwinproc|optional }, + { WM_KILLFOCUS, sent|optional }, + { WM_SETFOCUS, sent|optional }, + /* Note this WM_ACTIVATE message on XP even if the window is already active and focused */ + { WM_ACTIVATE, sent|wparam|lparam|optional, WA_ACTIVE, 0 }, + { WM_SYNCPAINT, sent|optional }, + { WM_PAINT, sent }, + { WM_GETMINMAXINFO, sent|optional }, + { 0 } +}; +/* ShowWindow(hwnd, SW_RESTORE) to an active minimized window */ +static const struct message WmShowRestoreActiveMinimizedOverlappedSeq[] = +{ + { HCBT_MINMAX, hook }, + { WM_QUERYOPEN, sent }, + { WM_GETTEXT, sent|optional }, + { WM_NCACTIVATE, sent }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_NCCALCSIZE, sent|optional }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends this. */ + { WM_MOVE, sent|optional }, + { WM_SIZE, sent|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends this. */ + { WM_GETTEXT, sent|optional }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { WM_GETMINMAXINFO, sent|defwinproc }, + { WM_NCCALCSIZE, sent }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win8+ sends this. */ + { WM_NCPAINT, sent }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ERASEBKGND, sent }, + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { WM_MOVE, sent|defwinproc }, + { WM_SIZE, sent|defwinproc }, + { WM_NCCALCSIZE, sent|optional }, + { WM_NCPAINT, sent|optional }, + { WM_ERASEBKGND, sent|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ + { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { HCBT_SETFOCUS, hook }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { WM_SETFOCUS, sent }, + /* Note this WM_ACTIVATE message even if the window is already active */ + { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, 0 }, + { WM_SYNCPAINT, sent|optional }, + { WM_PAINT, sent }, + { WM_GETMINMAXINFO, sent|optional }, + { 0 } +}; +/* ShowWindow(hwnd, SW_SHOWNOACTIVATE) to an active minimized window */ +static const struct message WmShowNoActivateActiveMinimizedOverlappedSeq[] = +{ + { HCBT_MINMAX, hook }, + { WM_QUERYOPEN, sent }, + { WM_GETTEXT, sent|optional }, + { WM_NCACTIVATE, sent }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_NCCALCSIZE, sent|optional }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends this. */ + { WM_MOVE, sent|optional }, + { WM_SIZE, sent|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends this. */ + { WM_GETTEXT, sent|optional }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { WM_GETMINMAXINFO, sent|defwinproc }, + { WM_NCCALCSIZE, sent }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win8+ sends this. */ + { WM_NCPAINT, sent }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ERASEBKGND, sent }, + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { WM_MOVE, sent|defwinproc }, + { WM_SIZE, sent|defwinproc }, + { WM_NCCALCSIZE, sent|optional }, + { WM_NCPAINT, sent|optional }, + { WM_ERASEBKGND, sent|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ + { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + /* Following optional messages are present on XP */ + { HCBT_SETFOCUS, hook|optional }, + { WM_SETFOCUS, sent|optional }, + /* Note this WM_ACTIVATE message even if the window is already active and with flag SW_SHOWNOACTIVATE */ + { WM_ACTIVATE, sent|wparam|lparam|optional, WA_ACTIVE, 0 }, + { WM_SYNCPAINT, sent|optional }, + { WM_PAINT, sent }, + { WM_GETMINMAXINFO, sent|optional }, + { 0 } +}; /* CreateWindow (for a child popup window, not initially visible) */ static const struct message WmCreateChildPopupSeq[] = { { HCBT_CREATEWND, hook }, @@ -957,20 +1145,29 @@ static const struct message WmShowPopupExtremeLocationSeq[] = { { WM_MOVE, sent }, { WM_SHOWWINDOW, sent|wparam, 1 }, { WM_WINDOWPOSCHANGING, sent }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_ACTIVATE, hook }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|optional }, { WM_QUERYNEWPALETTE, sent|optional }, + + /* occasionally received on test machines */ + { WM_NCPAINT, sent|optional }, + { WM_ERASEBKGND, sent|optional }, + { WM_WINDOWPOSCHANGED, sent|optional }, + { WM_ACTIVATEAPP, sent }, { WM_NCACTIVATE, sent }, { WM_ACTIVATE, sent }, { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 }, { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, - { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */ { HCBT_SETFOCUS, hook }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|defwinproc }, - { WM_NCPAINT, sent|wparam, 1 }, - { WM_ERASEBKGND, sent }, + { WM_NCPAINT, sent|wparam|optional, 1 }, /* Not always sent on Win8+ */ + { WM_ERASEBKGND, sent|optional }, /* Not always sent on Win8+ */ { WM_WINDOWPOSCHANGED, sent }, /* occasionally received on test machines */ { WM_NCPAINT, sent|optional }, @@ -989,7 +1186,9 @@ static const struct message WmShowPopupFirstDrawSeq_1[] = { { WM_MOVE, sent }, { WM_SHOWWINDOW, sent|wparam, 1 }, { WM_WINDOWPOSCHANGING, sent }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_ACTIVATE, hook }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|optional }, { WM_QUERYNEWPALETTE, sent|optional }, { WM_ACTIVATEAPP, sent }, @@ -998,8 +1197,9 @@ static const struct message WmShowPopupFirstDrawSeq_1[] = { { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 }, { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, - { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */ { HCBT_SETFOCUS, hook }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|defwinproc }, { WM_NCPAINT, sent|wparam, 1 }, { WM_ERASEBKGND, sent }, @@ -1024,7 +1224,9 @@ static const struct message WmShowPopupFirstDrawSeq_2[] = { { WM_GETMINMAXINFO, sent }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_STATECHANGED|SWP_SHOWWINDOW|SWP_FRAMECHANGED }, { WM_NCCALCSIZE, sent|wparam, TRUE }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_ACTIVATE, hook }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|optional }, { WM_NCPAINT, sent|optional|wparam, 1 }, { WM_ERASEBKGND, sent|optional }, @@ -1036,14 +1238,16 @@ static const struct message WmShowPopupFirstDrawSeq_2[] = { { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 }, { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, - { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */ { HCBT_SETFOCUS, hook }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|defwinproc }, { WM_NCPAINT, sent|wparam, 1 }, { WM_ERASEBKGND, sent }, { WM_WINDOWPOSCHANGED, sent|optional }, { WM_MOVE, sent|defwinproc }, { WM_SIZE, sent|defwinproc, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, { WM_PAINT, sent}, /* occasionally received on test machines */ { WM_NCPAINT, sent|beginpaint|optional }, @@ -1059,7 +1263,9 @@ static const struct message WmFirstDrawSetWindowPosSeq1[] = { { WM_SIZE, sent|wparam, SIZE_RESTORED }, { WM_MOVE, sent }, { WM_WINDOWPOSCHANGING, sent }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_ACTIVATE, hook }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|optional }, { WM_QUERYNEWPALETTE, sent|optional }, { WM_ACTIVATEAPP, sent }, @@ -1068,13 +1274,15 @@ static const struct message WmFirstDrawSetWindowPosSeq1[] = { { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 }, { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, - { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */ { HCBT_SETFOCUS, hook }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|defwinproc }, { WM_NCPAINT, sent|wparam, 1 }, { WM_ERASEBKGND, sent }, { WM_WINDOWPOSCHANGED, sent }, { WM_MOVE, sent|defwinproc }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, { 0 } }; static const struct message WmFirstDrawSetWindowPosSeq2[] = { @@ -1086,7 +1294,9 @@ static const struct message WmFirstDrawSetWindowPosSeq2[] = { { WM_SIZE, sent|wparam, SIZE_RESTORED }, { WM_MOVE, sent }, { WM_WINDOWPOSCHANGING, sent }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not always sent. */ { HCBT_ACTIVATE, hook }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, { WM_QUERYNEWPALETTE, sent|optional }, { WM_WINDOWPOSCHANGING, sent|optional }, { WM_ACTIVATEAPP, sent }, @@ -1095,11 +1305,13 @@ static const struct message WmFirstDrawSetWindowPosSeq2[] = { { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 }, { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, - { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */ { HCBT_SETFOCUS, hook }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|defwinproc }, { WM_WINDOWPOSCHANGED, sent }, { WM_MOVE, sent|defwinproc }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, { 0 } }; static const struct message WmFirstDrawSetWindowPosSeq3[] = { @@ -1110,14 +1322,17 @@ static const struct message WmFirstDrawSetWindowPosSeq3[] = { { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, { WM_SIZE, sent|wparam, SIZE_RESTORED }, { WM_MOVE, sent }, - { HCBT_ACTIVATE, hook|optional }, - /* Probably shouldn't happen, but not part of this test */ - { WM_QUERYNEWPALETTE, sent|optional }, - { WM_ACTIVATEAPP, sent|optional }, - { WM_NCACTIVATE, sent|optional }, - { WM_ACTIVATE, sent|optional }, - { HCBT_SETFOCUS, hook|optional }, - { WM_SETFOCUS, sent|defwinproc|optional }, + { EVENT_OBJECT_SHOW, winevent_hook|wine_only }, + { HCBT_ACTIVATE, hook|wine_only }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|wine_only, 0, 0 }, + { WM_QUERYNEWPALETTE, sent|wine_only }, + { WM_ACTIVATEAPP, sent|wine_only }, + { WM_NCACTIVATE, sent|wine_only }, + { WM_ACTIVATE, sent|wine_only }, + { HCBT_SETFOCUS, hook|wine_only }, + { EVENT_OBJECT_FOCUS, winevent_hook|lparam|wparam|wine_only, OBJID_CLIENT, 0 }, + { WM_SETFOCUS, sent|defwinproc|wine_only }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|lparam|wparam|wine_only, 0, 0 }, { 0 } }; static const struct message WmFirstDrawSetWindowPosSeq4[] = { @@ -1129,7 +1344,9 @@ static const struct message WmFirstDrawSetWindowPosSeq4[] = { { WM_SIZE, sent|wparam, SIZE_RESTORED }, { WM_MOVE, sent }, { WM_WINDOWPOSCHANGING, sent }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_ACTIVATE, hook }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|optional }, { WM_QUERYNEWPALETTE, sent|optional }, { WM_ACTIVATEAPP, sent }, @@ -1138,8 +1355,9 @@ static const struct message WmFirstDrawSetWindowPosSeq4[] = { { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 }, { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, - { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */ { HCBT_SETFOCUS, hook }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|defwinproc }, { WM_NCPAINT, sent|wparam, 1 }, { WM_ERASEBKGND, sent }, @@ -1155,7 +1373,9 @@ static const struct message WmFirstDrawSetWindowPosSeq5[] = { { WM_SIZE, sent|wparam, SIZE_RESTORED }, { WM_MOVE, sent }, { WM_WINDOWPOSCHANGING, sent }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_ACTIVATE, hook }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|optional }, { WM_QUERYNEWPALETTE, sent|optional }, { WM_ACTIVATEAPP, sent }, @@ -1164,13 +1384,36 @@ static const struct message WmFirstDrawSetWindowPosSeq5[] = { { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 }, { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, - { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Not sent on Win10. */ { HCBT_SETFOCUS, hook }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|defwinproc }, { WM_WINDOWPOSCHANGED, sent }, { 0 } }; +static const struct message WmFirstDrawSetWindowPosSeq6[] = { + { HCBT_CREATEWND, hook }, + { WM_NCCREATE, sent }, + { WM_NCCALCSIZE, sent|wparam, 0 }, + { WM_CREATE, sent }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, + { WM_SIZE, sent|wparam, SIZE_RESTORED }, + { WM_MOVE, sent }, + { EVENT_OBJECT_SHOW, winevent_hook|wine_only }, + { HCBT_ACTIVATE, hook|wine_only }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|wine_only, 0, 0 }, + { WM_QUERYNEWPALETTE, sent|wine_only }, + { WM_ACTIVATEAPP, sent|wine_only }, + { WM_NCACTIVATE, sent|wine_only }, + { WM_ACTIVATE, sent|wine_only }, + { HCBT_SETFOCUS, hook|wine_only }, + { EVENT_OBJECT_FOCUS, winevent_hook|lparam|wparam|wine_only, OBJID_CLIENT, 0 }, + { WM_SETFOCUS, sent|defwinproc|wine_only }, + { 0 } +}; static const struct message WmFirstDrawChildSeq1[] = { + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ { 0 } }; static const struct message WmFirstDrawChildSeq2[] = { @@ -1179,6 +1422,8 @@ static const struct message WmFirstDrawChildSeq2[] = { /* occasionally received on test machines */ { WM_NCPAINT, sent|optional }, { WM_ERASEBKGND, sent|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ { 0 } }; /* CreateWindow (for child window, not initially visible) */ @@ -1219,7 +1464,7 @@ static const struct message WmCreateVisibleChildSeq[] = { { WM_NCCREATE, sent }, /* child is inserted into parent's child list after WM_NCCREATE returns */ { WM_NCCALCSIZE, sent|wparam, 0 }, - { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */ { WM_CREATE, sent }, { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, { WM_SIZE, sent|wparam, SIZE_RESTORED }, @@ -1231,7 +1476,7 @@ static const struct message WmCreateVisibleChildSeq[] = { { WM_ERASEBKGND, sent|parent|optional }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */ - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { 0 } }; /* ShowWindow(SW_SHOW) for a not visible child window */ @@ -1300,8 +1545,6 @@ static const struct message WmShowChildInvisibleParentSeq_1[] = { { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, - /* FIXME: Wine creates an icon/title window while Windows doesn't */ - { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, { WM_GETTEXT, sent|optional }, { 0 } }; @@ -1340,8 +1583,6 @@ static const struct message WmShowChildInvisibleParentSeq_3[] = { { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, - /* FIXME: Wine creates an icon/title window while Windows doesn't */ - { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, { WM_GETTEXT, sent|optional }, { 0 } }; @@ -1362,7 +1603,6 @@ static const struct message WmShowChildInvisibleParentSeq_4[] = { { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* FIXME: Wine creates an icon/title window while Windows doesn't */ - { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, { WM_GETTEXT, sent|optional }, { 0 } }; @@ -1454,9 +1694,9 @@ static const struct message WmCreateCustomDialogSeq[] = { { WM_GETMINMAXINFO, sent }, { WM_NCCREATE, sent }, { WM_NCCALCSIZE, sent|wparam, 0 }, - { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */ { WM_CREATE, sent }, - { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_NOTIFYFORMAT, sent|optional }, { WM_QUERYUISTATE, sent|optional }, { WM_WINDOWPOSCHANGING, sent|optional }, @@ -1467,7 +1707,7 @@ static const struct message WmCreateCustomDialogSeq[] = { { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE }, { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_ACTIVATE, hook }, - { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, @@ -1502,7 +1742,7 @@ static const struct message WmCreateCustomDialogSeq[] = { { WM_GETTEXT, sent|optional|defwinproc }, { WM_ERASEBKGND, sent|optional }, { WM_CTLCOLORDLG, sent|optional|defwinproc }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */ { WM_SIZE, sent|wparam, SIZE_RESTORED }, { WM_MOVE, sent }, { 0 } @@ -1538,7 +1778,7 @@ static const struct message WmShowCustomDialogSeq[] = { { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE }, { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_ACTIVATE, hook }, - { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, @@ -1568,18 +1808,18 @@ static const struct message WmModalDialogSeq[] = { { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_KILLFOCUS, sent|parent }, { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 }, - { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_ENABLE, sent|parent|wparam, 0 }, { HCBT_CREATEWND, hook }, - { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 }, - { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */ + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_SETFONT, sent }, { WM_INITDIALOG, sent }, { WM_CHANGEUISTATE, sent|optional }, { WM_UPDATEUISTATE, sent|optional }, { WM_SHOWWINDOW, sent }, { HCBT_ACTIVATE, hook }, - { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE }, { WM_NCACTIVATE, sent }, @@ -1598,7 +1838,7 @@ static const struct message WmModalDialogSeq[] = { { WM_GETTEXT, sent|optional }, { WM_ERASEBKGND, sent|optional }, { WM_CTLCOLORDLG, sent|optional }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */ { WM_PAINT, sent|optional }, { WM_CTLCOLORBTN, sent|optional }, { WM_GETTITLEBARINFOEX, sent|optional }, @@ -1623,7 +1863,7 @@ static const struct message WmModalDialogSeq[] = { { WM_ENTERIDLE, sent|parent|optional }, { WM_ENTERIDLE, sent|parent|optional }, { WM_TIMER, sent }, - { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_ENABLE, sent|parent|wparam, 1 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE }, { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 }, @@ -1633,7 +1873,7 @@ static const struct message WmModalDialogSeq[] = { { WM_NCACTIVATE, sent|wparam, 0 }, { WM_GETTEXT, sent|optional }, { WM_ACTIVATE, sent|wparam, 0 }, - { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|optional }, { WM_WINDOWPOSCHANGED, sent|optional }, { HCBT_SETFOCUS, hook }, @@ -1643,7 +1883,7 @@ static const struct message WmModalDialogSeq[] = { { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_DESTROYWND, hook }, { 0x0090, sent|optional }, - { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_DESTROY, sent }, { WM_NCDESTROY, sent }, { 0 } @@ -1654,23 +1894,25 @@ static const struct message WmModalDialogSeq_2[] = { { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_KILLFOCUS, sent }, { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 }, - { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_ENABLE, sent|wparam, 0 }, { HCBT_CREATEWND, hook }, - { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 }, - { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_SETFONT, sent }, { WM_INITDIALOG, sent }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_CHANGEUISTATE, sent|optional }, { WM_UPDATEUISTATE, sent|optional }, { WM_ENABLE, sent|wparam, 1 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE }, - { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, { WM_CHANGEUISTATE, sent|optional }, { WM_UPDATEUISTATE, sent|optional }, + { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_DESTROYWND, hook }, { 0x0090, sent|optional }, - { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_DESTROY, sent }, { WM_NCDESTROY, sent }, { 0 } @@ -1679,7 +1921,7 @@ static const struct message WmModalDialogSeq_2[] = { static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = { { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { WM_NCCALCSIZE, sent|wparam, 1 }, - { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW }, { WM_MOVE, sent|defwinproc }, { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, @@ -1703,7 +1945,7 @@ static const struct message WmSetMenuVisibleSizeChangeSeq[] = { { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { WM_NCCALCSIZE, sent|wparam, 1 }, { 0x0093, sent|defwinproc|optional }, - { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_NCPAINT, sent|optional }, /* wparam != 1 */ { 0x0093, sent|defwinproc|optional }, { 0x0093, sent|defwinproc|optional }, @@ -1784,7 +2026,7 @@ static const struct message WmEnableWindowSeq_1[] = static const struct message WmEnableWindowSeq_2[] = { { WM_CANCELMODE, sent|wparam|lparam, 0, 0 }, - { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */ { 0 } }; @@ -1797,7 +2039,7 @@ static const struct message WmEnableWindowSeq_3[] = static const struct message WmEnableWindowSeq_4[] = { - { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win10. */ { 0 } }; @@ -1846,7 +2088,7 @@ static const struct message WmSetScrollRangeHV_NC_Seq[] = { { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE }, { WM_NCCALCSIZE, sent|wparam, 1 }, - { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_NCPAINT, sent|optional }, { WM_STYLECHANGING, sent|defwinproc|optional }, { WM_STYLECHANGED, sent|defwinproc|optional }, @@ -1919,25 +2161,89 @@ static const struct message WmSHOWNATopInvisible[] = { { WM_NCCALCSIZE, sent|wparam|optional, 1 }, { WM_NCPAINT, sent|wparam|optional, 1 }, { WM_ERASEBKGND, sent|optional }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends it, but Win8+ doesn't. */ { WM_SIZE, sent|wparam, SIZE_RESTORED }, { WM_MOVE, sent }, { 0 } }; -static const struct message WmTrackPopupMenu[] = { +static const struct message WmTrackPopupMenuMinimizeWindow[] = { { HCBT_CREATEWND, hook }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 }, + { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_INITMENU, sent|lparam, 0, 0 }, + { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_INITMENUPOPUP, sent|lparam, 0, 0 }, { 0x0093, sent|optional }, { 0x0094, sent|optional }, { 0x0094, sent|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, + { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { WM_ENTERIDLE, sent|wparam, 2 }, - { WM_CAPTURECHANGED, sent }, + { HCBT_MINMAX, hook }, + { HCBT_SETFOCUS, hook }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { WM_KILLFOCUS, sent|wparam, 0 }, + { WM_GETTEXT, sent|optional }, + { WM_WINDOWPOSCHANGING, sent }, + { WM_GETMINMAXINFO, sent|defwinproc }, + { WM_NCCALCSIZE, sent|wparam|optional, 1 }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { WM_WINDOWPOSCHANGED, sent }, + { WM_MOVE, sent|defwinproc }, + { WM_SIZE, sent|defwinproc }, + { WM_GETTEXT, sent|optional }, + { WM_NCCALCSIZE, sent|wparam|optional, 1 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ + { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { WM_CANCELMODE, sent }, + { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { WM_CAPTURECHANGED, sent|defwinproc }, + { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { HCBT_DESTROYWND, hook }, + { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { WM_UNINITMENUPOPUP, sent|defwinproc|lparam, 0, 0 }, + { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 }, + { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 1, 0 }, + { WM_NCACTIVATE, sent }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ACTIVATE, sent }, + { WM_ACTIVATEAPP, sent|wparam, 0 }, + { 0 } +}; + +static const struct message WmTrackPopupMenu[] = { + { HCBT_CREATEWND, hook }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 }, + { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { WM_INITMENU, sent|lparam, 0, 0 }, + { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { WM_INITMENUPOPUP, sent|lparam, 0, 0 }, + { 0x0093, sent|optional }, + { 0x0094, sent|optional }, + { 0x0094, sent|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, + { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, + { WM_ENTERIDLE, sent|wparam, 2 }, + { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { WM_CAPTURECHANGED, sent }, + { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, + { HCBT_DESTROYWND, hook }, + { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 }, { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 }, + { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 }, { 0 } }; @@ -1948,49 +2254,81 @@ static const struct message WmTrackPopupMenuEsc[] = { static const struct message WmTrackPopupMenuCapture[] = { { HCBT_CREATEWND, hook }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 }, + { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_CAPTURECHANGED, sent }, { WM_INITMENU, sent|lparam, 0, 0 }, + { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_INITMENUPOPUP, sent|lparam, 0, 0 }, { 0x0093, sent|optional }, { 0x0094, sent|optional }, { 0x0094, sent|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, + { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { WM_ENTERIDLE, sent|wparam, 2 }, + { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_CAPTURECHANGED, sent }, + { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { HCBT_DESTROYWND, hook }, + { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 }, { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 }, + { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 }, { 0 } }; static const struct message WmTrackPopupMenuEmpty[] = { { HCBT_CREATEWND, hook }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 }, + { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_INITMENU, sent|lparam, 0, 0 }, + { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_INITMENUPOPUP, sent|lparam, 0, 0 }, { 0x0093, sent|optional }, { 0x0094, sent|optional }, { 0x0094, sent|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_CAPTURECHANGED, sent }, { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 }, { HCBT_DESTROYWND, hook }, + { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 }, { 0 } }; static const struct message WmTrackPopupMenuAbort[] = { { HCBT_CREATEWND, hook }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 }, + { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_INITMENU, sent|lparam, 0, 0 }, + { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_INITMENUPOPUP, sent|lparam, 0, 0 }, { 0x0093, sent|optional }, { 0x0094, sent|optional }, { 0x0094, sent|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, + { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, + { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_CAPTURECHANGED, sent }, + { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { HCBT_DESTROYWND, hook }, + { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 }, { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 }, + { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 }, { 0 } }; @@ -2002,15 +2340,10 @@ static int log_all_parent_messages; static CRITICAL_SECTION sequence_cs; /* user32 functions */ -static HWND (WINAPI *pGetAncestor)(HWND,UINT); -static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO); static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG); -static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO); static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD); static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*); static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK); -static BOOL (WINAPI *pGetMonitorInfoA)(HMONITOR,LPMONITORINFO); -static HMONITOR (WINAPI *pMonitorFromPoint)(POINT,DWORD); static BOOL (WINAPI *pUpdateLayeredWindow)(HWND,HDC,POINT*,SIZE*,HDC,POINT*,COLORREF,BLENDFUNCTION*,DWORD); static UINT_PTR (WINAPI *pSetSystemTimer)(HWND, UINT_PTR, UINT, TIMERPROC); static UINT_PTR (WINAPI *pKillSystemTimer)(HWND, UINT_PTR); @@ -2029,15 +2362,10 @@ static void init_procs(void) trace("GetProcAddress(%s) failed\n", #func); \ } - GET_PROC(user32, GetAncestor) - GET_PROC(user32, GetMenuInfo) GET_PROC(user32, NotifyWinEvent) - GET_PROC(user32, SetMenuInfo) GET_PROC(user32, SetWinEventHook) GET_PROC(user32, TrackMouseEvent) GET_PROC(user32, UnhookWinEvent) - GET_PROC(user32, GetMonitorInfoA) - GET_PROC(user32, MonitorFromPoint) GET_PROC(user32, UpdateLayeredWindow) GET_PROC(user32, SetSystemTimer) GET_PROC(user32, KillSystemTimer) @@ -2083,7 +2411,8 @@ static BOOL ignore_message( UINT message ) message == WM_TIMECHANGE || message == WM_DISPLAYCHANGE || message == WM_DEVICECHANGE || - message == WM_DWMNCRENDERINGCHANGED); + message == WM_DWMNCRENDERINGCHANGED || + message == WM_WININICHANGE); } static unsigned hash_Ly_W(const WCHAR *str) @@ -2114,15 +2443,14 @@ static void add_message_(int line, const struct recvd_message *msg) EnterCriticalSection( &sequence_cs ); if (!sequence) { - sequence_size = 10; - sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof(*sequence) ); + sequence_size = 10; + sequence = malloc( sequence_size * sizeof(*sequence) ); } if (sequence_cnt == sequence_size) { - sequence_size *= 2; - sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof(*sequence) ); + sequence_size *= 2; + sequence = realloc( sequence, sequence_size * sizeof(*sequence) ); } - assert(sequence); seq = &sequence[sequence_cnt++]; seq->hwnd = msg->hwnd; @@ -2154,12 +2482,12 @@ static void add_message_(int line, const struct recvd_message *msg) }; const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown"; - sprintf( seq->output, "%s: hook %d (%s) wp %08lx lp %08lx", + sprintf( seq->output, "%s: hook %d (%s) wp %08Ix lp %08Ix", msg->descr, msg->message, code_name, msg->wParam, msg->lParam ); } else if (msg->flags & winevent_hook) { - sprintf( seq->output, "%s: winevent %p %08x %08lx %08lx", + sprintf( seq->output, "%s: winevent %p %08x %08Ix %08Ix", msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam ); } else @@ -2171,7 +2499,7 @@ static void add_message_(int line, const struct recvd_message *msg) { WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam; - sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08lx lp %08lx after %p x %d y %d cx %d cy %d flags %s", + sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08Ix lp %08Ix after %p x %d y %d cx %d cy %d flags %s", msg->descr, msg->hwnd, (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED", msg->wParam, msg->lParam, winpos->hwndInsertAfter, @@ -2184,9 +2512,31 @@ static void add_message_(int line, const struct recvd_message *msg) seq->wParam = winpos->flags & 0xffff; /* We are not interested in the flags that don't match under XP and Win9x */ seq->wParam &= ~SWP_NOZORDER; + seq->lParam = (!!winpos->cx) | ((!!winpos->cy) << 1) + | ((!!winpos->x) << 2) | ((!!winpos->y) << 3); break; } + case WM_NCCALCSIZE: + if (msg->wParam) + { + NCCALCSIZE_PARAMS *p = (NCCALCSIZE_PARAMS *)msg->lParam; + WINDOWPOS *winpos = p->lppos; + + sprintf(seq->output, "%s: %p WM_NCCALCSIZE: winpos->cx %u, winpos->cy %u", + msg->descr, msg->hwnd, winpos->cx, winpos->cy); + seq->lParam = (!!winpos->cx) | ((!!winpos->cy) << 1) + | ((!!winpos->x) << 2) | ((!!winpos->y) << 3); + } + else + { + RECT *rect = (RECT*)msg->lParam; + + sprintf(seq->output, "%s: %p WM_NCCALCSIZE: %s", + msg->descr, msg->hwnd, wine_dbgstr_rect(rect)); + seq->lParam = 0; + } + break; case WM_DRAWITEM: { DRAW_ITEM_STRUCT di; @@ -2216,7 +2566,7 @@ static void add_message_(int line, const struct recvd_message *msg) MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)msg->lParam; BOOL is_unicode_data = TRUE; - sprintf( seq->output, "%s: %p WM_MEASUREITEM: CtlType %#x, CtlID %#x, itemID %#x, itemData %#lx", + sprintf( seq->output, "%s: %p WM_MEASUREITEM: CtlType %#x, CtlID %#x, itemID %#x, itemData %#Ix", msg->descr, msg->hwnd, mis->CtlType, mis->CtlID, mis->itemID, mis->itemData); @@ -2245,12 +2595,12 @@ static void add_message_(int line, const struct recvd_message *msg) HWND ctrl = GetDlgItem(msg->hwnd, cis->CtlID); BOOL is_unicode_data = TRUE; - ok(msg->wParam == cis->CtlID, "expected %#x, got %#lx\n", cis->CtlID, msg->wParam); + ok(msg->wParam == cis->CtlID, "expected %#x, got %#Ix\n", cis->CtlID, msg->wParam); ok(cis->hwndItem == ctrl, "expected %p, got %p\n", ctrl, cis->hwndItem); ok((int)cis->itemID1 >= 0, "expected >= 0, got %d\n", cis->itemID1); ok((int)cis->itemID2 == -1, "expected -1, got %d\n", cis->itemID2); - sprintf( seq->output, "%s: %p WM_COMPAREITEM: CtlType %#x, CtlID %#x, itemID1 %#x, itemData1 %#lx, itemID2 %#x, itemData2 %#lx", + sprintf( seq->output, "%s: %p WM_COMPAREITEM: CtlType %#x, CtlID %#x, itemID1 %#x, itemData1 %#Ix, itemID2 %#x, itemData2 %#Ix", msg->descr, msg->hwnd, cis->CtlType, cis->CtlID, cis->itemID1, cis->itemData1, cis->itemID2, cis->itemData2); @@ -2272,7 +2622,7 @@ static void add_message_(int line, const struct recvd_message *msg) default: if (msg->message >= 0xc000) return; /* ignore registered messages */ - sprintf( seq->output, "%s: %p %04x wp %08lx lp %08lx", + sprintf( seq->output, "%s: %p %04x wp %08Ix lp %08Ix", msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam ); } if (msg->flags & (sent|posted|parent|defwinproc|beginpaint)) @@ -2300,12 +2650,98 @@ static void flush_events(void) static void flush_sequence(void) { EnterCriticalSection( &sequence_cs ); - HeapFree(GetProcessHeap(), 0, sequence); + free( sequence ); sequence = 0; sequence_cnt = sequence_size = 0; LeaveCriticalSection( &sequence_cs ); } +static const char* message_type_name(int flags) { + if (flags & hook) return "hook"; + if (flags & kbd_hook) return "kbd_hook"; + if (flags & winevent_hook) return "winevent_hook"; + return "msg"; +} + +static BOOL can_skip_message(const struct message *expected) +{ + if (expected->flags & optional) return TRUE; + + if ((expected->flags & winevent_hook) && !hEvent_hook) return TRUE; + if ((expected->flags & kbd_hook) && !hKBD_hook) return TRUE; + if ((expected->flags & hook) && !hCBT_hook) return TRUE; + + if ((expected->flags & msg_todo) && !strcmp(winetest_platform, "wine")) return TRUE; + + if ((expected->flags & wine_only) && strcmp(winetest_platform, "wine")) return TRUE; + + return FALSE; +} + +static BOOL messages_equal(const struct message *expected, const struct recvd_message *actual, + BOOL expect_equal, const char* file, int line) +{ + int todo = (expected->flags & msg_todo) != 0; + int msg_wine_only = (expected->flags & wine_only) != 0; + const int message_type_flags = hook|winevent_hook|kbd_hook; + static int todo_reported; + + if (!todo && can_skip_message(expected)) + expect_equal = FALSE; + + if (msg_wine_only && strcmp(winetest_platform, "wine")) + { + /* Ignore Wine-only message records on Windows. */ + return FALSE; + } + + if (!expected->message || !actual->message) { + if (expect_equal && (!todo || !todo_reported++)) + todo_wine_if(todo || msg_wine_only) + ok_( file, line) (msg_wine_only, "the msg sequence is not complete: expected %s %04x - actual %s %04x\n", + message_type_name(expected->flags), expected->message, message_type_name(actual->flags), actual->message); + return FALSE; + } + + if (expected->message != actual->message || + (expected->flags & message_type_flags) != (actual->flags & message_type_flags)) + { + if (expect_equal && (!todo || !todo_reported++)) + todo_wine_if(todo || msg_wine_only) + ok_( file, line) (msg_wine_only, "the %s 0x%04x was expected, but got %s 0x%04x instead\n", + message_type_name(expected->flags), expected->message, message_type_name(actual->flags), actual->message); + return FALSE; + } + + if (expected->flags & optional) + { + /* If a message can be sent in 2 different ways at the same time, we may need to treat + * them as unequal so that the optional message can be properly skipped. */ + if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) { + /* don't match messages if their defwinproc status differs */ + return FALSE; + } + } + + if (expect_equal) + todo_wine_if(todo || msg_wine_only) + ok_( file, line) (!msg_wine_only, "got %s 0x%04x as expected\n", + message_type_name(expected->flags), expected->message); + + return TRUE; +} + +static BOOL sequence_contains_message(const struct message *expected, const struct recvd_message *actual) +{ + while (expected->message) + { + if (messages_equal(expected, actual, FALSE, __FILE__, __LINE__)) + return TRUE; + expected++; + } + return FALSE; +} + static void dump_sequence(const struct message *expected, const char *context, const char *file, int line) { const struct recvd_message *actual = sequence; @@ -2316,56 +2752,29 @@ static void dump_sequence(const struct message *expected, const char *context, c { if (actual->output[0]) { - if (expected->flags & hook) - { - trace_(file, line)( " %u: expected: hook %04x - actual: %s\n", - count, expected->message, actual->output ); - } - else if (expected->flags & winevent_hook) - { - trace_(file, line)( " %u: expected: winevent %04x - actual: %s\n", - count, expected->message, actual->output ); - } - else if (expected->flags & kbd_hook) - { - trace_(file, line)( " %u: expected: kbd %04x - actual: %s\n", - count, expected->message, actual->output ); - } - else - { - trace_(file, line)( " %u: expected: msg %04x - actual: %s\n", - count, expected->message, actual->output ); - } + trace_(file, line)( " %u: expected: %s %04x - actual: %s\n", + count, message_type_name(expected->flags), expected->message, actual->output ); } - if (expected->message == actual->message) - { - if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && - (expected->flags & optional)) - { - /* don't match messages if their defwinproc status differs */ - expected++; - } - else - { - expected++; - actual++; - } - } - /* silently drop winevent messages if there is no support for them */ - else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook)) - expected++; - else + if (messages_equal(expected, actual, FALSE, file, line)) { expected++; actual++; + count++; + } + else if (can_skip_message(expected) || sequence_contains_message(expected, actual)) + { + expected++; + count++; + } + else + { + actual++; } - count++; } /* optional trailing messages */ - while (expected->message && ((expected->flags & optional) || - ((expected->flags & winevent_hook) && !hEvent_hook))) + while (can_skip_message(expected)) { trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message ); expected++; @@ -2398,15 +2807,17 @@ static void ok_sequence_(const struct message *expected_list, const char *contex const struct recvd_message *actual; int failcount = 0, dump = 0; unsigned int count = 0; + BOOL is_wine = !strcmp(winetest_platform, "wine"); add_message(&end_of_sequence); actual = sequence; + winetest_push_context("%s: %u", context, count); + while (expected->message && actual->message) { - if (expected->message == actual->message && - !((expected->flags ^ actual->flags) & (hook|winevent_hook|kbd_hook))) + if (messages_equal(expected, actual, !todo, file, line)) { if (expected->flags & wparam) { @@ -2414,17 +2825,18 @@ static void ok_sequence_(const struct message *expected_list, const char *contex { todo_wine { failcount ++; - if (strcmp(winetest_platform, "wine")) dump++; + dump++; ok_( file, line) (FALSE, - "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n", - context, count, expected->message, expected->wParam, actual->wParam); + "in msg 0x%04x expecting wParam 0x%Ix got 0x%Ix\n", + expected->message, expected->wParam, actual->wParam); } + if (is_wine) goto done; } else { ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0, - "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n", - context, count, expected->message, expected->wParam, actual->wParam); + "in msg 0x%04x expecting wParam 0x%Ix got 0x%Ix\n", + expected->message, expected->wParam, actual->wParam); if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++; } @@ -2435,144 +2847,128 @@ static void ok_sequence_(const struct message *expected_list, const char *contex { todo_wine { failcount ++; - if (strcmp(winetest_platform, "wine")) dump++; + dump++; ok_( file, line) (FALSE, - "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n", - context, count, expected->message, expected->lParam, actual->lParam); + "in msg 0x%04x expecting lParam 0x%Ix got 0x%Ix\n", + expected->message, expected->lParam, actual->lParam); } + if (is_wine) goto done; } else { ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0, - "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n", - context, count, expected->message, expected->lParam, actual->lParam); + "in msg 0x%04x expecting lParam 0x%Ix got 0x%Ix\n", + expected->message, expected->lParam, actual->lParam); if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++; } } - if ((expected->flags & optional) && - ((expected->flags ^ actual->flags) & (defwinproc|parent))) - { - /* don't match optional messages if their defwinproc or parent status differs */ - expected++; - count++; - continue; - } if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo) { todo_wine { failcount ++; - if (strcmp(winetest_platform, "wine")) dump++; + dump++; ok_( file, line) (FALSE, - "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n", - context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT "); + "the msg 0x%04x should %shave been sent by DefWindowProc\n", + expected->message, (expected->flags & defwinproc) ? "" : "NOT "); } + if (is_wine) goto done; } else { ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc), - "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n", - context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT "); + "the msg 0x%04x should %shave been sent by DefWindowProc\n", + expected->message, (expected->flags & defwinproc) ? "" : "NOT "); if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++; } ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint), - "%s: %u: the msg 0x%04x should %shave been sent by BeginPaint\n", - context, count, expected->message, (expected->flags & beginpaint) ? "" : "NOT "); + "the msg 0x%04x should %shave been sent by BeginPaint\n", + expected->message, (expected->flags & beginpaint) ? "" : "NOT "); if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++; ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)), - "%s: %u: the msg 0x%04x should have been %s\n", - context, count, expected->message, (expected->flags & posted) ? "posted" : "sent"); + "the msg 0x%04x should have been %s\n", + expected->message, (expected->flags & posted) ? "posted" : "sent"); if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++; ok_( file, line) ((expected->flags & parent) == (actual->flags & parent), - "%s: %u: the msg 0x%04x was expected in %s\n", - context, count, expected->message, (expected->flags & parent) ? "parent" : "child"); + "the msg 0x%04x was expected in %s\n", + expected->message, (expected->flags & parent) ? "parent" : "child"); if ((expected->flags & parent) != (actual->flags & parent)) dump++; - ok_( file, line) ((expected->flags & hook) == (actual->flags & hook), - "%s: %u: the msg 0x%04x should have been sent by a hook\n", - context, count, expected->message); - if ((expected->flags & hook) != (actual->flags & hook)) dump++; - - ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook), - "%s: %u: the msg 0x%04x should have been sent by a winevent hook\n", - context, count, expected->message); - if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++; - - ok_( file, line) ((expected->flags & kbd_hook) == (actual->flags & kbd_hook), - "%s: %u: the msg 0x%04x should have been sent by a keyboard hook\n", - context, count, expected->message); - if ((expected->flags & kbd_hook) != (actual->flags & kbd_hook)) dump++; - expected++; + count++; actual++; } - /* silently drop hook messages if there is no support for them */ - else if ((expected->flags & optional) || - ((expected->flags & hook) && !hCBT_hook) || - ((expected->flags & winevent_hook) && !hEvent_hook) || - ((expected->flags & kbd_hook) && !hKBD_hook)) + /* + * silently drop hook messages if there is no support for them + */ + else if (can_skip_message(expected)) + { expected++; + count++; + } else if (todo) { + todo_wine messages_equal(expected, actual, TRUE, file, line); failcount++; - todo_wine { - if (strcmp(winetest_platform, "wine")) dump++; - ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n", - context, count, expected->message, actual->message); - } + dump++; goto done; } + else if (sequence_contains_message(expected, actual)) + { + dump++; + expected++; + count++; + } else { - ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n", - context, count, expected->message, actual->message); dump++; - expected++; actual++; } - count++; + + winetest_pop_context(); + winetest_push_context("%s: %u", context, count); } /* skip all optional trailing messages */ - while (expected->message && ((expected->flags & optional) || - ((expected->flags & hook) && !hCBT_hook) || - ((expected->flags & winevent_hook) && !hEvent_hook))) + while (can_skip_message(expected)) + { + messages_equal(expected, actual, TRUE, file, line); /* check for message todo's */ expected++; + } if (todo) { todo_wine { if (expected->message || actual->message) { failcount++; - if (strcmp(winetest_platform, "wine")) dump++; - ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n", - context, count, expected->message, actual->message); + dump++; + messages_equal(expected, actual, TRUE, file, line); } } + if (is_wine && !failcount) /* succeeded yet marked todo */ + todo_wine { + dump++; + ok_( file, line)( TRUE, "marked \"todo_wine\" but succeeds\n"); + } } else { if (expected->message || actual->message) { dump++; - ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n", - context, count, expected->message, actual->message); + messages_equal(expected, actual, TRUE, file, line); } } - if( todo && !failcount) /* succeeded yet marked todo */ - todo_wine { - if (!strcmp(winetest_platform, "wine")) dump++; - ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context); - } done: - if (dump) dump_sequence(expected_list, context, file, line); + winetest_pop_context(); + if (dump && (!is_wine || winetest_debug > 1)) dump_sequence(expected_list, context, file, line); flush_sequence(); } -#define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT)) +#define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %ld\n", (EXPECTED), (GOT)) /******************************** MDI test **********************************/ @@ -2582,7 +2978,7 @@ static const struct message WmCreateMDIframeSeq[] = { { WM_GETMINMAXINFO, sent }, { WM_NCCREATE, sent }, { WM_NCCALCSIZE, sent|wparam, 0 }, - { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win8+. */ { WM_CREATE, sent }, { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, { WM_NOTIFYFORMAT, sent|optional }, @@ -2611,7 +3007,7 @@ static const struct message WmCreateMDIframeSeq[] = { /* Win9x adds SWP_NOZORDER below */ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */ - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win8+. */ { WM_SIZE, sent|wparam, SIZE_RESTORED }, { WM_MOVE, sent }, { 0 } @@ -2627,7 +3023,7 @@ static const struct message WmDestroyMDIframeSeq[] = { { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */ { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */ { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */ - { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, + { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 }, { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, { WM_DESTROY, sent }, { WM_NCDESTROY, sent }, @@ -2734,13 +3130,16 @@ static const struct message WmChildActivateWindowSeq[] = { { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, { WM_MDIACTIVATE, sent|defwinproc }, { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, { HCBT_SETFOCUS, hook }, { WM_KILLFOCUS, sent|defwinproc }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent }, { HCBT_SETFOCUS, hook }, { WM_KILLFOCUS, sent }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|defwinproc }, { WM_MDIACTIVATE, sent|defwinproc }, { 0 } @@ -2814,7 +3213,7 @@ static const struct message WmDestroyMDIchildVisibleSeq[] = { { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent }, /* in MDI client */ - { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { HCBT_SETFOCUS, hook }, /* set focus to MDI client */ { WM_KILLFOCUS, sent }, @@ -2879,8 +3278,6 @@ static const struct message WmDestroyMDIchildInvisibleSeq[] = { { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, { WM_DESTROY, sent }, { WM_NCDESTROY, sent }, - /* FIXME: Wine destroys an icon/title window while Windows doesn't */ - { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */ { 0 } }; /* CreateWindow for the 1st MDI child window, initially visible and maximized */ @@ -2889,7 +3286,7 @@ static const struct message WmCreateMDIchildVisibleMaxSeq1[] = { { WM_NCCREATE, sent }, { WM_NCCALCSIZE, sent|wparam, 0 }, { WM_CREATE, sent }, - { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_SIZE, sent|wparam, SIZE_RESTORED }, { WM_MOVE, sent }, { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE }, @@ -2902,8 +3299,8 @@ static const struct message WmCreateMDIchildVisibleMaxSeq1[] = { { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { WM_NCCALCSIZE, sent|wparam, 1 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */ - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI frame */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */ /* Win2k sends wparam set to * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated), * while Win9x doesn't bother to set child window id according to @@ -2938,7 +3335,7 @@ static const struct message WmCreateMDIchildVisibleMaxSeq1[] = { { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { WM_NCCALCSIZE, sent|wparam, 1 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI frame */ { 0 } }; /* CreateWindow for the 2nd MDI child window, initially visible and maximized */ @@ -2955,30 +3352,30 @@ static const struct message WmCreateMDIchildVisibleMaxSeq2[] = { { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { WM_NCCALCSIZE, sent|wparam, 1 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */ - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI frame */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */ { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */ /* create the 2nd MDI child */ { HCBT_CREATEWND, hook }, { WM_NCCREATE, sent }, { WM_NCCALCSIZE, sent|wparam, 0 }, { WM_CREATE, sent }, - { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_SIZE, sent|wparam, SIZE_RESTORED }, { WM_MOVE, sent }, { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE }, { WM_GETMINMAXINFO, sent }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED }, { WM_NCCALCSIZE, sent|wparam, 1 }, - { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in MDI frame */ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { WM_NCCALCSIZE, sent|wparam, 1 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */ - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI frame */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */ /* Win2k sends wparam set to * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated), * while Win9x doesn't bother to set child window id according to @@ -3019,7 +3416,7 @@ static const struct message WmCreateMDIchildVisibleMaxSeq2[] = { { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { WM_NCCALCSIZE, sent|wparam, 1 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI frame */ { 0 } }; /* WM_MDICREATE MDI child window, initially visible and maximized */ @@ -3029,7 +3426,7 @@ static const struct message WmCreateMDIchildVisibleMaxSeq3[] = { { WM_NCCREATE, sent }, { WM_NCCALCSIZE, sent|wparam, 0 }, { WM_CREATE, sent }, - { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_SIZE, sent|wparam, SIZE_RESTORED }, { WM_MOVE, sent }, { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE }, @@ -3043,8 +3440,8 @@ static const struct message WmCreateMDIchildVisibleMaxSeq3[] = { { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { WM_NCCALCSIZE, sent|wparam, 1 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */ - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI frame */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */ /* Win2k sends wparam set to * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated), @@ -3086,7 +3483,7 @@ static const struct message WmCreateMDIchildVisibleMaxSeq3[] = { { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { WM_NCCALCSIZE, sent|wparam, 1 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* in MDI frame */ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, @@ -3112,14 +3509,15 @@ static const struct message WmCreateMDIchildVisibleMaxSeq3[] = { { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, { 0x0093, sent|optional }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */ - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client, not sent on Win7. */ + { 0x0093, sent|optional }, /* Win8+ sends an extra. */ { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */ { 0x0093, sent|defwinproc|optional }, { 0x0093, sent|defwinproc|optional }, { 0x0093, sent|defwinproc|optional }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */ - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI frame */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */ { 0 } }; @@ -3129,7 +3527,7 @@ static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = { { WM_GETMINMAXINFO, sent }, { WM_NCCREATE, sent }, { WM_NCCALCSIZE, sent|wparam, 0 }, - { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not sent on Win8+. */ { WM_CREATE, sent }, { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, { WM_SIZE, sent|wparam, SIZE_RESTORED }, @@ -3152,7 +3550,7 @@ static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = { { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */ { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */ - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */ /* Win2k sends wparam set to * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated), * while Win9x doesn't bother to set child window id according to @@ -3172,7 +3570,7 @@ static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = { { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */ { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */ - { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */ { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */ @@ -3198,15 +3596,15 @@ static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = { { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI frame */ { WM_SETREDRAW, sent|defwinproc|wparam, 1 }, /* in MDI frame */ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { WM_NCCALCSIZE, sent|wparam, 1 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */ - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI frame */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */ /* bring the 1st MDI child to top */ { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, @@ -3247,7 +3645,7 @@ static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = { { WM_ERASEBKGND, sent|parent|optional }, { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, - { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_DESTROY, sent|defwinproc }, { WM_NCDESTROY, sent|defwinproc }, { 0 } @@ -3278,7 +3676,7 @@ static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = { { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { WM_NCCALCSIZE, sent|wparam, 1 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */ /* in MDI frame */ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, @@ -3305,7 +3703,7 @@ static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = { { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */ /* in MDI frame */ { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, @@ -3328,8 +3726,8 @@ static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = { { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE }, { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */ - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI client */ { 0x0093, sent|defwinproc|optional }, { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */ @@ -3338,11 +3736,12 @@ static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = { { 0x0093, sent|defwinproc|optional }, { 0x0093, sent|optional }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */ - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */ - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */ - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */ - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI frame */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI client */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame */ + { 0x0093, sent|optional }, /* Win8+ sends an extra. */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */ /* in MDI frame */ { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, @@ -3351,7 +3750,8 @@ static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = { { 0x0093, sent|defwinproc|optional }, { 0x0093, sent|defwinproc|optional }, { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */ + { 0x0093, sent|optional }, /* Win8+ sends an extra. */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI frame */ { 0x0093, sent|optional }, { WM_NCACTIVATE, sent|wparam, 0 }, @@ -3371,7 +3771,7 @@ static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = { { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */ /* in MDI frame */ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, @@ -3385,11 +3785,11 @@ static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = { { WM_NCCALCSIZE, sent|wparam, 1 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE }, { WM_SIZE, sent|wparam, SIZE_RESTORED }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI child */ { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */ - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */ - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */ - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI client */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* MDI frame */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */ { HCBT_SETFOCUS, hook }, { WM_KILLFOCUS, sent }, @@ -3415,7 +3815,7 @@ static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = { { WM_ERASEBKGND, sent|parent|optional }, { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, - { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_DESTROY, sent }, { WM_NCDESTROY, sent }, { 0 } @@ -3456,7 +3856,7 @@ static const struct message WmMaximizeMDIchildInvisibleSeq[] = { static const struct message WmMaximizeMDIchildInvisibleSeq2[] = { { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE }, { WM_GETMINMAXINFO, sent }, - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED, 0, SWP_STATECHANGED /* w1064v1809 */ }, { WM_GETMINMAXINFO, sent|defwinproc }, { WM_NCCALCSIZE, sent|wparam, 1 }, { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, @@ -3475,9 +3875,10 @@ static const struct message WmMaximizeMDIchildInvisibleSeq2[] = { { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|defwinproc|optional }, { WM_MDIACTIVATE, sent|defwinproc|optional }, - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */ + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_STATECHANGED /* w1064v1809 */ }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child, not sent on Win8+. */ { WM_SIZE, sent|defwinproc|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* w1064v1809. */ { 0 } }; /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */ @@ -3614,8 +4015,6 @@ static const struct message WmMinimizeMDIchildVisibleSeq[] = { { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */ { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */ - /* FIXME: Wine creates an icon/title window while Windows doesn't */ - { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */ { 0 } }; /* ShowWindow(SW_RESTORE) for a not visible MDI child window */ @@ -3745,9 +4144,10 @@ static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, return ret; } -static BOOL mdi_RegisterWindowClasses(void) +static void mdi_register_classes(void) { WNDCLASSA cls; + BOOL ret; cls.style = 0; cls.lpfnWndProc = mdi_frame_wnd_proc; @@ -3759,20 +4159,19 @@ static BOOL mdi_RegisterWindowClasses(void) cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = "MDI_frame_class"; - if (!RegisterClassA(&cls)) return FALSE; + register_class(&cls); cls.lpfnWndProc = mdi_child_wnd_proc; cls.lpszClassName = "MDI_child_class"; - if (!RegisterClassA(&cls)) return FALSE; + register_class(&cls); - if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0); + ret = GetClassInfoA(0, "MDIClient", &cls); + ok(ret, "Failed to get class info, error %lu.\n", GetLastError()); old_mdi_client_proc = cls.lpfnWndProc; cls.hInstance = GetModuleHandleA(0); cls.lpfnWndProc = mdi_client_hook_proc; cls.lpszClassName = "MDI_client_class"; - if (!RegisterClassA(&cls)) assert(0); - - return TRUE; + register_class(&cls); } static void test_mdi_messages(void) @@ -3785,24 +4184,24 @@ static void test_mdi_messages(void) HMENU hMenu = CreateMenu(); LONG val; - if (!mdi_RegisterWindowClasses()) assert(0); + mdi_register_classes(); flush_sequence(); - trace("creating MDI frame window\n"); + if (winetest_debug > 1) trace("creating MDI frame window\n"); mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window", WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE, 100, 100, CW_USEDEFAULT, CW_USEDEFAULT, GetDesktopWindow(), hMenu, GetModuleHandleA(0), NULL); - assert(mdi_frame); + ok(!!mdi_frame, "Failed to create window, error %lu.\n", GetLastError()); ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE); ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow()); ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus()); - trace("creating MDI client window\n"); + if (winetest_debug > 1) trace("creating MDI client window\n"); GetClientRect(mdi_frame, &rc); client_cs.hWindowMenu = 0; client_cs.idFirstChild = MDI_FIRST_CHILD_ID; @@ -3811,7 +4210,7 @@ static void test_mdi_messages(void) WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, mdi_frame, 0, GetModuleHandleA(0), &client_cs); - assert(mdi_client); + ok(!!mdi_client, "Failed to create window, error %lu.\n", GetLastError()); SetWindowLongA(mdi_client, 0, 0xdeadbeef); ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE); @@ -3825,12 +4224,12 @@ static void test_mdi_messages(void) SetFocus(0); flush_sequence(); - trace("creating invisible MDI child window\n"); + if (winetest_debug > 1) trace("creating invisible MDI child window\n"); mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child", WS_CHILD, 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, mdi_client, 0, GetModuleHandleA(0), NULL); - assert(mdi_child); + ok(!!mdi_child, "Failed to create window, error %lu.\n", GetLastError()); flush_sequence(); ShowWindow(mdi_child, SW_SHOWNORMAL); @@ -3866,12 +4265,12 @@ static void test_mdi_messages(void) DestroyWindow(mdi_child); flush_sequence(); - trace("creating visible MDI child window\n"); + if (winetest_debug > 1) trace("creating visible MDI child window\n"); mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child", WS_CHILD | WS_VISIBLE, 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, mdi_client, 0, GetModuleHandleA(0), NULL); - assert(mdi_child); + ok(!!mdi_child, "Failed to create window, error %lu.\n", GetLastError()); ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE); ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n"); @@ -3902,12 +4301,12 @@ static void test_mdi_messages(void) flush_sequence(); - trace("creating invisible MDI child window\n"); + if (winetest_debug > 1) trace("creating invisible MDI child window\n"); mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child", WS_CHILD, 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, mdi_client, 0, GetModuleHandleA(0), NULL); - assert(mdi_child2); + ok(!!mdi_child2, "Failed to create window, error %lu.\n", GetLastError()); ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE); ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n"); @@ -4021,7 +4420,7 @@ static void test_mdi_messages(void) ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow()); ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus()); - trace("Testing WM_CHILDACTIVATE\n"); + if (winetest_debug > 1) trace("Testing WM_CHILDACTIVATE\n"); mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child", WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_DISABLED, @@ -4066,12 +4465,12 @@ static void test_mdi_messages(void) flush_sequence(); /* test for maximized MDI children */ - trace("creating maximized visible MDI child window 1\n"); + if (winetest_debug > 1) trace("creating maximized visible MDI child window 1\n"); mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child", WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE, 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, mdi_client, 0, GetModuleHandleA(0), NULL); - assert(mdi_child); + ok(!!mdi_child, "Failed to create window, error %lu.\n", GetLastError()); ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE); ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n"); @@ -4085,12 +4484,12 @@ static void test_mdi_messages(void) ok(zoomed, "wrong zoomed state %d\n", zoomed); flush_sequence(); - trace("creating maximized visible MDI child window 2\n"); + if (winetest_debug > 1) trace("creating maximized visible MDI child window 2\n"); mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child", WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE, 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, mdi_client, 0, GetModuleHandleA(0), NULL); - assert(mdi_child2); + ok(!!mdi_child2, "Failed to create window, error %lu.\n", GetLastError()); ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE); ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n"); ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n"); @@ -4103,7 +4502,7 @@ static void test_mdi_messages(void) ok(zoomed, "wrong zoomed state %d\n", zoomed); flush_sequence(); - trace("destroying maximized visible MDI child window 2\n"); + if (winetest_debug > 1) trace("destroying maximized visible MDI child window 2\n"); DestroyWindow(mdi_child2); ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE); @@ -4128,12 +4527,12 @@ static void test_mdi_messages(void) ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow()); ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus()); - trace("re-creating maximized visible MDI child window 2\n"); + if (winetest_debug > 1) trace("re-creating maximized visible MDI child window 2\n"); mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child", WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE, 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, mdi_client, 0, GetModuleHandleA(0), NULL); - assert(mdi_child2); + ok(!!mdi_child2, "Failed to create window, error %lu.\n", GetLastError()); ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE); ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n"); ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n"); @@ -4174,12 +4573,15 @@ static void test_mdi_messages(void) "wrong active MDI child %p\n", active_child); flush_sequence(); - trace("creating maximized invisible MDI child window\n"); + if (winetest_debug > 1) trace("creating maximized invisible MDI child window\n"); mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child", WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME, 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, mdi_client, 0, GetModuleHandleA(0), NULL); - assert(mdi_child2); + ok(!!mdi_child2, "Failed to create window, error %lu.\n", GetLastError()); +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_WINBLUE) +#endif ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE); ok(IsZoomed(mdi_child2), "MDI child should be maximized\n"); ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n"); @@ -4194,7 +4596,7 @@ static void test_mdi_messages(void) "wrong active MDI child %p\n", active_child); flush_sequence(); - trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n"); + if (winetest_debug > 1) trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n"); ShowWindow(mdi_child2, SW_MAXIMIZE); ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE); ok(IsZoomed(mdi_child2), "MDI child should be maximized\n"); @@ -4212,12 +4614,12 @@ static void test_mdi_messages(void) /* end of test for maximized MDI children */ SetFocus(0); flush_sequence(); - trace("creating maximized visible MDI child window 1(Switch test)\n"); + if (winetest_debug > 1) trace("creating maximized visible MDI child window 1(Switch test)\n"); mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child", WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE, 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, mdi_client, 0, GetModuleHandleA(0), NULL); - assert(mdi_child); + ok(!!mdi_child, "Failed to create window, error %lu.\n", GetLastError()); ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE); ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n"); @@ -4231,12 +4633,12 @@ static void test_mdi_messages(void) ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed); flush_sequence(); - trace("creating maximized visible MDI child window 2(Switch test)\n"); + if (winetest_debug > 1) trace("creating maximized visible MDI child window 2(Switch test)\n"); mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child", WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE, 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, mdi_client, 0, GetModuleHandleA(0), NULL); - assert(mdi_child2); + ok(!!mdi_child2, "Failed to create window, error %lu.\n", GetLastError()); ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE); ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n"); @@ -4250,10 +4652,10 @@ static void test_mdi_messages(void) ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed); flush_sequence(); - trace("Switch child window.\n"); + if (winetest_debug > 1) trace("Switch child window.\n"); SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0); ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE); - trace("end of test for switch maximized MDI children\n"); + if (winetest_debug > 1) trace("end of test for switch maximized MDI children\n"); flush_sequence(); /* Prepare for switching test of not maximized MDI children */ @@ -4266,7 +4668,7 @@ static void test_mdi_messages(void) SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0); ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE); - trace("end of test for switch not maximized MDI children\n"); + if (winetest_debug > 1) trace("end of test for switch not maximized MDI children\n"); flush_sequence(); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); @@ -4317,7 +4719,7 @@ static void test_mdi_messages(void) flush_sequence(); val = GetWindowLongA(mdi_client, 0); - ok(val == 0xdeadbeef || broken(val == 0) /* >= Win Vista */, "Expected 0xdeadbeef, got 0x%x\n", val); + ok(val == 0xdeadbeef || broken(val == 0) /* >= Win Vista */, "Expected 0xdeadbeef, got 0x%lx\n", val); DestroyWindow(mdi_client); ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE); @@ -4459,29 +4861,29 @@ static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min /* do not be confused by WS_DLGFRAME set */ if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION; - if (clear) ok(style & clear, "style %08x should be set\n", clear); - if (set) ok(!(style & set), "style %08x should not be set\n", set); + if (clear) ok(style & clear, "style %08lx should be set\n", clear); + if (set) ok(!(style & set), "style %08lx should not be set\n", set); ret = SetScrollRange(hwnd, ctl, min, max, FALSE); - ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError()); + ok( ret, "SetScrollRange(%d) error %ld\n", ctl, GetLastError()); if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME)) ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE); else ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE); style = GetWindowLongA(hwnd, GWL_STYLE); - if (set) ok(style & set, "style %08x should be set\n", set); - if (clear) ok(!(style & clear), "style %08x should not be set\n", clear); + if (set) ok(style & set, "style %08lx should be set\n", set); + if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear); /* a subsequent call should do nothing */ ret = SetScrollRange(hwnd, ctl, min, max, FALSE); - ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError()); + ok( ret, "SetScrollRange(%d) error %ld\n", ctl, GetLastError()); ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE); xmin = 0xdeadbeef; xmax = 0xdeadbeef; ret = GetScrollRange(hwnd, ctl, &xmin, &xmax); - ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError()); + ok( ret, "GetScrollRange(%d) error %ld\n", ctl, GetLastError()); ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE); ok(xmin == min, "unexpected min scroll value %d\n", xmin); ok(xmax == max, "unexpected max scroll value %d\n", xmax); @@ -4498,8 +4900,8 @@ static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min /* do not be confused by WS_DLGFRAME set */ if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION; - if (clear) ok(style & clear, "style %08x should be set\n", clear); - if (set) ok(!(style & set), "style %08x should not be set\n", set); + if (clear) ok(style & clear, "style %08lx should be set\n", clear); + if (set) ok(!(style & set), "style %08lx should not be set\n", set); si.cbSize = sizeof(si); si.fMask = SIF_RANGE; @@ -4512,8 +4914,8 @@ static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE); style = GetWindowLongA(hwnd, GWL_STYLE); - if (set) ok(style & set, "style %08x should be set\n", set); - if (clear) ok(!(style & clear), "style %08x should not be set\n", clear); + if (set) ok(style & set, "style %08lx should be set\n", set); + if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear); /* a subsequent call should do nothing */ SetScrollInfo(hwnd, ctl, &si, TRUE); @@ -4538,7 +4940,7 @@ static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min si.nMin = 0xdeadbeef; si.nMax = 0xdeadbeef; ret = GetScrollInfo(hwnd, ctl, &si); - ok( ret, "GetScrollInfo error %d\n", GetLastError()); + ok( ret, "GetScrollInfo error %ld\n", GetLastError()); ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE); ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin); ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax); @@ -4557,14 +4959,14 @@ static void test_scroll_messages(HWND hwnd) min = 0xdeadbeef; max = 0xdeadbeef; ret = GetScrollRange(hwnd, SB_CTL, &min, &max); - ok( ret, "GetScrollRange error %d\n", GetLastError()); + ok( ret, "GetScrollRange error %ld\n", GetLastError()); if (sequence->message != WmGetScrollRangeSeq[0].message) trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message); /* values of min and max are undefined */ flush_sequence(); ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE); - ok( ret, "SetScrollRange error %d\n", GetLastError()); + ok( ret, "SetScrollRange error %ld\n", GetLastError()); if (sequence->message != WmSetScrollRangeSeq[0].message) trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message); flush_sequence(); @@ -4572,7 +4974,7 @@ static void test_scroll_messages(HWND hwnd) min = 0xdeadbeef; max = 0xdeadbeef; ret = GetScrollRange(hwnd, SB_CTL, &min, &max); - ok( ret, "GetScrollRange error %d\n", GetLastError()); + ok( ret, "GetScrollRange error %ld\n", GetLastError()); if (sequence->message != WmGetScrollRangeSeq[0].message) trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message); /* values of min and max are undefined */ @@ -4605,7 +5007,7 @@ static void test_scroll_messages(HWND hwnd) si.nMin = 0xdeadbeef; si.nMax = 0xdeadbeef; ret = GetScrollInfo(hwnd, SB_CTL, &si); - ok( ret, "GetScrollInfo error %d\n", GetLastError()); + ok( ret, "GetScrollInfo error %ld\n", GetLastError()); if (sequence->message != WmGetScrollInfoSeq[0].message) trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message); /* values of min and max are undefined */ @@ -4634,7 +5036,7 @@ static void test_scroll_messages(HWND hwnd) static void test_showwindow(void) { - HWND hwnd, hchild; + HWND hwnd, hwnd2, hchild; RECT rc; hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW, @@ -4646,12 +5048,12 @@ static void test_showwindow(void) flush_sequence(); /* ShowWindow( SW_SHOWNA) for invisible top level window */ - trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n"); + if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n"); ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" ); ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", FALSE); /* ShowWindow( SW_SHOWNA) for now visible top level window */ - trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n"); + if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n"); ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" ); ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE); /* back to invisible */ @@ -4659,26 +5061,26 @@ static void test_showwindow(void) ShowWindow(hwnd, SW_HIDE); flush_sequence(); /* ShowWindow(SW_SHOWNA) with child and parent invisible */ - trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n"); + if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n"); ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" ); ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE); /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */ ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" ); flush_sequence(); - trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n"); + if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n"); ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" ); ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE); /* ShowWindow(SW_SHOWNA) with child visible and parent visible */ ShowWindow( hwnd, SW_SHOW); flush_sequence(); - trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n"); + if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n"); ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" ); ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE); /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */ ShowWindow( hchild, SW_HIDE); flush_sequence(); - trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n"); + if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n"); ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" ); ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE); @@ -4696,7 +5098,7 @@ static void test_showwindow(void) * 2. Move and resize it. * 3. Show it maximized. */ - trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n"); + if (winetest_debug > 1) trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n"); hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE, 100, 100, 200, 200, 0, 0, 0, NULL); ok (hwnd != 0, "Failed to create popup window\n"); @@ -4712,7 +5114,7 @@ static void test_showwindow(void) ok(IsZoomed(hwnd), "window should be maximized\n"); flush_sequence(); - trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n"); + if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n"); ShowWindow(hwnd, SW_SHOWMAXIMIZED); ok(IsZoomed(hwnd), "window should be maximized\n"); ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE); @@ -4728,14 +5130,14 @@ static void test_showwindow(void) * 1. Create invisible maximized popup window. * 2. Show it maximized. */ - trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n"); + if (winetest_debug > 1) trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n"); hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE, 100, 100, 200, 200, 0, 0, 0, NULL); ok (hwnd != 0, "Failed to create popup window\n"); ok(IsZoomed(hwnd), "window should be maximized\n"); ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE); - trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n"); + if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n"); ShowWindow(hwnd, SW_SHOWMAXIMIZED); ok(IsZoomed(hwnd), "window should be maximized\n"); ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE); @@ -4745,7 +5147,7 @@ static void test_showwindow(void) /* Test 3: * 1. Create visible maximized popup window. */ - trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n"); + if (winetest_debug > 1) trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n"); hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE, 100, 100, 200, 200, 0, 0, 0, NULL); ok (hwnd != 0, "Failed to create popup window\n"); @@ -4758,50 +5160,85 @@ static void test_showwindow(void) * 1. Create visible popup window. * 2. Maximize it. */ - trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n"); + if (winetest_debug > 1) trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n"); hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE, 100, 100, 200, 200, 0, 0, 0, NULL); ok (hwnd != 0, "Failed to create popup window\n"); ok(!IsZoomed(hwnd), "window should NOT be maximized\n"); ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE); - trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n"); + if (winetest_debug > 1) trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n"); ShowWindow(hwnd, SW_SHOWMAXIMIZED); ok(IsZoomed(hwnd), "window should be maximized\n"); ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE); DestroyWindow(hwnd); flush_sequence(); -} -static void test_recursive_activation(void) -{ - static const struct message seq[] = - { - { HCBT_ACTIVATE, hook }, - { WM_NCACTIVATE, sent|wparam, TRUE }, - { WM_ACTIVATE, sent|wparam, WA_ACTIVE }, - { HCBT_ACTIVATE, hook }, - { WM_NCACTIVATE, sent|wparam, FALSE }, - { WM_ACTIVATE, sent|wparam, WA_INACTIVE }, - { WM_SETFOCUS, sent|optional }, - { 0 } - }; - HWND hwnd, recursive; + /* Test 5: + * 1. Restoring a minimized window. + */ + hwnd = CreateWindowA("TestWindowClass", "window1", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, 0, 0); + ok(hwnd != NULL, "Failed to create window\n"); - hwnd = CreateWindowExA(0, "SimpleWindowClass", NULL, WS_OVERLAPPED|WS_VISIBLE, - 100, 100, 200, 200, 0, 0, 0, NULL); - ok(hwnd != 0, "Failed to create simple window\n"); - - recursive = CreateWindowExA(0, "RecursiveActivationClass", NULL, WS_OVERLAPPED|WS_VISIBLE, - 10, 10, 50, 50, hwnd, 0, 0, NULL); - ok(recursive != 0, "Failed to create recursive activation window\n"); - SetActiveWindow(hwnd); + hwnd2 = CreateWindowA("static", "window2", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, 0, 0); + ok(hwnd2 != NULL, "Failed to create window\n"); + ShowWindow(hwnd, SW_MINIMIZE); + SetActiveWindow(hwnd2); + ok(GetActiveWindow() == hwnd2, "Unexpected active window\n"); + flush_events(); flush_sequence(); - SetActiveWindow(recursive); - ok_sequence(seq, "Recursive Activation", FALSE); + ShowWindow(hwnd, SW_RESTORE); + flush_events(); + ok_sequence(WmShowRestoreMinimizedOverlappedSeq, + "ShowWindow(hwnd, SW_RESTORE): minimized overlapped", TRUE); + + ShowWindow(hwnd, SW_MINIMIZE); + SetActiveWindow(hwnd2); + ok(GetActiveWindow() == hwnd2, "Unexpected active window\n"); + flush_events(); + flush_sequence(); + ShowWindow(hwnd, SW_SHOWNOACTIVATE); + flush_events(); +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) +#endif + ok_sequence(WmShowNoActivateMinimizedOverlappedSeq, + "ShowWindow(hwnd, SW_SHOWNOACTIVATE): minimized overlapped", TRUE); + + DestroyWindow(hwnd2); + DestroyWindow(hwnd); + flush_sequence(); + + /* Test 6: + * 1. Restoring a minimized but active window. + */ + hwnd = CreateWindowA("TestWindowClass", "parent", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, 0, 0); + ok(hwnd != NULL, "Failed to create window\n"); + + ShowWindow(hwnd, SW_MINIMIZE); + SetActiveWindow(hwnd); + ok(GetActiveWindow() == hwnd, "Unexpected active window\n"); + flush_events(); + flush_sequence(); + ShowWindow(hwnd, SW_RESTORE); + flush_events(); + ok_sequence(WmShowRestoreActiveMinimizedOverlappedSeq, + "ShowWindow(hwnd, SW_RESTORE): active minimized overlapped", TRUE); + + ShowWindow(hwnd, SW_MINIMIZE); + SetActiveWindow(hwnd); + ok(GetActiveWindow() == hwnd, "Unexpected active window\n"); + flush_events(); + flush_sequence(); + ShowWindow(hwnd, SW_SHOWNOACTIVATE); + flush_events(); +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) +#endif + ok_sequence(WmShowNoActivateActiveMinimizedOverlappedSeq, + "ShowWindow(hwnd, SW_SHOWNOACTIVATE): active minimized overlapped", TRUE); - DestroyWindow(recursive); DestroyWindow(hwnd); flush_sequence(); } @@ -4820,7 +5257,7 @@ static void test_sys_menu(void) /* test existing window without CS_NOCLOSE style */ hmenu = GetSystemMenu(hwnd, FALSE); - ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError()); + ok(hmenu != 0, "GetSystemMenu error %ld\n", GetLastError()); state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND); ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state); @@ -4845,7 +5282,7 @@ static void test_sys_menu(void) SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED); flush_sequence(); hmenu = GetSystemMenu(hwnd, FALSE); - ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError()); + ok(hmenu != 0, "GetSystemMenu error %ld\n", GetLastError()); DestroyWindow(hwnd); @@ -4855,7 +5292,7 @@ static void test_sys_menu(void) ok (hwnd != 0, "Failed to create overlapped window\n"); hmenu = GetSystemMenu(hwnd, FALSE); - ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError()); + ok(hmenu != 0, "GetSystemMenu error %ld\n", GetLastError()); state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND); ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state); @@ -4868,7 +5305,7 @@ static void test_sys_menu(void) ok(hwnd != 0, "Failed to create overlapped window\n"); hmenu = GetSystemMenu(hwnd, FALSE); - ok(!hmenu, "GetSystemMenu error %d\n", GetLastError()); + ok(!hmenu, "GetSystemMenu error %ld\n", GetLastError()); DestroyWindow(hwnd); } @@ -4935,6 +5372,7 @@ static const struct message WmZOrder[] = { { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 }, { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 }, { HCBT_ACTIVATE, hook }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 }, { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 }, @@ -4948,10 +5386,12 @@ static const struct message WmZOrder[] = { { HCBT_SETFOCUS, hook }, { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|wparam|defwinproc, 0 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { WM_GETTEXT, sent|optional }, { WM_NCCALCSIZE, sent|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends it, but Win8+ doesn't. */ { 0 } }; @@ -4966,36 +5406,36 @@ static void test_MsgWaitForMultipleObjects(HWND hwnd) MSG msg; ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE); - ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret); + ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %lx\n", ret); PostMessageA(hwnd, WM_USER, 0, 0); ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE); - ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret); + ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %lx\n", ret); ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n"); ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message); ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE); - ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret); + ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %lx\n", ret); PostMessageA(hwnd, WM_USER, 0, 0); ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE); - ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret); + ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %lx\n", ret); ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n"); ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message); /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */ ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE); - ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret); + ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %lx\n", ret); PostMessageA(hwnd, WM_USER, 0, 0); /* new incoming message causes it to become signaled again */ ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE); - ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret); + ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %lx\n", ret); ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n"); ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message); @@ -5008,30 +5448,30 @@ static void test_MsgWaitForMultipleObjects(HWND hwnd) ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message); ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_INPUTAVAILABLE ); - ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %x\n", ret); + ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %lx\n", ret); ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n"); ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message); /* without MWMO_ALERTABLE the result is never WAIT_IO_COMPLETION */ ret = QueueUserAPC( apc_test_proc, GetCurrentThread(), 0 ); - ok(ret, "QueueUserAPC failed %u\n", GetLastError()); + ok(ret, "QueueUserAPC failed %lu\n", GetLastError()); ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, 0 ); - ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjectsEx returned %x\n", ret); + ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjectsEx returned %lx\n", ret); /* but even with MWMO_ALERTABLE window events are preferred */ PostMessageA( hwnd, WM_USER, 0, 0 ); ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE ); - ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %x\n", ret); + ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %lx\n", ret); ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n"); ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message); /* the APC call is still queued */ ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE ); - ok(ret == WAIT_IO_COMPLETION, "MsgWaitForMultipleObjectsEx returned %x\n", ret); + ok(ret == WAIT_IO_COMPLETION, "MsgWaitForMultipleObjectsEx returned %lx\n", ret); } static void test_WM_DEVICECHANGE(HWND hwnd) @@ -5061,13 +5501,13 @@ static void test_WM_DEVICECHANGE(HWND hwnd) ret = PostMessageA(hwnd, WM_DEVICECHANGE, wparams[i], 0); if (wparams[i] & 0x8000) { - ok(ret == FALSE, "PostMessage should returned %d\n", ret); - ok(GetLastError() == ERROR_MESSAGE_SYNC_ONLY, "PostMessage error %08x\n", GetLastError()); + ok(ret == FALSE, "PostMessage returned %ld\n", ret); + ok(GetLastError() == ERROR_MESSAGE_SYNC_ONLY, "PostMessage error %08lx\n", GetLastError()); } else { ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE); - ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret); + ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %lx\n", ret); memset(&msg, 0, sizeof(msg)); ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should succeed\n"); ok(msg.message == WM_DEVICECHANGE, "got %04x instead of WM_DEVICECHANGE\n", msg.message); @@ -5075,7 +5515,7 @@ static void test_WM_DEVICECHANGE(HWND hwnd) } } -static DWORD CALLBACK show_window_thread(LPVOID arg) +static DWORD CALLBACK hide_window_thread( LPVOID arg ) { HWND hwnd = arg; @@ -5085,6 +5525,16 @@ static DWORD CALLBACK show_window_thread(LPVOID arg) return 0; } +static DWORD CALLBACK show_window_thread( LPVOID arg ) +{ + HWND hwnd = arg; + + /* function will not return if ShowWindow(SW_SHOW) calls SendMessage() */ + ok( ShowWindow( hwnd, SW_SHOW ), "ShowWindow(SW_SHOW) expected TRUE\n" ); /* actually it's 24... */ + + return 0; +} + /* Helper function to easier test SetWindowPos messages */ #define test_msg_setpos( expected_list, flags, todo ) \ test_msg_setpos_( (expected_list), (flags), (todo), __FILE__, __LINE__) @@ -5146,8 +5596,8 @@ static void test_messages(void) ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE); /* test ShowWindow(SW_HIDE) on a hidden window - multi-threaded */ - hthread = CreateThread(NULL, 0, show_window_thread, hwnd, 0, &tid); - ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError()); + hthread = CreateThread( NULL, 0, hide_window_thread, hwnd, 0, &tid ); + ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError()); ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); CloseHandle(hthread); flush_events(); @@ -5157,6 +5607,14 @@ static void test_messages(void) flush_events(); ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE); + /* test ShowWindow(SW_SHOW) on a visible window - multi-threaded */ + hthread = CreateThread( NULL, 0, show_window_thread, hwnd, 0, &tid ); + ok( hthread != NULL, "CreateThread failed, error %ld\n", GetLastError() ); + ok( WaitForSingleObject( hthread, INFINITE ) == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); + CloseHandle( hthread ); + flush_events(); + ok_sequence( WmEmptySeq, "ShowWindow(SW_SHOW):overlapped", FALSE ); + ShowWindow(hwnd, SW_HIDE); flush_events(); ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE); @@ -5183,7 +5641,7 @@ static void test_messages(void) { ShowWindow(hwnd, SW_RESTORE); flush_events(); - ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE); + ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", FALSE); flush_sequence(); } @@ -5201,7 +5659,7 @@ static void test_messages(void) flush_events(); test_WM_SETREDRAW(hwnd); - trace("testing scroll APIs on a visible top level window %p\n", hwnd); + if (winetest_debug > 1) trace("testing scroll APIs on a visible top level window %p\n", hwnd); test_scroll_messages(hwnd); /* test resizing and moving */ @@ -5265,7 +5723,7 @@ static void test_messages(void) /* Test SetWindowPos */ test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW, FALSE); test_msg_setpos(WmFirstDrawSetWindowPosSeq2, 0, FALSE); - test_msg_setpos(WmFirstDrawSetWindowPosSeq3, + test_msg_setpos(WmFirstDrawSetWindowPosSeq6, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER, FALSE); test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOSIZE, FALSE); @@ -5355,9 +5813,12 @@ static void test_messages(void) WS_CHILD | WS_VISIBLE | WS_CAPTION, 0, 0, 10, 10, hparent, 0, 0, NULL); ok (hchild != 0, "Failed to create child window\n"); +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_WINBLUE) +#endif ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE); - trace("testing scroll APIs on a visible child window %p\n", hchild); + if (winetest_debug > 1) trace("testing scroll APIs on a visible child window %p\n", hchild); test_scroll_messages(hchild); SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE); @@ -5370,7 +5831,7 @@ static void test_messages(void) 0, 0, 10, 10, hparent, 0, 0, NULL); ok (hchild != 0, "Failed to create child window\n"); ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE); - + hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD, 100, 100, 50, 50, hparent, 0, 0, NULL); ok (hchild2 != 0, "Failed to create child2 window\n"); @@ -5479,7 +5940,7 @@ static void test_messages(void) ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE); if(0) { - trace("testing scroll APIs on a visible dialog %p\n", hwnd); + if (winetest_debug > 1) trace("testing scroll APIs on a visible dialog %p\n", hwnd); test_scroll_messages(hwnd); } @@ -5504,14 +5965,14 @@ static void test_messages(void) 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL); ok(hwnd != 0, "Failed to create custom dialog window\n"); flush_sequence(); - trace("call ShowWindow(%p, SW_SHOW)\n", hwnd); + if (winetest_debug > 1) trace("call ShowWindow(%p, SW_SHOW)\n", hwnd); ShowWindow(hwnd, SW_SHOW); ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE); flush_events(); flush_sequence(); ret = DrawMenuBar(hwnd); - ok(ret, "DrawMenuBar failed: %d\n", GetLastError()); + ok(ret, "DrawMenuBar failed: %ld\n", GetLastError()); flush_events(); ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE); ok(SetCursorPos(pos.x, pos.y), "SetCursorPos failed\n"); @@ -5524,7 +5985,7 @@ static void test_messages(void) flush_events(); flush_sequence(); ret = DrawMenuBar(hwnd); - ok(ret, "DrawMenuBar failed: %d\n", GetLastError()); + ok(ret, "DrawMenuBar failed: %ld\n", GetLastError()); flush_events(); ok_sequence(WmEmptySeq, "DrawMenuBar for a child window", FALSE); @@ -5539,7 +6000,7 @@ static void test_messages(void) /* Message sequence for SetMenu */ ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a destroyed window\n"); - ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "last error is %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "last error is %ld\n", GetLastError()); ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE); hmenu = CreateMenu(); @@ -5614,7 +6075,7 @@ static void test_messages(void) ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" ); ok( GetLastError() == ERROR_NOACCESS || /* Win2k */ GetLastError() == 0xdeadbeef, /* NT4 */ - "last error is %d\n", GetLastError() ); + "last error is %ld\n", GetLastError() ); ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" ); ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message ); @@ -5623,7 +6084,7 @@ static void test_messages(void) flush_sequence(); /* Message sequences for WM_SETICON */ - trace("testing WM_SETICON\n"); + if (winetest_debug > 1) trace("testing WM_SETICON\n"); hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0, NULL, NULL, 0); @@ -5666,61 +6127,162 @@ static void test_messages(void) goto done; } ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE); - ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res); + ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %Id\n", res); res = SendMessageA(hwnd, 0x3B, 0x0000000b, 0); ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE); - ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res); + ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %Id\n", res); res = SendMessageA(hwnd, 0x3B, 0x0000000f, 0); ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE); - ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res); + ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %Id\n", res); flush_sequence(); res = SendMessageA(hwnd, 0x3B, 0x80000008, 0); ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE); - ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res); + ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %Id\n", res); res = SendMessageA(hwnd, 0x3B, 0x00000008, 0); ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE); - ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res); + ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %Id\n", res); res = SendMessageA(hwnd, 0x3B, 0x80000004, 0); ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE); - ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res); + ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %Id\n", res); res = SendMessageA(hwnd, 0x3B, 0x80000001, 0); ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE); - ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res); + ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %Id\n", res); done: DestroyWindow(hwnd); flush_sequence(); } +static const struct message WmFrameChanged[] = { + { WM_WINDOWPOSCHANGING, sent|wparam|lparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE, 0 }, + { WM_NCCALCSIZE, sent|wparam|lparam, 1, 0xf }, + { WM_WINDOWPOSCHANGED, sent|wparam|lparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW + |SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0xf }, + { WM_GETTEXT, sent|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ + { 0 } +}; + +static const struct message WmFrameChanged_move[] = { + { WM_WINDOWPOSCHANGING, sent|wparam|lparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE, 0 }, + { WM_NCCALCSIZE, sent|wparam|lparam, 1, 0x3 }, + { WM_WINDOWPOSCHANGED, sent|wparam|lparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW + |SWP_NOSIZE|SWP_NOCLIENTSIZE, 0x3 }, + { WM_MOVE, sent|defwinproc, 0 }, + { WM_GETTEXT, sent|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ + { 0 } +}; + +static const struct message WmMove_mouse[] = { + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE }, + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE }, + { WM_MOVE, sent|defwinproc, 0 }, + { WM_GETTEXT, sent|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ + { WM_SETCURSOR, sent|lparam, 0, HTCLIENT | (WM_MOUSEMOVE << 16) }, + { WM_MOUSEMOVE, sent }, + /* WM_MOUSEMOVE with accompanying WM_SETCURSOR may sometimes appear a few extra times on Windows 7 with the + * same parameters. */ + { WM_SETCURSOR, sent|lparam|optional, 0, HTCLIENT | (WM_MOUSEMOVE << 16) }, + { WM_MOUSEMOVE, sent|optional }, + { WM_SETCURSOR, sent|lparam|optional, 0, HTCLIENT | (WM_MOUSEMOVE << 16) }, + { WM_MOUSEMOVE, sent|optional }, + { WM_SETCURSOR, sent|lparam|optional, 0, HTCLIENT | (WM_MOUSEMOVE << 16) }, + { WM_MOUSEMOVE, sent|optional }, + { WM_SETCURSOR, sent|lparam|optional, 0, HTCLIENT | (WM_MOUSEMOVE << 16) }, + { WM_MOUSEMOVE, sent|optional }, + { WM_SETCURSOR, sent|lparam|optional, 0, HTCLIENT | (WM_MOUSEMOVE << 16) }, + { WM_MOUSEMOVE, sent|optional }, + { 0 } +}; + +static const struct message WmMove_mouse2[] = { + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE }, + { WM_GETTEXT, sent|optional }, + { WM_GETMINMAXINFO, sent|defwinproc }, + { 0 } +}; + static void test_setwindowpos(void) { HWND hwnd; RECT rc; LRESULT res; + const INT X = 50; + const INT Y = 50; const INT winX = 100; const INT winY = 100; const INT sysX = GetSystemMetrics(SM_CXMINTRACK); hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0, - 0, 0, winX, winY, 0, + X, Y, winX, winY, 0, NULL, NULL, 0); GetWindowRect(hwnd, &rc); - expect(sysX, rc.right); - expect(winY, rc.bottom); + expect(sysX + X, rc.right); + expect(winY + Y, rc.bottom); flush_events(); flush_sequence(); - res = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, winX, winY, 0); + res = SetWindowPos(hwnd, HWND_TOPMOST, 50, 50, winX, winY, 0); ok_sequence(WmZOrder, "Z-Order", TRUE); - ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res); + ok(res == TRUE, "SetWindowPos expected TRUE, got %Id\n", res); + + GetWindowRect(hwnd, &rc); + expect(sysX + X, rc.right); + expect(winY + Y, rc.bottom); + + res = SetWindowPos( hwnd, 0, 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); + ok_sequence(WmFrameChanged, "FrameChanged", FALSE); + ok(res == TRUE, "SetWindowPos expected TRUE, got %Id.\n", res); + + GetWindowRect(hwnd, &rc); + expect(sysX + X, rc.right); + expect(winY + Y, rc.bottom); + + GetWindowRect(hwnd, &rc); + res = SetWindowPos( hwnd, 0, 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); + ok_sequence(WmFrameChanged_move, "FrameChanged", FALSE); + ok(res == TRUE, "SetWindowPos expected TRUE, got %Id.\n", res); GetWindowRect(hwnd, &rc); expect(sysX, rc.right); expect(winY, rc.bottom); + + /* get away from possible menu bar to avoid spurious position changed induced by WM. */ + res = SetWindowPos( hwnd, HWND_TOPMOST, 200, 200, 200, 200, SWP_SHOWWINDOW ); + ok(res == TRUE, "SetWindowPos expected TRUE, got %Id.\n", res); + SetForegroundWindow( hwnd ); + SetActiveWindow( hwnd ); + flush_events(); + pump_msg_loop( hwnd, 0 ); + flush_sequence(); + GetWindowRect( hwnd, &rc ); + SetCursorPos( rc.left + 100, rc.top + 100 ); + flush_events(); + pump_msg_loop( hwnd, 0 ); + flush_sequence(); + ignore_mouse_messages = FALSE; + res = SetWindowPos( hwnd, 0, 205, 205, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE ); + ok(res == TRUE, "SetWindowPos expected TRUE, got %Id.\n", res); + flush_events(); + ok_sequence(WmMove_mouse, "MouseMove", FALSE); + /* if the window and client rects were not changed WM_MOUSEMOVE is not sent. */ + res = SetWindowPos( hwnd, 0, 205, 205, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE ); + ok(res == TRUE, "SetWindowPos expected TRUE, got %Id.\n", res); + flush_events(); + ok_sequence(WmMove_mouse2, "MouseMove2", FALSE); + ignore_mouse_messages = TRUE; + DestroyWindow(hwnd); } @@ -5907,7 +6469,7 @@ static const struct message WmSetFocusButtonSeq[] = static const struct message WmKillFocusButtonSeq[] = { { HCBT_SETFOCUS, hook }, - { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { WM_KILLFOCUS, sent|wparam, 0 }, { WM_CTLCOLORBTN, sent|parent }, { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) }, @@ -5934,7 +6496,7 @@ static const struct message WmSetFocusStaticSeq[] = static const struct message WmKillFocusStaticSeq[] = { { HCBT_SETFOCUS, hook }, - { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { WM_KILLFOCUS, sent|wparam, 0 }, { WM_CTLCOLORSTATIC, sent|parent }, { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) }, @@ -5961,7 +6523,7 @@ static const struct message WmSetFocusOwnerdrawSeq[] = static const struct message WmKillFocusOwnerdrawSeq[] = { { HCBT_SETFOCUS, hook }, - { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { WM_KILLFOCUS, sent|wparam, 0 }, { WM_CTLCOLORBTN, sent|parent }, { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000040e4 }, @@ -6030,9 +6592,12 @@ static const struct message WmLButtonUpAutoSeq[] = { BM_SETSTATE, sent|wparam|defwinproc, FALSE }, { WM_CTLCOLORSTATIC, sent|defwinproc }, { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, - { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|optional, 0, 0 }, { BM_SETCHECK, sent|defwinproc }, - { WM_CTLCOLORSTATIC, sent|defwinproc, 0, 0 }, + { WM_CTLCOLORSTATIC, sent|defwinproc|optional, 0, 0 }, /* Sent here on Win7. */ + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 }, + { WM_CTLCOLORSTATIC, sent|defwinproc|optional, 0, 0 }, /* Sent here on Win8+. */ { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 }, { 0 } }; @@ -6047,7 +6612,15 @@ static const struct message WmSetFontButtonSeq[] = { WM_PAINT, sent }, { WM_ERASEBKGND, sent|defwinproc|optional }, { WM_CTLCOLORBTN, sent|defwinproc }, - { WM_CTLCOLORBTN, sent|defwinproc|optional }, /* FIXME: Wine sends it twice for BS_OWNERDRAW */ + { 0 } +}; +static const struct message WmSetFontOwnerdrawSeq[] = +{ + { WM_SETFONT, sent }, + { WM_PAINT, sent }, + { WM_ERASEBKGND, sent|defwinproc|optional }, + { WM_CTLCOLORBTN, sent|defwinproc }, + { WM_CTLCOLORBTN, sent|defwinproc|wine_only }, /* FIXME: Wine sends it twice for BS_OWNERDRAW */ { 0 } }; static const struct message WmSetFontStaticSeq[] = @@ -6061,6 +6634,7 @@ static const struct message WmSetFontStaticSeq[] = static const struct message WmSetTextButtonSeq[] = { { WM_SETTEXT, sent }, + { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_CTLCOLORBTN, sent|parent }, { WM_CTLCOLORBTN, sent|parent }, { WM_COMMAND, sent|parent|optional }, @@ -6070,6 +6644,7 @@ static const struct message WmSetTextButtonSeq[] = static const struct message WmSetTextStaticSeq[] = { { WM_SETTEXT, sent }, + { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_CTLCOLORSTATIC, sent|parent }, { WM_CTLCOLORSTATIC, sent|parent }, { 0 } @@ -6078,21 +6653,23 @@ static const struct message WmSetTextGroupSeq[] = { { WM_SETTEXT, sent }, { WM_CTLCOLORSTATIC, sent|parent }, - { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */ - { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */ + { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { WM_CTLCOLORSTATIC, sent|parent|msg_todo }, /* FIXME: Missing in Wine */ + { WM_CTLCOLORSTATIC, sent|parent|msg_todo }, /* FIXME: Missing in Wine */ { 0 } }; static const struct message WmSetTextInvisibleSeq[] = { { WM_SETTEXT, sent }, + { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { 0 } }; static const struct message WmSetStyleButtonSeq[] = { { BM_SETSTYLE, sent }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_APP, sent|wparam|lparam, 0, 0 }, { WM_PAINT, sent }, - { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */ { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */ { WM_CTLCOLORBTN, sent|parent }, { 0 } @@ -6100,9 +6677,9 @@ static const struct message WmSetStyleButtonSeq[] = static const struct message WmSetStyleStaticSeq[] = { { BM_SETSTYLE, sent }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_APP, sent|wparam|lparam, 0, 0 }, { WM_PAINT, sent }, - { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */ { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */ { WM_CTLCOLORSTATIC, sent|parent }, { 0 } @@ -6110,9 +6687,10 @@ static const struct message WmSetStyleStaticSeq[] = static const struct message WmSetStyleUserSeq[] = { { BM_SETSTYLE, sent }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_APP, sent|wparam|lparam, 0, 0 }, { WM_PAINT, sent }, - { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */ + { WM_NCPAINT, sent|defwinproc|wine_only }, /* FIXME: Wine sends it */ { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */ { WM_CTLCOLORBTN, sent|parent }, { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_PAINT) }, @@ -6121,9 +6699,9 @@ static const struct message WmSetStyleUserSeq[] = static const struct message WmSetStyleOwnerdrawSeq[] = { { BM_SETSTYLE, sent }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_APP, sent|wparam|lparam, 0, 0 }, { WM_PAINT, sent }, - { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */ { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */ { WM_CTLCOLORBTN, sent|parent }, { WM_CTLCOLORBTN, sent|parent|optional }, /* Win9x doesn't send it */ @@ -6134,6 +6712,7 @@ static const struct message WmSetStateButtonSeq[] = { { BM_SETSTATE, sent }, { WM_CTLCOLORBTN, sent|parent }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_APP, sent|wparam|lparam, 0, 0 }, { 0 } }; @@ -6141,6 +6720,7 @@ static const struct message WmSetStateStaticSeq[] = { { BM_SETSTATE, sent }, { WM_CTLCOLORSTATIC, sent|parent }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_APP, sent|wparam|lparam, 0, 0 }, { 0 } }; @@ -6149,6 +6729,7 @@ static const struct message WmSetStateUserSeq[] = { BM_SETSTATE, sent }, { WM_CTLCOLORBTN, sent|parent }, { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_HILITE) }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_APP, sent|wparam|lparam, 0, 0 }, { 0 } }; @@ -6157,6 +6738,7 @@ static const struct message WmSetStateOwnerdrawSeq[] = { BM_SETSTATE, sent }, { WM_CTLCOLORBTN, sent|parent }, { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000120e4 }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_APP, sent|wparam|lparam, 0, 0 }, { 0 } }; @@ -6165,21 +6747,26 @@ static const struct message WmClearStateButtonSeq[] = { BM_SETSTATE, sent }, { WM_CTLCOLORBTN, sent|parent }, { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_UNHILITE) }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_APP, sent|wparam|lparam, 0, 0 }, { 0 } }; static const struct message WmDisableButtonSeq[] = { { WM_LBUTTONDOWN, sent }, + { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, { BM_SETSTATE, sent|defwinproc }, { WM_CTLCOLORSTATIC, sent|defwinproc|optional }, { WM_CTLCOLORBTN, sent|optional }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_LBUTTONUP, sent }, { BM_SETSTATE, sent|defwinproc }, { WM_CTLCOLORBTN, sent|defwinproc|optional }, { WM_CTLCOLORSTATIC, sent|defwinproc|optional }, { BM_SETCHECK, sent|defwinproc|optional }, { WM_CTLCOLORBTN, sent|optional }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 }, { WM_CTLCOLORSTATIC, sent|defwinproc|optional }, { WM_CAPTURECHANGED, sent|defwinproc }, { WM_COMMAND, sent }, @@ -6190,6 +6777,7 @@ static const struct message WmClearStateOwnerdrawSeq[] = { BM_SETSTATE, sent }, { WM_CTLCOLORBTN, sent|parent }, { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000020e4 }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_APP, sent|wparam|lparam, 0, 0 }, { 0 } }; @@ -6203,6 +6791,7 @@ static const struct message WmSetCheckStaticSeq[] = { { BM_SETCHECK, sent }, { WM_CTLCOLORSTATIC, sent|parent }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, { WM_APP, sent|wparam|lparam, 0, 0 }, { 0 } }; @@ -6263,8 +6852,10 @@ log_it: static void subclass_button(void) { WNDCLASSA cls; + BOOL ret; - if (!GetClassInfoA(0, "button", &cls)) assert(0); + ret = GetClassInfoA(0, "button", &cls); + ok(ret, "Failed to get class info, error %lu.\n", GetLastError()); old_button_proc = cls.lpfnWndProc; @@ -6272,7 +6863,7 @@ static void subclass_button(void) cls.lpfnWndProc = button_hook_proc; cls.lpszClassName = "my_button_class"; UnregisterClassA(cls.lpszClassName, cls.hInstance); - if (!RegisterClassA(&cls)) assert(0); + register_class(&cls); } static void test_button_messages(void) @@ -6345,7 +6936,7 @@ static void test_button_messages(void) { BS_OWNERDRAW, DLGC_BUTTON, WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq, WmSetStyleOwnerdrawSeq, WmSetStateOwnerdrawSeq, WmClearStateOwnerdrawSeq, WmSetCheckIgnoredSeq, - WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq, + WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontOwnerdrawSeq, WmSetTextButtonSeq }, }; LOGFONTA logfont = { 0 }; @@ -6387,7 +6978,7 @@ static void test_button_messages(void) char desc[64]; HDC hdc; - trace("button style %08x\n", button[i].style); + if (winetest_debug > 1) trace("button style %08lx\n", button[i].style); hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_CHILD | BS_NOTIFY, 0, 0, 50, 14, parent, (HMENU)ID_BUTTON, 0, NULL); @@ -6397,12 +6988,12 @@ static void test_button_messages(void) style &= ~(WS_CHILD | BS_NOTIFY); /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */ if (button[i].style == BS_USERBUTTON) - ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %x\n", style); + ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %lx\n", style); else - ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style); + ok(style == button[i].style, "expected style %lx got %lx\n", button[i].style, style); dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0); - ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code); + ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08lx\n", i, dlg_code); ShowWindow(hwnd, SW_SHOW); UpdateWindow(hwnd); @@ -6434,10 +7025,10 @@ static void test_button_messages(void) style = GetWindowLongA(hwnd, GWL_STYLE); style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY); /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */ - ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style); + ok(style == button[i].style, "expected style %04lx got %04lx\n", button[i].style, style); state = SendMessageA(hwnd, BM_GETSTATE, 0, 0); - ok(state == 0, "expected state 0, got %04x\n", state); + ok(state == 0, "expected state 0, got %04lx\n", state); flush_sequence(); @@ -6447,11 +7038,11 @@ static void test_button_messages(void) ok_sequence(button[i].setstate, "BM_SETSTATE/TRUE on a button", FALSE); state = SendMessageA(hwnd, BM_GETSTATE, 0, 0); - ok(state == 0x0004, "expected state 0x0004, got %04x\n", state); + ok(state == 0x0004, "expected state 0x0004, got %04lx\n", state); style = GetWindowLongA(hwnd, GWL_STYLE); style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE); - ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style); + ok(style == button[i].style, "expected style %04lx got %04lx\n", button[i].style, style); flush_sequence(); @@ -6461,14 +7052,14 @@ static void test_button_messages(void) ok_sequence(button[i].clearstate, "BM_SETSTATE/FALSE on a button", FALSE); state = SendMessageA(hwnd, BM_GETSTATE, 0, 0); - ok(state == 0, "expected state 0, got %04x\n", state); + ok(state == 0, "expected state 0, got %04lx\n", state); style = GetWindowLongA(hwnd, GWL_STYLE); style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE); - ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style); + ok(style == button[i].style, "expected style %04lx got %04lx\n", button[i].style, style); state = SendMessageA(hwnd, BM_GETCHECK, 0, 0); - ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state); + ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04lx\n", state); flush_sequence(); @@ -6478,11 +7069,11 @@ static void test_button_messages(void) ok_sequence(WmSetCheckIgnoredSeq, "BM_SETCHECK on a button", FALSE); state = SendMessageA(hwnd, BM_GETCHECK, 0, 0); - ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state); + ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04lx\n", state); style = GetWindowLongA(hwnd, GWL_STYLE); style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE); - ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style); + ok(style == button[i].style, "expected style %04lx got %04lx\n", button[i].style, style); flush_sequence(); @@ -6521,17 +7112,17 @@ static void test_button_messages(void) button[i].style == BS_GROUPBOX || button[i].style == BS_USERBUTTON || button[i].style == BS_OWNERDRAW) - ok(state == BST_UNCHECKED, "expected check 0, got %04x\n", state); + ok(state == BST_UNCHECKED, "expected check 0, got %04lx\n", state); else - ok(state == BST_CHECKED, "expected check 1, got %04x\n", state); + ok(state == BST_CHECKED, "expected check 1, got %04lx\n", state); style = GetWindowLongA(hwnd, GWL_STYLE); style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE); if (button[i].style == BS_RADIOBUTTON || button[i].style == BS_AUTORADIOBUTTON) - ok(style == (button[i].style | WS_TABSTOP), "expected style %04x | WS_TABSTOP got %04x\n", button[i].style, style); + ok(style == (button[i].style | WS_TABSTOP), "expected style %04lx | WS_TABSTOP got %04lx\n", button[i].style, style); else - ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style); + ok(style == button[i].style, "expected style %04lx got %04lx\n", button[i].style, style); log_all_parent_messages--; @@ -6754,9 +7345,9 @@ static const struct message auto_radio_button_BM_CLICK[] = { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 }, { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 }, { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO2, BN_CLICKED) }, - { WM_NCHITTEST, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */ - { WM_SETCURSOR, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */ - { WM_MOUSEMOVE, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */ + { WM_NCHITTEST, sent|optional, 0, 0 }, + { WM_SETCURSOR, sent|optional, 0, 0 }, + { WM_MOUSEMOVE, sent|optional, 0, 0 }, { 0 } }; @@ -6833,33 +7424,33 @@ static const struct message auto_radio_button_VK_DOWN_dialog[] = { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 }, { BM_CLICK, sent|wparam|lparam, 1, 0 }, { WM_LBUTTONDOWN, sent|wparam|lparam|defwinproc, 0, 0 }, - { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 }, { WM_CTLCOLORSTATIC, sent|parent }, - { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { WM_LBUTTONUP, sent|wparam|lparam|defwinproc, 0, 0 }, { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO1 }, { WM_CTLCOLORSTATIC, sent|parent }, - { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO1, 0 }, { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 }, { WM_CTLCOLORSTATIC, sent|parent }, - { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO3, 0 }, { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO3 }, { WM_CTLCOLORSTATIC, sent|parent }, - { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_TEXT, 0 }, { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO2, 0 }, { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO2 }, { WM_CTLCOLORSTATIC, sent|parent }, - { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, - { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, + { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 }, { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_CLICKED) }, - { WM_NCHITTEST, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */ - { WM_SETCURSOR, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */ - { WM_MOUSEMOVE, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */ + { WM_NCHITTEST, sent|optional, 0, 0 }, + { WM_SETCURSOR, sent|optional, 0, 0 }, + { WM_MOUSEMOVE, sent|optional, 0, 0 }, { WM_PAINT, sent }, { WM_CTLCOLORSTATIC, sent|parent }, { 0 } @@ -6915,38 +7506,38 @@ static void test_autoradio_BM_CLICK(void) flush_sequence(); ret = SendMessageA(radio1, BM_GETCHECK, 0, 0); - ok(ret == BST_UNCHECKED, "got %08x\n", ret); + ok(ret == BST_UNCHECKED, "got %08lx\n", ret); ret = SendMessageA(radio2, BM_GETCHECK, 0, 0); - ok(ret == BST_UNCHECKED, "got %08x\n", ret); + ok(ret == BST_UNCHECKED, "got %08lx\n", ret); ret = SendMessageA(radio3, BM_GETCHECK, 0, 0); - ok(ret == BST_UNCHECKED, "got %08x\n", ret); + ok(ret == BST_UNCHECKED, "got %08lx\n", ret); SendMessageA(radio1, BM_SETCHECK, BST_CHECKED, 0); ret = SendMessageA(radio1, BM_GETCHECK, 0, 0); - ok(ret == BST_CHECKED, "got %08x\n", ret); + ok(ret == BST_CHECKED, "got %08lx\n", ret); ret = SendMessageA(radio2, BM_GETCHECK, 0, 0); - ok(ret == BST_UNCHECKED, "got %08x\n", ret); + ok(ret == BST_UNCHECKED, "got %08lx\n", ret); ret = SendMessageA(radio3, BM_GETCHECK, 0, 0); - ok(ret == BST_UNCHECKED, "got %08x\n", ret); + ok(ret == BST_UNCHECKED, "got %08lx\n", ret); SendMessageA(radio2, BM_SETCHECK, BST_CHECKED, 0); ret = SendMessageA(radio1, BM_GETCHECK, 0, 0); - ok(ret == BST_CHECKED, "got %08x\n", ret); + ok(ret == BST_CHECKED, "got %08lx\n", ret); ret = SendMessageA(radio2, BM_GETCHECK, 0, 0); - ok(ret == BST_CHECKED, "got %08x\n", ret); + ok(ret == BST_CHECKED, "got %08lx\n", ret); ret = SendMessageA(radio3, BM_GETCHECK, 0, 0); - ok(ret == BST_UNCHECKED, "got %08x\n", ret); + ok(ret == BST_UNCHECKED, "got %08lx\n", ret); SendMessageA(radio3, BM_SETCHECK, BST_CHECKED, 0); ret = SendMessageA(radio1, BM_GETCHECK, 0, 0); - ok(ret == BST_CHECKED, "got %08x\n", ret); + ok(ret == BST_CHECKED, "got %08lx\n", ret); ret = SendMessageA(radio2, BM_GETCHECK, 0, 0); - ok(ret == BST_CHECKED, "got %08x\n", ret); + ok(ret == BST_CHECKED, "got %08lx\n", ret); ret = SendMessageA(radio3, BM_GETCHECK, 0, 0); - ok(ret == BST_CHECKED, "got %08x\n", ret); + ok(ret == BST_CHECKED, "got %08lx\n", ret); GetWindowRect(radio2, &rc); SetCursorPos(rc.left+1, rc.top+1); @@ -6963,11 +7554,11 @@ static void test_autoradio_BM_CLICK(void) log_all_parent_messages--; ret = SendMessageA(radio1, BM_GETCHECK, 0, 0); - ok(ret == BST_UNCHECKED, "got %08x\n", ret); + ok(ret == BST_UNCHECKED, "got %08lx\n", ret); ret = SendMessageA(radio2, BM_GETCHECK, 0, 0); - ok(ret == BST_CHECKED, "got %08x\n", ret); + ok(ret == BST_CHECKED, "got %08lx\n", ret); ret = SendMessageA(radio3, BM_GETCHECK, 0, 0); - ok(ret == BST_UNCHECKED, "got %08x\n", ret); + ok(ret == BST_UNCHECKED, "got %08lx\n", ret); DestroyWindow(parent); } @@ -6978,11 +7569,11 @@ static void test_radio_dbg(HWND radio1, int state1, HWND radio2, int state2, HWN DWORD ret; ret = SendMessageA(radio1, BM_GETCHECK, 0, 0); - ok_(__FILE__,line)(ret == state1 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret); + ok_(__FILE__,line)(ret == state1 ? BST_CHECKED : BST_UNCHECKED, "got %08lx\n", ret); ret = SendMessageA(radio2, BM_GETCHECK, 0, 0); - ok_(__FILE__,line)(ret == state2 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret); + ok_(__FILE__,line)(ret == state2 ? BST_CHECKED : BST_UNCHECKED, "got %08lx\n", ret); ret = SendMessageA(radio3, BM_GETCHECK, 0, 0); - ok_(__FILE__,line)(ret == state3 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret); + ok_(__FILE__,line)(ret == state3 ? BST_CHECKED : BST_UNCHECKED, "got %08lx\n", ret); } static void set_radio(HWND radio1, int state1, HWND radio2, int state2, HWND radio3, int state3) @@ -7054,8 +7645,8 @@ static void test_autoradio_kbd_move(void) ret = IsDialogMessageA(parent, &msg); ok(ret, "IsDialogMessage should return TRUE\n"); while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); -if (0) /* actual message sequence is different on every run in some Windows setups */ - ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #1", FALSE); + if (0) /* actual message sequence is different on every run in some Windows setups */ + ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #1", FALSE); /* what really matters is that nothing has changed */ test_radio(radio1, 1, radio2, 1, radio3, 1); @@ -7068,8 +7659,8 @@ if (0) /* actual message sequence is different on every run in some Windows setu ret = IsDialogMessageA(parent, &msg); ok(ret, "IsDialogMessage should return TRUE\n"); while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); -if (0) /* actual message sequence is different on every run in some Windows setups */ - ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #2", FALSE); + if (0) /* actual message sequence is different on every run in some Windows setups */ + ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #2", FALSE); /* what really matters is that nothing has changed */ test_radio(radio1, 0, radio2, 1, radio3, 1); @@ -7144,8 +7735,8 @@ if (0) /* actual message sequence is different on every run in some Windows setu ret = IsDialogMessageA(parent, &msg); ok(ret, "IsDialogMessage should return TRUE\n"); while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); -if (0) /* actual message sequence is different on every run in some Windows setups */ - ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #3", FALSE); + if (0) /* actual message sequence is different on every run in some Windows setups */ + ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #3", FALSE); /* what really matters is that nothing has changed */ test_radio(radio1, 1, radio2, 0, radio3, 0); @@ -7193,8 +7784,10 @@ static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, static void subclass_static(void) { WNDCLASSA cls; + BOOL ret; - if (!GetClassInfoA(0, "static", &cls)) assert(0); + ret = GetClassInfoA(0, "static", &cls); + ok(ret, "Failed to get class info, error %lu.\n", GetLastError()); old_static_proc = cls.lpfnWndProc; @@ -7202,7 +7795,7 @@ static void subclass_static(void) cls.lpfnWndProc = static_hook_proc; cls.lpszClassName = "my_static_class"; UnregisterClassA(cls.lpszClassName, cls.hInstance); - if (!RegisterClassA(&cls)) assert(0); + register_class(&cls); } static void test_static_messages(void) @@ -7230,14 +7823,14 @@ static void test_static_messages(void) ok(hwnd != 0, "Failed to create static window\n"); dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0); - ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code); + ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08lx\n", i, dlg_code); ShowWindow(hwnd, SW_SHOW); UpdateWindow(hwnd); SetFocus(0); flush_sequence(); - trace("static style %08x\n", static_ctrl[i].style); + if (winetest_debug > 1) trace("static style %08lx\n", static_ctrl[i].style); SendMessageA(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE); @@ -7342,6 +7935,7 @@ static const struct message SetFocusComboBoxSeq[] = { WM_CTLCOLORBTN, sent|parent }, { WM_SETFOCUS, sent }, { WM_KILLFOCUS, sent|defwinproc }, + { EM_GETPASSWORDCHAR, sent|optional }, /* Sent on some Win10 machines */ { WM_SETFOCUS, sent }, { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) }, { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX }, @@ -7468,8 +8062,10 @@ static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wPara static void subclass_combobox(void) { WNDCLASSA cls; + BOOL ret; - if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0); + ret = GetClassInfoA(0, "ComboBox", &cls); + ok(ret, "Failed to get class info, error %lu.\n", GetLastError()); old_combobox_proc = cls.lpfnWndProc; @@ -7477,7 +8073,7 @@ static void subclass_combobox(void) cls.lpfnWndProc = combobox_hook_proc; cls.lpszClassName = "my_combobox_class"; UnregisterClassA(cls.lpszClassName, cls.hInstance); - if (!RegisterClassA(&cls)) assert(0); + register_class(&cls); } static void test_combobox_messages(void) @@ -7501,14 +8097,14 @@ static void test_combobox_messages(void) UpdateWindow(combo); ret = SendMessageA(combo, WM_GETDLGCODE, 0, 0); - ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret); + ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08Ix\n", ret); ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0"); - ok(ret == 0, "expected 0, got %ld\n", ret); + ok(ret == 0, "expected 0, got %Id\n", ret); ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 1"); - ok(ret == 1, "expected 1, got %ld\n", ret); + ok(ret == 1, "expected 1, got %Id\n", ret); ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 2"); - ok(ret == 2, "expected 2, got %ld\n", ret); + ok(ret == 2, "expected 2, got %Id\n", ret); SendMessageA(combo, CB_SETCURSEL, 0, 0); SetFocus(combo); @@ -7539,7 +8135,7 @@ static void test_combobox_messages(void) cbInfo.cbSize = sizeof(COMBOBOXINFO); SetLastError(0xdeadbeef); res = GetComboBoxInfo(combo, &cbInfo); - ok(res, "Failed to get COMBOBOXINFO structure; LastError: %u\n", GetLastError()); + ok(res, "Failed to get COMBOBOXINFO structure; LastError: %lu\n", GetLastError()); edit = cbInfo.hwndItem; edit_window_proc = (WNDPROC)SetWindowLongPtrA(edit, GWLP_WNDPROC, @@ -7593,12 +8189,12 @@ static void test_combobox_messages(void) ok(combo != 0, "Failed to create combobox window\n"); ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0"); - ok(ret == 0, "expected 0, got %ld\n", ret); + ok(ret == 0, "expected 0, got %Id\n", ret); cbInfo.cbSize = sizeof(COMBOBOXINFO); SetLastError(0xdeadbeef); res = GetComboBoxInfo(combo, &cbInfo); - ok(res, "Failed to get COMBOBOXINFO structure; LastError: %u\n", GetLastError()); + ok(res, "Failed to get COMBOBOXINFO structure; LastError: %lu\n", GetLastError()); lbox = cbInfo.hwndList; lbox_window_proc = (WNDPROC)SetWindowLongPtrA(lbox, GWLP_WNDPROC, (ULONG_PTR)combobox_lbox_subclass_proc); @@ -7659,7 +8255,7 @@ static void register_wmime_keydown_class(void) cls.lpfnWndProc = wmime_keydown_procA; cls.hInstance = GetModuleHandleA(0); cls.lpszClassName = "wmime_keydown_class"; - if (!RegisterClassA(&cls)) assert(0); + register_class(&cls); } static void test_wmime_keydown_message(void) @@ -7667,7 +8263,7 @@ static void test_wmime_keydown_message(void) HWND hwnd; MSG msg; - trace("Message sequences by WM_IME_KEYDOWN\n"); + if (winetest_debug > 1) trace("Message sequences by WM_IME_KEYDOWN\n"); register_wmime_keydown_class(); hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW, @@ -7704,13 +8300,13 @@ void dump_region(HRGN hrgn) return; } if (!(size = GetRegionData( hrgn, 0, NULL ))) return; - if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return; + if (!(data = malloc( size ))) return; GetRegionData( hrgn, size, data ); - printf("%d rects:", data->rdh.nCount ); + printf("%ld rects:", data->rdh.nCount ); for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++) printf( " %s", wine_dbgstr_rect( rect )); printf("\n"); - HeapFree( GetProcessHeap(), 0, data ); + free( data ); } #define check_update_rgn( hwnd, hrgn ) check_update_rgn_( __LINE__, hwnd, hrgn ) @@ -7851,6 +8447,7 @@ static const struct message WmParentPaintNc[] = { { WM_NCPAINT, sent|beginpaint }, { WM_GETTEXT, sent|beginpaint|defwinproc|optional }, { WM_ERASEBKGND, sent|beginpaint|optional }, + { WM_GETMINMAXINFO, sent|optional }, { 0 } }; @@ -7891,6 +8488,7 @@ static void test_paint_messages(void) { BOOL ret; RECT rect, rect2; + DWORD style; POINT pt; MSG msg; HWND hparent, hchild; @@ -7931,6 +8529,61 @@ static void test_paint_messages(void) ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret); check_update_rgn( hwnd, 0 ); + /* test a zeroed rectangle */ + RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE ); + SetRect( &rect, 0, 0, 0, 0 ); + ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE ); + ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret); + check_update_rgn( hwnd, 0 ); + + /* a well ordered rectangle */ + RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE ); + SetRect( &rect, 10, 5, 17, 21 ); + ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE ); + ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret); + SetRectRgn( hrgn, 10, 5, 17, 21 ); + check_update_rgn( hwnd, hrgn ); + + /* empty rectangle, top and bottom are swapped but left and right have + the same value */ + RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE ); + SetRect( &rect, 5, 30, 5, 10 ); + ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE ); + ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret); + check_update_rgn( hwnd, 0 ); + + /* empty rectangle, left and right are swapped but top and bottom have + the same value */ + RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE ); + SetRect( &rect, 17, 10, 5, 10 ); + ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE ); + ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret); + check_update_rgn( hwnd, 0 ); + + /* Left and right are swapped */ + RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE ); + SetRect( &rect, 21, 12, 7, 30 ); + ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE ); + ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret); + SetRectRgn( hrgn, 7, 12, 21, 30 ); + check_update_rgn( hwnd, hrgn ); + + /* Top and bottom are swapped */ + RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE ); + SetRect( &rect, 7, 30, 21, 12 ); + ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE ); + ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret); + SetRectRgn( hrgn, 7, 12, 21, 30 ); + check_update_rgn( hwnd, hrgn ); + + /* both reference points are swapped */ + RedrawWindow( hwnd, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE ); + SetRect( &rect, 21, 30, 7, 12 ); + ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE ); + ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret); + SetRectRgn( hrgn, 7, 12, 21, 30 ); + check_update_rgn( hwnd, hrgn ); + /* flush pending messages */ flush_events(); flush_sequence(); @@ -8035,7 +8688,7 @@ static void test_paint_messages(void) SetLastError(0xdeadbeef); ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n"); ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef, - "wrong error code %d\n", GetLastError()); + "wrong error code %ld\n", GetLastError()); check_update_rgn( hwnd, 0 ); flush_events(); ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE ); @@ -8044,7 +8697,7 @@ static void test_paint_messages(void) ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n"); ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken( GetLastError() == 0xdeadbeef ) /* win9x */, - "wrong error code %d\n", GetLastError()); + "wrong error code %ld\n", GetLastError()); check_update_rgn( hwnd, 0 ); flush_events(); ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE ); @@ -8053,7 +8706,7 @@ static void test_paint_messages(void) ok(!UpdateWindow(NULL), "UpdateWindow(NULL) should fail\n"); ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken( GetLastError() == 0xdeadbeef ) /* win9x */, - "wrong error code %d\n", GetLastError()); + "wrong error code %ld\n", GetLastError()); check_update_rgn( hwnd, 0 ); flush_events(); ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE ); @@ -8376,11 +9029,12 @@ static void test_paint_messages(void) flush_events(); ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE ); - assert( GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN ); + style = GetWindowLongA(hparent, GWL_STYLE); + ok(style & WS_CLIPCHILDREN, "Got unexpected style %#lx.\n", style); UpdateWindow( hparent ); flush_events(); flush_sequence(); - trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n"); + if (winetest_debug > 1) trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n"); RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME ); SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED ); @@ -8390,7 +9044,7 @@ static void test_paint_messages(void) UpdateWindow( hparent ); flush_events(); flush_sequence(); - trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n"); + if (winetest_debug > 1) trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n"); RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME ); SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED ); @@ -8403,11 +9057,12 @@ static void test_paint_messages(void) flush_events(); ok_sequence( WmParentPaint, "WmParentPaint", FALSE ); - assert( !(GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN) ); + style = GetWindowLongA(hparent, GWL_STYLE); + ok(!(style & WS_CLIPCHILDREN), "Got unexpected style %#lx.\n", style); UpdateWindow( hparent ); flush_events(); flush_sequence(); - trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n"); + if (winetest_debug > 1) trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n"); RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME ); SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED ); @@ -8417,7 +9072,7 @@ static void test_paint_messages(void) UpdateWindow( hparent ); flush_events(); flush_sequence(); - trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n"); + if (winetest_debug > 1) trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n"); RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME ); SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED ); @@ -8430,7 +9085,7 @@ static void test_paint_messages(void) UpdateWindow( hparent ); flush_events(); flush_sequence(); - trace("testing SetWindowPos(-10000, -10000) on child\n"); + if (winetest_debug > 1) trace("testing SetWindowPos(-10000, -10000) on child\n"); SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER ); check_update_rgn( hchild, 0 ); flush_events(); @@ -8439,7 +9094,7 @@ static void test_paint_messages(void) UpdateWindow( hparent ); flush_events(); flush_sequence(); - trace("testing ShowWindow(SW_MINIMIZE) on child\n"); + if (winetest_debug > 1) trace("testing ShowWindow(SW_MINIMIZE) on child\n"); ShowWindow( hchild, SW_MINIMIZE ); check_update_rgn( hchild, 0 ); flush_events(); @@ -8448,7 +9103,7 @@ static void test_paint_messages(void) UpdateWindow( hparent ); flush_events(); flush_sequence(); - trace("testing SetWindowPos(-10000, -10000) on parent\n"); + if (winetest_debug > 1) trace("testing SetWindowPos(-10000, -10000) on parent\n"); SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER ); check_update_rgn( hparent, 0 ); flush_events(); @@ -8518,12 +9173,813 @@ static void test_paint_messages(void) DeleteObject( hrgn2 ); } +static void visualize_region_differences( HWND hwnd, HWND hother, HRGN hrgn_expect, HRGN hrgn_actual ) +{ + HBRUSH b_expectonly, b_actualonly, b_intersect; + HRGN hrgn_intersect; + HWND hstatic, hshow, hhide; + HDC hdc, hdctmp; + HBITMAP hbitmap; + MSG msg; + RECT rect; + DWORD start_time, elapsed, timeout = 60 * 1000; + BOOL toggle = TRUE, stop = FALSE; + + start_time = GetTickCount(); + + b_expectonly = CreateSolidBrush( RGB( 64, 64, 255 )); + b_actualonly = CreateSolidBrush( RGB( 255, 64, 64 )); + b_intersect = CreateSolidBrush( RGB( 159, 64, 159 )); + + hrgn_intersect = CreateRectRgn( 0, 0, 0, 0 ); + CombineRgn( hrgn_intersect, hrgn_expect, hrgn_actual, RGN_AND ); + + GetClientRect( hwnd, &rect ); + hdc = GetDC( hwnd ); + hbitmap = CreateCompatibleBitmap( hdc, rect.right, rect.bottom ); + hdctmp = CreateCompatibleDC( hdc ); + ReleaseDC( hwnd, hdc ); + + SelectObject( hdctmp, hbitmap ); + FillRgn( hdctmp, hrgn_expect, b_expectonly ); + FillRgn( hdctmp, hrgn_actual, b_actualonly ); + FillRgn( hdctmp, hrgn_intersect, b_intersect ); + + DeleteObject( hdctmp ); + DeleteObject( hrgn_intersect ); + DeleteObject( b_intersect ); + DeleteObject( b_actualonly ); + DeleteObject( b_expectonly ); + + hstatic = CreateWindowExA( 0, WC_STATICA, "", WS_CHILD | SS_BITMAP, + 0, 0, rect.right, rect.bottom, hwnd, 0, 0, NULL ); + SendMessageA( hstatic, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbitmap ); + + hshow = hstatic; + hhide = hother; + + for (;;) + { + if (stop) toggle = hshow == hother; + if (toggle) + { + HWND htmp; + HDWP hdwp; + + hdwp = BeginDeferWindowPos( !!hhide + !!hshow ); + if (hhide) + { + DeferWindowPos( hdwp, hhide, NULL, 0, 0, 0, 0, + SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER ); + } + if (hshow) + { + DeferWindowPos( hdwp, hshow, HWND_TOP, 0, 0, 0, 0, + SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE ); + } + EndDeferWindowPos( hdwp ); + + htmp = hshow; + hshow = hhide; + hhide = htmp; + toggle = FALSE; + } + if (stop) break; + if ((elapsed = GetTickCount() - start_time) >= timeout) + { + stop = TRUE; + continue; + } + MsgWaitForMultipleObjects( 0, NULL, FALSE, timeout - elapsed, QS_ALLINPUT ); + while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) + { + TranslateMessage( &msg ); + DispatchMessageA( &msg ); + if (msg.message == WM_MOUSEMOVE) + { + start_time = GetTickCount(); + } + else if (msg.message == WM_LBUTTONUP || (msg.message == WM_CHAR && msg.wParam == VK_SPACE)) + { + toggle = !toggle; + } + else if (msg.message == WM_RBUTTONUP || (msg.message == WM_CHAR && msg.wParam == VK_RETURN)) + { + stop = TRUE; + } + } + } + + DestroyWindow( hstatic ); + DeleteObject( hbitmap ); +} + +#define subtest_swp_paint_regions(w,p,c) subtest_swp_paint_regions_(__LINE__,w,p,c) + +static void subtest_swp_paint_regions_( int line, int wrap_toplevel, LPCSTR parent_class, LPCSTR child_class ) +{ + static const struct exposure_test { + int ex_style, style; + BOOL shuffle_zorder; + } exposure_tests[] = { + { 0, WS_CLIPCHILDREN, FALSE }, + { 0, 0, FALSE }, + { WS_EX_COMPOSITED, WS_CLIPCHILDREN, TRUE }, + { WS_EX_COMPOSITED, 0, FALSE }, + { WS_EX_COMPOSITED, 0, TRUE }, + }; + size_t i; + HWND htoplevel = NULL, hparent, hchild, hauxchild; + const RECT rect_old = { 10, 10, 100, 100 }; + HRGN hrgn_old_vis = CreateRectRgn( 0, 0, 0, 0 ); + HRGN hrgn_new_vis = CreateRectRgn( 0, 0, 0, 0 ); + HRGN hrgn_expect = CreateRectRgn( 0, 0, 0, 0 ); + HRGN hrgn_actual = CreateRectRgn( 0, 0, 0, 0 ); + HRGN hrgn_old_vis_child = CreateRectRgn( 0, 0, 0, 0 ); + HRGN hrgn_new_vis_child = CreateRectRgn( 0, 0, 0, 0 ); + HRGN hrgn_expect_child = CreateRectRgn( 0, 0, 0, 0 ); + HRGN hrgn_actual_child = CreateRectRgn( 0, 0, 0, 0 ); + int base_style; + BOOL is_composition_possible, has_parentdc_anomaly; + WNDCLASSA parent_wc; + + if (wrap_toplevel) + { + htoplevel = CreateWindowExA( 0, "SimpleWindowClass", "Test toplevel", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 400, 400, 0, 0, 0, NULL ); + ok( htoplevel != 0, "Failed to create top-level window: %lu\n", GetLastError() ); + base_style = WS_CHILD | WS_VISIBLE; + } + else + { + base_style = WS_OVERLAPPEDWINDOW | WS_VISIBLE; + } + + ok( GetClassInfoA( GetModuleHandleA( NULL ), parent_class, &parent_wc ), + "GetClassInfoA failed\n" ); + + is_composition_possible = (base_style & (WS_POPUP|WS_CHILD)) != WS_CHILD || + (parent_wc.style & CS_PARENTDC) == 0; + + has_parentdc_anomaly = (base_style & (WS_POPUP|WS_CHILD)) != WS_CHILD && + (parent_wc.style & CS_PARENTDC) != 0; + + hparent = CreateWindowExA( 0, parent_class, "Test parent", base_style, + 80, 80, 200, 200, htoplevel, 0, 0, NULL ); + ok( hparent != 0, "Creating parent window (%s) returned error %lu\n", + debugstr_a( parent_class ), GetLastError() ); + + hchild = CreateWindowExA( 0, child_class, "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER, + rect_old.left, rect_old.top, + rect_old.right - rect_old.left, rect_old.bottom - rect_old.top, + hparent, 0, 0, NULL ); + ok( hchild != 0, "Creating child window (%s) returned error %lu\n", + debugstr_a( child_class ), GetLastError() ); + + hauxchild = CreateWindowExA( 0, child_class, "Auxiliary child for z order test", WS_CHILD | WS_VISIBLE, + 110, 0, 0, 0, hparent, 0, 0, NULL ); + ok( hauxchild != 0, "Creating child window (%s) returned error %lu\n", + debugstr_a( child_class ), GetLastError() ); + + SetWindowPos( htoplevel ? htoplevel : hparent, NULL, 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_SHOWWINDOW ); + + for (i = 0; i < ARRAY_SIZE(exposure_tests); i++) + { + const struct exposure_test *extest = &exposure_tests[i]; + BOOL has_ws_ex_composited = (extest->ex_style & WS_EX_COMPOSITED) != 0; + BOOL is_composited = is_composition_possible && has_ws_ex_composited; + BOOL is_zorder_redraw = is_composited && extest->shuffle_zorder; + int delta; + + winetest_push_context( "%d: SetWindowPos redraw #%Id (ex_style = %#x, style = %#x, shuffle_zorder = %d)", + line, i, extest->ex_style, extest->style, extest->shuffle_zorder ); + + SetWindowLongA( hparent, GWL_EXSTYLE, extest->ex_style ); + SetWindowLongA( hparent, GWL_STYLE, base_style | extest->style ); + RedrawWindow( hparent, NULL, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME ); + + for (delta = -20; delta <= 0; delta += 20) + { + RECT rect_old_vis, rect_new, rect_new_vis; + RECT rect_parent_clip, rect_child_clip; + RECT rect_old_vis_child, rect_new_vis_child; + BOOL rgn_ok; + + winetest_push_context( "delta = %+d", delta ); + + SetWindowPos( hchild, HWND_TOP, + rect_old.left, + rect_old.top, + rect_old.right - rect_old.left, + rect_old.bottom - rect_old.top, + SWP_NOACTIVATE ); + + rect_new = rect_old; + OffsetRect( &rect_new, delta, delta ); + + rect_old_vis_child = rect_old; + MapWindowPoints( hparent, hchild, (POINT *)&rect_old_vis_child, 2 ); + + SetRectRgn( hrgn_actual, 0, 0, 0, 0 ); + SetRectRgn( hrgn_actual_child, 0, 0, 0, 0 ); + + UpdateWindow( hparent ); + flush_events(); + + if (extest->shuffle_zorder) + { + /* bring sibling to top/bottom first so we can trigger z-order change */ + SetWindowPos( hauxchild, HWND_TOP, 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE ); + } + + SetWindowPos( hchild, HWND_TOP, + rect_new.left, + rect_new.top, + rect_new.right - rect_new.left, + rect_new.bottom - rect_new.top, + SWP_NOACTIVATE | + (extest->shuffle_zorder ? 0 : SWP_NOZORDER) ); + + ok( GetUpdateRgn( hparent, hrgn_actual, FALSE ) != ERROR, + "GetUpdateRgn on parentshall succeed\n" ); + ok( GetUpdateRgn( hchild, hrgn_actual_child, FALSE ) != ERROR, + "GetUpdateRgn on child shall succeed\n" ); + + /* Compute parent window expose region */ + GetClientRect( hparent, &rect_parent_clip ); + IntersectRect( &rect_old_vis, &rect_old, &rect_parent_clip ); + SetRectRgn( hrgn_old_vis, rect_old_vis.left, rect_old_vis.top, rect_old_vis.right, rect_old_vis.bottom ); + IntersectRect( &rect_new_vis, &rect_new, &rect_parent_clip ); + SetRectRgn( hrgn_new_vis, rect_new_vis.left, rect_new_vis.top, rect_new_vis.right, rect_new_vis.bottom ); + + if (!EqualRect( &rect_old, &rect_new ) || is_zorder_redraw) + { + CombineRgn( hrgn_expect, hrgn_old_vis, hrgn_new_vis, is_composited ? RGN_OR : RGN_DIFF ); + } + else + { + SetRectRgn( hrgn_expect, 0, 0, 0, 0 ); + } + + rgn_ok = EqualRgn( hrgn_expect, hrgn_actual ); + if (!rgn_ok && broken( has_parentdc_anomaly && is_composited /* Win7 */ )) + { + if (winetest_debug > 1) + { + trace( "Forcing non-composited update region (broken)\n" ); + } + rgn_ok = 1; + } + else + { + ok( !!rgn_ok, "Parent update region shall match expected region\n" ); + } + + if (!rgn_ok) + { + trace( "Expected parent update region: " ); + dump_region( hrgn_expect ); + trace( "Actual parent update region: " ); + dump_region( hrgn_actual ); + trace( "Old child window visible area: %s\n", wine_dbgstr_rect( &rect_old_vis ) ); + trace( "New child window visible area: %s\n", wine_dbgstr_rect( &rect_new_vis ) ); + } + + if (winetest_interactive) + { + if (!rgn_ok) + { + visualize_region_differences( hparent, hchild, hrgn_expect, hrgn_actual ); + } + + /* Let the position change be visible to the user */ + flush_events(); + } + + rect_new_vis_child = rect_new; + MapWindowPoints( hparent, hchild, (POINT *)&rect_new_vis_child, 2 ); + + /* Compute child window expose region */ + GetClientRect( hchild, &rect_child_clip ); + if (is_composited) + { + RECT rect_outer_clip; + GetClientRect( hparent, &rect_outer_clip ); + MapWindowPoints( hparent, hchild, (POINT *)&rect_outer_clip, 2 ); + IntersectRect( &rect_child_clip, &rect_child_clip, &rect_outer_clip ); + } + IntersectRect( &rect_old_vis_child, &rect_old_vis_child, &rect_child_clip ); + SetRectRgn( hrgn_old_vis_child, rect_old_vis_child.left, rect_old_vis_child.top, rect_old_vis_child.right, rect_old_vis_child.bottom ); + IntersectRect( &rect_new_vis_child, &rect_new_vis_child, &rect_child_clip ); + SetRectRgn( hrgn_new_vis_child, rect_new_vis_child.left, rect_new_vis_child.top, rect_new_vis_child.right, rect_new_vis_child.bottom ); + + if (!EqualRect( &rect_old, &rect_new ) || is_zorder_redraw) + { + CombineRgn( hrgn_expect_child, hrgn_new_vis_child, hrgn_old_vis_child, is_composited ? RGN_OR : RGN_DIFF ); + } + else + { + SetRectRgn( hrgn_expect_child, 0, 0, 0, 0 ); + } + + rgn_ok = EqualRgn( hrgn_expect_child, hrgn_actual_child ); + if (!rgn_ok && broken( has_parentdc_anomaly && is_composited /* Win7 */ )) + { + if (winetest_debug > 1) + { + trace( "Forcing non-composited update region (broken)\n" ); + } + rgn_ok = 1; + } + else + { + ok( !!rgn_ok, "Child update region shall match expected region\n" ); + } + + if (!rgn_ok) + { + trace( "Expected child update region: " ); + dump_region( hrgn_expect_child ); + trace( "Actual child update region: " ); + dump_region( hrgn_actual_child ); + trace( "Old child window client visible area: %s\n", wine_dbgstr_rect( &rect_old_vis_child ) ); + trace( "New child window client visible area: %s\n", wine_dbgstr_rect( &rect_new_vis_child ) ); + } + + if (winetest_interactive) + { + if (!rgn_ok) + { + visualize_region_differences( hchild, NULL, hrgn_expect_child, hrgn_actual_child ); + } + + /* Let the position change be visible to the user */ + flush_events(); + } + + winetest_pop_context(); + } + + winetest_pop_context(); + } + + DestroyWindow( hauxchild ); + DestroyWindow( hchild ); + DestroyWindow( hparent ); + if (htoplevel) DestroyWindow( htoplevel ); + + DeleteObject( hrgn_actual_child ); + DeleteObject( hrgn_expect_child ); + DeleteObject( hrgn_new_vis_child ); + DeleteObject( hrgn_old_vis_child ); + DeleteObject( hrgn_actual ); + DeleteObject( hrgn_expect ); + DeleteObject( hrgn_new_vis ); + DeleteObject( hrgn_old_vis ); +} + +static void test_swp_paint_regions(void) +{ + subtest_swp_paint_regions( 1, "SimpleWindowClass", "SimpleWindowClass" ); + subtest_swp_paint_regions( 0, "SimpleWindowClass", "SimpleWindowClass" ); + subtest_swp_paint_regions( 0, "SimpleWindowClass", "SimpleWindowClassWithParentDC" ); + subtest_swp_paint_regions( 0, "SimpleWindowClassWithParentDC", "SimpleWindowClass" ); +} + +static void test_swp_paint_region_on_show(void) +{ + HRGN hrgn_actual_child = CreateRectRgn( 0, 0, 0, 0 ); + HRGN hrgn_actual = CreateRectRgn( 0, 0, 0, 0 ); + const RECT rect_1 = { 10, 10, 100, 100 }; + const RECT rect_2 = { 20, 20, 120, 120 }; + RECT rect_expect_child, rect_expect; + RECT rect_actual_child, rect_actual; + HWND hparent, hchild; + int result; + + hparent = CreateWindowExA( 0, "SimpleWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 80, 80, 200, 200, NULL, 0, 0, NULL ); + ok( hparent != 0, "Creating parent window returned error %lu\n", GetLastError() ); + + hchild = CreateWindowExA( 0, "SimpleWindowClass", "Test child", WS_CHILD | WS_BORDER, + 0, 0, 100, 100, hparent, 0, 0, NULL ); + ok( hchild != 0, "Creating child window returned error %lu\n", GetLastError() ); + + if (winetest_debug > 1) trace("testing show window (no move / size)\n"); + + SetWindowPos( hchild, HWND_TOP, + rect_1.left, rect_1.top, rect_1.right - rect_1.left, rect_1.bottom - rect_1.top, + SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOZORDER ); + + UpdateWindow( hparent ); + flush_events(); + + SetWindowPos( hchild, HWND_TOP, 0, 0, 0, 0, + SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE ); + + ok( GetUpdateRgn( hparent, hrgn_actual, FALSE ) != ERROR, + "GetUpdateRgn on parent shall succeed\n" ); + ok( GetUpdateRgn( hchild, hrgn_actual_child, FALSE ) != ERROR, + "GetUpdateRgn on child shall succeed\n" ); + + result = GetRgnBox( hrgn_actual, &rect_actual ); + ok( result == SIMPLEREGION, "GetRgnBox (on parent) returned %d\n", result ); + if (result == COMPLEXREGION) dump_region( hrgn_actual ); + + rect_expect = rect_1; + ok( EqualRect( &rect_actual, &rect_expect ), "parent update region: got %s, expected %s\n", + wine_dbgstr_rect( &rect_actual ), wine_dbgstr_rect( &rect_expect ) ); + + result = GetRgnBox( hrgn_actual_child, &rect_actual_child ); + ok( result == SIMPLEREGION, "GetRgnBox (on child) returned %d\n", result ); + if (result == COMPLEXREGION) dump_region( hrgn_actual_child ); + + ok( GetClientRect( hchild, &rect_expect_child ), "GetClientRect failed\n" ); + ok( EqualRect( &rect_actual_child, &rect_expect_child ), "child update region: got %s, expected %s\n", + wine_dbgstr_rect( &rect_actual_child ), wine_dbgstr_rect( &rect_expect_child ) ); + + if (winetest_debug > 1) trace("testing show window (with move / resize)\n"); + + SetWindowPos( hchild, HWND_TOP, + rect_1.left, rect_1.top, rect_1.right - rect_1.left, rect_1.bottom - rect_1.top, + SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOZORDER ); + + UpdateWindow( hparent ); + flush_events(); + + SetWindowPos( hchild, HWND_TOP, + rect_2.left, + rect_2.top, + rect_2.right - rect_2.left, + rect_2.bottom - rect_2.top, + SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER ); + + ok( GetUpdateRgn( hparent, hrgn_actual, FALSE ) != ERROR, + "GetUpdateRgn on parent shall succeed\n" ); + ok( GetUpdateRgn( hchild, hrgn_actual_child, FALSE ) != ERROR, + "GetUpdateRgn on child shall succeed\n" ); + + result = GetRgnBox( hrgn_actual, &rect_actual ); + ok( result == SIMPLEREGION, "GetRgnBox (on parent) returned %d\n", result ); + if (result == COMPLEXREGION) dump_region( hrgn_actual ); + + rect_expect = rect_2; + ok( EqualRect( &rect_actual, &rect_expect ), "parent update region: got %s, expected %s\n", + wine_dbgstr_rect( &rect_actual ), wine_dbgstr_rect( &rect_expect ) ); + + result = GetRgnBox( hrgn_actual_child, &rect_actual_child ); + ok( result == SIMPLEREGION, "GetRgnBox (on child) returned %d\n", result ); + if (result == COMPLEXREGION) dump_region( hrgn_actual_child ); + + ok( GetClientRect( hchild, &rect_expect_child ), "GetClientRect failed\n" ); + ok( EqualRect( &rect_actual_child, &rect_expect_child ), "child update region: got %s, expected %s\n", + wine_dbgstr_rect( &rect_actual_child ), wine_dbgstr_rect( &rect_expect_child ) ); + + DestroyWindow( hchild ); + DestroyWindow( hparent ); + DeleteObject( hrgn_actual_child ); + DeleteObject( hrgn_actual ); +} + +static void test_swp_paint_region_on_extend_zerosize(void) +{ + HRGN hrgn_actual_child = CreateRectRgn( 0, 0, 0, 0 ); + HRGN hrgn_actual = CreateRectRgn( 0, 0, 0, 0 ); + const RECT rect_1 = { 10, 10, 100, 100 }; + RECT rect_expect_child, rect_expect; + RECT rect_actual_child, rect_actual; + HWND hparent, hchild; + int result; + + hparent = CreateWindowExA( 0, "SimpleWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 80, 80, 200, 200, NULL, 0, 0, NULL ); + ok( hparent != 0, "Creating parent window returned error %lu\n", GetLastError() ); + + hchild = CreateWindowExA( 0, "SimpleWindowClass", "Test child (no border)", WS_CHILD | WS_VISIBLE, + 10, 10, 0, 0, hparent, 0, 0, NULL ); + ok( hchild != 0, "Creating child window returned error %lu\n", GetLastError() ); + + if (winetest_debug > 1) trace("testing extending zero-size window\n"); + + UpdateWindow( hparent ); + flush_events(); + + SetWindowPos( hchild, HWND_TOP, + rect_1.left, + rect_1.top, + rect_1.right - rect_1.left, + rect_1.bottom - rect_1.top, + SWP_NOACTIVATE | SWP_NOZORDER ); + + ok( GetUpdateRgn( hparent, hrgn_actual, FALSE ) != ERROR, + "GetUpdateRgn on parent shall succeed\n" ); + ok( GetUpdateRgn( hchild, hrgn_actual_child, FALSE ) != ERROR, + "GetUpdateRgn on child shall succeed\n" ); + + result = GetRgnBox( hrgn_actual, &rect_actual ); + ok( result == SIMPLEREGION, "GetRgnBox (on parent) returned %d\n", result ); + if (result == COMPLEXREGION) dump_region( hrgn_actual ); + + rect_expect = rect_1; + ok( EqualRect( &rect_actual, &rect_expect ), "parent update region: got %s, expected %s\n", + wine_dbgstr_rect( &rect_actual ), wine_dbgstr_rect( &rect_expect ) ); + + result = GetRgnBox( hrgn_actual_child, &rect_actual_child ); + ok( result == SIMPLEREGION, "GetRgnBox (on child) returned %d\n", result ); + if (result == COMPLEXREGION) dump_region( hrgn_actual_child ); + + ok( GetClientRect( hchild, &rect_expect_child ), "GetClientRect failed\n" ); + ok( EqualRect( &rect_actual_child, &rect_expect_child ), "child update region: got %s, expected %s\n", + wine_dbgstr_rect( &rect_actual_child ), wine_dbgstr_rect( &rect_expect_child ) ); + + DestroyWindow( hchild ); + DestroyWindow( hparent ); + DeleteObject( hrgn_actual_child ); + DeleteObject( hrgn_actual ); +} + +static void subtest_hvredraw(HWND hparent, UINT class_style, DWORD style) +{ + static const struct movesize_test { + int dx, dy, dw, dh; + } movesize_tests[] = { + { 0, 0, 0, 5 }, + { 0, 0, 5, 0 }, + { 0, 0, 5, 5 }, + { 0, 0, -5, -5 }, + { -5, -5, 0, 5 }, + { -5, -5, 5, 0 }, + { -5, -5, 5, 5 }, + }; + HRGN hrgn_old_vis = CreateRectRgn( 0, 0, 0, 0 ); + HRGN hrgn_new_vis = CreateRectRgn( 0, 0, 0, 0 ); + HRGN hrgn_expect = CreateRectRgn( 0, 0, 0, 0 ); + HRGN hrgn_actual = CreateRectRgn( 0, 0, 0, 0 ); + const int x0 = 100, y0 = 100, w0 = 150, h0 = 150; + size_t i; + HWND hwnd; + WNDCLASSA cls = { + .style = class_style, + .lpfnWndProc = DefWindowProcA, + .hInstance = GetModuleHandleA(0), + .hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW), + .hbrBackground = GetStockObject(WHITE_BRUSH), + .lpszClassName = "TestHVRedrawClass" + }; + + register_class(&cls); + + hwnd = CreateWindowExA( 0, cls.lpszClassName, "Test window", style, x0, y0, w0, h0, hparent, 0, 0, NULL ); + ok(hwnd != NULL, "Failed to create the window\n"); + + ShowWindow( hwnd, SW_SHOW ); + UpdateWindow( hwnd ); + + for (i = 0; i < ARRAY_SIZE(movesize_tests); i++) + { + const struct movesize_test *test = &movesize_tests[i]; + int is_redraw = (test->dw != 0 && (class_style & CS_HREDRAW)) || + (test->dh != 0 && (class_style & CS_VREDRAW)); + RECT rect_old_vis, rect_new_vis; + BOOL rgn_ok; + + winetest_push_context( "%x %08lx SetWindowPos redraw #%Id (%d, %d, %d, %d)", + class_style, style, i, test->dx, test->dy, test->dw, test->dh ); + + SetWindowPos( hwnd, HWND_TOP, x0, y0, w0, h0, SWP_NOACTIVATE ); + + GetClientRect( hwnd, &rect_old_vis ); + SetRectRgn( hrgn_old_vis, rect_old_vis.left, rect_old_vis.top, rect_old_vis.right, rect_old_vis.bottom ); + + UpdateWindow( hparent ); + flush_events(); + + SetWindowPos( hwnd, HWND_TOP, + x0 + test->dx, y0 + test->dy, + w0 + test->dw, h0 + test->dh, SWP_NOACTIVATE ); + ok( GetUpdateRgn( hwnd, hrgn_actual, FALSE ) != ERROR, "GetUpdateRgn shall succeed\n" ); + + GetClientRect( hwnd, &rect_new_vis ); + SetRectRgn( hrgn_new_vis, rect_new_vis.left, rect_new_vis.top, rect_new_vis.right, rect_new_vis.bottom ); + CombineRgn( hrgn_expect, hrgn_new_vis, hrgn_old_vis, is_redraw ? RGN_COPY : RGN_DIFF ); + + rgn_ok = EqualRgn( hrgn_expect, hrgn_actual ); +#ifdef __REACTOS__ + ok( !!rgn_ok || broken(GetNTVersion() == _WIN32_WINNT_WINBLUE), "Update region shall match expected region\n" ); +#else + ok( !!rgn_ok, "Update region shall match expected region\n" ); +#endif + + if (!rgn_ok) + { + trace( "Expected update region: " ); + dump_region( hrgn_expect ); + trace( "Actual update region: " ); + dump_region( hrgn_actual ); + trace( "Old window visible area: %s\n", wine_dbgstr_rect( &rect_old_vis ) ); + trace( "New window visible area: %s\n", wine_dbgstr_rect( &rect_new_vis ) ); + } + + if (winetest_interactive) + { + if (!rgn_ok) + { + visualize_region_differences( hwnd, NULL, hrgn_expect, hrgn_actual ); + } + + /* Let the position change be visible to the user */ + flush_events(); + } + + winetest_pop_context(); + } + + DestroyWindow( hwnd ); + DeleteObject( hrgn_actual ); + DeleteObject( hrgn_expect ); + DeleteObject( hrgn_new_vis ); + DeleteObject( hrgn_old_vis ); + UnregisterClassA( cls.lpszClassName, cls.hInstance ); +} + + +static void test_hvredraw(void) +{ + HWND htoplevel; + + subtest_hvredraw( NULL, CS_HREDRAW, WS_OVERLAPPEDWINDOW ); + subtest_hvredraw( NULL, CS_VREDRAW, WS_OVERLAPPEDWINDOW ); + subtest_hvredraw( NULL, CS_HREDRAW|CS_VREDRAW, WS_OVERLAPPEDWINDOW ); + + htoplevel = CreateWindowExA( 0, "SimpleWindowClass", "Test toplevel", + WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_VISIBLE, + 100, 100, 400, 400, 0, 0, 0, NULL ); + ok( htoplevel != 0, "Failed to create top-level window: %lu\n", GetLastError() ); + + subtest_hvredraw( htoplevel, CS_HREDRAW, WS_CHILD | WS_BORDER ); + subtest_hvredraw( htoplevel, CS_VREDRAW, WS_CHILD | WS_BORDER ); + subtest_hvredraw( htoplevel, CS_HREDRAW|CS_VREDRAW, WS_CHILD | WS_BORDER ); + + DestroyWindow( htoplevel ); +} + +struct run_in_temp_desktop_args +{ + const char *file; + int line; + const char *name; + void (*test_func)(void); +}; + +static DWORD WINAPI run_in_temp_desktop_thread_func(LPVOID param) +{ + HDESK prev_thr_desktop, prev_inp_desktop, post_inp_desktop, temp_desktop; + char temp_desktop_name[1024], curr_desktop_name[1024]; + struct run_in_temp_desktop_args *args = param; + const char *file = args->file; + int line = args->line; + LARGE_INTEGER qpc; + DWORD length; + int result; + + result = QueryPerformanceCounter( &qpc ); + ok_(file, line)( result, "QueryPerformanceCounter error %lu\n", GetLastError() ); + + /* + * Temporary desktops from previous runs may leak due to a Windows bug. + * Generate a unique name that is unlikely to collide with previous runs. + */ + result = snprintf( temp_desktop_name, ARRAY_SIZE(temp_desktop_name), + "WineTest-%08lX-%08lX-%08lX%08lX-%s", + GetCurrentProcessId(), GetCurrentThreadId(), + qpc.HighPart, qpc.LowPart, args->name ); + ok_(file, line)( result > 0 && result < ARRAY_SIZE(temp_desktop_name), + "sprintf returned %d (out of memory, or name too long?)\n", result ); + + if (winetest_debug > 1) + trace_(file, line)( "creating desktop: %s\n", debugstr_a( temp_desktop_name ) ); + + temp_desktop = CreateDesktopA( temp_desktop_name, NULL, NULL, 0, GENERIC_ALL, NULL ); + ok_(file, line)( temp_desktop != NULL, "CreateDesktopA(%s, ..) error %lu\n", + debugstr_a( temp_desktop_name ), GetLastError() ); + + prev_inp_desktop = OpenInputDesktop( 0, FALSE, DESKTOP_SWITCHDESKTOP ); + ok_(file, line)( prev_inp_desktop != NULL, "OpenInputDesktop [prev] error %lu\n", GetLastError() ); + + if (winetest_debug > 1) + trace_(file, line)( "sanity check: no concurrent WineTest desktop\n" ); + + /* + * Check if the desktop has not been properly restored. This is done to + * avoid any possible hard-to-debug failures due to unexpected desktop. + */ + result = GetUserObjectInformationA( prev_inp_desktop, UOI_NAME, + curr_desktop_name, sizeof(curr_desktop_name), &length ); + ok_(file, line)( result, "GetUserObjectInformationA error %lu [rl = %lu]\n", + GetLastError(), length ); + ok_(file, line)( _strnicmp( curr_desktop_name, temp_desktop_name, 8 ) != 0, + "unexpected input desktop name %s (concurrent WineTest run?)\n", + debugstr_a( curr_desktop_name ) ); + + if (winetest_debug > 1) + trace_(file, line)( "switching desktop to: %s (%p)\n", debugstr_a( temp_desktop_name ), temp_desktop ); + + result = SwitchDesktop( temp_desktop ); + ok_(file, line)( result, "SwitchDesktop(temp_desktop=%p) error %lu\n", + temp_desktop, GetLastError() ); + + prev_thr_desktop = GetThreadDesktop( GetCurrentThreadId() ); + ok_(file, line)( prev_thr_desktop != NULL, "GetThreadDesktop error %lu\n", GetLastError() ); + + result = SetThreadDesktop( temp_desktop ); + ok_(file, line)( result, "SetThreadDesktop(temp_desktop=%p) error %lu\n", + temp_desktop, GetLastError() ); + + if (winetest_debug > 1) + trace_(file, line)( "running test function %s()\n", args->name ); + + args->test_func(); + + if (winetest_debug > 1) + trace_(file, line)( "sanity check: input desktop has not been changed\n" ); + + /* + * Check if the input desktop has been tampered with. This is done to + * avoid any possible hard-to-debug failures due to unexpected desktop. + */ + post_inp_desktop = OpenInputDesktop( 0, FALSE, DESKTOP_ENUMERATE ); + ok_(file, line)( post_inp_desktop != NULL, "OpenInputDesktop [post] error %lu\n", GetLastError() ); + + result = GetUserObjectInformationA( post_inp_desktop, UOI_NAME, + curr_desktop_name, sizeof(curr_desktop_name), &length ); + ok_(file, line)( result, "GetUserObjectInformationA(post_inp_desktop=%p) error %lu [rl = %lu]\n", + post_inp_desktop, GetLastError(), length ); + ok_(file, line)( strcmp( curr_desktop_name, temp_desktop_name ) == 0, + "different desktop name: %s != %s (no switch or concurrent WineTest run?)\n", + debugstr_a( curr_desktop_name ), debugstr_a( temp_desktop_name ) ); + + result = CloseDesktop( post_inp_desktop ); + ok_(file, line)( result, "CloseDesktop(post_inp_desktop=%p) error %lu\n", + post_inp_desktop, GetLastError() ); + + if (winetest_debug > 1) + trace_(file, line)( "restoring previous desktop\n" ); + + result = SetThreadDesktop( prev_thr_desktop ); + ok_(file, line)( result || broken( GetLastError() == ERROR_BUSY ) /* == W10 */, + "SetThreadDesktop(prev_thr_desktop=%p) error %lu\n", + prev_thr_desktop, GetLastError() ); + + result = SwitchDesktop( prev_inp_desktop ); + ok_(file, line)( result, "SwitchDesktop(prev_inp_desktop=%p) error %lu\n", + prev_inp_desktop, GetLastError() ); + + result = CloseDesktop( prev_inp_desktop ); + ok_(file, line)( result, "CloseDesktop(prev_inp_desktop=%p) error %lu\n", + prev_inp_desktop, GetLastError() ); + + if (winetest_debug > 1) + trace_(file, line)( "closing desktop: %s (%p)\n", debugstr_a( temp_desktop_name ), temp_desktop ); + + result = CloseDesktop( temp_desktop ); + ok_(file, line)( result || broken( GetLastError() == ERROR_BUSY ) /* == W10 */, + "CloseDesktop(temp_desktop=%p) error %lu\n", + temp_desktop, GetLastError() ); + + return 0; +} + +#define run_in_temp_desktop(f) run_in_temp_desktop_(__FILE__, __LINE__, #f, f) +static void run_in_temp_desktop_(const char *file, int line, const char *name, void (*test_func)(void)) +{ + struct run_in_temp_desktop_args args; + HANDLE thread; + DWORD result; + + args.file = file; + args.line = line; + args.name = name; + args.test_func = test_func; + + thread = CreateThread( NULL, 0, run_in_temp_desktop_thread_func, &args, 0, NULL ); + ok_(file, line)( thread != NULL, "CreateThread error %lu\n", GetLastError() ); + + result = WaitForSingleObject( thread, INFINITE ); + ok_(file, line)( result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu, error %lu\n", + result, GetLastError() ); + + CloseHandle( thread ); +} + struct wnd_event { HWND hwnd; HANDLE grand_child; HANDLE start_event; HANDLE stop_event; + HANDLE getmessage_complete; }; static DWORD WINAPI thread_proc(void *param) @@ -8592,7 +10048,7 @@ static DWORD CALLBACK create_child_thread( void *param ) while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); } ret = WaitForSingleObject( wnd_event->stop_event, 5000 ); - ok( !ret, "WaitForSingleObject failed %x\n", ret ); + ok( !ret, "WaitForSingleObject failed %lx\n", ret ); return 0; } @@ -8620,7 +10076,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); } @@ -8636,11 +10092,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); @@ -8672,7 +10128,7 @@ static void test_interthread_messages(void) } hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid); - ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError()); + ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError()); ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); @@ -8681,16 +10137,16 @@ static void test_interthread_messages(void) SetLastError(0xdeadbeef); ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeeded\n"); ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef, - "wrong error code %d\n", GetLastError()); + "wrong error code %ld\n", GetLastError()); proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC); - ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError()); + ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %ld\n", GetLastError()); expected_len = lstrlenA("window caption text"); memset(buf, 0, sizeof(buf)); SetLastError(0xdeadbeef); len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf); - ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len); + ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %ld, len %d, expected len %d\n", GetLastError(), len, expected_len); ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n"); msg.hwnd = wnd_event.hwnd; @@ -8701,7 +10157,7 @@ static void test_interthread_messages(void) SetLastError(0xdeadbeef); len = DispatchMessageA(&msg); ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */ - "DispatchMessageA(WM_GETTEXT) succeeded on another thread window: ret %d, error %d\n", len, GetLastError()); + "DispatchMessageA(WM_GETTEXT) succeeded on another thread window: ret %d, error %ld\n", len, GetLastError()); /* the following test causes an exception in user.exe under win9x */ msg.hwnd = wnd_event.hwnd; @@ -8711,10 +10167,10 @@ static void test_interthread_messages(void) SetLastError(0xdeadbeef); len = DispatchMessageA(&msg); ok(!len && GetLastError() == 0xdeadbeef, - "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError()); + "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %ld\n", len, GetLastError()); ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0); - ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError()); + ok( ret, "PostMessageA(WM_QUIT) error %ld\n", GetLastError()); ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); CloseHandle(hThread); @@ -8754,13 +10210,7 @@ static void test_interthread_messages(void) log_all_parent_messages--; DestroyWindow( wnd_event.hwnd ); - /* activation context tests */ - if (!pActivateActCtx) - { - win_skip("Activation contexts are not supported, skipping\n"); - return; - } - + /* Activation context tests */ create_manifest_file("testdep1.manifest", manifest_dep); create_manifest_file("main.manifest", manifest_main); @@ -8769,25 +10219,25 @@ static void test_interthread_messages(void) DeleteFileA("main.manifest"); handle = (void*)0xdeadbeef; - ret = pGetCurrentActCtx(&handle); - ok(ret, "GetCurrentActCtx failed: %u\n", GetLastError()); + ret = GetCurrentActCtx(&handle); + ok(ret, "GetCurrentActCtx failed: %lu\n", GetLastError()); ok(handle == 0, "active context %p\n", handle); wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL); hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid); - ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError()); + ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError()); ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); CloseHandle(wnd_event.start_event); /* context is activated after thread creation, so it doesn't inherit it by default */ - ret = pActivateActCtx(context, &cookie); - ok(ret, "activation failed: %u\n", GetLastError()); + ret = ActivateActCtx(context, &cookie); + ok(ret, "activation failed: %lu\n", GetLastError()); handle = 0; - ret = pGetCurrentActCtx(&handle); - ok(ret, "GetCurrentActCtx failed: %u\n", GetLastError()); + ret = GetCurrentActCtx(&handle); + ok(ret, "GetCurrentActCtx failed: %lu\n", GetLastError()); ok(handle != 0, "active context %p\n", handle); - pReleaseActCtx(handle); + ReleaseActCtx(handle); /* destination window will test for active context */ ret = SendMessageA(wnd_event.hwnd, WM_USER+10, 0, 0); @@ -8800,14 +10250,14 @@ static void test_interthread_messages(void) CloseHandle(event); ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0); - ok(ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError()); + ok(ret, "PostMessageA(WM_QUIT) error %ld\n", GetLastError()); ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); CloseHandle(hThread); - ret = pDeactivateActCtx(0, cookie); - ok(ret, "DeactivateActCtx failed: %u\n", GetLastError()); - pReleaseActCtx(context); + ret = DeactivateActCtx(0, cookie); + ok(ret, "DeactivateActCtx failed: %lu\n", GetLastError()); + ReleaseActCtx(context); } @@ -8883,16 +10333,17 @@ static const struct message WmAltVkN[] = { { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' }, { HCBT_SYSCOMMAND, hook }, { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 }, - { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { 0x00AE, sent|defwinproc|optional }, /* XP */ { WM_GETTEXT, sent|defwinproc|optional }, /* XP */ { WM_INITMENU, sent|defwinproc }, - { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 }, + { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 0 }, { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) }, + { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|wine_only, 0, 0 }, { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 }, { WM_CAPTURECHANGED, sent|defwinproc }, { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) }, - { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 }, + { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 0 }, { WM_EXITMENULOOP, sent|defwinproc }, { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */ { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */ @@ -9000,19 +10451,19 @@ static const struct message WmAltPressRelease[] = { { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 }, { HCBT_SYSCOMMAND, hook }, { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 }, - { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_INITMENU, sent|defwinproc }, - { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 }, + { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 0 }, { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) }, - { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 1 }, { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */ - { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 }, - { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 0 }, + { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0, }, { WM_CAPTURECHANGED, sent|defwinproc }, { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, - { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 }, + { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 0 }, { WM_EXITMENULOOP, sent|defwinproc }, { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */ { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 }, @@ -9027,11 +10478,13 @@ static const struct message WmShiftMouseButton[] = { { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 }, { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 }, { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 }, - { WM_LBUTTONUP, wparam, MK_SHIFT, 0 }, - { WM_LBUTTONUP, sent|wparam, MK_SHIFT, 0 }, + { WM_LBUTTONUP, wparam|optional, MK_SHIFT, 0 }, /* < w1064v1809 */ + { WM_LBUTTONUP, sent|wparam|optional, MK_SHIFT, 0 }, /* < w1064v1809 */ { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */ { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 }, { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 }, + { WM_LBUTTONUP, optional, 0, 0 }, /* >= w1064v1809 */ + { WM_LBUTTONUP, sent|optional, 0, 0 }, /* >= w1064v1809 */ { 0 } }; static const struct message WmF1Seq[] = { @@ -9067,20 +10520,20 @@ static const struct message WmVkF10Seq[] = { { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU }, { HCBT_SYSCOMMAND, hook }, { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 }, - { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_INITMENU, sent|defwinproc }, - { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 }, + { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 0 }, { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) }, - { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 1 }, { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0x10000001 }, /* XP */ { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */ - { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 }, - { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 0 }, + { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0, }, { WM_CAPTURECHANGED, sent|defwinproc }, { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, - { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 }, + { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 0 }, { WM_EXITMENULOOP, sent|defwinproc }, { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */ { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 }, @@ -9101,12 +10554,18 @@ static const struct message WmShiftF10Seq[] = { { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU }, { HCBT_SYSCOMMAND, hook }, { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 }, + { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_INITMENU, sent|defwinproc }, + { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 0 }, { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 1 }, { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xd0000001 }, /* XP */ { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0x10000001 }, /* XP */ + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 0 }, + { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_CAPTURECHANGED, sent|defwinproc|wparam|lparam, 0, 0 }, { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 }, + { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam|msg_todo, OBJID_SYSMENU, 0 }, { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 }, { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 }, /* XP */ { WM_KEYUP, wparam|lparam, VK_ESCAPE, 0xc0000001 }, @@ -9152,9 +10611,10 @@ static void test_accelerators(void) HACCEL hAccel; HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 200, 200, 0, 0, 0, NULL); + BOOL us_kbd = (GetKeyboardLayout(0) == (HKL)(ULONG_PTR)0x04090409); BOOL ret; - assert(hwnd != 0); + ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError()); UpdateWindow(hwnd); flush_events(); flush_sequence(); @@ -9168,13 +10628,19 @@ static void test_accelerators(void) ok(state == 0, "wrong CapsLock state %04x\n", state); hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1)); - assert(hAccel != 0); + ok(!!hAccel, "Failed to load accelerators, error %lu.\n", GetLastError()); flush_events(); pump_msg_loop(hwnd, 0); flush_sequence(); - trace("testing VK_N press/release\n"); + if (!us_kbd) + { + skip("skipping ascii VK events on non-us keyboard\n"); + goto done; + } + + if (winetest_debug > 1) trace("testing VK_N press/release\n"); flush_sequence(); keybd_event('N', 0, 0, 0); keybd_event('N', 0, KEYEVENTF_KEYUP, 0); @@ -9186,7 +10652,7 @@ static void test_accelerators(void) } ok_sequence(WmVkN, "VK_N press/release", FALSE); - trace("testing Shift+VK_N press/release\n"); + if (winetest_debug > 1) trace("testing Shift+VK_N press/release\n"); flush_sequence(); keybd_event(VK_SHIFT, 0, 0, 0); keybd_event('N', 0, 0, 0); @@ -9195,16 +10661,19 @@ static void test_accelerators(void) pump_msg_loop(hwnd, hAccel); ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE); - trace("testing Ctrl+VK_N press/release\n"); + if (winetest_debug > 1) trace("testing Ctrl+VK_N press/release\n"); flush_sequence(); keybd_event(VK_CONTROL, 0, 0, 0); keybd_event('N', 0, 0, 0); keybd_event('N', 0, KEYEVENTF_KEYUP, 0); keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0); pump_msg_loop(hwnd, hAccel); +#ifdef __REACTOS__ + if (0) // Test failures on WS03-Win10 1607 +#endif ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE); - trace("testing Alt+VK_N press/release\n"); + if (winetest_debug > 1) trace("testing Alt+VK_N press/release\n"); flush_sequence(); keybd_event(VK_MENU, 0, 0, 0); keybd_event('N', 0, 0, 0); @@ -9213,7 +10682,7 @@ static void test_accelerators(void) pump_msg_loop(hwnd, hAccel); ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE); - trace("testing Ctrl+Alt+VK_N press/release 1\n"); + if (winetest_debug > 1) trace("testing Ctrl+Alt+VK_N press/release 1\n"); flush_sequence(); keybd_event(VK_CONTROL, 0, 0, 0); keybd_event(VK_MENU, 0, 0, 0); @@ -9225,19 +10694,19 @@ static void test_accelerators(void) ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE); ret = DestroyAcceleratorTable(hAccel); - ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError()); + ok( ret, "DestroyAcceleratorTable error %ld\n", GetLastError()); hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(2)); - assert(hAccel != 0); + ok(!!hAccel, "Failed to load accelerators, error %lu.\n", GetLastError()); - trace("testing VK_N press/release\n"); + if (winetest_debug > 1) trace("testing VK_N press/release\n"); flush_sequence(); keybd_event('N', 0, 0, 0); keybd_event('N', 0, KEYEVENTF_KEYUP, 0); pump_msg_loop(hwnd, hAccel); ok_sequence(WmVkN, "VK_N press/release", FALSE); - trace("testing Shift+VK_N press/release\n"); + if (winetest_debug > 1) trace("testing Shift+VK_N press/release\n"); flush_sequence(); keybd_event(VK_SHIFT, 0, 0, 0); keybd_event('N', 0, 0, 0); @@ -9246,7 +10715,7 @@ static void test_accelerators(void) pump_msg_loop(hwnd, hAccel); ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE); - trace("testing Ctrl+VK_N press/release 2\n"); + if (winetest_debug > 1) trace("testing Ctrl+VK_N press/release 2\n"); flush_sequence(); keybd_event(VK_CONTROL, 0, 0, 0); keybd_event('N', 0, 0, 0); @@ -9255,7 +10724,7 @@ static void test_accelerators(void) pump_msg_loop(hwnd, hAccel); ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE); - trace("testing Alt+VK_N press/release 2\n"); + if (winetest_debug > 1) trace("testing Alt+VK_N press/release 2\n"); flush_sequence(); keybd_event(VK_MENU, 0, 0, 0); keybd_event('N', 0, 0, 0); @@ -9264,7 +10733,7 @@ static void test_accelerators(void) pump_msg_loop(hwnd, hAccel); ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE); - trace("testing Ctrl+Alt+VK_N press/release 2\n"); + if (winetest_debug > 1) trace("testing Ctrl+Alt+VK_N press/release 2\n"); flush_sequence(); keybd_event(VK_CONTROL, 0, 0, 0); keybd_event(VK_MENU, 0, 0, 0); @@ -9275,7 +10744,7 @@ static void test_accelerators(void) pump_msg_loop(hwnd, hAccel); ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE); - trace("testing Ctrl+Shift+VK_N press/release\n"); + if (winetest_debug > 1) trace("testing Ctrl+Shift+VK_N press/release\n"); flush_sequence(); keybd_event(VK_CONTROL, 0, 0, 0); keybd_event(VK_SHIFT, 0, 0, 0); @@ -9286,7 +10755,7 @@ static void test_accelerators(void) pump_msg_loop(hwnd, hAccel); ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE); - trace("testing Ctrl+Alt+Shift+VK_N press/release\n"); + if (winetest_debug > 1) trace("testing Ctrl+Alt+Shift+VK_N press/release\n"); flush_sequence(); keybd_event(VK_CONTROL, 0, 0, 0); keybd_event(VK_MENU, 0, 0, 0); @@ -9300,10 +10769,10 @@ static void test_accelerators(void) ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE); ret = DestroyAcceleratorTable(hAccel); - ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError()); + ok( ret, "DestroyAcceleratorTable error %ld\n", GetLastError()); hAccel = 0; - trace("testing Alt press/release\n"); + if (winetest_debug > 1) trace("testing Alt press/release\n"); flush_sequence(); keybd_event(VK_MENU, 0, 0, 0); keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0); @@ -9313,19 +10782,19 @@ static void test_accelerators(void) /* this test doesn't pass in Wine for managed windows */ ok_sequence(WmAltPressRelease, "Alt press/release", TRUE); - trace("testing VK_F1 press/release\n"); + if (winetest_debug > 1) trace("testing VK_F1 press/release\n"); keybd_event(VK_F1, 0, 0, 0); keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0); pump_msg_loop(hwnd, 0); ok_sequence(WmF1Seq, "F1 press/release", FALSE); - trace("testing VK_APPS press/release\n"); + if (winetest_debug > 1) trace("testing VK_APPS press/release\n"); keybd_event(VK_APPS, 0, 0, 0); keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0); pump_msg_loop(hwnd, 0); ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE); - trace("testing VK_F10 press/release\n"); + if (winetest_debug > 1) trace("testing VK_F10 press/release\n"); keybd_event(VK_F10, 0, 0, 0); keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0); keybd_event(VK_F10, 0, 0, 0); @@ -9333,7 +10802,7 @@ static void test_accelerators(void) pump_msg_loop(hwnd, 0); ok_sequence(WmVkF10Seq, "VK_F10 press/release", TRUE); - trace("testing SHIFT+F10 press/release\n"); + if (winetest_debug > 1) trace("testing SHIFT+F10 press/release\n"); keybd_event(VK_SHIFT, 0, 0, 0); keybd_event(VK_F10, 0, 0, 0); keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0); @@ -9343,7 +10812,7 @@ static void test_accelerators(void) pump_msg_loop(hwnd, 0); ok_sequence(WmShiftF10Seq, "SHIFT+F10 press/release", TRUE); - trace("testing Shift+MouseButton press/release\n"); + if (winetest_debug > 1) trace("testing Shift+MouseButton press/release\n"); /* first, move mouse pointer inside of the window client area */ GetClientRect(hwnd, &rc); MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2); @@ -9393,7 +10862,7 @@ static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, { LONG style = GetWindowLongA(hwnd, GWL_STYLE); ok((BOOL)wParam == !(style & WS_DISABLED), - "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED)); + "wrong WS_DISABLED state: %Id != %d\n", wParam, !(style & WS_DISABLED)); break; } @@ -9419,14 +10888,13 @@ static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, if (capture) { ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture); - trace("current capture %p, releasing...\n", capture); + if (winetest_debug > 1) trace("current capture %p, releasing...\n", capture); ReleaseCapture(); } } /* fall through */ case WM_DESTROY: - if (pGetAncestor) - ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n"); + ok(GetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n"); if (test_DestroyWindow_flag) { DWORD style = GetWindowLongA(hwnd, GWL_STYLE); @@ -9450,16 +10918,16 @@ static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, BOOL ret; handle = (void*)0xdeadbeef; - ret = pGetCurrentActCtx(&handle); - ok(ret, "failed to get current context, %u\n", GetLastError()); + ret = GetCurrentActCtx(&handle); + ok(ret, "failed to get current context, %lu\n", GetLastError()); ok(handle == 0, "got active context %p\n", handle); memset(&basicinfo, 0xff, sizeof(basicinfo)); - ret = pQueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, handle, 0, ActivationContextBasicInformation, + ret = QueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, handle, 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 == NULL, "got %p\n", basicinfo.hActCtx); - ok(basicinfo.dwFlags == 0, "got %x\n", basicinfo.dwFlags); + ok(basicinfo.dwFlags == 0, "got %lx\n", basicinfo.dwFlags); if (event) SetEvent(event); return 1; @@ -9471,7 +10939,8 @@ static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, case WM_NCMOUSEMOVE: case WM_SETCURSOR: case WM_IME_SELECT: - return 0; + if (ignore_mouse_messages) return 0; + break; } msg.hwnd = hwnd; @@ -9491,17 +10960,19 @@ static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, MINMAXINFO *minmax = (MINMAXINFO *)lParam; GetClientRect(parent, &rc); - trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom); - trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n", - minmax->ptReserved.x, minmax->ptReserved.y, - minmax->ptMaxSize.x, minmax->ptMaxSize.y, - minmax->ptMaxPosition.x, minmax->ptMaxPosition.y, - minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y, - minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y); - - ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n", + if (winetest_debug > 1) + { + trace("parent %p client size = (%ld x %ld)\n", parent, rc.right, rc.bottom); + trace("Reserved=%ld,%ld MaxSize=%ld,%ld MaxPos=%ld,%ld MinTrack=%ld,%ld MaxTrack=%ld,%ld\n", + minmax->ptReserved.x, minmax->ptReserved.y, + minmax->ptMaxSize.x, minmax->ptMaxSize.y, + minmax->ptMaxPosition.x, minmax->ptMaxPosition.y, + minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y, + minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y); + } + ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %ld != %ld\n", minmax->ptMaxSize.x, rc.right); - ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n", + ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %ld != %ld\n", minmax->ptMaxSize.y, rc.bottom); } @@ -9602,15 +11073,6 @@ static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam case WM_MOUSEMOVE: case WM_NCMOUSEMOVE: return 0; - - case WM_ERASEBKGND: - { - RECT rc; - INT ret = GetClipBox((HDC)wParam, &rc); - - trace("WM_ERASEBKGND: GetClipBox()=%d, %s\n", ret, wine_dbgstr_rect(&rc)); - break; - } } msg.hwnd = hwnd; @@ -9641,7 +11103,7 @@ static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam return message == WM_COMPAREITEM ? -1 : ret; } -static INT_PTR CALLBACK StopQuitMsgCheckProcA(HWND hwnd, UINT message, WPARAM wp, LPARAM lp) +static LRESULT CALLBACK StopQuitMsgCheckProcA(HWND hwnd, UINT message, WPARAM wp, LPARAM lp) { if (message == WM_CREATE) PostMessageA(hwnd, WM_CLOSE, 0, 0); @@ -9669,9 +11131,9 @@ static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARA DefDlgProcA(hwnd, DM_SETDEFID, 1, 0); ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0); if (after_end_dialog) - ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret ); + ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %Ix\n", ret ); else - ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret); + ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %Ix\n", ret); } msg.hwnd = hwnd; @@ -9733,48 +11195,6 @@ static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LP return ret; } -static LRESULT WINAPI recursive_activation_wndprocA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - static LONG defwndproc_counter = 0; - struct recvd_message msg; - LRESULT ret; - - switch (message) - { - /* log only specific messages we are interested in */ - case WM_NCACTIVATE: - case WM_ACTIVATE: - case WM_SETFOCUS: - case WM_KILLFOCUS: - break; - default: - return DefWindowProcA(hwnd, message, wParam, lParam); - } - - msg.hwnd = hwnd; - msg.message = message; - msg.flags = sent|wparam|lparam; - if (defwndproc_counter) msg.flags |= defwinproc; - msg.wParam = wParam; - msg.lParam = lParam; - msg.descr = "recursive_activation"; - add_message(&msg); - - /* recursively activate ourselves by first losing activation and changing it back */ - if (message == WM_ACTIVATE && LOWORD(wParam) != WA_INACTIVE) - { - SetActiveWindow((HWND)lParam); - SetActiveWindow(hwnd); - return 0; - } - - defwndproc_counter++; - ret = DefWindowProcA(hwnd, message, wParam, lParam); - defwndproc_counter--; - - return ret; -} - static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) @@ -9833,21 +11253,21 @@ static LRESULT WINAPI HotkeyMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam if (message == WM_APP) { queue_status = GetQueueStatus(QS_HOTKEY); - ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status); + ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %lx\n", queue_status); queue_status = GetQueueStatus(QS_POSTMESSAGE); - ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status); + ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %lx\n", queue_status); PostMessageA(hwnd, WM_APP+1, 0, 0); } else if (message == WM_APP+1) { queue_status = GetQueueStatus(QS_HOTKEY); - ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status); + ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %lx\n", queue_status); } return ret; } -static BOOL RegisterWindowClasses(void) +static void register_classes(void) { WNDCLASSA cls; WNDCLASSW clsW; @@ -9862,43 +11282,39 @@ static BOOL RegisterWindowClasses(void) cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = "TestWindowClass"; - if(!RegisterClassA(&cls)) return FALSE; + register_class(&cls); cls.lpfnWndProc = HotkeyMsgCheckProcA; cls.lpszClassName = "HotkeyWindowClass"; - if(!RegisterClassA(&cls)) return FALSE; + register_class(&cls); cls.lpfnWndProc = ShowWindowProcA; cls.lpszClassName = "ShowWindowClass"; - if(!RegisterClassA(&cls)) return FALSE; - - cls.lpfnWndProc = recursive_activation_wndprocA; - cls.lpszClassName = "RecursiveActivationClass"; - if(!RegisterClassA(&cls)) return FALSE; + register_class(&cls); cls.lpfnWndProc = PopupMsgCheckProcA; cls.lpszClassName = "TestPopupClass"; - if(!RegisterClassA(&cls)) return FALSE; + register_class(&cls); cls.lpfnWndProc = ParentMsgCheckProcA; cls.lpszClassName = "TestParentClass"; - if(!RegisterClassA(&cls)) return FALSE; + register_class(&cls); cls.lpfnWndProc = StopQuitMsgCheckProcA; cls.lpszClassName = "StopQuitClass"; - if(!RegisterClassA(&cls)) return FALSE; + register_class(&cls); cls.lpfnWndProc = DefWindowProcA; cls.lpszClassName = "SimpleWindowClass"; - if(!RegisterClassA(&cls)) return FALSE; + register_class(&cls); cls.lpfnWndProc = PaintLoopProcA; cls.lpszClassName = "PaintLoopWindowClass"; - if(!RegisterClassA(&cls)) return FALSE; + register_class(&cls); cls.style = CS_NOCLOSE; cls.lpszClassName = "NoCloseWindowClass"; - if(!RegisterClassA(&cls)) return FALSE; + register_class(&cls); ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n"); cls.style = 0; @@ -9906,7 +11322,12 @@ static BOOL RegisterWindowClasses(void) cls.hbrBackground = 0; cls.lpfnWndProc = TestDlgProcA; cls.lpszClassName = "TestDialogClass"; - if(!RegisterClassA(&cls)) return FALSE; + register_class(&cls); + + cls.lpfnWndProc = DefWindowProcA; + cls.style = CS_PARENTDC; + cls.lpszClassName = "SimpleWindowClassWithParentDC"; + register_class(&cls); clsW.style = 0; clsW.lpfnWndProc = MsgCheckProcW; @@ -9919,8 +11340,6 @@ static BOOL RegisterWindowClasses(void) clsW.lpszMenuName = NULL; clsW.lpszClassName = testWindowClassW; RegisterClassW(&clsW); /* ignore error, this fails on Win9x */ - - return TRUE; } static BOOL is_our_logged_class(HWND hwnd) @@ -9931,7 +11350,6 @@ static BOOL is_our_logged_class(HWND hwnd) { if (!lstrcmpiA(buf, "TestWindowClass") || !lstrcmpiA(buf, "ShowWindowClass") || - !lstrcmpiA(buf, "RecursiveActivationClass") || !lstrcmpiA(buf, "TestParentClass") || !lstrcmpiA(buf, "TestPopupClass") || !lstrcmpiA(buf, "SimpleWindowClass") || @@ -10019,7 +11437,7 @@ static void CALLBACK win_event_proc(HWINEVENTHOOK hevent, DWORD thread_id, DWORD event_time) { - ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n"); + ok(thread_id == winevent_hook_thread_id, "we didn't ask for events from other threads\n"); /* ignore mouse cursor events */ if (object_id == OBJID_CURSOR) return; @@ -10041,17 +11459,33 @@ static void CALLBACK win_event_proc(HWINEVENTHOOK hevent, static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0}; static const WCHAR wszAnsi[] = {'U',0}; +static const GUID iface_guid = {0x66666666}; + static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + const DEV_BROADCAST_DEVICEINTERFACE_A *ifaceA = (const void *)lParam; + switch (uMsg) { case CB_FINDSTRINGEXACT: - trace("String: %p\n", (LPCWSTR)lParam); if (!lstrcmpW((LPCWSTR)lParam, wszUnicode)) return 1; if (!lstrcmpW((LPCWSTR)lParam, wszAnsi)) return 0; return -1; + + case WM_DEVICECHANGE: + if (wParam == DBT_DEVICEARRIVAL && IsEqualGUID(&ifaceA->dbcc_classguid, &iface_guid)) + { + DWORD expect_size = offsetof(DEV_BROADCAST_DEVICEINTERFACE_A, dbcc_name[strlen(ifaceA->dbcc_name)]); + + ok(ifaceA->dbcc_size == expect_size, "Expected %lu, got %lu.\n", expect_size, ifaceA->dbcc_size); + ok(ifaceA->dbcc_devicetype == DBT_DEVTYP_DEVICEINTERFACE, + "Got notification type %#lx.\n", ifaceA->dbcc_devicetype); + ok(!ifaceA->dbcc_reserved, "Got reserved %#lx.\n", ifaceA->dbcc_reserved); + ok(!strcmp(ifaceA->dbcc_name, "test name"), "Got name %s.\n", debugstr_a(ifaceA->dbcc_name)); + return 2; + } } return DefWindowProcW(hwnd, uMsg, wParam, lParam); } @@ -10083,6 +11517,8 @@ static void test_message_conversion(void) { static const WCHAR wszMsgConversionClass[] = {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0}; + char buffer[200]; + DEV_BROADCAST_DEVICEINTERFACE_A *dev_interface = (void *)buffer; WNDCLASSW cls; LRESULT lRes; HWND hwnd; @@ -10135,54 +11571,67 @@ static void test_message_conversion(void) SetLastError(0); lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode); ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER), - "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError()); + "PostMessage on sync only message returned %Id, last error %ld\n", lRes, GetLastError()); SetLastError(0); lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode); ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER), - "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError()); + "PostMessage on sync only message returned %Id, last error %ld\n", lRes, GetLastError()); SetLastError(0); lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode); ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER), - "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError()); + "PosThreadtMessage on sync only message returned %Id, last error %ld\n", lRes, GetLastError()); SetLastError(0); lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode); ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER), - "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError()); + "PosThreadtMessage on sync only message returned %Id, last error %ld\n", lRes, GetLastError()); SetLastError(0); lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode); ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER), - "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError()); + "SendNotifyMessage on sync only message returned %Id, last error %ld\n", lRes, GetLastError()); SetLastError(0); lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode); ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER), - "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError()); + "SendNotifyMessage on sync only message returned %Id, last error %ld\n", lRes, GetLastError()); SetLastError(0); lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0); ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER), - "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError()); + "SendMessageCallback on sync only message returned %Id, last error %ld\n", lRes, GetLastError()); SetLastError(0); lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0); ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER), - "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError()); + "SendMessageCallback on sync only message returned %Id, last error %ld\n", lRes, GetLastError()); + + /* Test WM_DEVICECHANGE. */ + + dev_interface->dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + dev_interface->dbcc_reserved = 0; + dev_interface->dbcc_classguid = iface_guid; + strcpy(dev_interface->dbcc_name, "test name"); + dev_interface->dbcc_size = offsetof(DEV_BROADCAST_DEVICEINTERFACE_A, + dbcc_name[strlen(dev_interface->dbcc_name)]); + lRes = SendMessageA(hwnd, WM_DEVICECHANGE, DBT_DEVICEARRIVAL, (LPARAM)dev_interface); + ok(lRes == 2, "Got %Id, error %lu.\n", lRes, GetLastError()); + + DestroyWindow(hwnd); /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */ hwnd = CreateWindowW (testWindowClassW, wszUnicode, WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL); - assert(hwnd); + ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError()); flush_sequence(); lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0); ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE); ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ), - "got bad length %ld\n", lRes ); + "got bad length %Id\n", lRes ); flush_sequence(); lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_GETTEXTLENGTH, 0, 0); ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE); ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ), - "got bad length %ld\n", lRes ); + "got bad length %Id\n", lRes ); wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc ); newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ); @@ -10190,17 +11639,17 @@ static void test_message_conversion(void) ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text), NULL, 0, NULL, NULL ) || broken(lRes == lstrlenW(dummy_window_text) + 37), - "got bad length %ld\n", lRes ); + "got bad length %Id\n", lRes ); SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc ); /* restore old wnd proc */ lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 ); ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text), NULL, 0, NULL, NULL ) || broken(lRes == lstrlenW(dummy_window_text) + 37), - "got bad length %ld\n", lRes ); + "got bad length %Id\n", lRes ); ret = DestroyWindow(hwnd); - ok( ret, "DestroyWindow() error %d\n", GetLastError()); + ok( ret, "DestroyWindow() error %ld\n", GetLastError()); } struct timer_info @@ -10214,20 +11663,67 @@ static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime) { } -#define TIMER_ID 0x19 -#define TIMER_COUNT_EXPECTED 100 -#define TIMER_COUNT_TOLERANCE 10 +#define TIMER_ID 0x19 +#define TIMER_COUNT 500 /* 499 samples */ +#define TIMER_DURATION_EXPECTED 10000 /* 10 ms */ +#define TIMER_DURATION_ALT 15600 /* 15.6 ms */ +#define TIMER_DURATION_TOLERANCE 1000 /* 1 ms */ static int count = 0; +static ULONGLONG timer_ticks[TIMER_COUNT]; +static int timer_duration = 0; + +static int compare_ulonglong(const void *a, const void *b) +{ + ULONGLONG la, lb; + la = *(ULONGLONG*)a; + lb = *(ULONGLONG*)b; + return (la > lb) - (la < lb); +} + +static void timer_fired(void) +{ + if (count < TIMER_COUNT) + { + LARGE_INTEGER performance_counter; + BOOL ret; + + ret = QueryPerformanceCounter(&performance_counter); + ok(ret, "QueryPerformanceCounter failed\n"); + + timer_ticks[count] = performance_counter.QuadPart; + } + + count++; + + if (count == TIMER_COUNT) + { + LARGE_INTEGER performance_frequency; + BOOL ret; + + /* calculate durations */ + for (int i=0; i < TIMER_COUNT-1; i++) + timer_ticks[i] = timer_ticks[i+1] - timer_ticks[i]; + + qsort(timer_ticks, TIMER_COUNT - 1, sizeof(timer_ticks[0]), compare_ulonglong); + + ret = QueryPerformanceFrequency(&performance_frequency); + ok(ret, "QueryPerformanceFrequency failed\n"); + + /* median duration, converted to microseconds */ + timer_duration = (int)(timer_ticks[(TIMER_COUNT - 1) / 2] * 1000000 / performance_frequency.QuadPart); + } +} + static void CALLBACK callback_count(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { - count++; + timer_fired(); } static DWORD exception; static void CALLBACK callback_exception(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { - count++; + timer_fired(); RaiseException(exception, 0, 0, NULL); } @@ -10249,7 +11745,6 @@ static DWORD WINAPI timer_thread_proc(LPVOID x) static void test_timers(void) { struct timer_info info; - DWORD start; DWORD id; MSG msg; @@ -10275,47 +11770,37 @@ static void test_timers(void) /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms, * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to - * 15.6 ms. Since there is some measurement error between test runs we are allowing for - * ±9 counts (~4 ms) around the expected value. + * 15.6 ms. */ count = 0; id = SetTimer(info.hWnd, TIMER_ID, 0, callback_count); ok(id != 0, "did not get id from SetTimer.\n"); ok(id==TIMER_ID, "SetTimer timer ID different\n"); - start = GetTickCount(); - while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0)) + while (count < TIMER_COUNT && GetMessageA(&msg, info.hWnd, 0, 0)) DispatchMessageA(&msg); -ros_skip_flaky -todo_wine - ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */ - || broken(abs(count-64) < TIMER_COUNT_TOLERANCE) /* most common */ - || broken(abs(count-43) < TIMER_COUNT_TOLERANCE) /* w2k3, win8 */, - "did not get expected count for minimum timeout (%d != ~%d).\n", - count, TIMER_COUNT_EXPECTED); + ok(abs(timer_duration-TIMER_DURATION_EXPECTED) < TIMER_DURATION_TOLERANCE /* xp, win7 */ + || broken(abs(timer_duration - TIMER_DURATION_ALT) < TIMER_DURATION_TOLERANCE) /* most common */, + "did not get expected median timeout (%d != ~%d).\n", + timer_duration, TIMER_DURATION_EXPECTED); ok(KillTimer(info.hWnd, id), "KillTimer failed\n"); /* Perform the same check on SetSystemTimer (only available on w2k3 and older) */ if (pSetSystemTimer) { - int syscount = 0; - count = 0; id = pSetSystemTimer(info.hWnd, TIMER_ID, 0, callback_count); ok(id != 0, "did not get id from SetSystemTimer.\n"); ok(id==TIMER_ID, "SetTimer timer ID different\n"); - start = GetTickCount(); - while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0)) + while (count < TIMER_COUNT && GetMessageA(&msg, info.hWnd, 0, 0)) { if (msg.message == WM_SYSTIMER) - syscount++; + timer_fired(); + ok(msg.message != WM_TIMER, "unexpected WM_TIMER\n"); DispatchMessageA(&msg); } - ok(abs(syscount-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE - || broken(abs(syscount-64) < TIMER_COUNT_TOLERANCE) /* most common */ - || broken(syscount > 4000 && syscount < 12000) /* win2k3sp0 */, - "did not get expected count for minimum timeout (%d != ~%d).\n", - syscount, TIMER_COUNT_EXPECTED); - todo_wine ok(count == 0, "did not get expected count for callback timeout (%d != 0).\n", - count); + ok(abs(timer_duration-TIMER_DURATION_EXPECTED) < TIMER_DURATION_TOLERANCE + || broken(abs(timer_duration - TIMER_DURATION_ALT) < TIMER_DURATION_TOLERANCE) /* most common */, + "did not get expected median timeout (%d != ~%d).\n", + timer_duration, TIMER_DURATION_EXPECTED); ok(pKillSystemTimer(info.hWnd, id), "KillSystemTimer failed\n"); } @@ -10334,7 +11819,7 @@ static void test_timers_no_wnd(void) id = SetTimer(NULL, 0, 100, callback_count); ok(id != 0, "did not get id from SetTimer.\n"); id2 = SetTimer(NULL, id, 200, callback_count); - ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id); + ok(id2 == id, "did not get same id from SetTimer when replacing (%Ii expected %Ii).\n", id2, id); Sleep(150); while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); ok(count == 0, "did not get zero count as expected (%i).\n", count); @@ -10348,20 +11833,17 @@ static void test_timers_no_wnd(void) /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms, * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to - * 15.6 ms. Since there is some measurement error between test runs we are allowing for - * ±9 counts (~4 ms) around the expected value. + * 15.6 ms. */ count = 0; id = SetTimer(NULL, 0, 0, callback_count); ok(id != 0, "did not get id from SetTimer.\n"); - start = GetTickCount(); - while (GetTickCount()-start < 1001 && GetMessageA(&msg, NULL, 0, 0)) + while (count < TIMER_COUNT && GetMessageA(&msg, NULL, 0, 0)) DispatchMessageA(&msg); -todo_wine - ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */ - || broken(abs(count-64) < TIMER_COUNT_TOLERANCE) /* most common */, - "did not get expected count for minimum timeout (%d != ~%d).\n", - count, TIMER_COUNT_EXPECTED); + ok(abs(timer_duration-TIMER_DURATION_EXPECTED) < TIMER_DURATION_TOLERANCE /* xp */ + || broken(abs(timer_duration - TIMER_DURATION_ALT) < TIMER_DURATION_TOLERANCE) /* most common */, + "did not get expected median timeout (%d != ~%d).\n", + timer_duration, TIMER_DURATION_EXPECTED); KillTimer(NULL, id); /* Note: SetSystemTimer doesn't support a NULL window, see test_timers */ @@ -10369,7 +11851,7 @@ todo_wine { count = 0; id = pSetCoalescableTimer(NULL, 0, 0, callback_count, 0); - ok(id != 0, "SetCoalescableTimer failed with %u.\n", GetLastError()); + ok(id != 0, "SetCoalescableTimer failed with %lu.\n", GetLastError()); start = GetTickCount(); while (GetTickCount()-start < 100 && GetMessageA(&msg, NULL, 0, 0)) DispatchMessageA(&msg); @@ -10388,7 +11870,7 @@ todo_wine } ok(i != ARRAY_SIZE(ids), "all timers were created successfully\n"); ok(GetLastError()==ERROR_NO_MORE_USER_HANDLES || broken(GetLastError()==0xdeadbeef), - "GetLastError() = %d\n", GetLastError()); + "GetLastError() = %ld\n", GetLastError()); while (i > 0) KillTimer(NULL, ids[--i]); } @@ -10599,11 +12081,9 @@ static DWORD WINAPI win_event_global_thread_proc(void *param) MSG msg; HANDLE hevent = *(HANDLE *)param; - assert(pNotifyWinEvent); - hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL); - assert(hwnd); - trace("created thread window %p\n", hwnd); + ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError()); + if (winetest_debug > 1) trace("created thread window %p\n", hwnd); *(HWND *)param = hwnd; @@ -10634,8 +12114,8 @@ static DWORD WINAPI cbt_global_hook_thread_proc(void *param) */ hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL); - assert(hwnd); - trace("created thread window %p\n", hwnd); + ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError()); + if (winetest_debug > 1) trace("created thread window %p\n", hwnd); *(HWND *)param = hwnd; @@ -10665,8 +12145,8 @@ static DWORD WINAPI mouse_ll_global_thread_proc(void *param) HANDLE hevent = *(HANDLE *)param; hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL); - assert(hwnd); - trace("created thread window %p\n", hwnd); + ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError()); + if (winetest_debug > 1) trace("created thread window %p\n", hwnd); *(HWND *)param = hwnd; @@ -10704,7 +12184,7 @@ static void test_winevents(void) WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0, NULL, NULL, 0); - assert(hwnd); + ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError()); /****** start of global hook test *************/ hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0); @@ -10716,11 +12196,11 @@ static void test_winevents(void) } hevent = CreateEventA(NULL, 0, 0, NULL); - assert(hevent); + ok(!!hevent, "Failed to create event, error %lu.\n", GetLastError()); hwnd2 = hevent; hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid); - ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError()); + ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError()); ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); @@ -10735,7 +12215,7 @@ static void test_winevents(void) ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE); ret = UnhookWindowsHookEx(hCBT_global_hook); - ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError()); + ok( ret, "UnhookWindowsHookEx error %ld\n", GetLastError()); PostThreadMessageA(tid, WM_QUIT, 0, 0); ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); @@ -10760,7 +12240,7 @@ static void test_winevents(void) pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam); ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */ GetLastError() == 0xdeadbeef, /* Win9x */ - "unexpected error %d\n", GetLastError()); + "unexpected error %ld\n", GetLastError()); ok_sequence(WmEmptySeq, "empty notify winevents", FALSE); } @@ -10776,14 +12256,14 @@ static void test_winevents(void) GetModuleHandleA(0), win_event_global_hook_proc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT); - ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError()); + ok(hhook != 0, "SetWinEventHook error %ld\n", GetLastError()); hevent = CreateEventA(NULL, 0, 0, NULL); - assert(hevent); + ok(!!hevent, "Failed to create event, error %lu.\n", GetLastError()); hwnd2 = hevent; hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid); - ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError()); + ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError()); ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); @@ -10799,7 +12279,7 @@ static void test_winevents(void) ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE); ret = pUnhookWinEvent(hhook); - ok( ret, "UnhookWinEvent error %d\n", GetLastError()); + ok( ret, "UnhookWinEvent error %ld\n", GetLastError()); PostThreadMessageA(tid, WM_QUIT, 0, 0); ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); @@ -10812,16 +12292,16 @@ static void test_winevents(void) hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_global_hook_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT); - ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError()); + ok(hhook != 0, "SetWinEventHook error %ld\n", GetLastError()); hevent = CreateEventA(NULL, 0, 0, NULL); - assert(hevent); + ok(!!hevent, "Failed to create event, error %lu.\n", GetLastError()); hwnd2 = hevent; flush_sequence(); hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid); - ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError()); + ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError()); ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); @@ -10843,7 +12323,7 @@ static void test_winevents(void) ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE); ret = pUnhookWinEvent(hhook); - ok( ret, "UnhookWinEvent error %d\n", GetLastError()); + ok( ret, "UnhookWinEvent error %ld\n", GetLastError()); PostThreadMessageA(tid, WM_QUIT, 0, 0); ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); @@ -10862,11 +12342,11 @@ static void test_winevents(void) } hevent = CreateEventA(NULL, 0, 0, NULL); - assert(hevent); + ok(!!hevent, "Failed to create event, error %lu.\n", GetLastError()); hwnd2 = hevent; hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid); - ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError()); + ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError()); while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT) while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg ); @@ -10881,7 +12361,7 @@ static void test_winevents(void) ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE); ret = UnhookWindowsHookEx(hCBT_global_hook); - ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError()); + ok( ret, "UnhookWindowsHookEx error %ld\n", GetLastError()); PostThreadMessageA(tid, WM_QUIT, 0, 0); ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); @@ -10894,37 +12374,132 @@ skip_mouse_ll_hook_test: ok(DestroyWindow(hwnd), "failed to destroy window\n"); } +static char *get_test_dll_path(void) +{ + static const char *dll_name = "testdll.dll"; + static char path[MAX_PATH]; + DWORD written; + HANDLE file; + HRSRC res; + void *ptr; + + GetTempPathA(ARRAY_SIZE(path), path); + strcat(path, dll_name); + + file = CreateFileA(path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "Failed to create file %s: %lu.\n", debugstr_a(path), GetLastError()); + + res = FindResourceA(NULL, dll_name, "TESTDLL"); +#ifdef __REACTOS__ + ok(!!res || broken(GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND) /* WS03 */, "Failed to load resource: %lu\n", GetLastError()); +#else + ok(!!res, "Failed to load resource: %lu\n", GetLastError()); +#endif + ptr = LockResource(LoadResource(GetModuleHandleA(NULL), res)); + WriteFile(file, ptr, SizeofResource(GetModuleHandleA(NULL), res), &written, NULL); + ok(written == SizeofResource(GetModuleHandleA(NULL), res), "Failed to write resource\n"); + CloseHandle(file); + + return path; +} + static void test_set_hook(void) { + LRESULT (CALLBACK *p_dummy_hook_proc)(int code, WPARAM wp, LPARAM lp); + HMODULE test_dll_module; + char *test_dll_path; + DWORD error; BOOL ret; HHOOK hhook; HWINEVENTHOOK hwinevent_hook; + int i; hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId()); ok(hhook != 0, "local hook does not require hModule set to 0\n"); UnhookWindowsHookEx(hhook); - if (0) - { - /* this test doesn't pass under Win9x: BUG! */ SetLastError(0xdeadbeef); hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0); ok(!hhook, "global hook requires hModule != 0\n"); - ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError()); - } + ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %ld\n", GetLastError()); + + SetLastError(0xdeadbeef); + hhook = SetWindowsHookExA(WH_JOURNALRECORD, cbt_hook_proc, 0, 0); +#ifdef __REACTOS__ + ok(!hhook || broken(GetNTVersion() == _WIN32_WINNT_VISTA || GetNTVersion() == _WIN32_WINNT_WIN7), "global hook requires hModule != 0\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED + || broken(GetLastError() == ERROR_HOOK_NEEDS_HMOD) /* WS03 */ + || broken(GetLastError() == 0xdeadbeef) /* Vista */, + "unexpected error %ld\n", GetLastError()); +#else + ok(!hhook, "global hook requires hModule != 0\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED, "unexpected error %ld\n", GetLastError()); +#endif SetLastError(0xdeadbeef); hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId()); ok(!hhook, "SetWinEventHook with invalid proc should fail\n"); - ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */ - GetLastError() == 0xdeadbeef, /* Win9x */ - "unexpected error %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_FILTER_PROC, "unexpected error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n"); - ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */ - GetLastError() == 0xdeadbeef, /* Win9x */ - "unexpected error %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE, "unexpected error %ld\n", GetLastError()); + + test_dll_path = get_test_dll_path(); + test_dll_module = LoadLibraryA(test_dll_path); + p_dummy_hook_proc = (void *)GetProcAddress(test_dll_module, "dummy_hook_proc"); +#ifdef __REACTOS__ + /* Test failures on WS03-Win 10 1607 */ + if (0) { +#endif + for (i = WH_MIN; i <= WH_MAX; i++) + { + winetest_push_context("ID %d", i); + + /* Test that setting hooks should succeed for hook procs in a library. But for WH_JOURNALRECORD + * and WH_JOURNALPLAYBACK, ERROR_ACCESS_DENIED is returned, even with administrator rights */ + SetLastError(0xdeadbeef); + hhook = SetWindowsHookExA(i, p_dummy_hook_proc, test_dll_module, 0); + error = GetLastError(); + if (i == WH_JOURNALRECORD || i == WH_JOURNALPLAYBACK) + { + ok(!hhook, "SetWinEventHook succeeded.\n"); + ok(error == ERROR_ACCESS_DENIED, "Got unexpected error %ld.\n", GetLastError()); + } + else + { + ok(!!hhook, "SetWinEventHook failed.\n"); + ok(error == NO_ERROR, "Got unexpected error %ld.\n", GetLastError()); + } + if (hhook) + UnhookWindowsHookEx(hhook); + + /* Test settings global hooks with a thread ID */ + SetLastError(0xdeadbeef); + hhook = SetWindowsHookExA(i, p_dummy_hook_proc, test_dll_module, GetCurrentThreadId()); + error = GetLastError(); + if (i == WH_JOURNALRECORD || i == WH_JOURNALPLAYBACK || i == WH_SYSMSGFILTER + || i == WH_KEYBOARD_LL || i == WH_MOUSE_LL) + { + ok(!hhook, "SetWinEventHook succeeded.\n"); + ok(error == ERROR_GLOBAL_ONLY_HOOK, "Got unexpected error %ld.\n", GetLastError()); + } + else + { + ok(!!hhook, "SetWinEventHook failed.\n"); + ok(error == NO_ERROR, "Got unexpected error %ld.\n", GetLastError()); + } + if (hhook) + UnhookWindowsHookEx(hhook); + + winetest_pop_context(); + } +#ifdef __REACTOS__ + } +#endif + FreeLibrary(test_dll_module); + ret = DeleteFileA(test_dll_path); + ok(ret, "Failed to remove the test dll, error %ld.\n", GetLastError()); if (!pSetWinEventHook || !pUnhookWinEvent) return; @@ -10933,48 +12508,41 @@ static void test_set_hook(void) hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT); ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n"); - ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */ - GetLastError() == 0xdeadbeef, /* Win9x */ - "unexpected error %d\n", GetLastError()); + ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %ld\n", GetLastError()); /* even thread local incontext hooks require hmodule */ SetLastError(0xdeadbeef); hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc, GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT); ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n"); - ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */ - GetLastError() == 0xdeadbeef, /* Win9x */ - "unexpected error %d\n", GetLastError()); + ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %ld\n", GetLastError()); - if (0) - { - /* these 3 tests don't pass under Win9x */ SetLastError(0xdeadbeef); hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT); ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n"); - ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %ld\n", GetLastError()); SetLastError(0xdeadbeef); hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT); ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n"); - ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %ld\n", GetLastError()); SetLastError(0xdeadbeef); hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc, 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT); ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n"); - ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError()); - } + todo_wine + ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %ld\n", GetLastError()); SetLastError(0xdeadbeef); hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT); - ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError()); - ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError()); + ok(hwinevent_hook != 0, "SetWinEventHook error %ld\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "unexpected error %ld\n", GetLastError()); ret = pUnhookWinEvent(hwinevent_hook); - ok( ret, "UnhookWinEvent error %d\n", GetLastError()); + ok( ret, "UnhookWinEvent error %ld\n", GetLastError()); todo_wine { /* This call succeeds under win2k SP4, but fails under Wine. @@ -10982,22 +12550,43 @@ todo_wine { SetLastError(0xdeadbeef); hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc, 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT); - ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError()); - ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError()); + ok(hwinevent_hook != 0, "SetWinEventHook error %ld\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "unexpected error %ld\n", GetLastError()); ret = pUnhookWinEvent(hwinevent_hook); - ok( ret, "UnhookWinEvent error %d\n", GetLastError()); + ok( ret, "UnhookWinEvent error %ld\n", GetLastError()); } SetLastError(0xdeadbeef); ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n"); - ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */ - GetLastError() == 0xdeadbeef, /* Win9x */ - "unexpected error %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HANDLE, "unexpected error %ld\n", GetLastError()); } static HWND hook_hwnd; static HHOOK recursive_hook; static int hook_depth, max_hook_depth; +static BOOL skip_WH_KEYBOARD_hook, skip_WH_MOUSE_hook; + +static void simulate_click(BOOL left, int x, int y) +{ + POINT old_pt; + INPUT input[2]; + UINT events_no; + + GetCursorPos(&old_pt); + SetCursorPos(x, y); + memset(input, 0, sizeof(input)); + input[0].type = INPUT_MOUSE; + input[0].mi.dx = x; + input[0].mi.dy = y; + input[0].mi.dwFlags = left ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_RIGHTDOWN; + input[1].type = INPUT_MOUSE; + input[1].mi.dx = x; + input[1].mi.dy = y; + input[1].mi.dwFlags = left ? MOUSEEVENTF_LEFTUP : MOUSEEVENTF_RIGHTUP; + events_no = SendInput(2, input, sizeof(input[0])); + ok(events_no == 2, "SendInput returned %d\n", events_no); + SetCursorPos(old_pt.x, old_pt.y); +} static LRESULT WINAPI rec_get_message_hook(int code, WPARAM w, LPARAM l) { @@ -11018,12 +12607,91 @@ static LRESULT WINAPI rec_get_message_hook(int code, WPARAM w, LPARAM l) return res; } +static LRESULT CALLBACK keyboard_recursive_hook_proc(int code, WPARAM wp, LPARAM lp) +{ + MSG msg; + + if (code < 0) + return CallNextHookEx(0, code, wp, lp); + + if (skip_WH_KEYBOARD_hook) + return 1; + + hook_depth++; + max_hook_depth = max(max_hook_depth, hook_depth); + PeekMessageW(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE); + hook_depth--; + return CallNextHookEx(0, code, wp, lp); +} + +static LRESULT CALLBACK mouse_recursive_hook_proc(int code, WPARAM wp, LPARAM lp) +{ + MSG msg; + + if (code < 0) + return CallNextHookEx(0, code, wp, lp); + + if (skip_WH_MOUSE_hook) + return 1; + + hook_depth++; + max_hook_depth = max(max_hook_depth, hook_depth); + PeekMessageW(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE); + hook_depth--; + return CallNextHookEx(0, code, wp, lp); +} + +static LRESULT CALLBACK keyboard_recursive_cbt_hook_proc(int code, WPARAM wp, LPARAM lp) +{ + MSG msg; + + if (code < 0) + return CallNextHookEx(0, code, wp, lp); + + if (code == HCBT_KEYSKIPPED) + { + hook_depth++; + max_hook_depth = max(max_hook_depth, hook_depth); + PeekMessageW(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE); + hook_depth--; + } + + return CallNextHookEx(0, code, wp, lp); +} + +static LRESULT CALLBACK mouse_recursive_cbt_hook_proc(int code, WPARAM wp, LPARAM lp) +{ + MSG msg; + + if (code < 0) + return CallNextHookEx(0, code, wp, lp); + + if (code == HCBT_CLICKSKIPPED) + { + hook_depth++; + max_hook_depth = max(max_hook_depth, hook_depth); + PeekMessageW(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE); + hook_depth--; + } + + return CallNextHookEx(0, code, wp, lp); +} + static void test_recursive_hook(void) { + HHOOK hook, cbt_hook; + INPUT input = {0}; MSG msg; BOOL b; - hook_hwnd = CreateWindowA("Static", NULL, WS_POPUP, 0, 0, 200, 60, NULL, NULL, NULL, NULL); +#ifdef __REACTOS__ + if (is_reactos()) { + ok(FALSE, "FIXME: Recursive msg tests crash on ReactOS!\n"); + return; + } +#endif + hook_hwnd = CreateWindowExA(WS_EX_TOPMOST, "Static", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 200, 60, + NULL, NULL, NULL, NULL); ok(hook_hwnd != NULL, "CreateWindow failed\n"); recursive_hook = SetWindowsHookExW(WH_GETMESSAGE, rec_get_message_hook, NULL, GetCurrentThreadId()); @@ -11035,14 +12703,136 @@ static void test_recursive_hook(void) hook_depth = 0; GetMessageW(&msg, hook_hwnd, 0, 0); ok(15 <= max_hook_depth && max_hook_depth < 45, "max_hook_depth = %d\n", max_hook_depth); - trace("max_hook_depth = %d\n", max_hook_depth); + if (winetest_debug > 1) trace("max_hook_depth = %d\n", max_hook_depth); b = UnhookWindowsHookEx(recursive_hook); ok(b, "UnhokWindowsHookEx failed\n"); + /* Test possible recursive hook conditions */ + b = SetForegroundWindow(hook_hwnd); + ok(b, "SetForegroundWindow failed, error %ld.\n", GetLastError()); + + /* Test a possible recursive WH_KEYBOARD hook condition */ + max_hook_depth = 0; + hook = SetWindowsHookExA(WH_KEYBOARD, keyboard_recursive_hook_proc, NULL, GetCurrentThreadId()); + ok(!!hook, "SetWindowsHookExA failed, error %ld.\n", GetLastError()); + + flush_events(); + input.type = INPUT_KEYBOARD; + input.ki.wVk = VK_F3; + SendInput(1, &input, sizeof(INPUT)); + flush_events(); + + /* Expect the WH_KEYBOARD hook not gets called recursively */ + ok(max_hook_depth == 1, "Got expected %d.\n", max_hook_depth); + + /* Test a possible recursive WH_CBT HCBT_KEYSKIPPED hook condition */ + max_hook_depth = 0; + skip_WH_KEYBOARD_hook = 1; + cbt_hook = SetWindowsHookExA(WH_CBT, keyboard_recursive_cbt_hook_proc, NULL, GetCurrentThreadId()); + ok(!!cbt_hook, "SetWindowsHookExA failed, error %ld.\n", GetLastError()); + + flush_events(); + input.type = INPUT_KEYBOARD; + input.ki.wVk = VK_F3; + SendInput(1, &input, sizeof(INPUT)); + while (PeekMessageA(&msg, hook_hwnd, WM_KEYFIRST, WM_KEYLAST, 0)) DispatchMessageA(&msg); + + /* Expect the WH_CBT HCBT_KEYSKIPPED hook not gets called recursively */ + ok(max_hook_depth == 1, "Got expected %d.\n", max_hook_depth); + + UnhookWindowsHookEx(cbt_hook); + UnhookWindowsHookEx(hook); + + /* Test a recursive WH_MOUSE hook condition */ + SetCapture(hook_hwnd); + + max_hook_depth = 0; + hook = SetWindowsHookExA(WH_MOUSE, mouse_recursive_hook_proc, NULL, GetCurrentThreadId()); + ok(!!hook, "SetWindowsHookExA failed, error %ld.\n", GetLastError()); + + flush_events(); + simulate_click(FALSE, 50, 50); + flush_events(); + + /* Expect the WH_MOUSE hook gets called recursively */ + ok(max_hook_depth > 10, "Got expected %d.\n", max_hook_depth); + + /* Test a possible recursive WH_CBT HCBT_CLICKSKIPPED hook condition */ + max_hook_depth = 0; + skip_WH_MOUSE_hook = 1; + cbt_hook = SetWindowsHookExA(WH_CBT, mouse_recursive_cbt_hook_proc, NULL, GetCurrentThreadId()); + ok(!!cbt_hook, "SetWindowsHookExA failed, error %ld.\n", GetLastError()); + + flush_events(); + simulate_click(FALSE, 50, 50); + flush_events(); + + /* Expect the WH_CBT HCBT_CLICKSKIPPED hook not gets called recursively */ + ok(max_hook_depth <= 10, "Got expected %d.\n", max_hook_depth); + + UnhookWindowsHookEx(cbt_hook); + UnhookWindowsHookEx(hook); + ReleaseCapture(); DestroyWindow(hook_hwnd); } +static int max_msg_depth; + +static LRESULT WINAPI recursive_messages_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp) +{ + static int msg_depth; + MSG msg; + + if (message == WM_SETCURSOR && max_msg_depth < 15) + { + msg_depth++; + max_msg_depth = max(max_msg_depth, msg_depth); + PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE); + msg_depth--; + } + return DefWindowProcA(hwnd, message, wp, lp); +} + +static void test_recursive_messages(void) +{ + WNDCLASSA cls = {0}; + HWND hwnd; + +#ifdef __REACTOS__ + if (is_reactos()) { + ok(FALSE, "FIXME: Recursive msg tests crash on ReactOS!\n"); + return; + } +#endif + cls.lpfnWndProc = recursive_messages_proc; + cls.hInstance = GetModuleHandleA(0); + cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); + cls.hbrBackground = GetStockObject(WHITE_BRUSH); + cls.lpszClassName = "TestRecursiveMsgClass"; + register_class(&cls); + + hwnd = CreateWindowExA(WS_EX_TOPMOST, "TestRecursiveMsgClass", NULL, WS_POPUP | WS_DISABLED | WS_VISIBLE, 0, 0, + 100, 100, NULL, NULL, NULL, NULL); + ok(hwnd != NULL, "CreateWindowExA failed, error %ld.\n", GetLastError()); + SetForegroundWindow(hwnd); + flush_events(); + + max_msg_depth = 0; + simulate_click(FALSE, 50, 50); + flush_events(); + + /* Expect recursive_messages_proc() gets called recursively for WM_SETCURSOR */ +#ifdef __REACTOS__ + ok(max_msg_depth == 15 || broken(max_msg_depth == 14) /* 64-bit */, "Got expected %d.\n", max_msg_depth); +#else + ok(max_msg_depth == 15, "Got expected %d.\n", max_msg_depth); +#endif + + DestroyWindow(hwnd); + UnregisterClassA(cls.lpszClassName, cls.hInstance); +} + static const struct message ScrollWindowPaint1[] = { { WM_PAINT, sent }, { WM_ERASEBKGND, sent|beginpaint }, @@ -11080,11 +12870,11 @@ static void test_scrollwindowex(void) flush_sequence(); /* scroll without the child window */ - trace("start scroll\n"); + if (winetest_debug > 1) trace("start scroll\n"); ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_ERASE|SW_INVALIDATE); ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE); - trace("end scroll\n"); + if (winetest_debug > 1) trace("end scroll\n"); flush_sequence(); flush_events(); ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE); @@ -11092,10 +12882,10 @@ static void test_scrollwindowex(void) flush_sequence(); /* Now without the SW_ERASE flag */ - trace("start scroll\n"); + if (winetest_debug > 1) trace("start scroll\n"); ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE); ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE); - trace("end scroll\n"); + if (winetest_debug > 1) trace("end scroll\n"); flush_sequence(); flush_events(); ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", FALSE); @@ -11103,13 +12893,13 @@ static void test_scrollwindowex(void) flush_sequence(); /* now scroll the child window as well */ - trace("start scroll\n"); + if (winetest_debug > 1) trace("start scroll\n"); ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE); /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */ /* windows sometimes a WM_MOVE */ ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE); - trace("end scroll\n"); + if (winetest_debug > 1) trace("end scroll\n"); flush_sequence(); flush_events(); ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE); @@ -11117,9 +12907,9 @@ static void test_scrollwindowex(void) flush_sequence(); /* now scroll with ScrollWindow() */ - trace("start scroll with ScrollWindow\n"); + if (winetest_debug > 1) trace("start scroll with ScrollWindow\n"); ScrollWindow( hwnd, 5, 5, NULL, NULL); - trace("end scroll\n"); + if (winetest_debug > 1) trace("end scroll\n"); flush_sequence(); flush_events(); ok_sequence(ScrollWindowPaint1, "ScrollWindow", FALSE); @@ -11135,8 +12925,9 @@ static const struct message destroy_window_with_children[] = { { 0x0090, sent|optional }, { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */ { 0x0090, sent|optional }, - { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */ + { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, /* popup */ { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */ + { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam|wine_only, 0, 0 }, /* popup */ { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */ { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */ { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */ @@ -11159,28 +12950,26 @@ static void test_DestroyWindow(void) parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL); - assert(parent != 0); + ok(!!parent, "Failed to create window, error %lu.\n", GetLastError()); child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD, 0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL); - assert(child1 != 0); + ok(!!child1, "Failed to create window, error %lu.\n", GetLastError()); child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD, 0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL); - assert(child2 != 0); + ok(!!child2, "Failed to create window, error %lu.\n", GetLastError()); child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD, 0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL); - assert(child3 != 0); + ok(!!child3, "Failed to create window, error %lu.\n", GetLastError()); child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP, 0, 0, 50, 50, parent, 0, 0, NULL); - assert(child4 != 0); + ok(!!child4, "Failed to create window, error %lu.\n", GetLastError()); /* test owner/parent of child2 */ test = GetParent(child2); ok(test == GetDesktopWindow(), "wrong parent %p\n", test); ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2); - if(pGetAncestor) { - test = pGetAncestor(child2, GA_PARENT); - ok(test == GetDesktopWindow(), "wrong parent %p\n", test); - } + test = GetAncestor(child2, GA_PARENT); + ok(test == GetDesktopWindow(), "wrong parent %p\n", test); test = GetWindow(child2, GW_OWNER); ok(!test, "wrong owner %p\n", test); @@ -11191,10 +12980,8 @@ static void test_DestroyWindow(void) test = GetParent(parent); ok(!test, "wrong parent %p\n", test); ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent); - if(pGetAncestor) { - test = pGetAncestor(parent, GA_PARENT); - ok(test == GetDesktopWindow(), "wrong parent %p\n", test); - } + test = GetAncestor(parent, GA_PARENT); + ok(test == GetDesktopWindow(), "wrong parent %p\n", test); test = GetWindow(parent, GW_OWNER); ok(!test, "wrong owner %p\n", test); @@ -11202,10 +12989,8 @@ static void test_DestroyWindow(void) test = GetParent(child1); ok(test == parent, "wrong parent %p\n", test); ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1); - if(pGetAncestor) { - test = pGetAncestor(child1, GA_PARENT); - ok(test == parent, "wrong parent %p\n", test); - } + test = GetAncestor(child1, GA_PARENT); + ok(test == parent, "wrong parent %p\n", test); test = GetWindow(child1, GW_OWNER); ok(!test, "wrong owner %p\n", test); @@ -11213,10 +12998,8 @@ static void test_DestroyWindow(void) test = GetParent(child2); ok(test == parent, "wrong parent %p\n", test); ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2); - if(pGetAncestor) { - test = pGetAncestor(child2, GA_PARENT); - ok(test == parent, "wrong parent %p\n", test); - } + test = GetAncestor(child2, GA_PARENT); + ok(test == parent, "wrong parent %p\n", test); test = GetWindow(child2, GW_OWNER); ok(!test, "wrong owner %p\n", test); @@ -11224,10 +13007,8 @@ static void test_DestroyWindow(void) test = GetParent(child3); ok(test == child1, "wrong parent %p\n", test); ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3); - if(pGetAncestor) { - test = pGetAncestor(child3, GA_PARENT); - ok(test == child1, "wrong parent %p\n", test); - } + test = GetAncestor(child3, GA_PARENT); + ok(test == child1, "wrong parent %p\n", test); test = GetWindow(child3, GW_OWNER); ok(!test, "wrong owner %p\n", test); @@ -11235,16 +13016,14 @@ static void test_DestroyWindow(void) test = GetParent(child4); ok(test == parent, "wrong parent %p\n", test); ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4); - if(pGetAncestor) { - test = pGetAncestor(child4, GA_PARENT); - ok(test == GetDesktopWindow(), "wrong parent %p\n", test); - } + test = GetAncestor(child4, GA_PARENT); + ok(test == GetDesktopWindow(), "wrong parent %p\n", test); test = GetWindow(child4, GW_OWNER); ok(test == parent, "wrong owner %p\n", test); flush_sequence(); - trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n", + if (winetest_debug > 1) trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n", parent, child1, child2, child3, child4); SetCapture(child4); @@ -11253,7 +13032,7 @@ static void test_DestroyWindow(void) test_DestroyWindow_flag = TRUE; ret = DestroyWindow(parent); - ok( ret, "DestroyWindow() error %d\n", GetLastError()); + ok( ret, "DestroyWindow() error %ld\n", GetLastError()); test_DestroyWindow_flag = FALSE; ok_sequence(destroy_window_with_children, "destroy window with children", FALSE); @@ -11313,7 +13092,7 @@ static void test_DispatchMessage(void) } ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" ); - trace("now without DispatchMessage\n"); + if (winetest_debug > 1) trace("now without DispatchMessage\n"); flush_sequence(); RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME ); count = 0; @@ -11368,16 +13147,18 @@ struct sendmsg_info HWND hwnd; DWORD timeout; DWORD ret; + HANDLE ready; }; static DWORD CALLBACK send_msg_thread( LPVOID arg ) { struct sendmsg_info *info = arg; SetLastError( 0xdeadbeef ); + SetEvent( info->ready ); info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL ); if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT || broken(GetLastError() == 0), /* win9x */ - "unexpected error %d\n", GetLastError()); + "unexpected error %ld\n", GetLastError()); return 0; } @@ -11403,6 +13184,7 @@ static void test_SendMessageTimeout(void) DWORD tid; BOOL is_win9x; + info.ready = CreateEventA( NULL, 0, 0, NULL ); info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL); flush_events(); @@ -11410,7 +13192,9 @@ static void test_SendMessageTimeout(void) info.timeout = 1000; info.ret = 0xdeadbeef; + ResetEvent( info.ready ); thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid ); + WaitForSingleObject( info.ready, INFINITE ); wait_for_thread( thread ); CloseHandle( thread ); ok( info.ret == 1, "SendMessageTimeout failed\n" ); @@ -11418,7 +13202,9 @@ static void test_SendMessageTimeout(void) info.timeout = 1; info.ret = 0xdeadbeef; + ResetEvent( info.ready ); thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid ); + WaitForSingleObject( info.ready, INFINITE ); Sleep(100); /* SendMessageTimeout should time out here */ wait_for_thread( thread ); CloseHandle( thread ); @@ -11428,7 +13214,9 @@ static void test_SendMessageTimeout(void) /* 0 means infinite timeout (but not on win9x) */ info.timeout = 0; info.ret = 0xdeadbeef; + ResetEvent( info.ready ); thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid ); + WaitForSingleObject( info.ready, INFINITE ); Sleep(100); wait_for_thread( thread ); CloseHandle( thread ); @@ -11439,7 +13227,9 @@ static void test_SendMessageTimeout(void) /* timeout is treated as signed despite the prototype (but not on win9x) */ info.timeout = 0x7fffffff; info.ret = 0xdeadbeef; + ResetEvent( info.ready ); thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid ); + WaitForSingleObject( info.ready, INFINITE ); Sleep(100); wait_for_thread( thread ); CloseHandle( thread ); @@ -11448,7 +13238,9 @@ static void test_SendMessageTimeout(void) info.timeout = 0x80000000; info.ret = 0xdeadbeef; + ResetEvent( info.ready ); thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid ); + WaitForSingleObject( info.ready, INFINITE ); Sleep(100); wait_for_thread( thread ); CloseHandle( thread ); @@ -11467,7 +13259,9 @@ static void test_SendMessageTimeout(void) SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc ); info.timeout = 100; info.ret = 0xdeadbeef; + ResetEvent( info.ready ); thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid ); + WaitForSingleObject( info.ready, INFINITE ); wait_for_thread( thread ); CloseHandle( thread ); /* we should time out but still get the message */ @@ -11475,6 +13269,7 @@ static void test_SendMessageTimeout(void) ok_sequence( WmUser, "WmUser", FALSE ); DestroyWindow( info.hwnd ); + CloseHandle( info.ready ); } @@ -11485,14 +13280,15 @@ static const struct message sl_edit_setfocus[] = { HCBT_SETFOCUS, hook }, { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { EM_GETPASSWORDCHAR, sent|optional }, /* Sent on some Win10 machines */ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|wparam, 0 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 }, { WM_CTLCOLOREDIT, sent|parent }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 }, - { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, - { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 }, { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) }, { 0 } }; @@ -11501,9 +13297,13 @@ static const struct message sl_edit_invisible[] = { HCBT_SETFOCUS, hook }, { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, - { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Sent for IME. */ { WM_KILLFOCUS, sent|parent }, + { EM_GETPASSWORDCHAR, sent|optional }, /* Sent on some Win10 machines */ + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 }, { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) }, { 0 } }; @@ -11512,22 +13312,24 @@ static const struct message ml_edit_setfocus[] = { HCBT_SETFOCUS, hook }, { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { EM_GETPASSWORDCHAR, sent|optional }, /* Sent on some Win10 machines */ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|wparam, 0 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 }, - { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, - { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CARET, 0 }, { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) }, { 0 } }; static const struct message sl_edit_killfocus[] = { { HCBT_SETFOCUS, hook }, - { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { WM_KILLFOCUS, sent|wparam, 0 }, - { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, - { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, + { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 }, + { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 }, { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) }, { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 }, @@ -11542,24 +13344,26 @@ static const struct message sl_edit_lbutton_dblclk[] = static const struct message sl_edit_lbutton_down[] = { { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 }, + { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|wine_only, 0, 0 }, { HCBT_SETFOCUS, hook }, { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { EM_GETPASSWORDCHAR, sent|defwinproc|optional }, /* Sent on some Win10 machines */ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|wparam|defwinproc, 0 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 }, { WM_CTLCOLOREDIT, sent|parent }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 }, - { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, - { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CARET, 0 }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 }, { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) }, - { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, - { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, + { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 }, { WM_CTLCOLOREDIT, sent|parent|optional }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, - { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CARET, 0 }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 }, { 0 } }; static const struct message ml_edit_lbutton_down[] = @@ -11569,22 +13373,23 @@ static const struct message ml_edit_lbutton_down[] = { HCBT_SETFOCUS, hook }, { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { EM_GETPASSWORDCHAR, sent|defwinproc|optional }, /* Sent on some Win10 machines */ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|wparam|defwinproc, 0 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 }, - { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, - { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 }, { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) }, { 0 } }; static const struct message sl_edit_lbutton_up[] = { { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 }, - { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, + { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 }, { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 }, { WM_CAPTURECHANGED, sent|defwinproc }, - { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 }, { 0 } }; static const struct message ml_edit_lbutton_up[] = @@ -11621,11 +13426,263 @@ static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, L return ret; } +static const struct message edit_wm_ime_composition_seq[] = +{ + {WM_IME_STARTCOMPOSITION, sent}, + {WM_IME_COMPOSITION, sent | wparam, 'W'}, + {WM_IME_CHAR, sent | wparam | defwinproc, 'W'}, + {WM_IME_CHAR, sent | wparam | defwinproc, 'i'}, + {WM_IME_CHAR, sent | wparam | defwinproc, 'n'}, + {WM_IME_CHAR, sent | wparam | defwinproc, 'e'}, + {WM_IME_ENDCOMPOSITION, sent}, + {WM_CHAR, sent | wparam, 'W'}, + {WM_CHAR, sent | wparam, 'i'}, + {WM_CHAR, sent | wparam, 'n'}, + {WM_CHAR, sent | wparam, 'e'}, + {0} +}; + +static const struct message edit_wm_ime_composition_korean_seq[] = +{ + {WM_IME_ENDCOMPOSITION, sent}, + {WM_IME_COMPOSITION, sent | wparam, 'W'}, + {WM_IME_CHAR, sent | wparam | defwinproc, 'W'}, + {WM_IME_CHAR, sent | wparam | defwinproc, 'i'}, + {WM_IME_CHAR, sent | wparam | defwinproc, 'n'}, + {WM_IME_CHAR, sent | wparam | defwinproc, 'e'}, + {WM_CHAR, sent | wparam, 'W'}, + {WM_CHAR, sent | wparam, 'i'}, + {WM_CHAR, sent | wparam, 'n'}, + {WM_CHAR, sent | wparam, 'e'}, + {0} +}; + +static const struct message edit_wm_ime_char_seq[] = +{ + {WM_IME_CHAR, sent | wparam, '0'}, + {WM_CHAR, sent | wparam, '0'}, + {0} +}; + +static const struct message edit_eimes_getcompstratonce_seq[] = +{ + {WM_IME_STARTCOMPOSITION, sent}, + {WM_IME_COMPOSITION, sent | wparam, 'W'}, + {WM_IME_ENDCOMPOSITION, sent}, + {0} +}; + +static const struct message edit_eimes_getcompstratonce_korean_seq[] = +{ + {WM_IME_ENDCOMPOSITION, sent}, + {WM_IME_COMPOSITION, sent | wparam, 'W'}, + {0} +}; + +static LRESULT CALLBACK edit_ime_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); + static LONG defwndproc_counter = 0; + struct recvd_message msg = {0}; + LRESULT ret; + + msg.message = message; + msg.flags = sent | wparam; + if (defwndproc_counter) + msg.flags |= defwinproc; + msg.wParam = wParam; + + if (message < 0xc000 && + message != WM_GETTEXTLENGTH && + message != WM_GETTEXT && + message != WM_GETFONT && + message != WM_GETICON && + message != WM_IME_SETCONTEXT && + message != WM_IME_NOTIFY && + message != WM_CTLCOLOREDIT && + message != WM_PAINT && + message != WM_ERASEBKGND && + message != WM_NCHITTEST && + message != WM_SETCURSOR && + message != WM_MOUSEMOVE && + message != WM_MOUSEACTIVATE && + message != WM_KEYUP && + (message < EM_GETSEL || message > EM_GETIMESTATUS)) + { + add_message(&msg); + } + + defwndproc_counter++; + if (IsWindowUnicode(hwnd)) + ret = CallWindowProcW(oldproc, hwnd, message, wParam, lParam); + else + ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam); + defwndproc_counter--; + + return ret; +} + +static DWORD WINAPI test_edit_ime_messages(void *unused_arg) +{ + static const HKL korean_hkl = (HKL)0x04120412; + WNDPROC old_proc; + LRESULT lr; + HIMC himc; + HWND hwnd; + BOOL ret; + HKL hkl; + MSG msg; + + hkl = GetKeyboardLayout(0); + + hwnd = CreateWindowA(WC_EDITA, "Test", WS_POPUP | WS_VISIBLE, 10, 10, 300, 300, NULL, NULL, + NULL, NULL); + ok(hwnd != NULL, "CreateWindowA failed.\n"); + + /* Test EM_{GET|SET}IMESTATUS */ + lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); + ok(lr == 0, "Got unexpected lr %#Ix.\n", lr); + + /* Note that EM_SETIMESTATUS always return 1, which is contrary to what MSDN says about + * returning the previous LPARAM value */ + lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_GETCOMPSTRATONCE); + ok(lr == 1, "Got unexpected lr %#Ix.\n", lr); + lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); + ok(lr == EIMES_GETCOMPSTRATONCE, "Got unexpected lr %#Ix.\n", lr); + + lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_CANCELCOMPSTRINFOCUS); + ok(lr == 1, "Got unexpected lr %#Ix.\n", lr); + lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); + ok(lr == EIMES_CANCELCOMPSTRINFOCUS, "Got unexpected lr %#Ix.\n", lr); + + lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_COMPLETECOMPSTRKILLFOCUS); + ok(lr == 1, "Got unexpected lr %#Ix.\n", lr); + lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); + ok(lr == EIMES_COMPLETECOMPSTRKILLFOCUS, "Got unexpected lr %#Ix.\n", lr); + + lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_GETCOMPSTRATONCE + | EIMES_CANCELCOMPSTRINFOCUS | EIMES_COMPLETECOMPSTRKILLFOCUS); + ok(lr == 1, "Got unexpected lr %#Ix.\n", lr); + lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); + ok(lr == (EIMES_GETCOMPSTRATONCE | EIMES_CANCELCOMPSTRINFOCUS | EIMES_COMPLETECOMPSTRKILLFOCUS), + "Got unexpected lr %#Ix.\n", lr); + + lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); + ok(lr == 1, "Got unexpected lr %#Ix.\n", lr); + lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); + ok(lr == 0, "Got unexpected lr %#Ix.\n", lr); + + /* Invalid EM_{GET|SET}IMESTATUS status types and flags */ + lr = SendMessageA(hwnd, EM_GETIMESTATUS, 0, 0); + ok(lr == 1, "Got unexpected lr %#Ix.\n", lr); + + lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING + 1, 0); + ok(lr == 1, "Got unexpected lr %#Ix.\n", lr); + + lr = SendMessageA(hwnd, EM_SETIMESTATUS, 0, EIMES_GETCOMPSTRATONCE); + ok(lr == 1, "Got unexpected lr %#Ix.\n", lr); + lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); + ok(lr == 0, "Got unexpected lr %#Ix.\n", lr); + + lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING + 1, EIMES_GETCOMPSTRATONCE); + ok(lr == 1, "Got unexpected lr %#Ix.\n", lr); + lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); + ok(lr == 0, "Got unexpected lr %#Ix.\n", lr); + + lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0xFFFFFFFF); + ok(lr == 1, "Got unexpected lr %#Ix.\n", lr); + lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); + ok(lr == 0xFFFF, "Got unexpected lr %#Ix.\n", lr); + + lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); + ok(lr == 1, "Got unexpected lr %#Ix.\n", lr); + lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); + ok(lr == 0, "Got unexpected lr %#Ix.\n", lr); + + /* Test IME messages when EIMES_GETCOMPSTRATONCE is not set */ + old_proc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)edit_ime_subclass_proc); + SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)old_proc); + + himc = ImmGetContext(hwnd); + ret = ImmSetCompositionStringA(himc, SCS_SETSTR, "Wine", 4, NULL, 0); +#ifdef __REACTOS__ + ok(ret || broken(GetNTVersion() < _WIN32_WINNT_VISTA), "ImmSetCompositionStringA failed.\n"); +#else + ok(ret, "ImmSetCompositionStringA failed.\n"); +#endif + flush_sequence(); + ret = ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); +#ifdef __REACTOS__ + ok(ret || broken(GetNTVersion() < _WIN32_WINNT_VISTA), "ImmNotifyIME failed.\n"); +#else + ok(ret, "ImmNotifyIME failed.\n"); +#endif + /* Note that the following message loop is necessary to get the WM_CHAR messages because they + * are posted. Same for the later message loops in this function. */ + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + if (hkl == korean_hkl) + ok_sequence(edit_wm_ime_composition_korean_seq, + "korean WM_IME_COMPOSITION", TRUE); + else +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) +#endif + ok_sequence(edit_wm_ime_composition_seq, "WM_IME_COMPOSITION", TRUE); + + /* Test that WM_IME_CHAR is passed to DefWindowProc() to get WM_CHAR */ + flush_sequence(); + SendMessageA(hwnd, WM_IME_CHAR, '0', 1); + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + ok_sequence(edit_wm_ime_char_seq, "WM_IME_CHAR", FALSE); + + /* Test IME messages when EIMES_GETCOMPSTRATONCE is set */ + lr = SendMessageA(hwnd, EM_SETIMESTATUS, EMSIS_COMPOSITIONSTRING, EIMES_GETCOMPSTRATONCE); + ok(lr == 1, "Got unexpected lr %#Ix.\n", lr); + lr = SendMessageA(hwnd, EM_GETIMESTATUS, EMSIS_COMPOSITIONSTRING, 0); + ok(lr == EIMES_GETCOMPSTRATONCE, "Got unexpected lr %#Ix.\n", lr); + + ret = ImmSetCompositionStringA(himc, SCS_SETSTR, "Wine", 4, NULL, 0); +#ifdef __REACTOS__ + ok(ret || broken(GetNTVersion() < _WIN32_WINNT_VISTA), "ImmSetCompositionStringA failed.\n"); +#else + ok(ret, "ImmSetCompositionStringA failed.\n"); +#endif + flush_sequence(); + ret = ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); +#ifdef __REACTOS__ + ok(ret || broken(GetNTVersion() < _WIN32_WINNT_VISTA), "ImmNotifyIME failed.\n"); +#else + ok(ret, "ImmNotifyIME failed.\n"); +#endif + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + if (hkl == korean_hkl) + ok_sequence(edit_eimes_getcompstratonce_korean_seq, + "korean WM_IME_COMPOSITION with EIMES_GETCOMPSTRATONCE", TRUE); + else +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) +#endif + ok_sequence(edit_eimes_getcompstratonce_seq, + "WM_IME_COMPOSITION with EIMES_GETCOMPSTRATONCE", TRUE); + + /* Test that WM_IME_CHAR is passed to DefWindowProc() to get WM_CHAR with EIMES_GETCOMPSTRATONCE */ + flush_sequence(); + SendMessageA(hwnd, WM_IME_CHAR, '0', 1); + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + ok_sequence(edit_wm_ime_char_seq, "WM_IME_CHAR", FALSE); + + ImmReleaseContext(hwnd, himc); + DestroyWindow(hwnd); + return 0; +} + static void subclass_edit(void) { WNDCLASSA cls; + BOOL ret; - if (!GetClassInfoA(0, "edit", &cls)) assert(0); + ret = GetClassInfoA(0, "edit", &cls); + ok(ret, "Failed to get class info, error %lu.\n", GetLastError()); old_edit_proc = cls.lpfnWndProc; @@ -11633,14 +13690,22 @@ static void subclass_edit(void) cls.lpfnWndProc = edit_hook_proc; cls.lpszClassName = "my_edit_class"; UnregisterClassA(cls.lpszClassName, cls.hInstance); - if (!RegisterClassA(&cls)) assert(0); + register_class(&cls); } static void test_edit_messages(void) { HWND hwnd, parent; DWORD dlg_code; + HANDLE thread; +#ifdef __REACTOS__ + /* test_edit_messages() crashes on Windows Vista and Windows 7 */ + if (!is_reactos() && (GetNTVersion() >= _WIN32_WINNT_VISTA && GetNTVersion() <= _WIN32_WINNT_WIN7)) { + skip("This test crashes on Windows Vista and Windows 7.\n"); + return; + } +#endif subclass_edit(); log_all_parent_messages++; @@ -11654,7 +13719,7 @@ static void test_edit_messages(void) ok(hwnd != 0, "Failed to create edit window\n"); dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0); - ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code); + ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08lx\n", dlg_code); flush_sequence(); SetFocus(hwnd); @@ -11697,7 +13762,7 @@ static void test_edit_messages(void) dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0); ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS), - "wrong dlg_code %08x\n", dlg_code); + "wrong dlg_code %08lx\n", dlg_code); ShowWindow(hwnd, SW_SHOW); UpdateWindow(hwnd); @@ -11731,6 +13796,11 @@ static void test_edit_messages(void) DestroyWindow(parent); log_all_parent_messages--; + + /* Test IME messages in another thread because IME is disabled in the current thread */ + thread = CreateThread(NULL, 0, test_edit_ime_messages, NULL, 0, NULL); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); } /**************************** End of Edit test ******************************/ @@ -11772,7 +13842,7 @@ static DWORD CALLBACK send_msg_thread_2(void *param) DWORD ret; struct peekmsg_info *info = param; - trace("thread: looping\n"); + if (winetest_debug > 1) trace("thread: looping\n"); SetEvent(info->hevent[EV_ACK]); while (1) @@ -11782,19 +13852,18 @@ static DWORD CALLBACK send_msg_thread_2(void *param) switch (ret) { case WAIT_OBJECT_0 + EV_STOP: - trace("thread: exiting\n"); + if (winetest_debug > 1) trace("thread: exiting\n"); return 0; case WAIT_OBJECT_0 + EV_SENDMSG: - trace("thread: sending message\n"); + if (winetest_debug > 1) trace("thread: sending message\n"); ret = SendNotifyMessageA(info->hwnd, WM_USER, 0, 0); - ok(ret, "SendNotifyMessageA failed error %u\n", GetLastError()); + ok(ret, "SendNotifyMessageA failed error %lu\n", GetLastError()); SetEvent(info->hevent[EV_ACK]); break; default: - trace("unexpected return: %04x\n", ret); - assert(0); + ok(0, "Unexpected return %#lx.\n", ret); break; } } @@ -11808,12 +13877,12 @@ static void test_PeekMessage(void) DWORD tid, qstatus; UINT qs_all_input = QS_ALLINPUT; UINT qs_input = QS_INPUT; - BOOL ret; + BOOL ret, broken_flags = FALSE; struct peekmsg_info info; info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL); - assert(info.hwnd); + ok(!!info.hwnd, "Failed to create window, error %lu.\n", GetLastError()); ShowWindow(info.hwnd, SW_SHOW); UpdateWindow(info.hwnd); SetFocus(info.hwnd); @@ -11835,30 +13904,41 @@ static void test_PeekMessage(void) trace("QS_RAWINPUT not supported on this platform\n"); qs_all_input &= ~QS_RAWINPUT; qs_input &= ~QS_RAWINPUT; + + SetLastError(0xdeadbeef); + qstatus = GetQueueStatus(qs_all_input); + if (GetLastError() == ERROR_INVALID_FLAGS) + broken_flags = TRUE; + ok(GetLastError() == 0xdeadbeef || broken(GetLastError() == ERROR_INVALID_FLAGS) /* win7 */, + "wrong error %ld\n", GetLastError()); } if (qstatus & QS_POSTMESSAGE) { while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ; qstatus = GetQueueStatus(qs_all_input); } - ok(qstatus == 0, "wrong qstatus %08x\n", qstatus); + ok(qstatus == 0, "wrong qstatus %08lx\n", qstatus); - trace("signalling to send message\n"); + if (winetest_debug > 1) trace("signalling to send message\n"); SetEvent(info.hevent[EV_SENDMSG]); WaitForSingleObject(info.hevent[EV_ACK], INFINITE); /* pass invalid QS_xxxx flags */ SetLastError(0xdeadbeef); qstatus = GetQueueStatus(0xffffffff); - ok(qstatus == 0 || broken(qstatus) /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus); + ok(qstatus == 0 || broken(qstatus) /* win9x */, "GetQueueStatus should fail: %08lx\n", qstatus); if (!qstatus) { - ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %ld\n", GetLastError()); + SetLastError(0xdeadbeef); qstatus = GetQueueStatus(qs_all_input); + ok(GetLastError() == 0xdeadbeef || broken(broken_flags && GetLastError() == ERROR_INVALID_FLAGS), + "wrong error %ld\n", GetLastError()); } qstatus &= ~MAKELONG( 0x4000, 0x4000 ); /* sometimes set on Win95 */ - ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE), - "wrong qstatus %08x\n", qstatus); + ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE) || + broken(broken_flags && qstatus == 0), + "wrong qstatus %08lx\n", qstatus); msg.message = 0; ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE); @@ -11868,7 +13948,7 @@ static void test_PeekMessage(void) ok_sequence(WmUser, "WmUser", FALSE); qstatus = GetQueueStatus(qs_all_input); - ok(qstatus == 0, "wrong qstatus %08x\n", qstatus); + ok(qstatus == 0, "wrong qstatus %08lx\n", qstatus); keybd_event('N', 0, 0, 0); keybd_event('N', 0, KEYEVENTF_KEYUP, 0); @@ -11881,27 +13961,27 @@ static void test_PeekMessage(void) ok(qstatus == MAKELONG(QS_KEY, QS_KEY) || /* keybd_event seems to trigger a sent message on NT4 */ qstatus == MAKELONG(QS_KEY|QS_SENDMESSAGE, QS_KEY|QS_SENDMESSAGE), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); PostMessageA(info.hwnd, WM_CHAR, 'z', 0); qstatus = GetQueueStatus(qs_all_input); ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY) || qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); InvalidateRect(info.hwnd, NULL, FALSE); qstatus = GetQueueStatus(qs_all_input); ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY) || qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); - trace("signalling to send message\n"); + if (winetest_debug > 1) trace("signalling to send message\n"); SetEvent(info.hevent[EV_SENDMSG]); WaitForSingleObject(info.hevent[EV_ACK], INFINITE); qstatus = GetQueueStatus(qs_all_input); ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); msg.message = 0; ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16)); @@ -11922,15 +14002,15 @@ static void test_PeekMessage(void) qstatus = GetQueueStatus(qs_all_input); ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); - trace("signalling to send message\n"); + if (winetest_debug > 1) trace("signalling to send message\n"); SetEvent(info.hevent[EV_SENDMSG]); WaitForSingleObject(info.hevent[EV_ACK], INFINITE); qstatus = GetQueueStatus(qs_all_input); ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); msg.message = 0; ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE ); @@ -11941,18 +14021,18 @@ static void test_PeekMessage(void) qstatus = GetQueueStatus(qs_all_input); ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); msg.message = 0; ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE); ok(ret && msg.message == WM_CHAR && msg.wParam == 'z', - "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n", + "got %d and %04x wParam %08Ix instead of TRUE and WM_CHAR wParam 'z'\n", ret, msg.message, msg.wParam); ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE); qstatus = GetQueueStatus(qs_all_input); ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); msg.message = 0; ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE); @@ -11963,7 +14043,7 @@ static void test_PeekMessage(void) qstatus = GetQueueStatus(qs_all_input); ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); msg.message = 0; ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT); @@ -11974,7 +14054,7 @@ static void test_PeekMessage(void) qstatus = GetQueueStatus(qs_all_input); ok(qstatus == MAKELONG(0, QS_KEY), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); msg.message = 0; ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT); @@ -11985,32 +14065,32 @@ static void test_PeekMessage(void) qstatus = GetQueueStatus(qs_all_input); ok(qstatus == MAKELONG(0, QS_KEY), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); - trace("signalling to send message\n"); + if (winetest_debug > 1) trace("signalling to send message\n"); SetEvent(info.hevent[EV_SENDMSG]); WaitForSingleObject(info.hevent[EV_ACK], INFINITE); qstatus = GetQueueStatus(qs_all_input); ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); PostMessageA(info.hwnd, WM_CHAR, 'z', 0); qstatus = GetQueueStatus(qs_all_input); ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); msg.message = 0; ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE); ok(ret && msg.message == WM_CHAR && msg.wParam == 'z', - "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n", + "got %d and %04x wParam %08Ix instead of TRUE and WM_CHAR wParam 'z'\n", ret, msg.message, msg.wParam); ok_sequence(WmUser, "WmUser", FALSE); qstatus = GetQueueStatus(qs_all_input); ok(qstatus == MAKELONG(0, QS_KEY), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); msg.message = 0; ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE); @@ -12021,21 +14101,21 @@ static void test_PeekMessage(void) qstatus = GetQueueStatus(qs_all_input); ok(qstatus == MAKELONG(0, QS_KEY), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); PostMessageA(info.hwnd, WM_CHAR, 'z', 0); qstatus = GetQueueStatus(qs_all_input); ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); - trace("signalling to send message\n"); + if (winetest_debug > 1) trace("signalling to send message\n"); SetEvent(info.hevent[EV_SENDMSG]); WaitForSingleObject(info.hevent[EV_ACK], INFINITE); qstatus = GetQueueStatus(qs_all_input); ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); msg.message = 0; ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16)); @@ -12046,7 +14126,7 @@ static void test_PeekMessage(void) qstatus = GetQueueStatus(qs_all_input); ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); msg.message = 0; if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */ @@ -12054,13 +14134,13 @@ static void test_PeekMessage(void) else /* workaround for a missing QS_RAWINPUT support */ ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE); ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N', - "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n", + "got %d and %04x wParam %08Ix instead of TRUE and WM_KEYDOWN wParam 'N'\n", ret, msg.message, msg.wParam); ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE); qstatus = GetQueueStatus(qs_all_input); ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); msg.message = 0; if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */ @@ -12068,13 +14148,13 @@ static void test_PeekMessage(void) else /* workaround for a missing QS_RAWINPUT support */ ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE); ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N', - "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n", + "got %d and %04x wParam %08Ix instead of TRUE and WM_KEYUP wParam 'N'\n", ret, msg.message, msg.wParam); ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE); qstatus = GetQueueStatus(qs_all_input); ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); msg.message = 0; ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE); @@ -12085,18 +14165,18 @@ static void test_PeekMessage(void) qstatus = GetQueueStatus(qs_all_input); ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); msg.message = 0; ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE); ok(ret && msg.message == WM_CHAR && msg.wParam == 'z', - "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n", + "got %d and %04x wParam %08Ix instead of TRUE and WM_CHAR wParam 'z'\n", ret, msg.message, msg.wParam); ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE); qstatus = GetQueueStatus(qs_all_input); ok(qstatus == 0, - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); msg.message = 0; ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE); @@ -12107,7 +14187,7 @@ static void test_PeekMessage(void) qstatus = GetQueueStatus(qs_all_input); ok(qstatus == 0, - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); /* test whether presence of the quit flag in the queue affects * the queue state @@ -12116,13 +14196,13 @@ static void test_PeekMessage(void) qstatus = GetQueueStatus(qs_all_input); ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); PostMessageA(info.hwnd, WM_USER, 0, 0); qstatus = GetQueueStatus(qs_all_input); ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); msg.message = 0; ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE); @@ -12132,20 +14212,20 @@ static void test_PeekMessage(void) qstatus = GetQueueStatus(qs_all_input); ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); msg.message = 0; ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE); ok(ret && msg.message == WM_QUIT, "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message); - ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam); - ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam); + ok(msg.wParam == 0x1234abcd, "got wParam %08Ix instead of 0x1234abcd\n", msg.wParam); + ok(msg.lParam == 0, "got lParam %08Ix instead of 0\n", msg.lParam); ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE); qstatus = GetQueueStatus(qs_all_input); todo_wine { ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); } msg.message = 0; @@ -12157,102 +14237,102 @@ todo_wine { qstatus = GetQueueStatus(qs_all_input); ok(qstatus == 0, - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); /* some GetMessage tests */ keybd_event('N', 0, 0, 0); qstatus = GetQueueStatus(qs_all_input); - ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus); + ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08lx\n", qstatus); PostMessageA(info.hwnd, WM_CHAR, 'z', 0); qstatus = GetQueueStatus(qs_all_input); - ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus); + ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08lx\n", qstatus); if (qstatus) { ret = GetMessageA( &msg, 0, 0, 0 ); ok(ret && msg.message == WM_CHAR && msg.wParam == 'z', - "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n", + "got %d and %04x wParam %08Ix instead of TRUE and WM_CHAR wParam 'z'\n", ret, msg.message, msg.wParam); qstatus = GetQueueStatus(qs_all_input); - ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus); + ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08lx\n", qstatus); } if (qstatus) { ret = GetMessageA( &msg, 0, 0, 0 ); ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N', - "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n", + "got %d and %04x wParam %08Ix instead of TRUE and WM_KEYDOWN wParam 'N'\n", ret, msg.message, msg.wParam); ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE); qstatus = GetQueueStatus(qs_all_input); - ok(qstatus == 0, "wrong qstatus %08x\n", qstatus); + ok(qstatus == 0, "wrong qstatus %08lx\n", qstatus); } keybd_event('N', 0, 0, 0); qstatus = GetQueueStatus(qs_all_input); - ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus); + ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08lx\n", qstatus); PostMessageA(info.hwnd, WM_CHAR, 'z', 0); qstatus = GetQueueStatus(qs_all_input); - ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus); + ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08lx\n", qstatus); if (qstatus & (QS_KEY << 16)) { ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP ); ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N', - "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n", + "got %d and %04x wParam %08Ix instead of TRUE and WM_KEYDOWN wParam 'N'\n", ret, msg.message, msg.wParam); ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE); qstatus = GetQueueStatus(qs_all_input); - ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus); + ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08lx\n", qstatus); } if (qstatus) { ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR ); ok(ret && msg.message == WM_CHAR && msg.wParam == 'z', - "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n", + "got %d and %04x wParam %08Ix instead of TRUE and WM_CHAR wParam 'z'\n", ret, msg.message, msg.wParam); qstatus = GetQueueStatus(qs_all_input); - ok(qstatus == 0, "wrong qstatus %08x\n", qstatus); + ok(qstatus == 0, "wrong qstatus %08lx\n", qstatus); } keybd_event('N', 0, KEYEVENTF_KEYUP, 0); qstatus = GetQueueStatus(qs_all_input); - ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus); + ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08lx\n", qstatus); PostMessageA(info.hwnd, WM_CHAR, 'z', 0); qstatus = GetQueueStatus(qs_all_input); - ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus); + ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08lx\n", qstatus); - trace("signalling to send message\n"); + if (winetest_debug > 1) trace("signalling to send message\n"); SetEvent(info.hevent[EV_SENDMSG]); WaitForSingleObject(info.hevent[EV_ACK], INFINITE); qstatus = GetQueueStatus(qs_all_input); ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY), - "wrong qstatus %08x\n", qstatus); + "wrong qstatus %08lx\n", qstatus); if (qstatus & (QS_KEY << 16)) { ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP ); ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N', - "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n", + "got %d and %04x wParam %08Ix instead of TRUE and WM_KEYDOWN wParam 'N'\n", ret, msg.message, msg.wParam); ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE); qstatus = GetQueueStatus(qs_all_input); - ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus); + ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08lx\n", qstatus); } if (qstatus) { ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR ); ok(ret && msg.message == WM_CHAR && msg.wParam == 'z', - "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n", + "got %d and %04x wParam %08Ix instead of TRUE and WM_CHAR wParam 'z'\n", ret, msg.message, msg.wParam); qstatus = GetQueueStatus(qs_all_input); - ok(qstatus == 0, "wrong qstatus %08x\n", qstatus); + ok(qstatus == 0, "wrong qstatus %08lx\n", qstatus); } PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0); @@ -12280,7 +14360,7 @@ todo_wine { ok(msg.message == WM_USER, "wrong message %u\n", msg.message); done: - trace("signalling to exit\n"); + if (winetest_debug > 1) trace("signalling to exit\n"); SetEvent(info.hevent[EV_STOP]); WaitForSingleObject(hthread, INFINITE); @@ -12296,15 +14376,16 @@ done: static void wait_move_event(HWND hwnd, int x, int y) { MSG msg; - DWORD time; + DWORD timeout = GetTickCount() + 500; BOOL ret; + int delay; - time = GetTickCount(); - while (GetTickCount() - time < 200) { - ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE); + while ((delay = timeout - GetTickCount()) > 0) + { + ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE); if (ret && msg.pt.x > x && msg.pt.y > y) break; - if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, GetTickCount() - time, QS_ALLINPUT ); - else Sleep( GetTickCount() - time ); + if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, delay, QS_ALLINPUT ); + else Sleep( delay ); } } @@ -12325,8 +14406,8 @@ static void test_PeekMessage2(void) /* Initialise window and make sure it is ready for events */ hwnd = CreateWindowA("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW, 10, 10, 800, 800, NULL, NULL, NULL, NULL); - assert(hwnd); - trace("Window for test_PeekMessage2 %p\n", hwnd); + ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError()); + if (winetest_debug > 1) trace("Window for test_PeekMessage2 %p\n", hwnd); ShowWindow(hwnd, SW_SHOW); UpdateWindow(hwnd); SetFocus(hwnd); @@ -12348,7 +14429,7 @@ static void test_PeekMessage2(void) } else { - trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y); + if (winetest_debug > 1) trace("1st move event: %04x %lx %ld %ld\n", msg.message, msg.time, msg.pt.x, msg.pt.y); message = msg.message; time1 = msg.time; x1 = msg.pt.x; @@ -12368,13 +14449,13 @@ static void test_PeekMessage2(void) ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE); ok(ret, "no message available\n"); if (ret) { - trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y); + if (winetest_debug > 1) trace("2nd move event: %04x %lx %ld %ld\n", msg.message, msg.time, msg.pt.x, msg.pt.y); message = msg.message; time2 = msg.time; x2 = msg.pt.x; y2 = msg.pt.y; ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message); - ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2); + ok(time2 > time1, "message time not advanced: %lx %lx\n", time1, time2); ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2); } @@ -12386,13 +14467,13 @@ static void test_PeekMessage2(void) ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE); ok(ret, "no message available\n"); if (ret) { - trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y); + if (winetest_debug > 1) trace("3rd move event: %04x %lx %ld %ld\n", msg.message, msg.time, msg.pt.x, msg.pt.y); message = msg.message; time3 = msg.time; x3 = msg.pt.x; y3 = msg.pt.y; ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message); - ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3); + ok(time3 > time2, "message time not advanced: %lx %lx\n", time2, time3); ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3); } @@ -12404,130 +14485,124 @@ done: static void test_PeekMessage3(void) { - HWND hwnd; + HWND parent_hwnd, hwnd; BOOL ret; MSG msg; - hwnd = CreateWindowA("TestWindowClass", "PeekMessage3", WS_OVERLAPPEDWINDOW, + parent_hwnd = CreateWindowA("SimpleWindowClass", "PeekMessage3", WS_OVERLAPPEDWINDOW, 10, 10, 800, 800, NULL, NULL, NULL, NULL); + ok(parent_hwnd != NULL, "expected parent_hwnd != NULL\n"); + + hwnd = CreateWindowA("TestWindowClass", "PeekMessage3", WS_CHILD, 0, 0, 1, 1, + parent_hwnd, NULL, NULL, NULL); ok(hwnd != NULL, "expected hwnd != NULL\n"); + flush_events(); /* GetMessage() and PeekMessage(..., PM_REMOVE) should prefer messages which * were already seen. */ - SetTimer(hwnd, 1, 0, NULL); - while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE)); + SetTimer(hwnd, 1, 100, NULL); + while (!PeekMessageA(&msg, hwnd, 0, 0, PM_NOREMOVE)); ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message); PostMessageA(hwnd, WM_USER, 0, 0); - ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE); + ret = PeekMessageA(&msg, hwnd, 0, 0, PM_NOREMOVE); + todo_wine ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message); - ret = GetMessageA(&msg, NULL, 0, 0); + ret = GetMessageA(&msg, hwnd, 0, 0); + todo_wine ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message); - ret = GetMessageA(&msg, NULL, 0, 0); + ret = GetMessageA(&msg, hwnd, 0, 0); + todo_wine ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message); - ret = PeekMessageA(&msg, NULL, 0, 0, 0); + ret = PeekMessageA(&msg, hwnd, 0, 0, 0); ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret); - SetTimer(hwnd, 1, 0, NULL); - while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE)); + SetTimer(hwnd, 1, 100, NULL); + while (!PeekMessageA(&msg, hwnd, 0, 0, PM_NOREMOVE)); ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message); PostMessageA(hwnd, WM_USER, 0, 0); - ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE); + ret = PeekMessageA(&msg, hwnd, 0, 0, PM_REMOVE); + todo_wine ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message); - ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE); + ret = PeekMessageA(&msg, hwnd, 0, 0, PM_REMOVE); + todo_wine ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message); - ret = PeekMessageA(&msg, NULL, 0, 0, 0); + ret = PeekMessageA(&msg, hwnd, 0, 0, 0); ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret); /* It doesn't matter if a message range is specified or not. */ - SetTimer(hwnd, 1, 0, NULL); - while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE)); + SetTimer(hwnd, 1, 100, NULL); + while (!PeekMessageA(&msg, hwnd, WM_TIMER, WM_TIMER, PM_NOREMOVE)); ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message); PostMessageA(hwnd, WM_USER, 0, 0); - ret = GetMessageA(&msg, NULL, 0, 0); + ret = GetMessageA(&msg, hwnd, 0, 0); + todo_wine ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message); - ret = GetMessageA(&msg, NULL, 0, 0); + ret = GetMessageA(&msg, hwnd, 0, 0); + todo_wine ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message); - ret = PeekMessageA(&msg, NULL, 0, 0, 0); + ret = PeekMessageA(&msg, hwnd, 0, 0, 0); ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret); /* But not if the post messages were added before the PeekMessage() call. */ PostMessageA(hwnd, WM_USER, 0, 0); - SetTimer(hwnd, 1, 0, NULL); - while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE)); + SetTimer(hwnd, 1, 100, NULL); + while (!PeekMessageA(&msg, hwnd, WM_TIMER, WM_TIMER, PM_NOREMOVE)); ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message); - ret = GetMessageA(&msg, NULL, 0, 0); + ret = GetMessageA(&msg, hwnd, 0, 0); ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message); - ret = GetMessageA(&msg, NULL, 0, 0); + ret = GetMessageA(&msg, hwnd, 0, 0); ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message); - ret = PeekMessageA(&msg, NULL, 0, 0, 0); + ret = PeekMessageA(&msg, hwnd, 0, 0, 0); ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret); /* More complicated test with multiple messages. */ PostMessageA(hwnd, WM_USER, 0, 0); - SetTimer(hwnd, 1, 0, NULL); - while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE)); + SetTimer(hwnd, 1, 100, NULL); + while (!PeekMessageA(&msg, hwnd, WM_TIMER, WM_TIMER, PM_NOREMOVE)); ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message); PostMessageA(hwnd, WM_USER + 1, 0, 0); - ret = GetMessageA(&msg, NULL, 0, 0); + ret = GetMessageA(&msg, hwnd, 0, 0); ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message); - ret = GetMessageA(&msg, NULL, 0, 0); + ret = GetMessageA(&msg, hwnd, 0, 0); + todo_wine ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message); - ret = GetMessageA(&msg, NULL, 0, 0); + ret = GetMessageA(&msg, hwnd, 0, 0); + todo_wine ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message); - ret = PeekMessageA(&msg, NULL, 0, 0, 0); - ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret); - - /* Newer messages are still returned when specifying a message range. */ - - SetTimer(hwnd, 1, 0, NULL); - while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE)); - ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message); - PostMessageA(hwnd, WM_USER + 1, 0, 0); - PostMessageA(hwnd, WM_USER, 0, 0); - ret = PeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); - ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message); - ret = PeekMessageA(&msg, NULL, WM_USER, WM_USER + 1, PM_NOREMOVE); - ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message); - ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE); - ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message); - ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE); - ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message); - ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE); - ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message); - ret = PeekMessageA(&msg, NULL, 0, 0, 0); + ret = PeekMessageA(&msg, hwnd, 0, 0, 0); ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret); /* Also works for posted messages, but the situation is a bit different, * because both messages are in the same queue. */ PostMessageA(hwnd, WM_TIMER, 0, 0); - while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE)); + while (!PeekMessageA(&msg, hwnd, WM_TIMER, WM_TIMER, PM_NOREMOVE)); ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message); PostMessageA(hwnd, WM_USER, 0, 0); - ret = GetMessageA(&msg, NULL, 0, 0); + ret = GetMessageA(&msg, hwnd, 0, 0); ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message); - ret = GetMessageA(&msg, NULL, 0, 0); + ret = GetMessageA(&msg, hwnd, 0, 0); ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message); - ret = PeekMessageA(&msg, NULL, 0, 0, 0); + ret = PeekMessageA(&msg, hwnd, 0, 0, 0); ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret); PostMessageA(hwnd, WM_USER, 0, 0); PostMessageA(hwnd, WM_TIMER, 0, 0); - while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE)); + while (!PeekMessageA(&msg, hwnd, WM_TIMER, WM_TIMER, PM_NOREMOVE)); ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message); - ret = GetMessageA(&msg, NULL, 0, 0); + ret = GetMessageA(&msg, hwnd, 0, 0); ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message); - ret = GetMessageA(&msg, NULL, 0, 0); + ret = GetMessageA(&msg, hwnd, 0, 0); ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message); - ret = PeekMessageA(&msg, NULL, 0, 0, 0); + ret = PeekMessageA(&msg, hwnd, 0, 0, 0); ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret); - DestroyWindow(hwnd); + DestroyWindow(parent_hwnd); flush_events(); } @@ -12565,11 +14640,14 @@ static INT_PTR CALLBACK wm_quit_dlg_proc(HWND hwnd, UINT message, WPARAM wp, LPA static const struct message WmQuitDialogSeq[] = { { HCBT_CREATEWND, hook }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, { WM_SETFONT, sent }, { WM_INITDIALOG, sent }, { WM_CHANGEUISTATE, sent|optional }, + { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_DESTROYWND, hook }, { 0x0090, sent|optional }, /* Vista */ + { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, { WM_DESTROY, sent }, { WM_NCDESTROY, sent }, { 0 } @@ -12596,22 +14674,22 @@ static void test_quit_message(void) ok(!ret, "got %x message\n", msg.message); ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE); - ok(ret, "PeekMessage failed with error %d\n", GetLastError()); + ok(ret, "PeekMessage failed with error %ld\n", GetLastError()); ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message); - ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam); + ok(msg.wParam == 0xbeef, "wParam was 0x%Ix instead of 0xbeef\n", msg.wParam); ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0); - ok(ret, "PostMessage failed with error %d\n", GetLastError()); + ok(ret, "PostMessage failed with error %ld\n", GetLastError()); ret = GetMessageA(&msg, NULL, 0, 0); - ok(ret > 0, "GetMessage failed with error %d\n", GetLastError()); + ok(ret > 0, "GetMessage failed with error %ld\n", GetLastError()); ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message); /* note: WM_QUIT message received after WM_USER message */ ret = GetMessageA(&msg, NULL, 0, 0); - ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError()); + ok(!ret, "GetMessage return %d with error %ld instead of FALSE\n", ret, GetLastError()); ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message); - ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam); + ok(msg.wParam == 0xbeef, "wParam was 0x%Ix instead of 0xbeef\n", msg.wParam); ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE); ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" ); @@ -12620,34 +14698,37 @@ static void test_quit_message(void) PostThreadMessageA(GetCurrentThreadId(), WM_QUIT, 0xdead, 0); ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE); - ok(ret, "PeekMessage failed with error %d\n", GetLastError()); + ok(ret, "PeekMessage failed with error %ld\n", GetLastError()); ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message); - ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam); + ok(msg.wParam == 0xdead, "wParam was 0x%Ix instead of 0xdead\n", msg.wParam); ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0); - ok(ret, "PostMessage failed with error %d\n", GetLastError()); + ok(ret, "PostMessage failed with error %ld\n", GetLastError()); /* note: we receive the WM_QUIT message first this time */ ret = GetMessageA(&msg, NULL, 0, 0); - ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError()); + ok(!ret, "GetMessage return %d with error %ld instead of FALSE\n", ret, GetLastError()); ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message); - ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam); + ok(msg.wParam == 0xdead, "wParam was 0x%Ix instead of 0xdead\n", msg.wParam); ret = GetMessageA(&msg, NULL, 0, 0); - ok(ret > 0, "GetMessage failed with error %d\n", GetLastError()); + ok(ret > 0, "GetMessage failed with error %ld\n", GetLastError()); ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message); flush_events(); flush_sequence(); ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, wm_quit_dlg_proc, 0); ok(ret == 1, "expected 1, got %d\n", ret); +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) +#endif ok_sequence(WmQuitDialogSeq, "WmQuitDialogSeq", FALSE); memset(&msg, 0xab, sizeof(msg)); ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE); ok(ret, "PeekMessage failed\n"); ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message); - ok(msg.wParam == 0x1234, "wParam was 0x%lx instead of 0x1234\n", msg.wParam); - ok(msg.lParam == 0, "lParam was 0x%lx instead of 0\n", msg.lParam); + ok(msg.wParam == 0x1234, "wParam was 0x%Ix instead of 0x1234\n", msg.wParam); + ok(msg.lParam == 0, "lParam was 0x%Ix instead of 0\n", msg.lParam); /* Check what happens to a WM_QUIT message posted to a window that gets * destroyed. @@ -12691,33 +14772,33 @@ static void test_notify_message(void) flush_sequence(); ret = SendNotifyMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef); - ok(ret == TRUE, "SendNotifyMessageA failed with error %u\n", GetLastError()); + ok(ret == TRUE, "SendNotifyMessageA failed with error %lu\n", GetLastError()); ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE); ret = SendNotifyMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef); - ok(ret == TRUE, "SendNotifyMessageW failed with error %u\n", GetLastError()); + ok(ret == TRUE, "SendNotifyMessageW failed with error %lu\n", GetLastError()); ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE); ret = SendMessageCallbackA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0); - ok(ret == TRUE, "SendMessageCallbackA failed with error %u\n", GetLastError()); + ok(ret == TRUE, "SendMessageCallbackA failed with error %lu\n", GetLastError()); ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE); ret = SendMessageCallbackW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0); - ok(ret == TRUE, "SendMessageCallbackW failed with error %u\n", GetLastError()); + ok(ret == TRUE, "SendMessageCallbackW failed with error %lu\n", GetLastError()); ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE); ret = PostMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef); - ok(ret == TRUE, "PostMessageA failed with error %u\n", GetLastError()); + ok(ret == TRUE, "PostMessageA failed with error %lu\n", GetLastError()); flush_events(); ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE); ret = PostMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef); - ok(ret == TRUE, "PostMessageW failed with error %u\n", GetLastError()); + ok(ret == TRUE, "PostMessageW failed with error %lu\n", GetLastError()); flush_events(); ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE); ret = PostThreadMessageA(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef); - ok(ret == TRUE, "PostThreadMessageA failed with error %u\n", GetLastError()); + ok(ret == TRUE, "PostThreadMessageA failed with error %lu\n", GetLastError()); while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) { msg.hwnd = hwnd; @@ -12726,7 +14807,7 @@ static void test_notify_message(void) ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE); ret = PostThreadMessageW(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef); - ok(ret == TRUE, "PostThreadMessageW failed with error %u\n", GetLastError()); + ok(ret == TRUE, "PostThreadMessageW failed with error %lu\n", GetLastError()); while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) { msg.hwnd = hwnd; @@ -12738,6 +14819,7 @@ static void test_notify_message(void) } static const struct message WmMouseHoverSeq[] = { + { WM_GETMINMAXINFO, sent|optional }, /* sometimes seen on w1064v1809 */ { WM_MOUSEACTIVATE, sent|optional }, /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */ { WM_MOUSEACTIVATE, sent|optional }, { WM_TIMER, sent|optional }, /* XP sends it */ @@ -12805,7 +14887,7 @@ static void test_TrackMouseEvent(void) tme.dwHoverTime = track_hover_time; \ SetLastError(0xdeadbeef); \ ret = pTrackMouseEvent(&tme); \ - ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError()) + ok(ret, "TrackMouseEvent(TME_HOVER) error %ld\n", GetLastError()) #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \ tme.cbSize = sizeof(tme); \ @@ -12814,14 +14896,14 @@ static void test_TrackMouseEvent(void) tme.dwHoverTime = 0xdeadbeef; \ SetLastError(0xdeadbeef); \ ret = pTrackMouseEvent(&tme); \ - ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\ - ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \ + ok(ret, "TrackMouseEvent(TME_QUERY) error %ld\n", GetLastError());\ + ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %lu\n", tme.cbSize); \ ok(tme.dwFlags == (expected_track_flags), \ - "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \ + "wrong tme.dwFlags %08lx, expected %08x\n", tme.dwFlags, (expected_track_flags)); \ ok(tme.hwndTrack == (expected_track_hwnd), \ "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \ ok(tme.dwHoverTime == (expected_hover_time), \ - "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time)) + "wrong tme.dwHoverTime %lu, expected %u\n", tme.dwHoverTime, (expected_hover_time)) #define track_hover_cancel(track_hwnd) \ tme.cbSize = sizeof(tme); \ @@ -12830,39 +14912,39 @@ static void test_TrackMouseEvent(void) tme.dwHoverTime = 0xdeadbeef; \ SetLastError(0xdeadbeef); \ ret = pTrackMouseEvent(&tme); \ - ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError()) + ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %ld\n", GetLastError()) default_hover_time = 0xdeadbeef; SetLastError(0xdeadbeef); ret = SystemParametersInfoA(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0); ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */ - "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError()); + "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %lu\n", GetLastError()); if (!ret) default_hover_time = 400; - trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time); + if (winetest_debug > 1) trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time); SetLastError(0xdeadbeef); ret = SystemParametersInfoA(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0); ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */ - "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError()); + "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %lu\n", GetLastError()); if (!ret) hover_width = 4; SetLastError(0xdeadbeef); ret = SystemParametersInfoA(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0); ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */ - "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError()); + "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %lu\n", GetLastError()); if (!ret) hover_height = 4; - trace("hover rect is %u x %d\n", hover_width, hover_height); + if (winetest_debug > 1) trace("hover rect is %u x %d\n", hover_width, hover_height); hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0, NULL, NULL, 0); - assert(hwnd); + ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError()); hchild = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD | WS_BORDER | WS_VISIBLE, 50, 50, 200, 200, hwnd, NULL, NULL, 0); - assert(hchild); + ok(!!hchild, "Failed to create window, error %lu.\n", GetLastError()); SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE ); flush_events(); @@ -12876,7 +14958,7 @@ static void test_TrackMouseEvent(void) ret = pTrackMouseEvent(&tme); ok(!ret, "TrackMouseEvent should fail\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef), - "not expected error %u\n", GetLastError()); + "not expected error %lu\n", GetLastError()); tme.cbSize = sizeof(tme); tme.dwFlags = TME_HOVER; @@ -12886,7 +14968,7 @@ static void test_TrackMouseEvent(void) ret = pTrackMouseEvent(&tme); ok(!ret, "TrackMouseEvent should fail\n"); ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef), - "not expected error %u\n", GetLastError()); + "not expected error %lu\n", GetLastError()); tme.cbSize = sizeof(tme); tme.dwFlags = TME_HOVER | TME_CANCEL; @@ -12896,7 +14978,7 @@ static void test_TrackMouseEvent(void) ret = pTrackMouseEvent(&tme); ok(!ret, "TrackMouseEvent should fail\n"); ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef), - "not expected error %u\n", GetLastError()); + "not expected error %lu\n", GetLastError()); GetWindowRect(hwnd, &rc_parent); GetWindowRect(hchild, &rc_child); @@ -12923,17 +15005,17 @@ static void test_TrackMouseEvent(void) tme.dwHoverTime = 0xdeadbeef; SetLastError(0xdeadbeef); ret = pTrackMouseEvent(&tme); - ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError()); - ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); + ok(ret, "TrackMouseEvent(TME_QUERY) error %ld\n", GetLastError()); + ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %lu\n", tme.cbSize); if (!tme.dwFlags) { skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" ); DestroyWindow( hwnd ); return; } - ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags); + ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08lx, expected TME_HOVER\n", tme.dwFlags); ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd); - ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %u, expected %u\n", + ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %lu, expected %u\n", tme.dwHoverTime, default_hover_time); pump_msg_loop_timeout(default_hover_time, FALSE); @@ -12976,7 +15058,8 @@ static void test_TrackMouseEvent(void) static const struct message WmSetWindowRgn[] = { - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGING, sent|wparam|lparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE + |SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE, 0 }, { WM_NCCALCSIZE, sent|wparam, 1 }, { WM_NCPAINT, sent|optional }, /* wparam != 1 */ { WM_GETTEXT, sent|defwinproc|optional }, @@ -12987,7 +15070,8 @@ static const struct message WmSetWindowRgn[] = { }; static const struct message WmSetWindowRgn_no_redraw[] = { - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW }, + { WM_WINDOWPOSCHANGING, sent|wparam|lparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE + |SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW, 0 }, { WM_NCCALCSIZE, sent|wparam, 1 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, @@ -12995,16 +15079,20 @@ static const struct message WmSetWindowRgn_no_redraw[] = { }; static const struct message WmSetWindowRgn_clear[] = { - { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ }, + { WM_WINDOWPOSCHANGING, sent/*|wparam|lparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED + |SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ + /* Some newer Windows versions set window coordinates instead of zeros in WINDOWPOS structure */}, { WM_NCCALCSIZE, sent|wparam, 1 }, { WM_NCPAINT, sent|optional }, { WM_GETTEXT, sent|defwinproc|optional }, - { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */ + { WM_ERASEBKGND, sent }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE }, { WM_NCCALCSIZE, sent|wparam|optional, 1 }, { WM_NCPAINT, sent|optional }, { WM_GETTEXT, sent|defwinproc|optional }, { WM_ERASEBKGND, sent|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|optional }, { WM_NCCALCSIZE, sent|optional|wparam, 1 }, { WM_NCPAINT, sent|optional }, @@ -13015,8 +15103,8 @@ static const struct message WmSetWindowRgn_clear[] = { { WM_NCPAINT, sent|optional }, { WM_GETTEXT, sent|defwinproc|optional }, { WM_ERASEBKGND, sent|optional }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Not always sent. */ { 0 } }; @@ -13032,7 +15120,7 @@ static void test_SetWindowRgn(void) flush_events(); flush_sequence(); - trace("testing SetWindowRgn\n"); + if (winetest_debug > 1) trace("testing SetWindowRgn\n"); hrgn = CreateRectRgn( 0, 0, 150, 150 ); SetWindowRgn( hwnd, hrgn, TRUE ); ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE ); @@ -13046,6 +15134,9 @@ static void test_SetWindowRgn(void) ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE ); SetWindowRgn( hwnd, 0, TRUE ); +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_WINBLUE) +#endif ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE ); DestroyWindow( hwnd ); @@ -13055,48 +15146,72 @@ static void test_SetWindowRgn(void) static const struct message WmShowNormal[] = { { WM_SHOWWINDOW, sent|wparam, 1 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_ACTIVATE, hook }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */ { HCBT_SETFOCUS, hook }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends it, but Win8+ doesn't. */ { 0 } }; static const struct message WmShow[] = { { WM_SHOWWINDOW, sent|wparam, 1 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */ + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|wine_only, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */ { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */ + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|wine_only, OBJID_CLIENT, 0 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { 0 } }; static const struct message WmShowNoActivate_1[] = { { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE }, { WM_MOVE, sent|defwinproc|optional }, { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ { 0 } }; static const struct message WmShowNoActivate_2[] = { { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_ACTIVATE, hook|optional }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends this. */ { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGED, sent|optional }, /* Sometimes sent on Win8+. */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, { HCBT_SETFOCUS, hook|optional }, - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* Win7 sends this. */ + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE }, { WM_MOVE, sent|defwinproc }, { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|wine_only, 0, 0 }, + { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|wine_only, 0, 0 }, { HCBT_SETFOCUS, hook|optional }, { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */ + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|wine_only, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */ { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|wine_only, OBJID_CLIENT, 0 }, + { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { 0 } }; static const struct message WmShowNA_1[] = { { WM_SHOWWINDOW, sent|wparam, 1 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { 0 } }; @@ -13109,21 +15224,32 @@ static const struct message WmShowNA_2[] = { static const struct message WmRestore_1[] = { { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */ + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|wine_only, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */ { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */ + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|wine_only, OBJID_CLIENT, 0 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, { WM_MOVE, sent|defwinproc }, { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ + { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */ + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, { 0 } }; static const struct message WmRestore_2[] = { { WM_SHOWWINDOW, sent|wparam, 1 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */ + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|wine_only, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */ { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */ + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|wine_only, OBJID_CLIENT, 0 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { 0 } }; @@ -13131,13 +15257,21 @@ static const struct message WmRestore_3[] = { { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE }, { WM_GETMINMAXINFO, sent }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */ + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */ + { WM_WINDOWPOSCHANGED, sent|optional }, /* Win8+ sometimes sends this. */ { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */ - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, + { WM_WINDOWPOSCHANGED, sent|optional }, { WM_MOVE, sent|defwinproc }, { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ + { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */ + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|wine_only, OBJID_CLIENT, 0 }, { 0 } }; static const struct message WmRestore_4[] = { @@ -13146,6 +15280,8 @@ static const struct message WmRestore_4[] = { { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE }, { WM_MOVE, sent|defwinproc|optional }, { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ { 0 } }; static const struct message WmRestore_5[] = { @@ -13156,19 +15292,24 @@ static const struct message WmRestore_5[] = { { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE }, { WM_MOVE, sent|defwinproc|optional }, { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ { 0 } }; static const struct message WmHide_1[] = { { WM_SHOWWINDOW, sent|wparam, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOACTIVATE }, + { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOACTIVATE }, { HCBT_ACTIVATE, hook|optional }, { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */ + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, { 0 } }; static const struct message WmHide_2[] = { { WM_SHOWWINDOW, sent|wparam, 0 }, { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */ + { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 }, { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */ { HCBT_ACTIVATE, hook|optional }, { 0 } @@ -13176,53 +15317,78 @@ static const struct message WmHide_2[] = { static const struct message WmHide_3[] = { { WM_SHOWWINDOW, sent|wparam, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE }, + { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { HCBT_SETFOCUS, hook|optional }, - { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, { 0 } }; static const struct message WmShowMinimized_1[] = { { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */ + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|wine_only, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */ + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|wine_only, OBJID_CLIENT, 0 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, { WM_MOVE, sent|defwinproc }, { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ + { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, { 0 } }; static const struct message WmMinimize_1[] = { { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE }, { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */ - { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, { WM_MOVE, sent|defwinproc }, { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ + { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, { 0 } }; static const struct message WmMinimize_2[] = { { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE }, { HCBT_SETFOCUS, hook|optional }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE }, { WM_MOVE, sent|defwinproc }, { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ + { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, { 0 } }; static const struct message WmMinimize_3[] = { { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_ACTIVATE, hook|optional }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sometimes sent on Win8/10. */ { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE }, + { WM_WINDOWPOSCHANGED, sent|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sometimes sent on Win7. */ + { WM_WINDOWPOSCHANGED, sent|optional }, { WM_MOVE, sent|defwinproc }, { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ + { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, { 0 } }; static const struct message WmShowMinNoActivate[] = { { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE }, { WM_WINDOWPOSCHANGING, sent }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { WM_WINDOWPOSCHANGED, sent }, { WM_MOVE, sent|defwinproc|optional }, { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 }, @@ -13262,13 +15428,21 @@ static const struct message WmShowMaximized_1[] = { { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED }, { WM_GETMINMAXINFO, sent }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */ + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|wine_only, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */ { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */ + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|wine_only, OBJID_CLIENT, 0 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, { WM_MOVE, sent|defwinproc }, { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ + { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */ + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, { 0 } }; static const struct message WmShowMaximized_2[] = { @@ -13277,14 +15451,21 @@ static const struct message WmShowMaximized_2[] = { { WM_WINDOWPOSCHANGING, sent|optional }, { HCBT_ACTIVATE, hook|optional }, { WM_WINDOWPOSCHANGED, sent|optional }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, { WM_MOVE, sent|optional }, /* Win9x doesn't send it */ { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 sends this. */ { WM_WINDOWPOSCHANGING, sent|optional }, { HCBT_SETFOCUS, hook|optional }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, { WM_MOVE, sent|defwinproc }, { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ + { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_SETFOCUS, hook|optional }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, { 0 } }; static const struct message WmShowMaximized_3[] = { @@ -13297,6 +15478,8 @@ static const struct message WmShowMaximized_3[] = { { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE }, { WM_MOVE, sent|defwinproc|optional }, { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ { 0 } }; @@ -13435,37 +15618,33 @@ static void test_ShowWindow(void) INT i; WINDOWPLACEMENT wp; RECT win_rc, work_rc = {0, 0, 0, 0}; + HMONITOR hmon; + MONITORINFO mi; + POINT pt = {0, 0}; #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS) hwnd = CreateWindowExA(0, "ShowWindowClass", NULL, WS_BASE, 120, 120, 90, 90, 0, 0, 0, NULL); - assert(hwnd); + ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError()); style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE; - ok(style == 0, "expected style 0, got %08x\n", style); + ok(style == 0, "expected style 0, got %08lx\n", style); flush_events(); flush_sequence(); - if (pGetMonitorInfoA && pMonitorFromPoint) - { - HMONITOR hmon; - MONITORINFO mi; - POINT pt = {0, 0}; + SetLastError(0xdeadbeef); + hmon = MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY); + ok(hmon != 0, "MonitorFromPoint error %lu\n", GetLastError()); - SetLastError(0xdeadbeef); - hmon = pMonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY); - ok(hmon != 0, "MonitorFromPoint error %u\n", GetLastError()); - - mi.cbSize = sizeof(mi); - SetLastError(0xdeadbeef); - ret = pGetMonitorInfoA(hmon, &mi); - ok(ret, "GetMonitorInfo error %u\n", GetLastError()); - trace("monitor %s, work %s\n", wine_dbgstr_rect(&mi.rcMonitor), - wine_dbgstr_rect(&mi.rcWork)); - work_rc = mi.rcWork; - } + mi.cbSize = sizeof(mi); + SetLastError(0xdeadbeef); + ret = GetMonitorInfoA(hmon, &mi); + ok(ret, "GetMonitorInfo error %lu\n", GetLastError()); + if (winetest_debug > 1) trace("monitor %s, work %s\n", wine_dbgstr_rect(&mi.rcMonitor), + wine_dbgstr_rect(&mi.rcWork)); + work_rc = mi.rcWork; GetWindowRect(hwnd, &win_rc); OffsetRect(&win_rc, -work_rc.left, -work_rc.top); @@ -13473,13 +15652,13 @@ static void test_ShowWindow(void) wp.length = sizeof(wp); SetLastError(0xdeadbeaf); ret = GetWindowPlacement(hwnd, &wp); - ok(ret, "GetWindowPlacement error %u\n", GetLastError()); + ok(ret, "GetWindowPlacement error %lu\n", GetLastError()); ok(wp.flags == 0, "expected 0, got %#x\n", wp.flags); ok(wp.showCmd == SW_SHOWNORMAL, "expected SW_SHOWNORMAL, got %d\n", wp.showCmd); ok(wp.ptMinPosition.x == -1 && wp.ptMinPosition.y == -1, - "expected -1,-1 got %d,%d\n", wp.ptMinPosition.x, wp.ptMinPosition.y); + "expected -1,-1 got %ld,%ld\n", wp.ptMinPosition.x, wp.ptMinPosition.y); ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1, - "expected -1,-1 got %d,%d\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y); + "expected -1,-1 got %ld,%ld\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y); todo_wine_if (work_rc.left || work_rc.top) /* FIXME: remove once Wine is fixed */ ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n", wine_dbgstr_rect(&win_rc), wine_dbgstr_rect(&wp.rcNormalPosition)); @@ -13499,19 +15678,24 @@ static void test_ShowWindow(void) idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd; style = GetWindowLongA(hwnd, GWL_STYLE); - trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style); + if (winetest_debug > 1) trace("%d: sending %s, current window style %08lx\n", i+1, sw_cmd_name[idx], style); ret = ShowWindow(hwnd, sw[i].cmd); - ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret); + ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %Iu, got %Iu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret); style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE; - ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style); + ok(style == sw[i].style, "%d: expected style %08lx, got %08lx\n", i+1, sw[i].style, style); sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]); +#if !defined(__REACTOS__) || !defined(_WIN64) +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) +#endif ok_sequence(sw[i].msg, comment, sw[i].todo_msg); +#endif wp.length = sizeof(wp); SetLastError(0xdeadbeaf); ret = GetWindowPlacement(hwnd, &wp); - ok(ret, "GetWindowPlacement error %u\n", GetLastError()); + ok(ret, "GetWindowPlacement error %lu\n", GetLastError()); ok(wp.flags == sw[i].wp_flags, "expected %#x, got %#x\n", sw[i].wp_flags, wp.flags); ok(wp.showCmd == sw[i].wp_cmd, "expected %d, got %d\n", sw[i].wp_cmd, wp.showCmd); @@ -13521,17 +15705,17 @@ static void test_ShowWindow(void) { ok((wp.ptMinPosition.x + work_rc.left == sw[i].wp_min.x && wp.ptMinPosition.y + work_rc.top == sw[i].wp_min.y) || (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000), - "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y); + "expected %ld,%ld got %ld,%ld\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y); } else { ok(wp.ptMinPosition.x == sw[i].wp_min.x && wp.ptMinPosition.y == sw[i].wp_min.y, - "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y); + "expected %ld,%ld got %ld,%ld\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y); } todo_wine_if(wp.ptMaxPosition.x != sw[i].wp_max.x || wp.ptMaxPosition.y != sw[i].wp_max.y) ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y, - "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y); + "expected %ld,%ld got %ld,%ld\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y); if (0) /* FIXME: Wine behaves completely different here */ ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n", @@ -13647,14 +15831,15 @@ static const struct message WmDefDlgSetFocus_1[] = { { HCBT_SETFOCUS, hook }, { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { EM_GETPASSWORDCHAR, sent|optional }, /* Sent on some Win10 machines */ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|wparam, 0 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 }, { WM_CTLCOLOREDIT, sent }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 }, - { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, - { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 }, { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) }, { 0 } }; @@ -13664,9 +15849,9 @@ static const struct message WmDefDlgSetFocus_2[] = { { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */ { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */ { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */ - { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, + { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 }, { WM_CTLCOLOREDIT, sent|optional }, /* XP */ - { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|msg_todo, OBJID_CARET, 0 }, { 0 } }; /* Creation of a dialog */ @@ -13694,15 +15879,21 @@ static const struct message WmCreateDialogParamSeq_1[] = { { WM_MOVE, sent }, { WM_SETFONT, sent }, { WM_INITDIALOG, sent }, - { WM_GETDLGCODE, sent|wparam|lparam|optional, 0, 0 }, /* FIXME: Wine doesn't send it */ + { WM_GETDLGCODE, sent|wparam|lparam|msg_todo, 0, 0 }, /* FIXME: Wine doesn't send it */ { HCBT_SETFOCUS, hook }, { HCBT_ACTIVATE, hook }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, { WM_QUERYNEWPALETTE, sent|optional }, { WM_PALETTEISCHANGING, sent|optional }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOREDRAW }, + { WM_GETTEXT, sent|optional }, /* win7 */ + { WM_NCCALCSIZE, sent|optional }, /* win7 */ + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win7 */ { WM_ACTIVATEAPP, sent|wparam, 1 }, { WM_NCACTIVATE, sent }, { WM_ACTIVATE, sent|wparam, 1 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent }, { WM_CHANGEUISTATE, sent|optional }, { 0 } @@ -13722,6 +15913,7 @@ static const struct message WmCreateDialogParamSeq_2[] = { static const struct message WmCreateDialogParamSeq_3[] = { { HCBT_CREATEWND, hook }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_SETFONT, sent|parent }, { WM_INITDIALOG, sent|parent }, { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 }, @@ -13730,14 +15922,20 @@ static const struct message WmCreateDialogParamSeq_3[] = { { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX }, { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX }, { HCBT_ACTIVATE, hook }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */ { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, { WM_WINDOWPOSCHANGED, sent|parent|wparam|optional, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { WM_WINDOWPOSCHANGED, sent|parent|wparam|optional, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_NCCALCSIZE, sent|parent|optional, 0 }, + { WM_MOVE, sent|parent|optional }, + { WM_SIZE, sent|parent|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, { WM_ACTIVATEAPP, sent|parent|wparam, 1 }, { WM_NCACTIVATE, sent|parent }, { WM_ACTIVATE, sent|parent|wparam, 1 }, + { EM_GETPASSWORDCHAR, sent|optional }, /* Sent on some Win10 machines */ { WM_SETFOCUS, sent }, { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) }, { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 }, @@ -13751,7 +15949,7 @@ static const struct message WmCreateDialogParamSeq_4[] = { { WM_NCCREATE, sent|parent }, { WM_NCCALCSIZE, sent|parent|wparam, 0 }, { WM_CREATE, sent|parent }, - { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_SIZE, sent|parent|wparam, SIZE_RESTORED }, { WM_MOVE, sent|parent }, { WM_SETFONT, sent|parent }, @@ -13762,15 +15960,21 @@ static const struct message WmCreateDialogParamSeq_4[] = { { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX }, { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX }, { HCBT_ACTIVATE, hook }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */ { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGED, sent|parent|wparam|optional, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_NCCALCSIZE, sent|parent|optional, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, { WM_ACTIVATEAPP, sent|parent|wparam, 1 }, { WM_NCACTIVATE, sent|parent }, { WM_ACTIVATE, sent|parent|wparam, 1 }, { HCBT_SETFOCUS, hook }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|parent }, { WM_KILLFOCUS, sent|parent }, + { EM_GETPASSWORDCHAR, sent|optional }, /* Sent on some Win10 machines */ { WM_SETFOCUS, sent }, { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) }, { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 }, @@ -13789,7 +15993,7 @@ static void test_dialog_messages(void) #define set_selection(hctl, start, end) \ ret = SendMessageA(hctl, EM_SETSEL, start, end); \ - ok(ret == 1, "EM_SETSEL returned %ld\n", ret); + ok(ret == 1, "EM_SETSEL returned %Id\n", ret); #define check_selection(hctl, start, end) \ ret = SendMessageA(hctl, EM_GETSEL, 0, 0); \ @@ -13833,7 +16037,7 @@ static void test_dialog_messages(void) flush_sequence(); ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0); - ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret); + ok(ret == 0, "WM_SETFOCUS returned %Id\n", ret); ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE); hfocus = GetFocus(); @@ -13844,7 +16048,7 @@ static void test_dialog_messages(void) flush_sequence(); ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0); - ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret); + ok(ret == 0, "WM_SETFOCUS returned %Id\n", ret); ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE); hfocus = GetFocus(); @@ -13866,8 +16070,8 @@ static void test_dialog_messages(void) cls.lpszClassName = "MyDialogClass"; cls.hInstance = GetModuleHandleA(NULL); /* need a cast since a dlgproc is used as a wndproc */ - cls.lpfnWndProc = test_dlg_proc; - if (!RegisterClassA(&cls)) assert(0); + cls.lpfnWndProc = (WNDPROC)test_dlg_proc; + register_class(&cls); SetFocus(0); flush_sequence(); @@ -13900,6 +16104,9 @@ static void test_dialog_messages(void) hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_3", 0, test_dlg_proc2, 0); ok(IsWindow(hdlg), "CreateDialogParam failed\n"); +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) +#endif ok_sequence(WmCreateDialogParamSeq_3, "CreateDialogParam_3", TRUE); EndDialog(hdlg, 0); DestroyWindow(hdlg); @@ -13907,9 +16114,12 @@ static void test_dialog_messages(void) UnregisterClassA( cls.lpszClassName, cls.hInstance ); cls.lpfnWndProc = test_dlg_proc4; - ok( RegisterClassA(&cls), "failed to register class again\n" ); + register_class(&cls); hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_4", 0, test_dlg_proc3, 0); ok(IsWindow(hdlg), "CreateDialogParam failed\n"); +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) +#endif ok_sequence(WmCreateDialogParamSeq_4, "CreateDialogParam_4", TRUE); EndDialog(hdlg, 0); DestroyWindow(hdlg); @@ -13952,11 +16162,13 @@ static void test_dialog_messages(void) static void test_enddialog_seq(HWND dialog, HWND owner) { const struct message seq[] = { + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 }, { WM_ENABLE, sent }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner }, { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner }, { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, /* FIXME: Following two are optional because Wine sends WM_QUERYNEWPALETTE instead of WM_WINDOWPOSCHANGING */ { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, { WM_QUERYNEWPALETTE, sent|optional }, @@ -13965,6 +16177,7 @@ static void test_enddialog_seq(HWND dialog, HWND owner) { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog }, { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner }, { WM_KILLFOCUS, sent|wparam, (WPARAM)owner }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|defwinproc|wparam, (WPARAM)dialog }, { 0 } }; @@ -13977,15 +16190,18 @@ static void test_enddialog_seq(HWND dialog, HWND owner) static void test_enddialog_seq2(HWND dialog, HWND owner) { const struct message seq[] = { + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 }, { WM_ENABLE, parent|sent }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner }, { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner }, { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner }, { WM_KILLFOCUS, sent|wparam, (WPARAM)owner }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|parent|defwinproc|wparam, (WPARAM)dialog }, { 0 } }; @@ -14013,8 +16229,8 @@ static void test_EndDialog(void) ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n"); cls.lpszClassName = "MyDialogClass"; cls.hInstance = GetModuleHandleA(NULL); - cls.lpfnWndProc = test_dlg_proc; - if (!RegisterClassA(&cls)) assert(0); + cls.lpfnWndProc = (WNDPROC)test_dlg_proc; + register_class(&cls); flush_sequence(); SetForegroundWindow(hother); @@ -14129,6 +16345,7 @@ static const struct message SetActiveWindowSeq0[] = { WM_NCACTIVATE, sent|wparam, 0 }, { WM_GETTEXT, sent|defwinproc|optional }, { WM_ACTIVATE, sent|wparam, 0 }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, @@ -14146,6 +16363,7 @@ static const struct message SetActiveWindowSeq0[] = { WM_IME_SETCONTEXT, sent|optional }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|defwinproc|optional }, { WM_GETTEXT, sent|optional }, { 0 } @@ -14163,6 +16381,7 @@ static const struct message SetActiveWindowSeq2[] = { WM_NCACTIVATE, sent|wparam, 0 }, { WM_GETTEXT, sent|defwinproc|optional }, { WM_ACTIVATE, sent|wparam, 0 }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE }, @@ -14179,6 +16398,7 @@ static const struct message SetActiveWindowSeq2[] = { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|defwinproc }, { WM_GETTEXT, sent|optional }, { 0 } @@ -14188,6 +16408,7 @@ static const struct message SetActiveWindowSeq2[] = static const struct message SetActiveWindowSeq3[] = { { HCBT_ACTIVATE, hook }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE }, @@ -14200,6 +16421,7 @@ static const struct message SetActiveWindowSeq3[] = { HCBT_SETFOCUS, hook }, { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|defwinproc }, { 0 } }; @@ -14210,6 +16432,7 @@ static const struct message SetActiveWindowSeq4[] = { WM_NCACTIVATE, sent|wparam, 0 }, { WM_GETTEXT, sent|defwinproc|optional }, { WM_ACTIVATE, sent|wparam, 0 }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE }, @@ -14224,6 +16447,7 @@ static const struct message SetActiveWindowSeq4[] = { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|defwinproc }, { 0 } }; @@ -14246,18 +16470,18 @@ static void test_SetActiveWindow(void) SetForegroundWindow( popup ); flush_sequence(); - trace("SetActiveWindow(0)\n"); + if (winetest_debug > 1) trace("SetActiveWindow(0)\n"); ret = SetActiveWindow(0); - ok( ret == popup, "Failed to SetActiveWindow(0)\n"); - ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE); + ok( ret == popup || broken(ret == 0) /* w1064v1809 */, "Failed to SetActiveWindow(0), ret:%p\n", ret); + if (ret == popup) ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE); flush_sequence(); - trace("SetActiveWindow(hwnd), hwnd visible\n"); + if (winetest_debug > 1) trace("SetActiveWindow(hwnd), hwnd visible\n"); ret = SetActiveWindow(hwnd); if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE); flush_sequence(); - trace("SetActiveWindow(popup), hwnd visible, popup visible\n"); + if (winetest_debug > 1) trace("SetActiveWindow(popup), hwnd visible, popup visible\n"); ret = SetActiveWindow(popup); ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n"); ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE); @@ -14267,19 +16491,23 @@ static void test_SetActiveWindow(void) ShowWindow(popup, SW_HIDE); flush_sequence(); - trace("SetActiveWindow(hwnd), hwnd not visible\n"); + if (winetest_debug > 1) trace("SetActiveWindow(hwnd), hwnd not visible\n"); ret = SetActiveWindow(hwnd); +#ifdef __REACTOS__ + ok( ret == NULL || broken(GetNTVersion() == _WIN32_WINNT_VISTA || GetNTVersion() == _WIN32_WINNT_WIN7), "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret ); +#else ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret ); +#endif ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE); flush_sequence(); - trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n"); + if (winetest_debug > 1) trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n"); ret = SetActiveWindow(popup); ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n"); ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE); flush_sequence(); - trace("done\n"); + if (winetest_debug > 1) trace("done\n"); DestroyWindow(hwnd); } @@ -14307,14 +16535,17 @@ static void test_SetForegroundWindow(void) SetForegroundWindow( hwnd ); flush_sequence(); - trace("SetForegroundWindow( 0 )\n"); + if (winetest_debug > 1) trace("SetForegroundWindow( 0 )\n"); SetForegroundWindow( 0 ); ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE); - trace("SetForegroundWindow( GetDesktopWindow() )\n"); + if (winetest_debug > 1) trace("SetForegroundWindow( GetDesktopWindow() )\n"); SetForegroundWindow( GetDesktopWindow() ); +#ifdef __REACTOS__ + if (GetNTVersion() != _WIN32_WINNT_VISTA && GetNTVersion() != _WIN32_WINNT_WIN7) +#endif ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from " "foreground top level window", FALSE); - trace("done\n"); + if (winetest_debug > 1) trace("done\n"); DestroyWindow(hwnd); } @@ -14387,7 +16618,7 @@ static void test_dbcs_wm_char(void) skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" ); return; } - trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n", + if (winetest_debug > 1) trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n", dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName ); hwnd = CreateWindowExW(0, testWindowClassW, NULL, @@ -14396,6 +16627,7 @@ static void test_dbcs_wm_char(void) WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL); ok (hwnd != 0, "Failed to create overlapped window\n"); ok (hwnd2 != 0, "Failed to create overlapped window\n"); + flush_events(); flush_sequence(); memset( wmCharSeq, 0, sizeof(wmCharSeq) ); @@ -14411,7 +16643,7 @@ static void test_dbcs_wm_char(void) ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ); ok( ret, "no message\n" ); ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message ); - ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch ); + ok( msg.wParam == wch, "bad wparam %Ix/%x\n", msg.wParam, wch ); ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ); ok( !ret, "got message %x\n", msg.message ); @@ -14423,7 +16655,7 @@ static void test_dbcs_wm_char(void) ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ); ok( ret, "no message\n" ); ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message ); - ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch ); + ok( msg.wParam == wch, "bad wparam %Ix/%x\n", msg.wParam, wch ); ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ); ok( !ret, "got message %x\n", msg.message ); @@ -14502,7 +16734,7 @@ static void test_dbcs_wm_char(void) ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ); ok( ret, "no message\n" ); ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message ); - ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch ); + ok( msg.wParam == wch, "bad wparam %Ix/%x\n", msg.wParam, wch ); ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ); ok( !ret, "got message %x\n", msg.message ); SendMessageA( hwnd, WM_CHAR, dbch[1], 0 ); @@ -14556,14 +16788,14 @@ static void test_dbcs_wm_char(void) ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ); ok( ret, "no message\n" ); ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message ); - ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch ); + ok( msg.wParam == bad_wch, "bad wparam %Ix/%x\n", msg.wParam, bad_wch ); ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ); ok( !ret, "got message %x\n", msg.message ); PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 ); ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ); ok( ret, "no message\n" ); ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message ); - ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch ); + ok( msg.wParam == bad_wch, "bad wparam %Ix/%x\n", msg.wParam, bad_wch ); ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ); ok( !ret, "got message %x\n", msg.message ); @@ -14574,12 +16806,12 @@ static void test_dbcs_wm_char(void) ok( ret, "no message\n" ); ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd ); ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message ); - ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] ); + ok( msg.wParam == dbch[0], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] ); ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ); ok( ret, "no message\n" ); ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd ); ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message ); - ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] ); + ok( msg.wParam == dbch[1], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] ); ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ); ok( !ret, "got message %x\n", msg.message ); @@ -14589,7 +16821,7 @@ static void test_dbcs_wm_char(void) ok( ret, "no message\n" ); ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd ); ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message ); - ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] ); + ok( msg.wParam == dbch[0], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] ); /* message id is filtered, hwnd is not */ ret = PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ); ok( !ret, "no message\n" ); @@ -14597,7 +16829,7 @@ static void test_dbcs_wm_char(void) ok( ret, "no message\n" ); ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd ); ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message ); - ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] ); + ok( msg.wParam == dbch[1], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] ); ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ); ok( !ret, "got message %x\n", msg.message ); @@ -14606,19 +16838,19 @@ static void test_dbcs_wm_char(void) ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" ); ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd ); ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message ); - ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] ); - ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam ); + ok( msg.wParam == dbch[0], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] ); + ok( msg.lParam == 0xbeef, "bad lparam %Ix\n", msg.lParam ); time = msg.time; pt = msg.pt; - ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time ); + ok( time - GetTickCount() <= 100, "bad time %lx\n", msg.time ); ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ); ok( ret, "no message\n" ); ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd ); ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message ); - ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] ); - ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam ); - ok( msg.time == time, "bad time %x/%x\n", msg.time, time ); - ok( msg.pt.x == pt.x && msg.pt.y == pt.y, "bad point %u,%u/%u,%u\n", msg.pt.x, msg.pt.y, pt.x, pt.y ); + ok( msg.wParam == dbch[1], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] ); + ok( msg.lParam == 0xbeef, "bad lparam %Ix\n", msg.lParam ); + ok( msg.time == time, "bad time %lx/%lx\n", msg.time, time ); + ok( msg.pt.x == pt.x && msg.pt.y == pt.y, "bad point %lu,%lu/%lu,%lu\n", msg.pt.x, msg.pt.y, pt.x, pt.y ); ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ); ok( !ret, "got message %x\n", msg.message ); @@ -14628,22 +16860,22 @@ static void test_dbcs_wm_char(void) ok( ret, "no message\n" ); ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd ); ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message ); - ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] ); + ok( msg.wParam == dbch[0], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] ); ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ); ok( ret, "no message\n" ); ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd ); ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message ); - ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] ); + ok( msg.wParam == dbch[0], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] ); ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ); ok( ret, "no message\n" ); ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd ); ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message ); - ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] ); + ok( msg.wParam == dbch[1], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] ); ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ); ok( ret, "no message\n" ); ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd ); ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message ); - ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] ); + ok( msg.wParam == dbch[1], "bad wparam %Ix/%x\n", msg.wParam, dbch[0] ); ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ); ok( !ret, "got message %x\n", msg.message ); @@ -14664,7 +16896,7 @@ static void test_unicode_wm_char(void) GetLocaleInfoW( LOWORD( hkl_orig ), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (WCHAR*)&cp, sizeof(cp) / sizeof(WCHAR) ); if (cp != 1252) { - skip( "Default codepage %d\n", cp ); + skip( "Default codepage %ld\n", cp ); return; } @@ -14688,8 +16920,8 @@ static void test_unicode_wm_char(void) ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd ); ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message ); - ok( msg.wParam == 0x3b1, "bad wparam %lx\n", msg.wParam ); - ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam ); + ok( msg.wParam == 0x3b1, "bad wparam %Ix\n", msg.wParam ); + ok( msg.lParam == 0, "bad lparam %Ix\n", msg.lParam ); DispatchMessageW( &msg ); @@ -14708,8 +16940,8 @@ static void test_unicode_wm_char(void) ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" ); ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd ); ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message ); - ok( msg.wParam == 0x61, "bad wparam %lx\n", msg.wParam ); - ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam ); + ok( msg.wParam == 0x61, "bad wparam %Ix\n", msg.wParam ); + ok( msg.lParam == 0, "bad lparam %Ix\n", msg.lParam ); DispatchMessageA( &msg ); @@ -14718,7 +16950,7 @@ static void test_unicode_wm_char(void) thread_locale = GetThreadLocale(); ActivateKeyboardLayout( hkl_greek, 0 ); - ok( GetThreadLocale() == thread_locale, "locale changed from %08x to %08x\n", + ok( GetThreadLocale() == thread_locale, "locale changed from %08lx to %08lx\n", thread_locale, GetThreadLocale() ); flush_sequence(); @@ -14729,8 +16961,8 @@ static void test_unicode_wm_char(void) ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" ); ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd ); ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message ); - ok( msg.wParam == 0xe1, "bad wparam %lx\n", msg.wParam ); - ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam ); + ok( msg.wParam == 0xe1, "bad wparam %Ix\n", msg.wParam ); + ok( msg.lParam == 0, "bad lparam %Ix\n", msg.lParam ); DispatchMessageA( &msg ); @@ -14739,7 +16971,6 @@ static void test_unicode_wm_char(void) DestroyWindow( hwnd ); ActivateKeyboardLayout( hkl_orig, 0 ); - UnloadKeyboardLayout( hkl_greek ); } #define ID_LISTBOX 0x000f @@ -14810,6 +17041,7 @@ static const struct message wm_lb_click_0[] = static const struct message wm_lb_deletestring[] = { { LB_DELETESTRING, sent|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 }, { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 }, { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX }, { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX }, @@ -14818,6 +17050,7 @@ static const struct message wm_lb_deletestring[] = static const struct message wm_lb_deletestring_reset[] = { { LB_DELETESTRING, sent|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 }, { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 }, { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 }, { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX }, @@ -14827,31 +17060,47 @@ static const struct message wm_lb_deletestring_reset[] = static const struct message wm_lb_addstring[] = { { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 }, { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed }, + /* Child ID changes each test, don't test lparam. */ + { EVENT_OBJECT_CREATE, winevent_hook|wparam, OBJID_CLIENT, 0 }, { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam, OBJID_CLIENT, 0 }, { 0 } }; static const struct message wm_lb_addstring_ownerdraw[] = { { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed }, { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 }, { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee }, { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 }, { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef }, { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 }, { 0 } }; static const struct message wm_lb_addstring_sort_ownerdraw[] = { { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed }, { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 }, { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee }, { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ee }, { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 }, { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef }, { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ef }, { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ee, 0xf30604ef }, { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 }, + { 0 } +}; +static const struct message wm_lb_dblclick_0[] = +{ + { WM_LBUTTONDBLCLK, sent|wparam|lparam, 0, MAKELPARAM(1,1) }, + { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 }, { 0 } }; @@ -14901,15 +17150,15 @@ static void check_lb_state_dbg(HWND listbox, int count, int cur_sel, /* calling an orig proc helps to avoid unnecessary message logging */ ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0); - ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret); + ok_(__FILE__, line)(ret == count, "expected count %d, got %Id\n", count, ret); ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0); - ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret); + ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %Id\n", cur_sel, ret); ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0); ok_(__FILE__, line)(ret == caret_index || broken(cur_sel == -1 && caret_index == 0 && ret == -1), /* nt4 */ - "expected caret index %d, got %ld\n", caret_index, ret); + "expected caret index %d, got %Id\n", caret_index, ret); ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0); - ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret); + ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %Id\n", top_index, ret); } static void test_listbox_messages(void) @@ -14932,72 +17181,91 @@ static void test_listbox_messages(void) log_all_parent_messages++; ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0"); - ok(ret == 0, "expected 0, got %ld\n", ret); + ok(ret == 0, "expected 0, got %Id\n", ret); ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1"); - ok(ret == 1, "expected 1, got %ld\n", ret); + ok(ret == 1, "expected 1, got %Id\n", ret); ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2"); - ok(ret == 2, "expected 2, got %ld\n", ret); + ok(ret == 2, "expected 2, got %Id\n", ret); ok_sequence(wm_lb_addstring_ownerdraw, "LB_ADDSTRING", FALSE); check_lb_state(listbox, 3, LB_ERR, 0, 0); flush_sequence(); - trace("selecting item 0\n"); + if (winetest_debug > 1) trace("selecting item 0\n"); ret = SendMessageA(listbox, LB_SETCURSEL, 0, 0); - ok(ret == 0, "expected 0, got %ld\n", ret); + ok(ret == 0, "expected 0, got %Id\n", ret); ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE ); check_lb_state(listbox, 3, 0, 0, 0); flush_sequence(); - trace("selecting item 1\n"); + if (winetest_debug > 1) trace("selecting item 1\n"); ret = SendMessageA(listbox, LB_SETCURSEL, 1, 0); - ok(ret == 1, "expected 1, got %ld\n", ret); + ok(ret == 1, "expected 1, got %Id\n", ret); ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE ); check_lb_state(listbox, 3, 1, 1, 0); - trace("selecting item 2\n"); + if (winetest_debug > 1) trace("selecting item 2\n"); ret = SendMessageA(listbox, LB_SETCURSEL, 2, 0); - ok(ret == 2, "expected 2, got %ld\n", ret); + ok(ret == 2, "expected 2, got %Id\n", ret); ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE ); check_lb_state(listbox, 3, 2, 2, 0); - trace("clicking on item 0\n"); + if (winetest_debug > 1) trace("clicking on item 0\n"); ret = SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1)); - ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret); + ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret); ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0); - ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret); + ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret); ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE ); check_lb_state(listbox, 3, 0, 0, 0); flush_sequence(); - trace("deleting item 0\n"); + if (winetest_debug > 1) trace("deleting item 0\n"); ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0); - ok(ret == 2, "expected 2, got %ld\n", ret); + ok(ret == 2, "expected 2, got %Id\n", ret); ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE ); check_lb_state(listbox, 2, -1, 0, 0); flush_sequence(); - trace("deleting item 0\n"); + if (winetest_debug > 1) trace("deleting item 0\n"); ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0); - ok(ret == 1, "expected 1, got %ld\n", ret); + ok(ret == 1, "expected 1, got %Id\n", ret); ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE ); check_lb_state(listbox, 1, -1, 0, 0); flush_sequence(); - trace("deleting item 0\n"); + if (winetest_debug > 1) trace("deleting item 0\n"); ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0); - ok(ret == 0, "expected 0, got %ld\n", ret); + ok(ret == 0, "expected 0, got %Id\n", ret); ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE ); check_lb_state(listbox, 0, -1, 0, 0); flush_sequence(); - trace("deleting item 0\n"); + if (winetest_debug > 1) trace("deleting item 0\n"); ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0); - ok(ret == LB_ERR, "expected LB_ERR, got %ld\n", ret); + ok(ret == LB_ERR, "expected LB_ERR, got %Id\n", ret); check_lb_state(listbox, 0, -1, 0, 0); flush_sequence(); + ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0); + ok(ret == LB_ERR, "expected LB_ERR, got %Id\n", ret); + check_lb_state(listbox, 0, LB_ERR, 0, 0); + flush_sequence(); + + ret = SendMessageA(listbox, LB_RESETCONTENT, 0, 0); + ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret); + check_lb_state(listbox, 0, LB_ERR, 0, 0); + flush_sequence(); + + if (winetest_debug > 1) trace("clicking on item 0\n"); + ret = SendMessageA(listbox, WM_LBUTTONDBLCLK, 0, MAKELPARAM(1, 1)); + ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret); + ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0); + ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret); + ok_sequence(wm_lb_dblclick_0, "WM_LBUTTONDBLCLK 0", FALSE ); + check_lb_state(listbox, 0, LB_ERR, 0, 0); + flush_sequence(); + log_all_parent_messages--; DestroyWindow(listbox); @@ -15015,15 +17283,30 @@ static void test_listbox_messages(void) log_all_parent_messages++; ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0"); - ok(ret == 0, "expected 0, got %ld\n", ret); + ok(ret == 0, "expected 0, got %Id\n", ret); ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1"); - ok(ret == 1, "expected 1, got %ld\n", ret); + ok(ret == 1, "expected 1, got %Id\n", ret); ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2"); - ok(ret == 2, "expected 2, got %ld\n", ret); + ok(ret == 2, "expected 2, got %Id\n", ret); ok_sequence(wm_lb_addstring_sort_ownerdraw, "LB_ADDSTRING", FALSE); check_lb_state(listbox, 3, LB_ERR, 0, 0); + ret = SendMessageA(listbox, LB_RESETCONTENT, 0, 0); + ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret); + check_lb_state(listbox, 0, LB_ERR, 0, 0); + SetFocus(listbox); /* avoid focus messages */ + flush_sequence(); + + if (winetest_debug > 1) trace("clicking on item 0\n"); + ret = SendMessageA(listbox, WM_LBUTTONDBLCLK, 0, MAKELPARAM(1, 1)); + ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret); + ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0); + ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret); + ok_sequence(wm_lb_dblclick_0, "WM_LBUTTONDBLCLK 0", FALSE ); + check_lb_state(listbox, 0, LB_ERR, 0, 0); + flush_sequence(); + log_all_parent_messages--; DestroyWindow(listbox); @@ -15041,15 +17324,30 @@ static void test_listbox_messages(void) log_all_parent_messages++; ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2"); - ok(ret == 0, "expected 0, got %ld\n", ret); + ok(ret == 0, "expected 0, got %Id\n", ret); ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0"); - ok(ret == 1, "expected 1, got %ld\n", ret); + ok(ret == 1, "expected 1, got %Id\n", ret); ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1"); - ok(ret == 2, "expected 2, got %ld\n", ret); + ok(ret == 2, "expected 2, got %Id\n", ret); ok_sequence(wm_lb_addstring, "LB_ADDSTRING", FALSE); check_lb_state(listbox, 3, LB_ERR, 0, 0); + ret = SendMessageA(listbox, LB_RESETCONTENT, 0, 0); + ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret); + check_lb_state(listbox, 0, LB_ERR, 0, 0); + SetFocus(listbox); /* avoid focus messages */ + flush_sequence(); + + if (winetest_debug > 1) trace("clicking on item 0\n"); + ret = SendMessageA(listbox, WM_LBUTTONDBLCLK, 0, MAKELPARAM(1, 1)); + ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret); + ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0); + ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret); + ok_sequence(wm_lb_dblclick_0, "WM_LBUTTONDBLCLK 0", FALSE ); + check_lb_state(listbox, 0, LB_ERR, 0, 0); + flush_sequence(); + log_all_parent_messages--; DestroyWindow(listbox); @@ -15067,15 +17365,30 @@ static void test_listbox_messages(void) log_all_parent_messages++; ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2"); - ok(ret == 0, "expected 0, got %ld\n", ret); + ok(ret == 0, "expected 0, got %Id\n", ret); ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0"); - ok(ret == 0, "expected 0, got %ld\n", ret); + ok(ret == 0, "expected 0, got %Id\n", ret); ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1"); - ok(ret == 1, "expected 1, got %ld\n", ret); + ok(ret == 1, "expected 1, got %Id\n", ret); ok_sequence(wm_lb_addstring, "LB_ADDSTRING", FALSE); check_lb_state(listbox, 3, LB_ERR, 0, 0); + ret = SendMessageA(listbox, LB_RESETCONTENT, 0, 0); + ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret); + check_lb_state(listbox, 0, LB_ERR, 0, 0); + SetFocus(listbox); /* avoid focus messages */ + flush_sequence(); + + if (winetest_debug > 1) trace("clicking on item 0\n"); + ret = SendMessageA(listbox, WM_LBUTTONDBLCLK, 0, MAKELPARAM(1, 1)); + ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret); + ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0); + ok(ret == LB_OKAY, "expected LB_OKAY, got %Id\n", ret); + ok_sequence(wm_lb_dblclick_0, "WM_LBUTTONDBLCLK 0", FALSE ); + check_lb_state(listbox, 0, LB_ERR, 0, 0); + flush_sequence(); + log_all_parent_messages--; DestroyWindow(listbox); @@ -15096,11 +17409,21 @@ static const struct message wm_popup_menu_1[] = { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) }, { WM_INITMENUPOPUP, sent|lparam, 0, 1 }, { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */ + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 1 }, { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 }, { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 }, { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001, 0, 0x40000000 }, + { EVENT_OBJECT_INVOKED, winevent_hook|wparam|lparam|msg_todo, OBJID_MENU, 0 }, + { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */ + { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 }, { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 }, { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 }, @@ -15124,19 +17447,38 @@ static const struct message wm_popup_menu_2[] = { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */ { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */ { HCBT_CREATEWND, hook }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */ + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 1 }, { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 }, { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 }, { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 }, { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */ { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */ + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 1 }, { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 }, { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 }, + { EVENT_OBJECT_INVOKED, winevent_hook|wparam|lparam|msg_todo, OBJID_MENU, 0 }, + { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { HCBT_DESTROYWND, hook }, + { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 }, + { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */ + { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 }, { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 }, { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 }, @@ -15160,19 +17502,38 @@ static const struct message wm_popup_menu_3[] = { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */ { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */ { HCBT_CREATEWND, hook }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */ + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 1 }, { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 }, { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 }, { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 }, { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */ { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */ + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 1 }, { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 }, { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 }, + { EVENT_OBJECT_INVOKED, winevent_hook|wparam|lparam|msg_todo, OBJID_MENU, 100 }, + { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { HCBT_DESTROYWND, hook }, + { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 }, + { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam|msg_todo, OBJID_CLIENT, 0 }, { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */ + { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 }, { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 }, { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 }, @@ -15251,8 +17612,8 @@ static void set_menu_style(HMENU hmenu, DWORD style) mi.fMask = MIM_STYLE; mi.dwStyle = style; SetLastError(0xdeadbeef); - ret = pSetMenuInfo(hmenu, &mi); - ok(ret, "SetMenuInfo error %u\n", GetLastError()); + ret = SetMenuInfo(hmenu, &mi); + ok(ret, "SetMenuInfo error %lu\n", GetLastError()); } static DWORD get_menu_style(HMENU hmenu) @@ -15264,8 +17625,8 @@ static DWORD get_menu_style(HMENU hmenu) mi.fMask = MIM_STYLE; mi.dwStyle = 0; SetLastError(0xdeadbeef); - ret = pGetMenuInfo(hmenu, &mi); - ok(ret, "GetMenuInfo error %u\n", GetLastError()); + ret = GetMenuInfo(hmenu, &mi); + ok(ret, "GetMenuInfo error %lu\n", GetLastError()); return mi.dwStyle; } @@ -15277,12 +17638,8 @@ static void test_menu_messages(void) HMENU hmenu, hmenu_popup; HWND hwnd; DWORD style; + BOOL us_kbd = (GetKeyboardLayout(0) == (HKL)(ULONG_PTR)0x04090409); - if (!pGetMenuInfo || !pSetMenuInfo) - { - win_skip("GetMenuInfo and/or SetMenuInfo are not available\n"); - return; - } cls.style = 0; cls.lpfnWndProc = parent_menu_proc; cls.cbClsExtra = 0; @@ -15294,16 +17651,16 @@ static void test_menu_messages(void) cls.lpszMenuName = NULL; cls.lpszClassName = "TestMenuClass"; UnregisterClassA(cls.lpszClassName, cls.hInstance); - if (!RegisterClassA(&cls)) assert(0); + register_class(&cls); SetLastError(0xdeadbeef); hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 200, 200, 0, 0, 0, NULL); - ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError()); + ok(hwnd != 0, "LoadMenuA error %lu\n", GetLastError()); SetLastError(0xdeadbeef); hmenu = LoadMenuA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1)); - ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError()); + ok(hmenu != 0, "LoadMenuA error %lu\n", GetLastError()); SetMenu(hwnd, hmenu); SetForegroundWindow( hwnd ); @@ -15311,20 +17668,26 @@ static void test_menu_messages(void) set_menu_style(hmenu, MNS_NOTIFYBYPOS); style = get_menu_style(hmenu); - ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style); + ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %lu\n", style); hmenu_popup = GetSubMenu(hmenu, 0); ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n"); style = get_menu_style(hmenu_popup); - ok(style == 0, "expected 0, got %u\n", style); + ok(style == 0, "expected 0, got %lu\n", style); hmenu_popup = GetSubMenu(hmenu_popup, 0); ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n"); style = get_menu_style(hmenu_popup); - ok(style == 0, "expected 0, got %u\n", style); + ok(style == 0, "expected 0, got %lu\n", style); + + if (!us_kbd) + { + skip("skipping ascii VK events on non-us keyboard\n"); + goto done; + } /* Alt+E, Enter */ - trace("testing a popup menu command\n"); + if (winetest_debug > 1) trace("testing a popup menu command\n"); flush_sequence(); keybd_event(VK_MENU, 0, 0, 0); keybd_event('E', 0, 0, 0); @@ -15348,10 +17711,13 @@ static void test_menu_messages(void) win_skip( "menu tracking through VK_MENU not supported\n" ); goto done; } +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA) +#endif ok_sequence(wm_popup_menu_1, "popup menu command", FALSE); /* Alt+F, Right, Enter */ - trace("testing submenu of a popup menu command\n"); + if (winetest_debug > 1) trace("testing submenu of a popup menu command\n"); flush_sequence(); keybd_event(VK_MENU, 0, 0, 0); keybd_event('F', 0, 0, 0); @@ -15366,9 +17732,12 @@ static void test_menu_messages(void) TranslateMessage(&msg); DispatchMessageA(&msg); } +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA && GetNTVersion() != _WIN32_WINNT_WIN7) +#endif ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE); - trace("testing single menu item command\n"); + if (winetest_debug > 1) trace("testing single menu item command\n"); flush_sequence(); keybd_event(VK_MENU, 0, 0, 0); keybd_event('Q', 0, 0, 0); @@ -15381,25 +17750,28 @@ static void test_menu_messages(void) TranslateMessage(&msg); DispatchMessageA(&msg); } +#ifdef __REACTOS__ + if (GetNTVersion() != _WIN32_WINNT_WIN7) +#endif ok_sequence(wm_single_menu_item, "single menu item command", FALSE); set_menu_style(hmenu, 0); style = get_menu_style(hmenu); - ok(style == 0, "expected 0, got %u\n", style); + ok(style == 0, "expected 0, got %lu\n", style); hmenu_popup = GetSubMenu(hmenu, 0); ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n"); set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS); style = get_menu_style(hmenu_popup); - ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style); + ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %lu\n", style); hmenu_popup = GetSubMenu(hmenu_popup, 0); ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n"); style = get_menu_style(hmenu_popup); - ok(style == 0, "expected 0, got %u\n", style); + ok(style == 0, "expected 0, got %lu\n", style); /* Alt+F, Right, Enter */ - trace("testing submenu of a popup menu command\n"); + if (winetest_debug > 1) trace("testing submenu of a popup menu command\n"); flush_sequence(); keybd_event(VK_MENU, 0, 0, 0); keybd_event('F', 0, 0, 0); @@ -15414,6 +17786,9 @@ static void test_menu_messages(void) TranslateMessage(&msg); DispatchMessageA(&msg); } +#ifdef __REACTOS__ + if (GetNTVersion() >= _WIN32_WINNT_VISTA && GetNTVersion() != _WIN32_WINNT_WIN7) +#endif ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE); done: @@ -15426,11 +17801,17 @@ static void test_paintingloop(void) { HWND hwnd; +#ifdef __REACTOS__ + if (!is_reactos() && GetNTVersion() == _WIN32_WINNT_WS03) { + skip("I think this test crashes on our WS03 test bot!\n"); + return; + } +#endif paint_loop_done = FALSE; hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass", "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW, 100, 100, 100, 100, 0, 0, 0, NULL ); - ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError()); + ok(hwnd != 0, "PaintLoop window error %lu\n", GetLastError()); ShowWindow(hwnd,SW_NORMAL); SetFocus(hwnd); @@ -15480,17 +17861,20 @@ static const struct message WmRestoreMinimizedOverlappedSeq[] = { WM_WINDOWPOSCHANGING, sent|optional }, { WM_GETMINMAXINFO, sent|defwinproc }, { WM_NCCALCSIZE, sent|optional }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_NCPAINT, sent|optional }, { WM_GETTEXT, sent|defwinproc|optional }, { WM_ERASEBKGND, sent|optional }, { WM_WINDOWPOSCHANGED, sent|optional }, { HCBT_ACTIVATE, hook }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE }, { WM_ACTIVATEAPP, sent|wparam, TRUE }, { WM_NCACTIVATE, sent|wparam, TRUE }, { WM_GETTEXT, sent|defwinproc|optional }, { WM_ACTIVATE, sent|wparam, TRUE }, { HCBT_SETFOCUS, hook }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|defwinproc }, { WM_NCPAINT, sent }, { WM_GETTEXT, sent|defwinproc|optional }, @@ -15501,12 +17885,58 @@ static const struct message WmRestoreMinimizedOverlappedSeq[] = { WM_NCCALCSIZE, sent|optional }, { WM_NCPAINT, sent|optional }, { WM_ERASEBKGND, sent|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ + { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_ACTIVATE, sent|wparam, TRUE }, { WM_SYNCPAINT, sent|optional }, { WM_PAINT, sent }, { 0 } }; +/* DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0) to an active minimized window */ +static const struct message WmRestoreActiveMinimizedOverlappedSeq[] = +{ + { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_RESTORE, 0 }, + { HCBT_MINMAX, hook }, + { WM_QUERYOPEN, sent }, + { WM_GETTEXT, sent|optional }, + { WM_NCACTIVATE, sent }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_NCCALCSIZE, sent|optional }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sent on Win7. */ + { WM_MOVE, sent|optional }, + { WM_SIZE, sent|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sent on Win7. */ + { WM_GETTEXT, sent|optional }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { WM_GETMINMAXINFO, sent|defwinproc }, + { WM_NCCALCSIZE, sent }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Sent on Win8+. */ + { WM_NCPAINT, sent }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ERASEBKGND, sent }, + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { WM_MOVE, sent|defwinproc }, + { WM_SIZE, sent|defwinproc }, + { WM_NCCALCSIZE, sent|optional }, + { WM_NCPAINT, sent|optional }, + { WM_ERASEBKGND, sent|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ + { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { HCBT_SETFOCUS, hook }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { WM_SETFOCUS, sent }, + /* Note this WM_ACTIVATE messages even if the window is already active */ + { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, 0 }, + { WM_SYNCPAINT, sent|optional }, + { WM_PAINT, sent }, + { WM_GETMINMAXINFO, sent|optional }, + { 0 } +}; + static struct message WmContextMenuSeq[] = { { WM_CONTEXTMENU, sent|wparam, 0 }, /* wparams set in the code */ { WM_CONTEXTMENU, sent|wparam|defwinproc, 0 }, @@ -15526,7 +17956,7 @@ static DWORD CALLBACK post_rbuttonup_msg( void *arg ) DWORD ret; ret = WaitForSingleObject( data->wndproc_finished, 500 ); - todo_wine ok( ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret ); + todo_wine ok( ret == WAIT_OBJECT_0, "WaitForSingleObject returned %lx\n", ret ); if( ret == WAIT_OBJECT_0 ) return 0; PostMessageA( data->hwnd, WM_RBUTTONUP, 0, 0 ); @@ -15548,7 +17978,7 @@ static void test_defwinproc(void) hwnd = CreateWindowExA(0, "TestWindowClass", "test_defwndproc", WS_VISIBLE | WS_CAPTION | WS_OVERLAPPEDWINDOW, 0,0,500,100,0,0,0, NULL); - assert(hwnd); + ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError()); flush_events(); buffA[0] = 0; @@ -15557,13 +17987,13 @@ static void test_defwinproc(void) /* Zero high word of the lParam */ res = DefWindowProcA(hwnd, WM_SETTEXT, 0, 0x1234); - ok(res == 0, "WM_SETTEXT was expected to fail, %ld\n", res); + ok(res == 0, "WM_SETTEXT was expected to fail, %Id\n", res); GetWindowTextA(hwnd, buffA, ARRAY_SIZE(buffA)); ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA); res = DefWindowProcW(hwnd, WM_SETTEXT, 0, 0x1234); - ok(res == 0, "WM_SETTEXT was expected to fail, %ld\n", res); + ok(res == 0, "WM_SETTEXT was expected to fail, %Id\n", res); GetWindowTextA(hwnd, buffA, ARRAY_SIZE(buffA)); ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA); @@ -15574,9 +18004,30 @@ static void test_defwinproc(void) DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0); flush_events(); +#if !defined(__REACTOS__) || !defined(_MSC_VER) // Fails on Windows when built with MSVC ok_sequence(WmRestoreMinimizedOverlappedSeq, "DefWindowProcA(SC_RESTORE):overlapped", TRUE); - flush_sequence(); +#endif + ShowWindow(hwnd, SW_MINIMIZE); + SetActiveWindow(hwnd); + ok(GetActiveWindow() == hwnd, "Unexpected active window\n"); + flush_events(); + flush_sequence(); + DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0); + flush_events(); +#ifdef __REACTOS__ + if (GetNTVersion() != _WIN32_WINNT_VISTA && GetNTVersion() != _WIN32_WINNT_WIN7) +#endif + ok_sequence(WmRestoreActiveMinimizedOverlappedSeq, "DefWindowProcA(SC_RESTORE):active minimized overlapped", TRUE); + +#ifdef __REACTOS__ + if (!is_reactos() && GetNTVersion() == _WIN32_WINNT_WS03) { + skip("The rest of these tests crash on WHS testbot!\n"); + flush_sequence(); + DestroyWindow(hwnd); + return; + } +#endif child[0] = CreateWindowExA(0, "TestWindowClass", "1st child", WS_VISIBLE | WS_CHILD, 0,0,500,100, hwnd, 0, 0, NULL); child[1] = CreateWindowExA(0, "TestWindowClass", "2nd child", @@ -15601,7 +18052,7 @@ static void test_defwinproc(void) SetCursorPos(x, y); flush_events(); res = DefWindowProcA( hwnd, WM_NCHITTEST, 0, MAKELPARAM(x, y)); - ok(res == HTCAPTION, "WM_NCHITTEST returned %ld\n", res); + ok(res == HTCAPTION, "WM_NCHITTEST returned %Id\n", res); mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 ); mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 ); @@ -15618,21 +18069,53 @@ static void test_defwinproc(void) ok_sequence(NCRBUTTONDOWNSeq, "WM_NCRBUTTONDOWN on caption", FALSE); res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, 0, MAKELPARAM(x, y)); - ok(!res, "WM_NCXBUTTONUP returned %ld\n", res); + ok(!res, "WM_NCXBUTTONUP returned %Id\n", res); ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP without button", FALSE); res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON1), MAKELPARAM(x, y)); - ok(!res, "WM_NCXBUTTONUP returned %ld\n", res); + ok(!res, "WM_NCXBUTTONUP returned %Id\n", res); ok_sequence(NCXBUTTONUPSeq1, "WM_NCXBUTTONUP with XBUTTON1", FALSE); res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON2), MAKELPARAM(x, y)); - ok(!res, "WM_NCXBUTTONUP returned %ld\n", res); + ok(!res, "WM_NCXBUTTONUP returned %Id\n", res); ok_sequence(NCXBUTTONUPSeq2, "WM_NCXBUTTONUP with XBUTTON2", FALSE); res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, 3), MAKELPARAM(x, y)); - ok(!res, "WM_NCXBUTTONUP returned %ld\n", res); + ok(!res, "WM_NCXBUTTONUP returned %Id\n", res); ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP with invalid button", FALSE); + /* Test WM_MOUSEACTIVATE */ +#define TEST_MOUSEACTIVATE(A,B,C) \ + res = DefWindowProcA(hwnd, WM_MOUSEACTIVATE, (WPARAM)hwnd, (LPARAM)MAKELRESULT(A,0)); \ + ok(res == B, "WM_MOUSEACTIVATE for %s returned %Id\n", #A, res); \ + res = DefWindowProcA(hwnd, WM_MOUSEACTIVATE, (WPARAM)hwnd, (LPARAM)MAKELRESULT(A,WM_LBUTTONDOWN)); \ + ok(res == C, "WM_MOUSEACTIVATE for %s returned %Id\n", #A, res); + + TEST_MOUSEACTIVATE(HTERROR, MA_ACTIVATE, MA_ACTIVATE); + TEST_MOUSEACTIVATE(HTTRANSPARENT, MA_ACTIVATE, MA_ACTIVATE); + TEST_MOUSEACTIVATE(HTNOWHERE, MA_ACTIVATE, MA_ACTIVATE); + TEST_MOUSEACTIVATE(HTCLIENT, MA_ACTIVATE, MA_ACTIVATE); + TEST_MOUSEACTIVATE(HTCAPTION, MA_ACTIVATE, MA_NOACTIVATE); + TEST_MOUSEACTIVATE(HTSYSMENU, MA_ACTIVATE, MA_ACTIVATE); + TEST_MOUSEACTIVATE(HTSIZE, MA_ACTIVATE, MA_ACTIVATE); + TEST_MOUSEACTIVATE(HTMENU, MA_ACTIVATE, MA_ACTIVATE); + TEST_MOUSEACTIVATE(HTHSCROLL, MA_ACTIVATE, MA_ACTIVATE); + TEST_MOUSEACTIVATE(HTVSCROLL, MA_ACTIVATE, MA_ACTIVATE); + TEST_MOUSEACTIVATE(HTMINBUTTON, MA_ACTIVATE, MA_ACTIVATE); + TEST_MOUSEACTIVATE(HTMAXBUTTON, MA_ACTIVATE, MA_ACTIVATE); + TEST_MOUSEACTIVATE(HTLEFT, MA_ACTIVATE, MA_ACTIVATE); + TEST_MOUSEACTIVATE(HTRIGHT, MA_ACTIVATE, MA_ACTIVATE); + TEST_MOUSEACTIVATE(HTTOP, MA_ACTIVATE, MA_ACTIVATE); + TEST_MOUSEACTIVATE(HTTOPLEFT, MA_ACTIVATE, MA_ACTIVATE); + TEST_MOUSEACTIVATE(HTTOPRIGHT, MA_ACTIVATE, MA_ACTIVATE); + TEST_MOUSEACTIVATE(HTBOTTOM, MA_ACTIVATE, MA_ACTIVATE); + TEST_MOUSEACTIVATE(HTBOTTOMLEFT, MA_ACTIVATE, MA_ACTIVATE); + TEST_MOUSEACTIVATE(HTBOTTOMRIGHT, MA_ACTIVATE, MA_ACTIVATE); + TEST_MOUSEACTIVATE(HTBORDER, MA_ACTIVATE, MA_ACTIVATE); + TEST_MOUSEACTIVATE(HTOBJECT, MA_ACTIVATE, MA_ACTIVATE); + TEST_MOUSEACTIVATE(HTCLOSE, MA_ACTIVATE, MA_ACTIVATE); + TEST_MOUSEACTIVATE(HTHELP, MA_ACTIVATE, MA_ACTIVATE); + SetEvent( data.wndproc_finished ); WaitForSingleObject( thread, 1000 ); CloseHandle( data.wndproc_finished ); @@ -15670,8 +18153,7 @@ static void test_desktop_winproc(void) cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszClassName = "TestDesktopClass"; - ret = !!RegisterClassA(&cls); - ok(ret, "Failed to register class.\n"); + register_class(&cls); hwnd = CreateWindowExA(0, cls.lpszClassName, "test_desktop_wndproc", WS_VISIBLE | WS_CAPTION | WS_OVERLAPPEDWINDOW, 0, 0, 500, 100, 0, 0, 0, NULL); @@ -15690,17 +18172,17 @@ static void test_desktop_winproc(void) todo_wine ok(!strcmp(buffer, "test_desktop_wndproc"), "Got unexpected window text: %s.\n", buffer); res = CallWindowProcA(desktop_proc, hwnd, WM_SETTEXT, 0, (LPARAM)"test"); - ok(res == TRUE, "Failed to set text, %ld.\n", res); + ok(res == TRUE, "Failed to set text, %Id.\n", res); GetWindowTextA(hwnd, buffer, ARRAY_SIZE(buffer)); ok(!strcmp(buffer, "test"), "Got unexpected window text: %s.\n", buffer); SetRect(&default_rect, 0, 0, 100, 100); res = DefWindowProcW(hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&default_rect); - ok(!res, "Got unexpected result %ld.\n", res); + ok(!res, "Got unexpected result %Id.\n", res); SetRect(&rect, 0, 0, 100, 100); res = CallWindowProcA(desktop_proc, hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rect); - ok(!res, "Got unexpected result %ld.\n", res); + ok(!res, "Got unexpected result %Id.\n", res); todo_wine ok(EqualRect(&rect, &default_rect), "rect Got %s, expected %s.\n", wine_dbgstr_rect(&rect), wine_dbgstr_rect(&default_rect)); @@ -15710,16 +18192,46 @@ out_unregister: UnregisterClassA("TestDesktopClass", instance); } +#define open_clipboard(hwnd) open_clipboard_(__LINE__, hwnd) +static BOOL open_clipboard_(int line, HWND hwnd) +{ + DWORD start = GetTickCount(); + while (1) + { + BOOL ret = OpenClipboard(hwnd); + if (ret || GetLastError() != ERROR_ACCESS_DENIED) + return ret; + if (GetTickCount() - start > 100) + { + char classname[256]; + DWORD le = GetLastError(); + HWND clipwnd = GetOpenClipboardWindow(); + /* Provide a hint as to the source of interference: + * - The class name would typically be CLIPBRDWNDCLASS if the + * clipboard was opened by a Windows application using the + * ole32 API. + * - And it would be __wine_clipboard_manager if it was opened in + * response to a native application. + */ + GetClassNameA(clipwnd, classname, ARRAY_SIZE(classname)); + trace_(__FILE__, line)("%p (%s) opened the clipboard\n", clipwnd, classname); + SetLastError(le); + return ret; + } + Sleep(15); + } +} + #define clear_clipboard(hwnd) clear_clipboard_(__LINE__, (hwnd)) static void clear_clipboard_(int line, HWND hWnd) { BOOL succ; - succ = OpenClipboard(hWnd); - ok_(__FILE__, line)(succ, "OpenClipboard failed, err=%u\n", GetLastError()); + succ = open_clipboard_(line, hWnd); + ok_(__FILE__, line)(succ, "OpenClipboard failed, err=%lu\n", GetLastError()); succ = EmptyClipboard(); - ok_(__FILE__, line)(succ, "EmptyClipboard failed, err=%u\n", GetLastError()); + ok_(__FILE__, line)(succ, "EmptyClipboard failed, err=%lu\n", GetLastError()); succ = CloseClipboard(); - ok_(__FILE__, line)(succ, "CloseClipboard failed, err=%u\n", GetLastError()); + ok_(__FILE__, line)(succ, "CloseClipboard failed, err=%lu\n", GetLastError()); } #define expect_HWND(expected, got) expect_HWND_(__LINE__, (expected), (got)) @@ -15776,16 +18288,18 @@ static void test_clipboard_viewers(void) WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, GetDesktopWindow(), NULL, hInst, NULL); + ok(!!hWnd1, "Failed to create window, error %lu.\n", GetLastError()); hWnd2 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 2", WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, GetDesktopWindow(), NULL, hInst, NULL); + ok(!!hWnd2, "Failed to create window, error %lu.\n", GetLastError()); hWnd3 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 3", WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, GetDesktopWindow(), NULL, hInst, NULL); - trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3); - assert(hWnd1 && hWnd2 && hWnd3); + ok(!!hWnd3, "Failed to create window, error %lu.\n", GetLastError()); + if (winetest_debug > 1) trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3); CountClipboardFormats(); /* Ensure that we do not have an X11 update to the clipboard */ flush_sequence(); @@ -15905,7 +18419,7 @@ static void test_PostMessage(void) win_skip("Skipping some PostMessage tests on Win9x/WinMe\n"); return; } - assert(hwnd); + ok(!!hwnd, "Failed to create window, error %lu.\n", GetLastError()); flush_events(); @@ -15922,12 +18436,12 @@ static void test_PostMessage(void) if (data[i].hwnd) ok(ret && msg.hwnd == 0 && msg.message == WM_USER+2 && msg.wParam == 0x5678 && msg.lParam == 0x1234, - "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/0/WM_USER+2/0x5678/0x1234\n", + "%d: got ret %d hwnd %p msg %04x wParam %08Ix lParam %08Ix instead of TRUE/0/WM_USER+2/0x5678/0x1234\n", i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam); else ok(ret && msg.hwnd == hwnd && msg.message == WM_USER+1 && msg.wParam == 0x1234 && msg.lParam == 0x5678, - "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n", + "%d: got ret %d hwnd %p msg %04x wParam %08Ix lParam %08Ix instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n", i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam, msg.hwnd); } } @@ -15936,18 +18450,28 @@ static void test_PostMessage(void) flush_events(); } -static LPARAM g_broadcast_lparam; +static WPARAM g_broadcast_wparam; +static UINT g_broadcast_msg; static LRESULT WINAPI broadcast_test_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); - if (wParam == 0xbaadbeef) - g_broadcast_lparam = wParam; - else - g_broadcast_lparam = 0; + if (message == g_broadcast_msg) + g_broadcast_wparam = wParam; return CallWindowProcA(oldproc, hwnd, message, wParam, lParam); } +static WNDPROC *g_oldproc_sub; +static WPARAM *g_broadcast_sub_wparam; +static LRESULT WINAPI broadcast_test_sub_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + int sub_index = GetWindowLongPtrA(hwnd, GWLP_USERDATA); + + if (message == g_broadcast_msg) + g_broadcast_sub_wparam[sub_index] = wParam; + + return CallWindowProcA(g_oldproc_sub[sub_index], hwnd, message, wParam, lParam); +} static void test_broadcast(void) { @@ -15960,9 +18484,34 @@ static void test_broadcast(void) 0xc000, /* lowest possible atom returned by RegisterWindowMessage */ 0xffff, }; + static const struct + { + LONG style; + BOOL receive; + } bcast_expect[] = + { + {WS_OVERLAPPED, TRUE}, + {WS_OVERLAPPED|WS_DLGFRAME, TRUE}, + {WS_OVERLAPPED|WS_BORDER, TRUE}, + {WS_OVERLAPPED|WS_CAPTION, TRUE}, + {WS_CHILD, FALSE}, + {WS_CHILD|WS_DLGFRAME, FALSE}, + {WS_CHILD|WS_BORDER, FALSE}, + {WS_CHILD|WS_CAPTION, FALSE}, + {WS_CHILD|WS_POPUP, TRUE}, + {WS_POPUP, TRUE}, + {WS_POPUP|WS_DLGFRAME, TRUE}, + {WS_POPUP|WS_BORDER, TRUE}, + {WS_POPUP|WS_CAPTION, TRUE}, + }; WNDPROC oldproc; - unsigned int i; + unsigned int i, j; HWND hwnd; + HWND *hwnd_sub; + + hwnd_sub = malloc(ARRAY_SIZE(bcast_expect) * sizeof(*hwnd_sub)); + g_oldproc_sub = malloc(ARRAY_SIZE(bcast_expect) * sizeof(*g_oldproc_sub)); + g_broadcast_sub_wparam = malloc(ARRAY_SIZE(bcast_expect) * sizeof(*g_broadcast_sub_wparam)); hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, NULL); ok(hwnd != NULL, "got %p\n", hwnd); @@ -15973,6 +18522,7 @@ static void test_broadcast(void) for (i = 0; i < ARRAY_SIZE(messages); i++) { BOOL ret; + BOOL msg_expected = (messages[i] < WM_USER || messages[i] >= 0xc000); MSG msg; flush_events(); @@ -15981,75 +18531,92 @@ static void test_broadcast(void) /* post, broadcast */ ret = PostMessageA(HWND_BROADCAST, messages[i], 0, 0); - ok(ret, "%d: got %d, error %d\n", i, ret, GetLastError()); + ok(ret, "%d: got %d, error %ld\n", i, ret, GetLastError()); memset(&msg, 0xab, sizeof(msg)); ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE); - if (messages[i] < WM_USER || messages[i] >= 0xc000) - { - ok(ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError()); + ok(ret == msg_expected, "%d: message %04x, got %d, error %ld\n", i, messages[i], ret, GetLastError()); + if (msg_expected) ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd); - } - else - { - ok(!ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError()); - } /* post, topmost */ ret = PostMessageA(HWND_TOPMOST, messages[i], 0, 0); - ok(ret, "%d: got %d, error %d\n", i, ret, GetLastError()); + ok(ret, "%d: got %d, error %ld\n", i, ret, GetLastError()); memset(&msg, 0xab, sizeof(msg)); ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE); - if (messages[i] < WM_USER || messages[i] >= 0xc000) - { - ok(ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError()); + ok(ret == msg_expected, "%d: message %04x, got %d, error %ld\n", i, messages[i], ret, GetLastError()); + if (msg_expected) ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd); - } - else - { - ok(!ret, "%d: got %d, error %d\n", i, ret, GetLastError()); - } + } + + for (j = 0; j < ARRAY_SIZE(bcast_expect); j++) + { + hwnd_sub[j] = CreateWindowA("static", NULL, bcast_expect[j].style, 0, 0, 0, 0, hwnd, 0, 0, NULL); + ok(hwnd_sub[j] != NULL, "got %p\n", hwnd_sub[j]); + /* CreateWindow adds extra style flags, so call SetWindowLong to clear some of those. */ + SetWindowLongA(hwnd_sub[j], GWL_STYLE, bcast_expect[j].style); + + g_oldproc_sub[j] = (WNDPROC)SetWindowLongPtrA(hwnd_sub[j], GWLP_WNDPROC, (LONG_PTR)broadcast_test_sub_proc); + SetWindowLongPtrA(hwnd_sub[j], GWLP_USERDATA, (LONG_PTR)j); + } + + for (i = 0; i < ARRAY_SIZE(messages); i++) + { + BOOL ret; + BOOL msg_expected = (messages[i] < WM_USER || messages[i] >= 0xc000); /* send, broadcast */ - g_broadcast_lparam = 0xdead; + g_broadcast_wparam = 0xdead; + for (j = 0; j < ARRAY_SIZE(bcast_expect); j++) + g_broadcast_sub_wparam[j] = 0xdead; + g_broadcast_msg = messages[i]; ret = SendMessageTimeoutA(HWND_BROADCAST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL); if (!ret && GetLastError() == ERROR_TIMEOUT) win_skip("broadcasting test %d, timeout\n", i); else { - if (messages[i] < WM_USER || messages[i] >= 0xc000) + WPARAM wparam_expected = msg_expected ? 0xbaadbeef : 0xdead; + ok(g_broadcast_wparam == wparam_expected, "%d: message %04x, got %#Ix, error %ld\n", + i, messages[i], g_broadcast_wparam, GetLastError()); + for (j = 0; j < ARRAY_SIZE(bcast_expect); j++) { - ok(g_broadcast_lparam == 0xbaadbeef, "%d: message %04x, got %#lx, error %d\n", i, messages[i], - g_broadcast_lparam, GetLastError()); - } - else - { - ok(g_broadcast_lparam == 0xdead, "%d: message %04x, got %#lx, error %d\n", i, messages[i], - g_broadcast_lparam, GetLastError()); + wparam_expected = (msg_expected && bcast_expect[j].receive) ? 0xbaadbeef : 0xdead; + ok(g_broadcast_sub_wparam[j] == wparam_expected, + "%d,%d: message %04x, got %#Ix, error %ld\n", i, j, messages[i], + g_broadcast_sub_wparam[j], GetLastError()); } } /* send, topmost */ - g_broadcast_lparam = 0xdead; + g_broadcast_wparam = 0xdead; + for (j = 0; j < ARRAY_SIZE(bcast_expect); j++) + g_broadcast_sub_wparam[j] = 0xdead; ret = SendMessageTimeoutA(HWND_TOPMOST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL); if (!ret && GetLastError() == ERROR_TIMEOUT) win_skip("broadcasting test %d, timeout\n", i); else { - if (messages[i] < WM_USER || messages[i] >= 0xc000) + WPARAM wparam_expected = msg_expected ? 0xbaadbeef : 0xdead; + ok(g_broadcast_wparam == wparam_expected, "%d: message %04x, got %#Ix, error %ld\n", + i, messages[i], g_broadcast_wparam, GetLastError()); + for (j = 0; j < ARRAY_SIZE(bcast_expect); j++) { - ok(g_broadcast_lparam == 0xbaadbeef, "%d: message %04x, got %#lx, error %d\n", i, messages[i], - g_broadcast_lparam, GetLastError()); - } - else - { - ok(g_broadcast_lparam == 0xdead, "%d: message %04x, got %#lx, error %d\n", i, messages[i], - g_broadcast_lparam, GetLastError()); + wparam_expected = (msg_expected && bcast_expect[j].receive) ? 0xbaadbeef : 0xdead; + ok(g_broadcast_sub_wparam[j] == wparam_expected, + "%d,%d: message %04x, got %#Ix, error %ld\n", i, j, messages[i], + g_broadcast_sub_wparam[j], GetLastError()); } } } + for (j = 0; j < ARRAY_SIZE(bcast_expect); j++) + DestroyWindow(hwnd_sub[j]); + + free(g_broadcast_sub_wparam); + free(g_oldproc_sub); + free(hwnd_sub); + DestroyWindow(hwnd); } @@ -16107,12 +18674,12 @@ static void do_wait_idle_child( int arg ) cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); cls.lpszClassName = "TestClass"; - RegisterClassA( &cls ); + register_class(&cls); PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ); /* create the msg queue */ - ok( start_event != 0, "failed to create start event, error %u\n", GetLastError() ); - ok( end_event != 0, "failed to create end event, error %u\n", GetLastError() ); + ok( start_event != 0, "failed to create start event, error %lu\n", GetLastError() ); + ok( end_event != 0, "failed to create end event, error %lu\n", GetLastError() ); switch (arg) { @@ -16264,7 +18831,7 @@ static DWORD CALLBACK wait_idle_thread( void *arg ) cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); cls.lpszClassName = "TestClass"; - RegisterClassA( &cls ); + register_class(&cls); hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL); while (GetMessageA( &msg, 0, 0, 0 )) DispatchMessageA( &msg ); @@ -16290,8 +18857,8 @@ static void test_WaitForInputIdle( char *argv0 ) start_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_start"); end_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_end"); - ok(start_event != 0, "failed to create start event, error %u\n", GetLastError()); - ok(end_event != 0, "failed to create end event, error %u\n", GetLastError()); + ok(start_event != 0, "failed to create start event, error %lu\n", GetLastError()); + ok(end_event != 0, "failed to create end event, error %lu\n", GetLastError()); memset( &startup, 0, sizeof(startup) ); startup.cb = sizeof(startup); @@ -16304,13 +18871,9 @@ static void test_WaitForInputIdle( char *argv0 ) { ResetEvent( start_event ); ResetEvent( end_event ); -#ifdef __REACTOS__ - sprintf( path, "%s msg_queue %u", argv0, i ); -#else sprintf( path, "%s msg %u", argv0, i ); -#endif ret = CreateProcessA( NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &pi ); - ok( ret, "CreateProcess '%s' failed err %u.\n", path, GetLastError() ); + ok( ret, "CreateProcess '%s' failed err %lu.\n", path, GetLastError() ); if (ret) { ret = WaitForSingleObject( start_event, 5000 ); @@ -16322,23 +18885,24 @@ static void test_WaitForInputIdle( char *argv0 ) ok( console_app || ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken), - "%u: WaitForInputIdle error %08x expected %08x\n", + "%u: WaitForInputIdle error %08x expected %08lx\n", i, ret, wait_idle_expect[i].exp ); else todo_wine_if (wait_idle_expect[i].todo) ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken), - "%u: WaitForInputIdle error %08x expected %08x\n", + "%u: WaitForInputIdle error %08x expected %08lx\n", i, ret, wait_idle_expect[i].exp ); SetEvent( end_event ); WaitForSingleObject( pi.hProcess, 1000 ); /* give it a chance to exit on its own */ } TerminateProcess( pi.hProcess, 0 ); /* just in case */ - winetest_wait_child_process( pi.hProcess ); + wait_child_process( pi.hProcess ); ret = WaitForInputIdle( pi.hProcess, 100 ); ok( ret == WAIT_FAILED, "%u: WaitForInputIdle after exit error %08x\n", i, ret ); CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); } } + CloseHandle( end_event ); CloseHandle( start_event ); PostThreadMessageA( id, WM_QUIT, 0, 0 ); WaitForSingleObject( thread, 10000 ); @@ -16347,7 +18911,7 @@ static void test_WaitForInputIdle( char *argv0 ) static const struct message WmSetParentSeq_1[] = { { WM_SHOWWINDOW, sent|wparam, 0 }, - { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE }, { WM_CHILDACTIVATE, sent }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE }, @@ -16366,20 +18930,21 @@ static const struct message WmSetParentSeq_2[] = { { WM_NCACTIVATE, sent|wparam|optional, 0 }, { WM_ACTIVATE, sent|wparam|optional, 0 }, { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_KILLFOCUS, sent|wparam, 0 }, - { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE }, { HCBT_ACTIVATE, hook|optional }, - { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, { WM_NCACTIVATE, sent|wparam|optional, 1 }, { WM_ACTIVATE, sent|wparam|optional, 1 }, { HCBT_SETFOCUS, hook|optional }, - { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|optional|defwinproc }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOCLIENTSIZE }, { WM_MOVE, sent|defwinproc|wparam, 0 }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_SHOWWINDOW, sent|wparam, 1 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE }, { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, @@ -16407,10 +18972,10 @@ static void test_SetParent(void) ok(child != 0, "Failed to create child window\n"); GetWindowRect(parent1, &rc); - trace("parent1 %s\n", wine_dbgstr_rect(&rc)); + if (winetest_debug > 1) trace("parent1 %s\n", wine_dbgstr_rect(&rc)); GetWindowRect(child, &rc_old); MapWindowPoints(0, parent1, (POINT *)&rc_old, 2); - trace("child %s\n", wine_dbgstr_rect(&rc_old)); + if (winetest_debug > 1) trace("child %s\n", wine_dbgstr_rect(&rc_old)); flush_sequence(); @@ -16422,10 +18987,10 @@ static void test_SetParent(void) ok(!IsWindowVisible(child), "IsWindowVisible() should return FALSE\n"); GetWindowRect(parent2, &rc); - trace("parent2 %s\n", wine_dbgstr_rect(&rc)); + if (winetest_debug > 1) trace("parent2 %s\n", wine_dbgstr_rect(&rc)); GetWindowRect(child, &rc); MapWindowPoints(0, parent2, (POINT *)&rc, 2); - trace("child %s\n", wine_dbgstr_rect(&rc)); + if (winetest_debug > 1) trace("child %s\n", wine_dbgstr_rect(&rc)); ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old), wine_dbgstr_rect(&rc)); @@ -16436,22 +19001,24 @@ static void test_SetParent(void) ok(popup != 0, "Failed to create popup window\n"); GetWindowRect(popup, &rc_old); - trace("popup %s\n", wine_dbgstr_rect(&rc_old)); + if (winetest_debug > 1) trace("popup %s\n", wine_dbgstr_rect(&rc_old)); flush_sequence(); SetParent(popup, child); flush_events(); +#if !defined(__REACTOS__) || !defined(_WIN64) ok_sequence(WmSetParentSeq_2, "SetParent() visible WS_POPUP", TRUE); +#endif ok(GetWindowLongA(popup, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n"); ok(!IsWindowVisible(popup), "IsWindowVisible() should return FALSE\n"); GetWindowRect(child, &rc); - trace("parent2 %s\n", wine_dbgstr_rect(&rc)); + if (winetest_debug > 1) trace("parent2 %s\n", wine_dbgstr_rect(&rc)); GetWindowRect(popup, &rc); MapWindowPoints(0, child, (POINT *)&rc, 2); - trace("popup %s\n", wine_dbgstr_rect(&rc)); + if (winetest_debug > 1) trace("popup %s\n", wine_dbgstr_rect(&rc)); ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old), wine_dbgstr_rect(&rc)); @@ -16493,7 +19060,8 @@ static void test_keyflags(void) MSG msg; test_window = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, - 100, 100, 200, 200, 0, 0, 0, NULL); + 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), + 0, 0, 0, NULL); flush_events(); flush_sequence(); @@ -16652,6 +19220,29 @@ static const struct message WmHotkeyNew[] = { { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */ { 0 } }; +static const struct message WmHotkeyPressALT[] = { + { WM_SYSKEYDOWN, kbd_hook|wparam|lparam, VK_LMENU, LLKHF_INJECTED|LLKHF_ALTDOWN }, + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, + { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 }, + { 0 } +}; +static const struct message WmHotkeyPressWithALT[] = { + { WM_SYSKEYDOWN, kbd_hook, 0, LLKHF_INJECTED|LLKHF_ALTDOWN }, /* lparam not checked */ + { WM_HOTKEY, sent|wparam, 6 }, + { 0 } +}; +static const struct message WmHotkeyReleaseWithALT[] = { + { WM_SYSKEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP|LLKHF_ALTDOWN }, + { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 0xa0000001 }, + { WM_SYSKEYUP, sent|lparam, 0, 0xa0000001 }, + { 0 } +}; +static const struct message WmHotkeyReleaseALT[] = { + { WM_KEYUP, kbd_hook|wparam|lparam, VK_LMENU, LLKHF_INJECTED|LLKHF_UP }, + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, + { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 }, + { 0 } +}; static int hotkey_letter; @@ -16671,10 +19262,13 @@ static LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam msg.descr = "KeyboardHookProc"; add_message(&msg); - if (wParam == WM_KEYUP || wParam == WM_KEYDOWN) + if (wParam == WM_KEYUP || wParam == WM_KEYDOWN || + wParam == WM_SYSKEYUP || wParam == WM_SYSKEYDOWN) { - ok(kdbhookstruct->vkCode == VK_LWIN || kdbhookstruct->vkCode == hotkey_letter, - "unexpected keycode %x\n", kdbhookstruct->vkCode); + ok(kdbhookstruct->vkCode == VK_LWIN || + kdbhookstruct->vkCode == VK_LMENU || + kdbhookstruct->vkCode == hotkey_letter, + "unexpected keycode %lx\n", kdbhookstruct->vkCode); } } @@ -16699,21 +19293,24 @@ static void test_hotkey(void) ok(ret == FALSE, "expected FALSE, got %i\n", ret); ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef), - "unexpected error %d\n", GetLastError()); + "unexpected error %ld\n", GetLastError()); test_window = CreateWindowExA(0, "HotkeyWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, - 100, 100, 200, 200, 0, 0, 0, NULL); + 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), + 0, 0, 0, NULL); + SetForegroundWindow(test_window); + flush_events(); flush_sequence(); SetLastError(0xdeadbeef); ret = UnregisterHotKey(test_window, 0); ok(ret == FALSE, "expected FALSE, got %i\n", ret); ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef), - "unexpected error %d\n", GetLastError()); + "unexpected error %ld\n", GetLastError()); /* Search for a Windows Key + letter combination that hasn't been registered */ - for (hotkey_letter = 0x41; hotkey_letter <= 0x51; hotkey_letter ++) + for (hotkey_letter = 'A'; hotkey_letter <= 'Z'; hotkey_letter ++) { SetLastError(0xdeadbeef); ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter); @@ -16725,11 +19322,11 @@ static void test_hotkey(void) else { ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef), - "unexpected error %d\n", GetLastError()); + "unexpected error %ld\n", GetLastError()); } } - if (hotkey_letter == 0x52) + if (hotkey_letter > 'Z') { ok(0, "Couldn't find any free Windows Key + letter combination\n"); goto end; @@ -16743,21 +19340,21 @@ static void test_hotkey(void) ret = RegisterHotKey(test_window, 4, MOD_WIN, hotkey_letter); ok(ret == FALSE, "expected FALSE, got %i\n", ret); ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef), - "unexpected error %d\n", GetLastError()); + "unexpected error %ld\n", GetLastError()); /* Same key combination, different window */ SetLastError(0xdeadbeef); ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter); ok(ret == FALSE, "expected FALSE, got %i\n", ret); ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef), - "unexpected error %d\n", GetLastError()); + "unexpected error %ld\n", GetLastError()); /* Register the same hotkey twice */ SetLastError(0xdeadbeef); ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter); ok(ret == FALSE, "expected FALSE, got %i\n", ret); ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef), - "unexpected error %d\n", GetLastError()); + "unexpected error %ld\n", GetLastError()); /* Window on another thread */ taskbar_window = FindWindowA("Shell_TrayWnd", NULL); @@ -16771,7 +19368,7 @@ static void test_hotkey(void) ret = RegisterHotKey(taskbar_window, 5, 0, hotkey_letter); ok(ret == FALSE, "expected FALSE, got %i\n", ret); ok(GetLastError() == ERROR_WINDOW_OF_OTHER_THREAD || broken(GetLastError() == 0xdeadbeef), - "unexpected error %d\n", GetLastError()); + "unexpected error %ld\n", GetLastError()); } /* Inject the appropriate key sequence */ @@ -16782,20 +19379,20 @@ static void test_hotkey(void) keybd_event(hotkey_letter, 0, 0, 0); queue_status = GetQueueStatus(QS_HOTKEY); - ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status); + ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %lx\n", queue_status); while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_HOTKEY) { ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd); - ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam); + ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %Ix\n", msg.lParam); } DispatchMessageA(&msg); } ok_sequence(WmHotkeyPress, "window hotkey press", FALSE); queue_status = GetQueueStatus(QS_HOTKEY); - ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status); + ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %lx\n", queue_status); key_state = GetAsyncKeyState(hotkey_letter); ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state); @@ -16813,9 +19410,9 @@ static void test_hotkey(void) /* normal posted WM_HOTKEY messages set QS_HOTKEY */ PostMessageA(test_window, WM_HOTKEY, 0, 0); queue_status = GetQueueStatus(QS_HOTKEY); - ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status); + ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %lx\n", queue_status); queue_status = GetQueueStatus(QS_POSTMESSAGE); - ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status); + ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %lx\n", queue_status); while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); flush_sequence(); @@ -16832,7 +19429,7 @@ static void test_hotkey(void) if (msg.message == WM_HOTKEY) { ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd); - ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam); + ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %Ix\n", msg.lParam); } DispatchMessageA(&msg); } @@ -16840,7 +19437,7 @@ static void test_hotkey(void) /* Register same hwnd/id with different key combination */ ret = RegisterHotKey(test_window, 5, 0, hotkey_letter); - ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError()); + ok(ret == TRUE, "expected TRUE, got %i, err=%ld\n", ret, GetLastError()); /* Previous key combination does not work */ keybd_event(VK_LWIN, 0, 0, 0); @@ -16861,7 +19458,7 @@ static void test_hotkey(void) if (msg.message == WM_HOTKEY) { ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd); - ok(msg.lParam == MAKELPARAM(0, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam); + ok(msg.lParam == MAKELPARAM(0, hotkey_letter), "unexpected WM_HOTKEY lparam %Ix\n", msg.lParam); } DispatchMessageA(&msg); } @@ -16869,18 +19466,18 @@ static void test_hotkey(void) /* Unregister hotkey properly */ ret = UnregisterHotKey(test_window, 5); - ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError()); + ok(ret == TRUE, "expected TRUE, got %i, err=%ld\n", ret, GetLastError()); /* Unregister hotkey again */ SetLastError(0xdeadbeef); ret = UnregisterHotKey(test_window, 5); ok(ret == FALSE, "expected FALSE, got %i\n", ret); ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef), - "unexpected error %d\n", GetLastError()); + "unexpected error %ld\n", GetLastError()); /* Register thread hotkey */ ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter); - ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError()); + ok(ret == TRUE, "expected TRUE, got %i, err=%ld\n", ret, GetLastError()); /* Inject the appropriate key sequence */ keybd_event(VK_LWIN, 0, 0, 0); @@ -16898,7 +19495,7 @@ static void test_hotkey(void) { struct recvd_message message; ok(msg.hwnd == NULL, "unexpected hwnd %p\n", msg.hwnd); - ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam); + ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %Ix\n", msg.lParam); message.message = msg.message; message.flags = sent|wparam|lparam; message.wParam = msg.wParam; @@ -16923,15 +19520,64 @@ static void test_hotkey(void) keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0); while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) { - ros_skip_flaky ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message); DispatchMessageA(&msg); } ok_sequence(WmHotkeyReleaseLWIN, "thread hotkey release LWIN", FALSE); + /* Search for an ALT + letter combination that hasn't been registered */ + for (hotkey_letter = 'A'; hotkey_letter <= 'Z'; hotkey_letter ++) + { + SetLastError(0xdeadbeef); + ret = RegisterHotKey(test_window, 6, MOD_ALT, hotkey_letter); + + if (ret == TRUE) + { + break; + } + else + { + ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef), + "unexpected error %ld\n", GetLastError()); + } + } + + if (hotkey_letter > 'Z') + { + ok(0, "Couldn't find any free ALT + letter combination\n"); + goto end; + } + + keybd_event(VK_LMENU, 0, 0, 0); + while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) + DispatchMessageA(&msg); + ok_sequence(WmHotkeyPressALT, "window hotkey press ALT", TRUE); + + keybd_event(hotkey_letter, 0, 0, 0); + while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (msg.message == WM_HOTKEY) + { + ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd); + ok(msg.lParam == MAKELPARAM(MOD_ALT, hotkey_letter), "unexpected WM_HOTKEY lparam %Ix\n", msg.lParam); + } + DispatchMessageA(&msg); + } + ok_sequence(WmHotkeyPressWithALT, "window hotkey press with ALT", FALSE); + + keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0); + while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) + DispatchMessageA(&msg); + ok_sequence(WmHotkeyReleaseWithALT, "window hotkey release with ALT", TRUE); + + keybd_event(VK_LMENU, 0, KEYEVENTF_KEYUP, 0); + while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) + DispatchMessageA(&msg); + ok_sequence(WmHotkeyReleaseALT, "window hotkey release ALT", FALSE); + /* Unregister thread hotkey */ ret = UnregisterHotKey(NULL, 5); - ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError()); + ok(ret == TRUE, "expected TRUE, got %i, err=%ld\n", ret, GetLastError()); if (hKBD_hook) UnhookWindowsHookEx(hKBD_hook); hKBD_hook = NULL; @@ -16939,6 +19585,7 @@ static void test_hotkey(void) end: UnregisterHotKey(NULL, 5); UnregisterHotKey(test_window, 5); + UnregisterHotKey(test_window, 6); DestroyWindow(test_window); flush_sequence(); } @@ -16947,6 +19594,7 @@ end: static const struct message WmSetFocus_1[] = { { HCBT_SETFOCUS, hook }, /* child */ { HCBT_ACTIVATE, hook }, /* parent */ + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_QUERYNEWPALETTE, sent|wparam|lparam|parent|optional, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|parent, 0, SWP_NOSIZE|SWP_NOMOVE }, { WM_ACTIVATEAPP, sent|wparam|parent, 1 }, @@ -16955,14 +19603,17 @@ static const struct message WmSetFocus_1[] = { { WM_GETTEXT, sent|defwinproc|parent|optional }, { WM_ACTIVATE, sent|wparam|parent, 1 }, { HCBT_SETFOCUS, hook }, /* parent */ + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|defwinproc|parent }, { WM_KILLFOCUS, sent|parent }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent }, { 0 } }; static const struct message WmSetFocus_2[] = { { HCBT_SETFOCUS, hook }, /* parent */ { WM_KILLFOCUS, sent }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|parent }, { 0 } }; @@ -16980,9 +19631,9 @@ static void test_SetFocus(void) DWORD ret, tid; wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL); - ok(wnd_event.start_event != 0, "CreateEvent error %d\n", GetLastError()); + ok(wnd_event.start_event != 0, "CreateEvent error %ld\n", GetLastError()); hthread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid); - ok(hthread != 0, "CreateThread error %d\n", GetLastError()); + ok(hthread != 0, "CreateThread error %ld\n", GetLastError()); ret = WaitForSingleObject(wnd_event.start_event, INFINITE); ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); CloseHandle(wnd_event.start_event); @@ -16994,7 +19645,7 @@ static void test_SetFocus(void) 0, 0, 0, 0, parent, 0, 0, NULL); ok(child != 0, "failed to create child window\n"); - trace("parent %p, child %p, thread window %p\n", parent, child, wnd_event.hwnd); + if (winetest_debug > 1) trace("parent %p, child %p, thread window %p\n", parent, child, wnd_event.hwnd); SetFocus(0); SetActiveWindow(0); @@ -17024,7 +19675,7 @@ static void test_SetFocus(void) SetLastError(0xdeadbeef); old_focus = SetFocus((HWND)0xdeadbeef); ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef), - "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError()); + "expected ERROR_INVALID_WINDOW_HANDLE, got %ld\n", GetLastError()); while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); ok_sequence(WmEmptySeq, "SetFocus on an invalid window", FALSE); ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus); @@ -17034,7 +19685,7 @@ static void test_SetFocus(void) SetLastError(0xdeadbeef); old_focus = SetFocus(GetDesktopWindow()); ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ || - broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError()); while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); ok_sequence(WmEmptySeq, "SetFocus on a desktop window", TRUE); ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus); @@ -17044,7 +19695,7 @@ static void test_SetFocus(void) SetLastError(0xdeadbeef); old_focus = SetFocus(wnd_event.hwnd); ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ || - broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError()); while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); ok_sequence(WmEmptySeq, "SetFocus on another thread window", TRUE); ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus); @@ -17054,7 +19705,7 @@ static void test_SetFocus(void) SetLastError(0xdeadbeef); old_active = SetActiveWindow((HWND)0xdeadbeef); ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef), - "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError()); + "expected ERROR_INVALID_WINDOW_HANDLE, got %ld\n", GetLastError()); while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); ok_sequence(WmEmptySeq, "SetActiveWindow on an invalid window", FALSE); ok(old_active == 0, "expected old focus 0, got %p\n", old_active); @@ -17063,8 +19714,8 @@ static void test_SetFocus(void) SetLastError(0xdeadbeef); old_active = SetActiveWindow(GetDesktopWindow()); -todo_wine - ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); + todo_wine + ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError()); while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); ok_sequence(WmEmptySeq, "SetActiveWindow on a desktop window", TRUE); ok(old_active == 0, "expected old focus 0, got %p\n", old_focus); @@ -17073,8 +19724,8 @@ todo_wine SetLastError(0xdeadbeef); old_active = SetActiveWindow(wnd_event.hwnd); -todo_wine - ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); + todo_wine + ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError()); while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); ok_sequence(WmEmptySeq, "SetActiveWindow on another thread window", TRUE); ok(old_active == 0, "expected old focus 0, got %p\n", old_active); @@ -17083,7 +19734,7 @@ todo_wine SetLastError(0xdeadbeef); ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE); - ok(ret, "AttachThreadInput error %d\n", GetLastError()); + ok(ret, "AttachThreadInput error %ld\n", GetLastError()); ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow()); ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus()); @@ -17114,7 +19765,7 @@ todo_wine SetLastError(0xdeadbeef); ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE); - ok(ret, "AttachThreadInput error %d\n", GetLastError()); + ok(ret, "AttachThreadInput error %ld\n", GetLastError()); ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow()); ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus()); @@ -17136,10 +19787,10 @@ todo_wine SetLastError(0xdeadbeef); old_focus = SetFocus(child); -todo_wine + todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER /* Vista+ */ || broken(GetLastError() == 0) /* XP */ || - broken(GetLastError() == 0xdeadbeef), "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + broken(GetLastError() == 0xdeadbeef), "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError()); while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); ok_sequence(WmSetFocus_3, "SetFocus on a child window", TRUE); ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus); @@ -17148,7 +19799,7 @@ todo_wine SetLastError(0xdeadbeef); old_active = SetActiveWindow(child); - ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError()); while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); ok_sequence(WmEmptySeq, "SetActiveWindow on a child window", FALSE); ok(old_active == parent, "expected old active %p, got %p\n", parent, old_active); @@ -17161,7 +19812,7 @@ todo_wine DestroyWindow(parent); ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0); - ok(ret, "PostMessage(WM_QUIT) error %d\n", GetLastError()); + ok(ret, "PostMessage(WM_QUIT) error %ld\n", GetLastError()); ret = WaitForSingleObject(hthread, INFINITE); ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); CloseHandle(hthread); @@ -17169,6 +19820,7 @@ todo_wine static const struct message WmSetLayeredStyle[] = { { WM_STYLECHANGING, sent }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, { WM_STYLECHANGED, sent }, { WM_GETTEXT, sent|defwinproc|optional }, { 0 } @@ -17179,9 +19831,16 @@ static const struct message WmSetLayeredStyle2[] = { { WM_STYLECHANGED, sent }, { WM_WINDOWPOSCHANGING, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { WM_NCCALCSIZE, sent|optional|wparam|defwinproc, 1 }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 }, { WM_WINDOWPOSCHANGED, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { WM_MOVE, sent|optional|defwinproc|wparam, 0 }, { WM_SIZE, sent|optional|defwinproc|wparam, SIZE_RESTORED }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, + { 0 } +}; + +static const struct message WmLayeredWinEmptySeq[] = { + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { 0 } }; @@ -17247,13 +19906,13 @@ static void test_layered_window(void) size.cx = size.cy = 250; ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE ); ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED ); ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE ); ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE ); - ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() ); - ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE ); + ok( ret, "UpdateLayeredWindow failed err %lu\n", GetLastError() ); + ok_sequence( WmLayeredWinEmptySeq, "UpdateLayeredWindow", FALSE ); GetWindowRect( hwnd, &rect ); ok( rect.left == 300 && rect.top == 300 && rect.right == 550 && rect.bottom == 550, "wrong window rect %s\n", wine_dbgstr_rect( &rect )); @@ -17264,8 +19923,8 @@ static void test_layered_window(void) size.cx = 150; pos.y = 200; ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE ); - ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() ); - ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE ); + ok( ret, "UpdateLayeredWindow failed err %lu\n", GetLastError() ); + ok_sequence( WmLayeredWinEmptySeq, "UpdateLayeredWindow", FALSE ); GetWindowRect( hwnd, &rect ); ok( rect.left == 300 && rect.top == 200 && rect.right == 450 && rect.bottom == 450, "wrong window rect %s\n", wine_dbgstr_rect( &rect )); @@ -17280,8 +19939,8 @@ static void test_layered_window(void) size.cx = 200; pos.x = 200; ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE ); - ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() ); - ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE ); + ok( ret, "UpdateLayeredWindow failed err %lu\n", GetLastError() ); + ok_sequence( WmLayeredWinEmptySeq, "UpdateLayeredWindow", FALSE ); GetWindowRect( hwnd, &rect ); ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450, "wrong window rect %s\n", wine_dbgstr_rect( &rect )); @@ -17294,12 +19953,12 @@ static void test_layered_window(void) ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE ); ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" ); ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == ERROR_MR_MID_NOT_FOUND) || - broken(GetLastError() == ERROR_GEN_FAILURE) /* win7 */, "wrong error %u\n", GetLastError() ); + broken(GetLastError() == ERROR_GEN_FAILURE) /* win7 */, "wrong error %lu\n", GetLastError() ); size.cx = 1; size.cy = -1; ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE ); ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED ); ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE ); @@ -17338,6 +19997,25 @@ static void test_layered_window(void) static HMENU hpopupmenu; +static LRESULT WINAPI minimize_popup_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + LRESULT ret; + + if (ignore_message( message )) return 0; + ret = MsgCheckProc( FALSE, hwnd, message, wParam, lParam ); + + switch (message) { + case WM_ENTERIDLE: + ShowWindow(hwnd, SW_MINIMIZE); + break; + case WM_TIMER: + EndMenu(); + break; + } + + return ret; +} + static LRESULT WINAPI cancel_popup_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { if (ignore_message( message )) return 0; @@ -17350,10 +20028,10 @@ static LRESULT WINAPI cancel_popup_proc(HWND hwnd, UINT message, WPARAM wParam, case WM_INITMENU: case WM_INITMENUPOPUP: case WM_UNINITMENUPOPUP: - ok((HMENU)wParam == hpopupmenu, "expected %p, got %lx\n", hpopupmenu, wParam); + ok((HMENU)wParam == hpopupmenu, "expected %p, got %Ix\n", hpopupmenu, wParam); break; case WM_CAPTURECHANGED: - todo_wine ok(!lParam || (HWND)lParam == hwnd, "lost capture to %lx\n", lParam); + todo_wine ok(!lParam || (HWND)lParam == hwnd, "lost capture to %Ix\n", lParam); break; } @@ -17382,12 +20060,12 @@ static void test_TrackPopupMenu(void) hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0, 0, 0, 1, 1, 0, NULL, NULL, 0); - ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); + ok(hwnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError()); SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc); hpopupmenu = CreatePopupMenu(); - ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); + ok(hpopupmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError()); AppendMenuA(hpopupmenu, MF_STRING, 100, "item 1"); AppendMenuA(hpopupmenu, MF_STRING, 100, "item 2"); @@ -17396,13 +20074,13 @@ static void test_TrackPopupMenu(void) flush_sequence(); ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL); ok_sequence(WmTrackPopupMenu, "TrackPopupMenu", TRUE); - ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError()); + ok(ret == 1, "TrackPopupMenu failed with error %li\n", GetLastError()); /* Test popup closing with an ESC-press */ flush_events(); PostMessageW(hwnd, WM_KEYDOWN, VK_ESCAPE, 0); ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL); - ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError()); + ok(ret == 1, "TrackPopupMenu failed with error %li\n", GetLastError()); PostQuitMessage(0); flush_sequence(); while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) ) @@ -17420,6 +20098,24 @@ static void test_TrackPopupMenu(void) ok_sequence(WmTrackPopupMenuAbort, "WmTrackPopupMenuAbort", TRUE); ok(ret == TRUE, "TrackPopupMenu failed\n"); + SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)minimize_popup_proc); + + /* set cursor over the window, otherwise the WM_CANCELMODE message may not always be sent */ + SetCursorPos( 0, 0 ); + ShowWindow( hwnd, SW_SHOW ); + + flush_events(); + flush_sequence(); + SetTimer( hwnd, TIMER_ID, 500, NULL ); + ret = TrackPopupMenu( hpopupmenu, 0, 100,100, 0, hwnd, NULL ); +#ifdef __REACTOS__ + if (GetNTVersion() != _WIN32_WINNT_VISTA && GetNTVersion() != _WIN32_WINNT_WIN7) +#endif + ok_sequence( WmTrackPopupMenuMinimizeWindow, "TrackPopupMenuMinimizeWindow", TRUE ); + ok( ret == 1, "TrackPopupMenu failed with error %li\n", GetLastError() ); + KillTimer( hwnd, TIMER_ID ); + ShowWindow( hwnd, SW_RESTORE ); + SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc); SetCapture(hwnd); @@ -17428,7 +20124,7 @@ static void test_TrackPopupMenu(void) flush_sequence(); ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL); ok_sequence(WmTrackPopupMenuCapture, "TrackPopupMenuCapture", TRUE); - ok(ret == 1, "TrackPopupMenuCapture failed with error %i\n", GetLastError()); + ok(ret == 1, "TrackPopupMenuCapture failed with error %li\n", GetLastError()); DestroyMenu(hpopupmenu); DestroyWindow(hwnd); @@ -17442,12 +20138,12 @@ static void test_TrackPopupMenuEmpty(void) hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0, 0, 0, 1, 1, 0, NULL, NULL, 0); - ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); + ok(hwnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError()); SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc); hpopupmenu = CreatePopupMenu(); - ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); + ok(hpopupmenu != NULL, "CreateMenu failed with error %ld\n", GetLastError()); flush_events(); flush_sequence(); @@ -17473,56 +20169,41 @@ static const struct message send_message_3[] = { { WM_USER+1, sent|wparam|lparam, 0, 0 }, { 0 } }; +static const struct message send_message_5[] = { + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE, 0, SWP_NOZORDER }, /* win7+ dual monitor */ + { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* win7+ dual monitor */ + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE, 0, SWP_NOZORDER }, /* win7+ dual monitor */ + { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* win7+ dual monitor */ + { 0 } +}; static DWORD WINAPI SendMessage_thread_1(void *param) { struct wnd_event *wnd_event = param; + DWORD ret; - trace("thread: starting\n"); + if (winetest_debug > 1) trace("thread: starting\n"); WaitForSingleObject(wnd_event->start_event, INFINITE); - trace("thread: call PostMessage\n"); + if (winetest_debug > 1) trace("thread: call PostMessage\n"); PostMessageA(wnd_event->hwnd, WM_USER, 0, 0); - trace("thread: call PostMessage\n"); + if (winetest_debug > 1) trace("thread: call PostMessage\n"); PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0); - trace("thread: call SendMessage\n"); + if (winetest_debug > 1) trace("thread: call SendMessage\n"); SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0); + SetEvent(wnd_event->stop_event); + ret = WaitForSingleObject(wnd_event->getmessage_complete, 100); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed, ret:%lx\n", ret); - trace("thread: call SendMessage\n"); + if (winetest_debug > 1) trace("thread: call SendMessage\n"); SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0); return 0; } -static DWORD WINAPI SendMessage_thread_2(void *param) -{ - struct wnd_event *wnd_event = param; - - trace("thread: starting\n"); - WaitForSingleObject(wnd_event->start_event, INFINITE); - - trace("thread: call PostMessage\n"); - PostMessageA(wnd_event->hwnd, WM_USER, 0, 0); - - trace("thread: call PostMessage\n"); - PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0); - - /* this leads to sending an internal message under Wine */ - trace("thread: call SetParent\n"); - SetParent(wnd_event->hwnd, wnd_event->hwnd); - - trace("thread: call SendMessage\n"); - SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0); - - trace("thread: call SendMessage\n"); - SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0); - - return 0; -} - -static void test_SendMessage_other_thread(int thread_n) +static void test_SendMessage_other_thread(void) { DWORD qs_all_input = QS_ALLINPUT & ~QS_RAWINPUT; HANDLE hthread; @@ -17531,20 +20212,22 @@ static void test_SendMessage_other_thread(int thread_n) MSG msg; wnd_event.start_event = CreateEventA(NULL, 0, 0, NULL); + wnd_event.stop_event = CreateEventA(NULL, 0, 0, NULL); + wnd_event.getmessage_complete = CreateEventA(NULL, 0, 0, NULL); wnd_event.hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL); ok(wnd_event.hwnd != 0, "CreateWindowEx failed\n"); - hthread = CreateThread(NULL, 0, thread_n == 1 ? SendMessage_thread_1 : SendMessage_thread_2, &wnd_event, 0, &tid); - ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError()); + hthread = CreateThread(NULL, 0, SendMessage_thread_1, &wnd_event, 0, &tid); + ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError()); CloseHandle(hthread); flush_events(); flush_sequence(); ret = GetQueueStatus(QS_SENDMESSAGE); - ok(ret == 0, "wrong status %08x\n", ret); + ok(ret == 0, "wrong status %08lx\n", ret); SetEvent(wnd_event.start_event); @@ -17557,50 +20240,105 @@ static void test_SendMessage_other_thread(int thread_n) } ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE); - ok(ret == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08x\n", ret); + ok(ret == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08lx\n", ret); - trace("main: call GetMessage\n"); + if (winetest_debug > 1) trace("main: call GetMessage\n"); GetMessageA(&msg, 0, 0, 0); ok(msg.message == WM_USER, "expected WM_USER, got %04x\n", msg.message); DispatchMessageA(&msg); - ok_sequence(send_message_1, "SendMessage from other thread 1", thread_n == 2); + ok_sequence(send_message_1, "SendMessage from other thread 1", FALSE); + + SetEvent(wnd_event.getmessage_complete); + + ret = WaitForSingleObject(wnd_event.stop_event, 100); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed, ret:%lx\n", ret); /* intentionally yield */ MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input); - trace("main: call SendMessage\n"); + if (winetest_debug > 1) trace("main: call SendMessage\n"); SendMessageA(wnd_event.hwnd, WM_USER+4, 0, 0); ok_sequence(send_message_2, "SendMessage from other thread 2", FALSE); ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE); - ok(ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08x\n", ret); + ok(ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08lx\n", ret); - trace("main: call PeekMessage\n"); + if (winetest_debug > 1) trace("main: call PeekMessage\n"); ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should not fail\n"); ok(msg.message == WM_USER+1, "expected WM_USER+1, got %04x\n", msg.message); DispatchMessageA(&msg); - ok_sequence(send_message_3, "SendMessage from other thread 3", thread_n == 2); + ok_sequence(send_message_3, "SendMessage from other thread 3", FALSE); /* intentionally yield */ MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input); - ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE); - /* FIXME: remove once Wine is fixed */ -todo_wine_if (thread_n == 2) - ok(ret == 0, "wrong status %08x\n", ret); - - trace("main: call PeekMessage\n"); - ok(!PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should fail\n"); - ok_sequence(WmEmptySeq, "SendMessage from other thread 5", thread_n == 2); + if (winetest_debug > 1) trace("main: call PeekMessage\n"); + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) { + ok(ignore_message(msg.message), "got unexpected message %04x from PeekMessageA\n", msg.message); + } + ok_sequence(send_message_5, "SendMessage from other thread 5", FALSE); ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE); - ok(ret == 0, "wrong status %08x\n", ret); + ok(ret == 0, "wrong status %08lx\n", ret); - trace("main: call DestroyWindow\n"); + if (winetest_debug > 1) trace("main: call DestroyWindow\n"); DestroyWindow(msg.hwnd); flush_events(); flush_sequence(); + + CloseHandle(wnd_event.start_event); + CloseHandle(wnd_event.stop_event); + CloseHandle(wnd_event.getmessage_complete); +} + +static DWORD WINAPI SetParent_thread(void *param) +{ + struct wnd_event *wnd_event = param; + + if (winetest_debug > 1) trace("thread: started\n"); + SetEvent(wnd_event->start_event); + + /* this leads to sending an internal message under Wine */ + if (winetest_debug > 1) trace("thread: call SetParent\n"); + SetParent(wnd_event->hwnd, wnd_event->hwnd); + + return 0; +} + +static void test_setparent_status(void) +{ + HANDLE hthread; + struct wnd_event wnd_event; + DWORD ret; + + wnd_event.start_event = CreateEventA(NULL, 0, 0, NULL); + + wnd_event.hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW, + 100, 100, 200, 200, 0, 0, 0, NULL); + ok(wnd_event.hwnd != 0, "CreateWindowEx failed\n"); + + ret = GetQueueStatus(QS_SENDMESSAGE); + ok(ret == 0, "wrong status %08lx\n", ret); + + hthread = CreateThread(NULL, 0, SetParent_thread, &wnd_event, 0, NULL); + ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError()); + + WaitForSingleObject(wnd_event.start_event, INFINITE); + + /* background thread's SetParent should complete allowing the thread to exit */ + ret = MsgWaitForMultipleObjects(1, &hthread, FALSE, 1000, QS_SENDMESSAGE); + todo_wine ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %08lx\n", ret); + + /* QS_SENDMESSAGE status should not have been set by SetParent */ + ret = GetQueueStatus(QS_SENDMESSAGE); + todo_wine ok(ret == 0, "wrong status %08lx\n", ret); + + DestroyWindow(wnd_event.hwnd); + + WaitForSingleObject(hthread, INFINITE); + CloseHandle(hthread); + CloseHandle(wnd_event.start_event); } static LRESULT CALLBACK insendmessage_wnd_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) @@ -17611,34 +20349,35 @@ static LRESULT CALLBACK insendmessage_wnd_proc( HWND hwnd, UINT msg, WPARAM wp, switch (msg) { case WM_USER: - ok( flags == ISMEX_SEND, "wrong flags %x\n", flags ); + ok( flags == ISMEX_SEND, "wrong flags %lx\n", flags ); ok( InSendMessage(), "InSendMessage returned false\n" ); ret = ReplyMessage( msg ); - ok( ret, "ReplyMessage failed err %u\n", GetLastError() ); + ok( ret, "ReplyMessage failed err %lu\n", GetLastError() ); flags = InSendMessageEx( NULL ); - ok( flags == (ISMEX_SEND | ISMEX_REPLIED), "wrong flags %x\n", flags ); + ok( flags == (ISMEX_SEND | ISMEX_REPLIED) || broken( flags == (ISMEX_NOTIFY | ISMEX_REPLIED) ), + "wrong flags %lx\n", flags ); ok( InSendMessage(), "InSendMessage returned false\n" ); break; case WM_USER + 1: - ok( flags == ISMEX_NOTIFY, "wrong flags %x\n", flags ); + ok( flags == ISMEX_NOTIFY, "wrong flags %lx\n", flags ); ok( InSendMessage(), "InSendMessage returned false\n" ); ret = ReplyMessage( msg ); - ok( ret, "ReplyMessage failed err %u\n", GetLastError() ); + ok( ret, "ReplyMessage failed err %lu\n", GetLastError() ); flags = InSendMessageEx( NULL ); - ok( flags == ISMEX_NOTIFY, "wrong flags %x\n", flags ); + ok( flags == ISMEX_NOTIFY, "wrong flags %lx\n", flags ); ok( InSendMessage(), "InSendMessage returned false\n" ); break; case WM_USER + 2: - ok( flags == ISMEX_CALLBACK, "wrong flags %x\n", flags ); + ok( flags == ISMEX_CALLBACK, "wrong flags %lx\n", flags ); ok( InSendMessage(), "InSendMessage returned false\n" ); ret = ReplyMessage( msg ); - ok( ret, "ReplyMessage failed err %u\n", GetLastError() ); + ok( ret, "ReplyMessage failed err %lu\n", GetLastError() ); flags = InSendMessageEx( NULL ); - ok( flags == (ISMEX_CALLBACK | ISMEX_REPLIED) || flags == ISMEX_SEND, "wrong flags %x\n", flags ); + ok( flags == (ISMEX_CALLBACK | ISMEX_REPLIED) || flags == ISMEX_SEND, "wrong flags %lx\n", flags ); ok( InSendMessage(), "InSendMessage returned false\n" ); break; case WM_USER + 3: - ok( flags == ISMEX_NOSEND, "wrong flags %x\n", flags ); + ok( flags == ISMEX_NOSEND, "wrong flags %lx\n", flags ); ok( !InSendMessage(), "InSendMessage returned true\n" ); ret = ReplyMessage( msg ); ok( !ret, "ReplyMessage succeeded\n" ); @@ -17651,7 +20390,7 @@ static LRESULT CALLBACK insendmessage_wnd_proc( HWND hwnd, UINT msg, WPARAM wp, static void CALLBACK msg_callback( HWND hwnd, UINT msg, ULONG_PTR arg, LRESULT result ) { ok( msg == WM_USER + 2, "wrong msg %x\n", msg ); - ok( result == WM_USER + 2, "wrong result %lx\n", result ); + ok( result == WM_USER + 2, "wrong result %Ix\n", result ); } static DWORD WINAPI send_message_thread( void *arg ) @@ -17678,13 +20417,13 @@ static void test_InSendMessage(void) cls.lpfnWndProc = insendmessage_wnd_proc; cls.hInstance = GetModuleHandleA(NULL); cls.lpszClassName = "InSendMessage_test"; - RegisterClassA(&cls); + register_class(&cls); win = CreateWindowA( "InSendMessage_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0 ); - ok( win != NULL, "CreateWindow failed: %d\n", GetLastError() ); + ok( win != NULL, "CreateWindow failed: %ld\n", GetLastError() ); thread = CreateThread( NULL, 0, send_message_thread, win, 0, &tid ); - ok( thread != NULL, "CreateThread failed: %d\n", GetLastError() ); + ok( thread != NULL, "CreateThread failed: %ld\n", GetLastError() ); while (GetMessageA(&msg, NULL, 0, 0)) DispatchMessageA( &msg ); @@ -17697,6 +20436,9 @@ static void test_InSendMessage(void) static const struct message DoubleSetCaptureSeq[] = { + { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, { WM_CAPTURECHANGED, sent }, { 0 } }; @@ -17725,6 +20467,7 @@ static void test_DoubleSetCapture(void) static const struct message WmRestoreMinimizedSeq[] = { { HCBT_ACTIVATE, hook }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { WM_ACTIVATEAPP, sent|wparam, 1 }, @@ -17744,16 +20487,20 @@ static const struct message WmRestoreMinimizedSeq[] = { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, { WM_GETMINMAXINFO, sent|defwinproc }, { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, + { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 }, { WM_GETTEXT, sent|defwinproc|optional }, { WM_ERASEBKGND, sent|defwinproc }, { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, { WM_MOVE, sent|defwinproc }, { WM_SIZE, sent|defwinproc }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, + { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam|msg_todo, 0, 0 }, { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 }, { WM_ERASEBKGND, sent|defwinproc|optional }, { HCBT_SETFOCUS, hook }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|defwinproc }, { WM_ACTIVATE, sent|wparam|defwinproc, 1 }, { WM_PAINT, sent| optional }, @@ -17764,6 +20511,10 @@ static const struct message WmRestoreMinimizedSeq[] = { WM_SYSKEYUP, sent|optional }, { HCBT_KEYSKIPPED, hook|optional }, { WM_KEYUP, sent|optional }, + { HCBT_KEYSKIPPED, hook|optional }, + { WM_SYSKEYUP, sent|optional }, + { HCBT_KEYSKIPPED, hook|optional }, + { WM_KEYUP, sent|optional }, { WM_PAINT, sent| optional }, { 0 } }; @@ -17774,6 +20525,12 @@ static void test_restore_messages(void) HWND hwnd; INT i; +#ifdef __REACTOS__ + if (GetNTVersion() == _WIN32_WINNT_WIN7 && !is_reactos()) { + skip("The Alt+Tab tests here can cause Windows 7 to lock up\n"); + return; + } +#endif hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 200, 200, 0, 0, 0, NULL); ok (hwnd != 0, "Failed to create overlapped window\n"); @@ -17806,6 +20563,9 @@ static void test_restore_messages(void) skip("Alt+Tab failed to bring up test window.\n"); goto done; } +#ifdef __REACTOS__ + if (GetNTVersion() != _WIN32_WINNT_VISTA) +#endif ok_sequence(WmRestoreMinimizedSeq, "Restore minimized window", TRUE); done: @@ -17820,40 +20580,314 @@ static void test_invalid_window(void) SetLastError(0xdeadbeef); ret = GetMessageA(&msg, (HWND)0xdeadbeef, 0, 0); ok(ret == -1, "wrong ret %d\n", ret); - ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = PeekMessageA(&msg, (HWND)0xdeadbeef, 0, 0, PM_REMOVE); ok(!ret, "wrong ret %d\n", ret); - ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %lu\n", GetLastError()); } -static void init_funcs(void) +static void test_button_style(void) { - HMODULE hKernel32 = GetModuleHandleA("kernel32.dll"); + DWORD type, expected_type; + HWND button; + LRESULT ret; + DWORD i, j; -#define X(f) p##f = (void*)GetProcAddress(hKernel32, #f) - X(ActivateActCtx); - X(CreateActCtxW); - X(DeactivateActCtx); - X(GetCurrentActCtx); - X(QueryActCtxW); - X(ReleaseActCtx); -#undef X + for (i = BS_PUSHBUTTON; i <= BS_DEFCOMMANDLINK; ++i) + { + button = CreateWindowA(WC_BUTTONA, "test", i, 0, 0, 50, 50, NULL, 0, 0, NULL); + ok(button != NULL, "Expected button not null.\n"); + + type = GetWindowLongW(button, GWL_STYLE) & BS_TYPEMASK; + expected_type = (i == BS_USERBUTTON ? BS_PUSHBUTTON : i); + ok(type == expected_type, "Expected type %#lx, got %#lx.\n", expected_type, type); + + for (j = BS_PUSHBUTTON; j <= BS_DEFCOMMANDLINK; ++j) + { + ret = SendMessageA(button, BM_SETSTYLE, j, FALSE); + ok(ret == 0, "Expected %#x, got %#Ix.\n", 0, ret); + + type = GetWindowLongW(button, GWL_STYLE) & BS_TYPEMASK; + expected_type = j; + + ok(type == expected_type, "Original type %#lx, expected new type %#lx, got %#lx.\n", i, + expected_type, type); + } + DestroyWindow(button); + } +} + +static LRESULT WINAPI test_create_name_procW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + switch (msg) + { + case WM_NCCREATE: + case WM_CREATE: + { + CREATESTRUCTW *cs = (CREATESTRUCTW *)lparam; + memcpy( cs->lpCreateParams, cs->lpszName, 3 * sizeof(WCHAR) ); + break; + } + case WM_SETTEXT: + if (winetest_debug > 1) trace("%s\n", debugstr_w((const WCHAR *)lparam)); + break; + } + + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + +static void test_create_name(void) +{ + WNDCLASSW clsW = { 0 }; + WCHAR name_buf[3]; + HWND hwnd; + + clsW.lpfnWndProc = test_create_name_procW; + clsW.lpszClassName = L"TestCreateNameClassW"; + RegisterClassW( &clsW ); + + hwnd = CreateWindowExW( 0, L"TestCreateNameClassW", L"\xffff\x6162", + WS_POPUP, 0,0,0,0,0,0,0, name_buf ); + ok( hwnd != NULL, "CreateWindowEx failed: %lu\n", GetLastError() ); + ok(!memcmp(name_buf, L"\xffff\x6162", 2 * sizeof(WCHAR)), + "name param = %s\n", debugstr_wn(name_buf, 2)); + DestroyWindow( hwnd ); + + hwnd = CreateWindowExA( 0, "TestCreateNameClassW", "\xff\0\x61\x60", + WS_POPUP, 0,0,0,0,0,0,0, name_buf ); + ok( hwnd != NULL, "CreateWindowEx failed: %lu\n", GetLastError() ); + ok(!memcmp(name_buf, L"\xffff\x6100", 2 * sizeof(WCHAR)), + "name param = %s\n", debugstr_wn(name_buf, 2)); + DestroyWindow( hwnd ); + + UnregisterClassW( L"TestCreateNameClassW", NULL ); +} + +static LRESULT WINAPI changed_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + if (msg == WM_USER) return 3; + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + +static LRESULT WINAPI call_window_proc_hook( INT code, WPARAM wparam, LPARAM lparam ) +{ + CWPSTRUCT *cwp = (CWPSTRUCT *)lparam; + + ok( cwp->message == WM_USER, "message = %u\n", cwp->message ); + SetWindowLongPtrW( cwp->hwnd, GWLP_WNDPROC, (LONG_PTR)changed_window_proc ); + return CallNextHookEx( NULL, code, wparam, lparam ); +} + +static void test_hook_changing_window_proc(void) +{ + HWND hwnd; + HHOOK hook; + LRESULT res; + + hwnd = CreateWindowExW( 0, L"static", NULL, WS_POPUP, 0,0,0,0,GetDesktopWindow(),0,0, NULL ); + hook = SetWindowsHookExW( WH_CALLWNDPROC, call_window_proc_hook, NULL, GetCurrentThreadId() ); + ok( hook != NULL, "SetWindowsHookExW failed: %lu\n", GetLastError() ); + + res = SendMessageW( hwnd, WM_USER, 1, 2 ); + ok( res == 3, "SendMessageW(WM_USER) returned %Iu\n", res ); + + UnhookWindowsHookEx( hook ); + DestroyWindow( hwnd ); +} + +static void test_radiobutton_focus(void) +{ + HWND hwnd, button; + DWORD style; + int i; + DWORD types[] = { BS_RADIOBUTTON, BS_AUTORADIOBUTTON }; + + static const struct message set_focus_default_seq[] = + { + { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) }, + { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, + { 0 } + }; + + static const struct message set_focus_checked_seq[] = + { + { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) }, + { 0 } + }; + + static const struct message WM_LBUTTONDOWN_seq[] = + { + { WM_KILLFOCUS, sent|parent }, + { WM_IME_SETCONTEXT, sent|optional|parent }, + { WM_IME_SETCONTEXT, sent|optional|defwinproc }, + { WM_COMMAND, sent|parent }, + { 0 } + }; + + static const struct message set_focus_without_notify_seq[] = + { + { WM_COMMAND, sent|parent|wparam, ID_BUTTON }, + { 0 } + }; + + hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 200, 200, 0, 0, 0, NULL); + ok(hwnd != 0, "Failed to create parent window\n"); + + for (i = 0; i < ARRAY_SIZE(types); i++) + { + /* Test default button */ + style = types[i] | WS_CHILD | WS_VISIBLE | BS_NOTIFY; + button = CreateWindowExA(0, WC_BUTTONA, "test", style, 0, 0, 50, 14, hwnd, (HMENU)ID_BUTTON, 0, NULL); + ok(button != NULL, "failed to create a button, 0x%08lx, %p\n", style, hwnd); + flush_events(); + flush_sequence(); + SendMessageA(button, WM_SETFOCUS, 0, 0); + flush_events(); + ok_sequence(set_focus_default_seq, "WM_SETFOCUS on default radiobutton", FALSE); + DestroyWindow(button); + + /* Test already checked button */ + button = CreateWindowExA(0, WC_BUTTONA, "test", style, 0, 0, 50, 14, hwnd, (HMENU)ID_BUTTON, 0, NULL); + SendMessageA(button, BM_SETCHECK, BST_CHECKED, 0); + flush_events(); + flush_sequence(); + SendMessageA(button, WM_SETFOCUS, 0, 0); + flush_events(); + ok_sequence(set_focus_checked_seq, "WM_SETFOCUS on checked radiobutton", FALSE); + DestroyWindow(button); + + /* Test already focused button */ + button = CreateWindowExA(0, WC_BUTTONA, "test", style, 0, 0, 50, 14, hwnd, (HMENU)ID_BUTTON, 0, NULL); + SendMessageA(button, WM_SETFOCUS, 0, 0); + SendMessageA(button, BM_SETCHECK, BST_UNCHECKED, 0); + flush_events(); + flush_sequence(); + SendMessageA(button, WM_SETFOCUS, 0, 0); + flush_events(); + ok_sequence(set_focus_default_seq, "WM_SETFOCUS on focused radiobutton", FALSE); + DestroyWindow(button); + + /* Test WM_LBUTTONDOWN */ + button = CreateWindowExA(0, WC_BUTTONA, "test", style, 0, 0, 50, 14, hwnd, (HMENU)ID_BUTTON, 0, NULL); + flush_events(); + flush_sequence(); + SendMessageA(button, WM_LBUTTONDOWN, 0, MAKELPARAM(7, 7)); + flush_events(); + ok_sequence(WM_LBUTTONDOWN_seq, "WM_LBUTTONDOWN on radiobutton", FALSE); + DestroyWindow(button); + + /* Test without BS_NOTIFY */ + style = types[i] | WS_CHILD | WS_VISIBLE; + button = CreateWindowExA(0, WC_BUTTONA, "test", style, 0, 0, 50, 14, hwnd, (HMENU)ID_BUTTON, 0, NULL); + flush_events(); + flush_sequence(); + SendMessageA(button, WM_SETFOCUS, 0, 0); + flush_events(); + ok_sequence(set_focus_without_notify_seq, "WM_SETFOCUS on radiobutton without BS_NOTIFY", FALSE); + DestroyWindow(button); + + /* Test disabled button */ + style = types[i] | WS_CHILD | WS_VISIBLE | BS_NOTIFY; + button = CreateWindowExA(0, WC_BUTTONA, "test", style, 0, 0, 50, 14, hwnd, (HMENU)ID_BUTTON, 0, NULL); + EnableWindow(button, FALSE); + flush_events(); + flush_sequence(); + SendMessageA(button, WM_SETFOCUS, 0, 0); + flush_events(); + ok_sequence(set_focus_default_seq, "WM_SETFOCUS on disabled radiobutton", FALSE); + DestroyWindow(button); + } + + DestroyWindow(hwnd); +} + +static LONG test_hook_cleanup_hook_proc_child_id; +static DWORD test_hook_cleanup_hook_proc_thread_id, test_hook_cleanup_hook_proc_call_thread_id; + +static void CALLBACK test_hook_cleanup_hook_proc( HWINEVENTHOOK hook, DWORD event_id, HWND hwnd, LONG obj_id, + LONG child_id, DWORD thread_id, DWORD event_time ) +{ + test_hook_cleanup_hook_proc_child_id = child_id; + test_hook_cleanup_hook_proc_call_thread_id = GetCurrentThreadId(); + test_hook_cleanup_hook_proc_thread_id = thread_id; +} + +struct test_hook_cleanup_data +{ + HWND hwnd; + HANDLE hook_installed_event; + HANDLE done_event; + DWORD main_thread_id; +}; + +static DWORD WINAPI test_hook_cleanup_thread_proc( void *context ) +{ + struct test_hook_cleanup_data *d = context; + HWINEVENTHOOK hook; + + hook = SetWinEventHook( EVENT_MIN, EVENT_MAX, GetModuleHandleW( NULL ), test_hook_cleanup_hook_proc, + GetCurrentProcessId(), 0, WINEVENT_INCONTEXT ); + ok( !!hook, "got error %ld.\n", GetLastError() ); + + test_hook_cleanup_hook_proc_child_id = -1; + NotifyWinEvent( EVENT_MIN, d->hwnd, 1, 1 ); + ok( test_hook_cleanup_hook_proc_child_id == 1, "got %ld.\n", test_hook_cleanup_hook_proc_child_id ); + todo_wine ok( test_hook_cleanup_hook_proc_thread_id == d->main_thread_id, "got %#lx.\n", + test_hook_cleanup_hook_proc_thread_id ); + ok( test_hook_cleanup_hook_proc_call_thread_id == GetCurrentThreadId(), "got %#lx.\n", + test_hook_cleanup_hook_proc_call_thread_id ); + + SetEvent( d->hook_installed_event ); + WaitForSingleObject( d->done_event, INFINITE ); + return 0; +} + +static void test_hook_cleanup(void) +{ + struct test_hook_cleanup_data d; + HANDLE thread; + + d.main_thread_id = GetCurrentThreadId(); + d.hwnd = CreateWindowA ("static", "window", WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, 0, 0 ); + d.hook_installed_event = CreateEventW( NULL, FALSE, FALSE, NULL ); + d.done_event = CreateEventW( NULL, FALSE, FALSE, NULL ); + + thread = CreateThread( NULL, 0, test_hook_cleanup_thread_proc, &d, 0, NULL ); + WaitForSingleObject( d.hook_installed_event, INFINITE ); + + test_hook_cleanup_hook_proc_child_id = -1; + NotifyWinEvent( EVENT_MIN, d.hwnd, 1, 2 ); + ok( test_hook_cleanup_hook_proc_child_id == 2, "got %ld.\n", test_hook_cleanup_hook_proc_child_id ); + ok( test_hook_cleanup_hook_proc_thread_id == GetCurrentThreadId(), "got %#lx.\n", + test_hook_cleanup_hook_proc_thread_id ); + ok( test_hook_cleanup_hook_proc_call_thread_id == GetCurrentThreadId(), "got %#lx.\n", + test_hook_cleanup_hook_proc_call_thread_id ); + + SetEvent( d.done_event ); + WaitForSingleObject( thread, INFINITE ); + + /* Hook is removed when thread which created it is terminated. */ + test_hook_cleanup_hook_proc_child_id = -1; + NotifyWinEvent( EVENT_MIN, d.hwnd, 1, 3 ); + ok( test_hook_cleanup_hook_proc_child_id == -1, "got %ld.\n", test_hook_cleanup_hook_proc_child_id ); + + DestroyWindow( d.hwnd ); } -#ifndef __REACTOS__ START_TEST(msg) { char **test_argv; BOOL ret; BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/ - HMODULE hModuleImm32; - BOOL (WINAPI *pImmDisableIME)(DWORD); int argc; - init_funcs(); - +#ifdef __REACTOS__ + // Temp for now to see where this is crashing on WS03 testbot + winetest_debug = 2; +#endif argc = winetest_get_mainargs( &test_argv ); if (argc >= 3) { @@ -17866,17 +20900,9 @@ START_TEST(msg) InitializeCriticalSection( &sequence_cs ); init_procs(); + ImmDisableIME(0); - hModuleImm32 = LoadLibraryA("imm32.dll"); - if (hModuleImm32) { - pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME"); - if (pImmDisableIME) - pImmDisableIME(0); - } - pImmDisableIME = NULL; - FreeLibrary(hModuleImm32); - - if (!RegisterWindowClasses()) assert(0); + register_classes(); if (pSetWinEventHook) { @@ -17893,25 +20919,16 @@ START_TEST(msg) } if (!hEvent_hook) win_skip( "no win event hook support\n" ); - cbt_hook_thread_id = GetCurrentThreadId(); + cbt_hook_thread_id = winevent_hook_thread_id = GetCurrentThreadId(); hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId()); if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" ); test_winevents(); - - /* Fix message sequences before removing 4 lines below */ - if (pUnhookWinEvent && hEvent_hook) - { - ret = pUnhookWinEvent(hEvent_hook); - ok( ret, "UnhookWinEvent error %d\n", GetLastError()); - pUnhookWinEvent = 0; - } - hEvent_hook = 0; - - test_SendMessage_other_thread(1); - test_SendMessage_other_thread(2); + test_SendMessage_other_thread(); + test_setparent_status(); test_InSendMessage(); test_SetFocus(); + test_radiobutton_focus(); test_SetParent(); test_PostMessage(); test_broadcast(); @@ -17924,11 +20941,11 @@ START_TEST(msg) test_messages(); test_setwindowpos(); test_showwindow(); - test_recursive_activation(); invisible_parent_tests(); test_mdi_messages(); test_button_messages(); test_button_bm_get_set_image(); + test_button_style(); test_autoradio_BM_CLICK(); test_autoradio_kbd_move(); test_static_messages(); @@ -17936,6 +20953,10 @@ START_TEST(msg) test_combobox_messages(); test_wmime_keydown_message(); test_paint_messages(); + run_in_temp_desktop(test_swp_paint_regions); + run_in_temp_desktop(test_swp_paint_region_on_show); + run_in_temp_desktop(test_swp_paint_region_on_extend_zerosize); + run_in_temp_desktop(test_hvredraw); test_interthread_messages(); test_message_conversion(); test_accelerators(); @@ -17947,6 +20968,7 @@ START_TEST(msg) test_set_hook(); test_recursive_hook(); } + test_recursive_messages(); test_DestroyWindow(); test_DispatchMessage(); test_SendMessageTimeout(); @@ -17956,6 +20978,8 @@ START_TEST(msg) test_SetActiveWindow(); test_restore_messages(); test_invalid_window(); + test_menu_messages(); + test_paintingloop(); if (!pTrackMouseEvent) win_skip("TrackMouseEvent is not available\n"); @@ -17969,8 +20993,32 @@ START_TEST(msg) test_nullCallback(); test_dbcs_wm_char(); test_unicode_wm_char(); - test_menu_messages(); - test_paintingloop(); +#ifdef __REACTOS__ + trace("Running test_defwinproc()...\n"); + test_defwinproc(); + trace("Running test_desktop_winproc()...\n"); + test_desktop_winproc(); + trace("Running test_clipboard_viewers()...\n"); + test_clipboard_viewers(); + trace("Running test_keyflags()...\n"); + test_keyflags(); + trace("Running test_hotkey()...\n"); + test_hotkey(); + trace("Running test_layered_window()...\n"); + test_layered_window(); + trace("Running test_TrackPopupMenu()...\n"); + test_TrackPopupMenu(); + trace("Running test_TrackPopupMenuEmpty()...\n"); + test_TrackPopupMenuEmpty(); + trace("Running test_DoubleSetCapture()...\n"); + test_DoubleSetCapture(); + trace("Running test_create_name()...\n"); + test_create_name(); + trace("Running test_hook_changing_window_proc()...\n"); + test_hook_changing_window_proc(); + trace("Running test_hook_cleanup()...\n"); + test_hook_cleanup(); +#else test_defwinproc(); test_desktop_winproc(); test_clipboard_viewers(); @@ -17980,293 +21028,27 @@ START_TEST(msg) test_TrackPopupMenu(); test_TrackPopupMenuEmpty(); test_DoubleSetCapture(); + test_create_name(); + test_hook_changing_window_proc(); +#endif /* keep it the last test, under Windows it tends to break the tests * which rely on active/foreground windows being correct. */ +#ifdef __REACTOS__ + trace("Running test_SetForegroundWindow()..."); +#endif test_SetForegroundWindow(); UnhookWindowsHookEx(hCBT_hook); if (pUnhookWinEvent && hEvent_hook) { ret = pUnhookWinEvent(hEvent_hook); - ok( ret, "UnhookWinEvent error %d\n", GetLastError()); + ok( ret, "UnhookWinEvent error %ld\n", GetLastError()); SetLastError(0xdeadbeef); ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n"); ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */ GetLastError() == 0xdeadbeef, /* Win9x */ - "unexpected error %d\n", GetLastError()); + "unexpected error %ld\n", GetLastError()); } DeleteCriticalSection( &sequence_cs ); } -#endif /* __REACTOS__ */ - -static void init_tests() -{ - HMODULE hModuleImm32; - BOOL (WINAPI *pImmDisableIME)(DWORD); - - init_funcs(); - - InitializeCriticalSection( &sequence_cs ); - init_procs(); - - hModuleImm32 = LoadLibraryA("imm32.dll"); - if (hModuleImm32) { - pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME"); - if (pImmDisableIME) - pImmDisableIME(0); - } - pImmDisableIME = NULL; - FreeLibrary(hModuleImm32); - - if (!RegisterWindowClasses()) assert(0); - - cbt_hook_thread_id = GetCurrentThreadId(); - hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId()); - if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" ); -} - -static void cleanup_tests() -{ - BOOL ret; - UnhookWindowsHookEx(hCBT_hook); - if (pUnhookWinEvent && hEvent_hook) - { - ret = pUnhookWinEvent(hEvent_hook); - ok( ret, "UnhookWinEvent error %d\n", GetLastError()); - SetLastError(0xdeadbeef); - ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n"); - ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */ - GetLastError() == 0xdeadbeef, /* Win9x */ - "unexpected error %d\n", GetLastError()); - } - DeleteCriticalSection( &sequence_cs ); - -} - -START_TEST(msg_queue) -{ - int argc; - char **test_argv; - argc = winetest_get_mainargs( &test_argv ); - if (argc >= 3) - { - unsigned int arg; - /* Child process. */ - sscanf (test_argv[2], "%d", (unsigned int *) &arg); - do_wait_idle_child( arg ); - return; - } - - init_tests(); - test_SendMessage_other_thread(1); - test_SendMessage_other_thread(2); - test_InSendMessage(); - test_PostMessage(); - test_broadcast(); - test_PeekMessage(); - test_PeekMessage2(); - test_PeekMessage3(); - test_interthread_messages(); - test_DispatchMessage(); - test_SendMessageTimeout(); - test_quit_message(); - test_notify_message(); - test_WaitForInputIdle( test_argv[0] ); - test_DestroyWindow(); - cleanup_tests(); -} - -START_TEST(msg_messages) -{ - init_tests(); - test_message_conversion(); - test_messages(); - test_wmime_keydown_message(); - test_nullCallback(); - test_dbcs_wm_char(); - test_unicode_wm_char(); - test_defwinproc(); - test_desktop_winproc(); - cleanup_tests(); -} - -START_TEST(msg_focus) -{ - init_tests(); - - test_SetFocus(); - - /* HACK: For some reason the tests fail on Windows if run consecutively. - * Putting these in between helps, and is essentially what happens in the - * "normal" msg test. */ - keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0); - flush_events(); - - test_SetActiveWindow(); - - /* HACK */ - keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0); - flush_events(); - - test_restore_messages(); - test_invalid_window(); - - test_DoubleSetCapture(); - - /* keep it the last test, under Windows it tends to break the tests - * which rely on active/foreground windows being correct. - */ - test_SetForegroundWindow(); - cleanup_tests(); -} - -START_TEST(msg_winpos) -{ - init_tests(); - test_SetParent(); - test_ShowWindow(); - test_setwindowpos(); - test_showwindow(); - test_recursive_activation(); - test_SetWindowRgn(); - invisible_parent_tests(); - cleanup_tests(); -} - -START_TEST(msg_paint) -{ - init_tests(); - test_scrollwindowex(); - test_paint_messages(); -#ifdef __REACTOS__ - if (!winetest_interactive && - !strcmp(winetest_platform, "windows")) - { - skip("ROSTESTS-185: Skipping user32_winetest:msg_paint test_paintingloop because it hangs on WHS-Testbot. Set winetest_interactive to run it anyway.\n"); - } - else -#endif - test_paintingloop(); - cleanup_tests(); -} - -START_TEST(msg_input) -{ - init_tests(); - test_accelerators(); - if (!pTrackMouseEvent) - win_skip("TrackMouseEvent is not available\n"); - else - test_TrackMouseEvent(); - - test_keyflags(); - test_hotkey(); - cleanup_tests(); -} - -START_TEST(msg_timer) -{ - init_tests(); - test_timers(); - test_timers_no_wnd(); - test_timers_exceptions(); - cleanup_tests(); -} - -typedef BOOL (WINAPI *IS_WINEVENT_HOOK_INSTALLED)(DWORD); - -START_TEST(msg_hook) -{ -// HMODULE user32 = GetModuleHandleA("user32.dll"); -// IS_WINEVENT_HOOK_INSTALLED pIsWinEventHookInstalled = (IS_WINEVENT_HOOK_INSTALLED)GetProcAddress(user32, "IsWinEventHookInstalled"); - BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/ - - init_tests(); - - if (pSetWinEventHook) - { - hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, - GetModuleHandleA(0), win_event_proc, - 0, GetCurrentThreadId(), - WINEVENT_INCONTEXT); - if (pIsWinEventHookInstalled && hEvent_hook) - { - UINT event; - for (event = EVENT_MIN; event <= EVENT_MAX; event++) - ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event); - } - } - if (!hEvent_hook) win_skip( "no win event hook support\n" ); - - test_winevents(); - - /* Fix message sequences before removing 4 lines below */ - if (pUnhookWinEvent && hEvent_hook) - { - BOOL ret; - ret = pUnhookWinEvent(hEvent_hook); - ok( ret, "UnhookWinEvent error %d\n", GetLastError()); - pUnhookWinEvent = 0; - } - hEvent_hook = 0; - if (hCBT_hook) - { - test_set_hook(); - test_recursive_hook(); - } - cleanup_tests(); -} - -START_TEST(msg_menu) -{ - init_tests(); - test_sys_menu(); - test_menu_messages(); - test_TrackPopupMenu(); - test_TrackPopupMenuEmpty(); - cleanup_tests(); -} - -START_TEST(msg_mdi) -{ - init_tests(); - test_mdi_messages(); - cleanup_tests(); -} - -START_TEST(msg_controls) -{ - init_tests(); - test_button_messages(); - test_button_bm_get_set_image(); - test_autoradio_BM_CLICK(); - test_autoradio_kbd_move(); - test_static_messages(); - test_listbox_messages(); - test_combobox_messages(); - test_edit_messages(); - cleanup_tests(); -} - -START_TEST(msg_layered_window) -{ - init_tests(); - test_layered_window(); - cleanup_tests(); -} - -START_TEST(msg_dialog) -{ - init_tests(); - test_dialog_messages(); - test_EndDialog(); - cleanup_tests(); -} - -START_TEST(msg_clipboard) -{ - init_tests(); - test_clipboard_viewers(); - cleanup_tests(); -} diff --git a/modules/rostests/winetests/user32/rawinput.c b/modules/rostests/winetests/user32/rawinput.c deleted file mode 100644 index f4c8eb6738b..00000000000 --- a/modules/rostests/winetests/user32/rawinput.c +++ /dev/null @@ -1,101 +0,0 @@ -/* Unit test suite for rawinput. - * - * Copyright 2019 Remi Bernon for CodeWeavers - * - * 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 -#include - -#define STRICT -#define WIN32_LEAN_AND_MEAN -#include - -#include "wine/test.h" - -static void test_RegisterRawInputDevices(void) -{ - HWND hwnd; - RAWINPUTDEVICE raw_devices[1]; - BOOL res; - - raw_devices[0].usUsagePage = 0x01; - raw_devices[0].usUsage = 0x05; - - hwnd = CreateWindowExA(WS_EX_TOPMOST, "static", "dinput", WS_POPUP | WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, NULL, NULL); - ok(hwnd != NULL, "CreateWindowExA failed\n"); - - - res = RegisterRawInputDevices(NULL, 0, 0); - ok(res == FALSE, "RegisterRawInputDevices succeeded\n"); - - - raw_devices[0].dwFlags = 0; - raw_devices[0].hwndTarget = 0; - - SetLastError(0xdeadbeef); - res = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), 0); - ok(res == FALSE, "RegisterRawInputDevices succeeded\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "RegisterRawInputDevices returned %08x\n", GetLastError()); - - SetLastError(0xdeadbeef); - res = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE)); - ok(res == TRUE, "RegisterRawInputDevices failed\n"); - ok(GetLastError() == 0xdeadbeef, "RegisterRawInputDevices returned %08x\n", GetLastError()); - - - /* RIDEV_REMOVE requires hwndTarget == NULL */ - raw_devices[0].dwFlags = RIDEV_REMOVE; - raw_devices[0].hwndTarget = hwnd; - - SetLastError(0xdeadbeef); - res = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE)); - ok(res == FALSE, "RegisterRawInputDevices succeeded\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "RegisterRawInputDevices returned %08x\n", GetLastError()); - - raw_devices[0].hwndTarget = 0; - - SetLastError(0xdeadbeef); - res = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE)); - ok(res == TRUE, "RegisterRawInputDevices failed\n"); - ok(GetLastError() == 0xdeadbeef, "RegisterRawInputDevices returned %08x\n", GetLastError()); - - - /* RIDEV_INPUTSINK requires hwndTarget != NULL */ - raw_devices[0].dwFlags = RIDEV_INPUTSINK; - raw_devices[0].hwndTarget = 0; - - SetLastError(0xdeadbeef); - res = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE)); - todo_wine - ok(res == FALSE, "RegisterRawInputDevices failed\n"); - todo_wine - ok(GetLastError() == ERROR_INVALID_PARAMETER, "RegisterRawInputDevices returned %08x\n", GetLastError()); - - raw_devices[0].hwndTarget = hwnd; - - SetLastError(0xdeadbeef); - res = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE)); - ok(res == TRUE, "RegisterRawInputDevices succeeded\n"); - ok(GetLastError() == 0xdeadbeef, "RegisterRawInputDevices returned %08x\n", GetLastError()); - - DestroyWindow(hwnd); -} - -START_TEST(rawinput) -{ - test_RegisterRawInputDevices(); -} diff --git a/modules/rostests/winetests/user32/resource.c b/modules/rostests/winetests/user32/resource.c index 5d4c4e2f968..cb2d13cd260 100644 --- a/modules/rostests/winetests/user32/resource.c +++ b/modules/rostests/winetests/user32/resource.c @@ -36,7 +36,27 @@ static void test_LoadStringW(void) HINSTANCE hInst = GetModuleHandleA(NULL); WCHAR copiedstringw[128], returnedstringw[128], *resourcepointer = NULL; char copiedstring[128], returnedstring[128]; - int length1, length2, retvalue; + int length1, length2, retvalue, i; + static struct + { + int id; + const WCHAR *string; + } string_table_tests[] = + { + { 2, L"Error" }, + { 13, L"&More Windows..." }, + { 800, L"OK" }, + { 801, L"Cancel" }, + { 802, L"&Abort" }, + { 803, L"&Retry" }, + { 804, L"&Ignore" }, + { 805, L"&Yes" }, + { 806, L"&No" }, + { 807, L"&Close" }, + { 808, L"Help" }, + { 809, L"&Try Again" }, + { 810, L"&Continue" }, + }; /* Check that the string which is returned by LoadStringW matches the string at the pointer returned by LoadStringW when called with buflen = 0 */ @@ -51,10 +71,10 @@ static void test_LoadStringW(void) return; } length2 = LoadStringW(hInst, 2, returnedstringw, ARRAY_SIZE(returnedstringw)); /* get resource string */ - ok(length2 > 0, "LoadStringW failed to load resource 2, ret %d, err %d\n", length2, GetLastError()); + ok(length2 > 0, "LoadStringW failed to load resource 2, ret %d, err %ld\n", length2, GetLastError()); ok(length1 == length2, "LoadStringW returned different values dependent on buflen. ret1 %d, ret2 %d\n", length1, length2); - ok(length1 > 0 && resourcepointer != NULL, "LoadStringW failed to get pointer to resource 2, ret %d, err %d\n", + ok(length1 > 0 && resourcepointer != NULL, "LoadStringW failed to get pointer to resource 2, ret %d, err %ld\n", length1, GetLastError()); /* Copy the resource since it is not '\0' terminated, and add '\0' to the end */ @@ -75,10 +95,78 @@ static void test_LoadStringW(void) /* check again, with a different buflen value, that calling LoadStringW with buffer = NULL returns zero */ retvalue = LoadStringW(hInst, 2, NULL, 128); ok(!retvalue, "LoadStringW returned a non-zero value when called with buffer = NULL, retvalue = %d\n", retvalue); + + /* Test builtin string table in user32. */ + if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) + || (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH)) + { + skip("Skip for Non-English system.\n"); + return; + } + else + { + hInst = GetModuleHandleW(L"user32.dll"); + ok(!!hInst, "Can't get module %#lx.\n", GetLastError()); + + for (i = 0; i < ARRAYSIZE(string_table_tests); i++) + { + winetest_push_context("Test %u", i); + + length1 = LoadStringW(hInst, string_table_tests[i].id, returnedstringw, ARRAY_SIZE(returnedstringw)); + ok(length1 == wcslen(string_table_tests[i].string), "Got wrong length %d.\n", length1); + ok(!wcscmp(returnedstringw, string_table_tests[i].string), "Got wrong string %s.\n", + debugstr_w(returnedstringw)); + + winetest_pop_context(); + } + } + + /* Test missing resource. */ + SetLastError(0xdeadbeef); + memset(returnedstringw, 0xcc, sizeof(returnedstringw)); + length1 = LoadStringW(hInst, 0xdeadbeef, returnedstringw, ARRAY_SIZE(returnedstringw)); + ok(!length1, "got %d.\n", length1); + ok(GetLastError() == ERROR_RESOURCE_NAME_NOT_FOUND || broken(GetLastError() == ERROR_MUI_FILE_NOT_FOUND) /* Win7 */, + "got %lu.\n", GetLastError()); + ok(!returnedstringw[0], "got %#x.\n", returnedstringw[0]); + ok(returnedstringw[1] == 0xcccc, "got %#x.\n", returnedstringw[1]); + + SetLastError(0xdeadbeef); + memset(returnedstringw, 0xcc, sizeof(returnedstringw)); + length1 = LoadStringW(hInst, 0xdeadbeef, returnedstringw, 0); + ok(!length1, "got %d.\n", length1); + ok(GetLastError() == ERROR_RESOURCE_NAME_NOT_FOUND || broken(GetLastError() == ERROR_MUI_FILE_NOT_LOADED) /* Win7 */, + "got %lu.\n", GetLastError()); + ok(returnedstringw[0] == 0xcccc, "got %#x.\n", returnedstringw[1]); + + SetLastError(0xdeadbeef); + memset(returnedstringw, 0xcc, sizeof(returnedstringw)); + length1 = LoadStringW(hInst, 0xdeadbeef, returnedstringw, 1); + ok(!length1, "got %d.\n", length1); + ok(GetLastError() == ERROR_RESOURCE_NAME_NOT_FOUND || broken(GetLastError() == ERROR_MUI_FILE_NOT_LOADED) /* Win7 */, + "got %lu.\n", GetLastError()); + ok(!returnedstringw[0], "got %#x.\n", returnedstringw[0]); + ok(returnedstringw[1] == 0xcccc, "got %#x.\n", returnedstringw[1]); + + /* Test short buffer */ + SetLastError(0xdeadbeef); + memset(returnedstringw, 0xcc, sizeof(returnedstringw)); + length1 = LoadStringW(hInst, 2, returnedstringw, 1); /* get resource string */ + ok(!length1, "got %d.\n", length1); + ok(GetLastError() == 0xdeadbeef, "got %lu.\n", GetLastError()); +#ifdef __REACTOS__ + ok(!returnedstringw[0] || broken(returnedstringw[0] == 0xcccc) /* WS03 */, "got %#x.\n", returnedstringw[0]); +#else + ok(!returnedstringw[0], "got %#x.\n", returnedstringw[0]); +#endif + ok(returnedstringw[1] == 0xcccc, "got %#x.\n", returnedstringw[1]); } static void test_LoadStringA (void) { +#if defined(__REACTOS__) && defined(_M_AMD64) + skip("LoadStringA test broken on amd64!\n"); +#else HINSTANCE hInst = GetModuleHandleA(NULL); static const char str[] = "String resource"; /* same in resource.rc */ char buf[128]; @@ -109,22 +197,22 @@ static void test_LoadStringA (void) } ret = LoadStringA(hInst, 1, buf, sizeof(buf) ); - ok( ret > 0, "LoadString failed: ret %d err %d\n", ret, GetLastError()); + ok( ret > 0, "LoadString failed: ret %d err %ld\n", ret, GetLastError()); ret2 = LoadStringA( hInst, MAKELONG( 1, 0x8000 ), buf, sizeof(buf)); - ok( ret2 == ret, "LoadString failed: ret %d err %d\n", ret, GetLastError()); + ok( ret2 == ret, "LoadString failed: ret %d err %ld\n", ret, GetLastError()); ret2 = LoadStringA( hInst, MAKELONG( 1, 0xffff ), buf, sizeof(buf)); - ok( ret2 == ret, "LoadString failed: ret %d err %d\n", ret, GetLastError()); + ok( ret2 == ret, "LoadString failed: ret %d err %ld\n", ret, GetLastError()); ret = LoadStringA(hInst, 65534, buf, sizeof(buf) ); - ok( ret > 0, "LoadString failed: ret %d err %d\n", ret, GetLastError()); + ok( ret > 0, "LoadString failed: ret %d err %ld\n", ret, GetLastError()); ret2 = LoadStringA( hInst, MAKELONG( 65534, 0x8000 ), buf, sizeof(buf)); - ok( ret2 == ret, "LoadString failed: ret %d err %d\n", ret, GetLastError()); + ok( ret2 == ret, "LoadString failed: ret %d err %ld\n", ret, GetLastError()); ret2 = LoadStringA( hInst, MAKELONG( 65534, 0xffff ), buf, sizeof(buf)); - ok( ret2 == ret, "LoadString failed: ret %d err %d\n", ret, GetLastError()); + ok( ret2 == ret, "LoadString failed: ret %d err %ld\n", ret, GetLastError()); ret = LoadStringA(hInst, 0, buf, 0); ok( ret == -1 || broken(ret == 0), - "LoadStringA did not return -1 when called with buflen = 0, got %d, err %d\n", + "LoadStringA did not return -1 when called with buflen = 0, got %d, err %ld\n", ret, GetLastError()); SetLastError(0xdeadbeef); @@ -132,7 +220,8 @@ static void test_LoadStringA (void) ret = LoadStringA(hInst, 1, buf, 1); ok( !ret, "LoadString returned %d\n", ret); ok( buf[0] == 0, "buf[0] = %c (%x)\n", buf[0], buf[0]); - ok( GetLastError() == 0xdeadbeef, "GetLastError() = %d\n", GetLastError()); + ok( GetLastError() == 0xdeadbeef, "GetLastError() = %ld\n", GetLastError()); +#endif } static void test_accel1(void) @@ -172,11 +261,11 @@ static void test_accel1(void) ac[n++].fVirt = (SHORT) 0xffff; ac[n].cmd = 0xfff0; - ac[n].key = 0xffff; + ac[n].key = 'B'; ac[n++].fVirt = (SHORT) 0xfff0; ac[n].cmd = 0xfff0; - ac[n].key = 0xffff; + ac[n].key = 'C'; ac[n++].fVirt = 0x0000; ac[n].cmd = 0xfff0; @@ -204,12 +293,12 @@ static void test_accel1(void) if (++n == r) goto done; ok( ac[n].cmd == 0xfff0, "cmd 2 not preserved got %x\n", ac[n].cmd); - ok( (ac[n].key & 0xff) == 0xff, "key 2 not preserved got %x\n", ac[n].key); + ok( ac[n].key == 'B', "key 2 not preserved got %x\n", ac[n].key); ok( ac[n].fVirt == 0x0070, "fVirt 2 wrong got %x\n", ac[n].fVirt); if (++n == r) goto done; ok( ac[n].cmd == 0xfff0, "cmd 3 not preserved got %x\n", ac[n].cmd); - ok( (ac[n].key & 0xff) == 0xff, "key 3 not preserved got %x\n", ac[n].key); + ok( ac[n].key == 'C', "key 3 not preserved got %x\n", ac[n].key); ok( ac[n].fVirt == 0x0000, "fVirt 3 wrong got %x\n", ac[n].fVirt); if (++n == r) goto done; @@ -348,7 +437,8 @@ static void test_PrivateExtractIcons(void) { ok(cIcons == ~0u, "got %u\n", cIcons); cIcons = pPrivateExtractIconsA("notepad.exe", 0, 16, 16, NULL, NULL, 1, 0); - ok(cIcons == 1 || broken(cIcons == 2) /* win2k */, "got %u\n", cIcons); + ok(cIcons == 1 || broken(cIcons == 4) /* win11 */ || + broken(cIcons == 2) /* win2k */, "got %u\n", cIcons); ahIcon[0] = (HICON)0xdeadbeef; cIcons = pPrivateExtractIconsA("notepad.exe", 0, 16, 16, ahIcon, NULL, 1, 0); diff --git a/modules/rostests/winetests/user32/resource.rc b/modules/rostests/winetests/user32/resource.rc index 4301af6d687..a957e50689d 100644 --- a/modules/rostests/winetests/user32/resource.rc +++ b/modules/rostests/winetests/user32/resource.rc @@ -249,6 +249,9 @@ FONT 8, "MS Shell Dlg" /* @makedep: test_mono.bmp */ 100 BITMAP test_mono.bmp +/* @makedep: bmp1x1_32bpp.bmp */ +101 BITMAP bmp1x1_32bpp.bmp + 1 MENU { POPUP "&File" @@ -273,3 +276,13 @@ FONT 8, "MS Shell Dlg" } MENUITEM "&Quit", 300 } + +IDD_SS_ICON_DIALOG DIALOG 0, 0, 186, 95 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL 0x6100, 1003, "STATIC", SS_ICON | WS_CHILD | WS_VISIBLE, 7, 57, 21, 20 + DEFPUSHBUTTON "OK",IDOK,129,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 +END diff --git a/modules/rostests/winetests/user32/scroll.c b/modules/rostests/winetests/user32/scroll.c index fbc94a6d680..70947f5626b 100644 --- a/modules/rostests/winetests/user32/scroll.c +++ b/modules/rostests/winetests/user32/scroll.c @@ -120,7 +120,7 @@ static void test_EnableScrollBar(void) todo_wine ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef), /* winxp */ - "GetLastError() = %u\n", GetLastError() ); + "GetLastError() = %lu\n", GetLastError() ); /* disable window, try to re-enable */ ret = EnableWindow( hScroll, FALSE ); @@ -181,12 +181,12 @@ static void test_SetScrollPos(void) SetLastError( 0xdeadbeef ); ret = SetScrollPos( mainwnd, SB_CTL, 30, TRUE ); ok( !ret, "The position should not be set.\n" ); - ok( GetLastError() == 0xdeadbeef, "GetLastError() = %u\n", GetLastError() ); + ok( GetLastError() == 0xdeadbeef, "GetLastError() = %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); ret = GetScrollPos( mainwnd, SB_CTL ); ok( !ret, "The position should be equal to zero\n"); - ok( GetLastError() == 0xdeadbeef, "GetLastError() = %u\n", GetLastError() ); + ok( GetLastError() == 0xdeadbeef, "GetLastError() = %lu\n", GetLastError() ); DestroyWindow(hScroll); DestroyWindow(mainwnd); @@ -242,7 +242,7 @@ static void test_GetScrollBarInfo(void) GetWindowRect( hScroll, &rect ); ok( ret, "The GetWindowRect() call should not fail.\n" ); ok( !(sbi.rgstate[0] & (STATE_SYSTEM_INVISIBLE|STATE_SYSTEM_OFFSCREEN)), - "unexpected rgstate(0x%x)\n", sbi.rgstate[0]); + "unexpected rgstate(0x%lx)\n", sbi.rgstate[0]); ok(EqualRect(&rect, &sbi.rcScrollBar), "WindowRect %s != rcScrollBar %s\n", wine_dbgstr_rect(&rect), wine_dbgstr_rect(&sbi.rcScrollBar)); @@ -301,40 +301,40 @@ static void scrollbar_test_default( DWORD style) /* range is 0,0 if there are no H or V scroll bars. 0,100 otherwise */ if( !( style & ( WS_VSCROLL | WS_HSCROLL))) ok( min == 0 && max == 0, - "Scroll bar range is %d,%d. Expected 0,0. Style %08x\n", min, max, style); + "Scroll bar range is %d,%d. Expected 0,0. Style %08lx\n", min, max, style); else ok(( min == 0 && max == 100) || broken( min == 0 && max == 0), /* Win 9x/ME */ - "Scroll bar range is %d,%d. Expected 0,100. Style %08x\n", min, max, style); + "Scroll bar range is %d,%d. Expected 0,100. Style %08lx\n", min, max, style); ret = GetScrollRange( hwnd, SB_HORZ, &min, &max); ok( ret || broken( !ret) /* Win 9x/ME */ , "GetScrollRange failed.\n"); /* range is 0,0 if there are no H or V scroll bars. 0,100 otherwise */ if( !( style & ( WS_VSCROLL | WS_HSCROLL))) ok( min == 0 && max == 0, - "Scroll bar range is %d,%d. Expected 0,0. Style %08x\n", min, max, style); + "Scroll bar range is %d,%d. Expected 0,0. Style %08lx\n", min, max, style); else ok(( min == 0 && max == 100) || broken( min == 0 && max == 0), /* Win 9x/ME */ - "Scroll bar range is %d,%d. Expected 0,100. Style %08x\n", min, max, style); + "Scroll bar range is %d,%d. Expected 0,100. Style %08lx\n", min, max, style); /* test GetScrollInfo, vist for vertical SB */ ret = GetScrollInfo( hwnd, SB_VERT, &si); /* should fail if no H or V scroll bar styles are present. Succeed otherwise */ if( !( style & ( WS_VSCROLL | WS_HSCROLL))) - ok( !ret, "GetScrollInfo succeeded unexpectedly. Style is %08x\n", style); + ok( !ret, "GetScrollInfo succeeded unexpectedly. Style is %08lx\n", style); else ok( ret || broken( !ret), /* Win 9x/ME */ - "GetScrollInfo failed unexpectedly. Style is %08x\n", style); + "GetScrollInfo failed unexpectedly. Style is %08lx\n", style); /* Same for Horizontal SB */ ret = GetScrollInfo( hwnd, SB_HORZ, &si); /* should fail if no H or V scroll bar styles are present. Succeed otherwise */ if( !( style & ( WS_VSCROLL | WS_HSCROLL))) - ok( !ret, "GetScrollInfo succeeded unexpectedly. Style is %08x\n", style); + ok( !ret, "GetScrollInfo succeeded unexpectedly. Style is %08lx\n", style); else ok( ret || broken( !ret), /* Win 9x/ME */ - "GetScrollInfo failed unexpectedly. Style is %08x\n", style); + "GetScrollInfo failed unexpectedly. Style is %08lx\n", style); /* now set the Vertical Scroll range to something that could be the default value it * already has */; ret = SetScrollRange( hwnd, SB_VERT, 0, 100, FALSE); @@ -344,26 +344,26 @@ static void scrollbar_test_default( DWORD style) ok( ret, "GetScrollRange failed.\n"); /* now the range should be 0,100 in ALL cases */ ok( min == 0 && max == 100, - "Scroll bar range is %d,%d. Expected 0,100. Style %08x\n", min, max, style); + "Scroll bar range is %d,%d. Expected 0,100. Style %08lx\n", min, max, style); /* See what is different now for GetScrollRange */ ret = GetScrollInfo( hwnd, SB_HORZ, &si); /* should succeed in ALL cases */ - ok( ret, "GetScrollInfo failed unexpectedly. Style is %08x\n", style); + ok( ret, "GetScrollInfo failed unexpectedly. Style is %08lx\n", style); ret = GetScrollInfo( hwnd, SB_VERT, &si); /* should succeed in ALL cases */ - ok( ret, "GetScrollInfo failed unexpectedly. Style is %08x\n", style); + ok( ret, "GetScrollInfo failed unexpectedly. Style is %08lx\n", style); /* report the windows style */ winstyle = GetWindowLongA( hwnd, GWL_STYLE ); /* WS_VSCROLL added to the window style */ if( !(style & WS_VSCROLL)) { if (bThemeActive || style != WS_HSCROLL) -todo_wine + todo_wine ok( (winstyle & (WS_HSCROLL|WS_VSCROLL)) == ( style | WS_VSCROLL), - "unexpected style change %08x/%08x\n", winstyle, style); + "unexpected style change %08lx/%08lx\n", winstyle, style); else ok( (winstyle & (WS_HSCROLL|WS_VSCROLL)) == style, - "unexpected style change %08x/%08x\n", winstyle, style); + "unexpected style change %08lx/%08lx\n", winstyle, style); } /* do the test again with H and V reversed. * Start with a clean window */ @@ -380,26 +380,26 @@ todo_wine ok( ret, "GetScrollRange failed.\n"); /* now the range should be 0,100 in ALL cases */ ok( min == 0 && max == 100, - "Scroll bar range is %d,%d. Expected 0,100. Style %08x\n", min, max, style); + "Scroll bar range is %d,%d. Expected 0,100. Style %08lx\n", min, max, style); /* See what is different now for GetScrollRange */ ret = GetScrollInfo( hwnd, SB_HORZ, &si); /* should succeed in ALL cases */ - ok( ret, "GetScrollInfo failed unexpectedly. Style is %08x\n", style); + ok( ret, "GetScrollInfo failed unexpectedly. Style is %08lx\n", style); ret = GetScrollInfo( hwnd, SB_VERT, &si); /* should succeed in ALL cases */ - ok( ret, "GetScrollInfo failed unexpectedly. Style is %08x\n", style); + ok( ret, "GetScrollInfo failed unexpectedly. Style is %08lx\n", style); /* report the windows style */ winstyle = GetWindowLongA( hwnd, GWL_STYLE ); /* WS_HSCROLL added to the window style */ if( !(style & WS_HSCROLL)) { if (bThemeActive || style != WS_VSCROLL) -todo_wine + todo_wine ok( (winstyle & (WS_HSCROLL|WS_VSCROLL)) == ( style | WS_HSCROLL), - "unexpected style change %08x/%08x\n", winstyle, style); + "unexpected style change %08lx/%08lx\n", winstyle, style); else ok( (winstyle & (WS_HSCROLL|WS_VSCROLL)) == style, - "unexpected style change %08x/%08x\n", winstyle, style); + "unexpected style change %08lx/%08lx\n", winstyle, style); } /* Slightly change the test to use SetScrollInfo * Start with a clean window */ @@ -413,20 +413,20 @@ todo_wine si.nMax = 22; si.fMask |= SIF_RANGE; ret = SetScrollInfo( hwnd, SB_HORZ, &si, FALSE); - ok( ret, "SetScrollInfo failed. Style is %08x\n", style); + ok( ret, "SetScrollInfo failed. Style is %08lx\n", style); /* and request the Vertical range */ ret = GetScrollRange( hwnd, SB_VERT, &min, &max); ok( ret, "GetScrollRange failed.\n"); /* now the range should be 0,100 in ALL cases */ ok( min == 0 && max == 100, - "Scroll bar range is %d,%d. Expected 0,100. Style %08x\n", min, max, style); + "Scroll bar range is %d,%d. Expected 0,100. Style %08lx\n", min, max, style); /* See what is different now for GetScrollRange */ ret = GetScrollInfo( hwnd, SB_HORZ, &si); /* should succeed in ALL cases */ - ok( ret, "GetScrollInfo failed unexpectedly. Style is %08x\n", style); + ok( ret, "GetScrollInfo failed unexpectedly. Style is %08lx\n", style); ret = GetScrollInfo( hwnd, SB_VERT, &si); /* should succeed in ALL cases */ - ok( ret, "GetScrollInfo failed unexpectedly. Style is %08x\n", style); + ok( ret, "GetScrollInfo failed unexpectedly. Style is %08lx\n", style); /* also test if the window scroll bars are enabled */ ret = EnableScrollBar( hwnd, SB_VERT, ESB_ENABLE_BOTH); ok( !ret, "Vertical window scroll bar was not enabled\n"); @@ -443,13 +443,13 @@ todo_wine assert( hwnd != 0); ret = GetScrollInfo( hwnd, SB_VERT, &si); /* should fail */ - ok( !ret, "GetScrollInfo succeeded unexpectedly. Style is %08x\n", style); + ok( !ret, "GetScrollInfo succeeded unexpectedly. Style is %08lx\n", style); /* add scroll styles */ winstyle = GetWindowLongA( hwnd, GWL_STYLE ); SetWindowLongW( hwnd, GWL_STYLE, winstyle | WS_VSCROLL | WS_HSCROLL); ret = GetScrollInfo( hwnd, SB_VERT, &si); /* should still fail */ - ok( !ret, "GetScrollInfo succeeded unexpectedly. Style is %08x\n", style); + ok( !ret, "GetScrollInfo succeeded unexpectedly. Style is %08lx\n", style); /* clean up */ DestroyWindow( hwnd); } @@ -561,6 +561,8 @@ static void test_SetScrollInfo(void) ret = IsWindowEnabled(hScroll); ok(!ret, "scroll bar enabled\n"); + ret = IsWindowVisible(hScroll); + ok(!ret, "Unexpected visible state.\n"); memset(&si, 0, sizeof(si)); si.cbSize = sizeof(si); @@ -581,6 +583,8 @@ static void test_SetScrollInfo(void) SetScrollInfo(hScroll, SB_CTL, &si, TRUE); ret = IsWindowEnabled(hScroll); ok(!ret, "scroll bar enabled\n"); + ret = IsWindowVisible(hScroll); + ok(!ret, "Unexpected visible state.\n"); si.fMask = 0xf; ret = GetScrollInfo(hScroll, SB_CTL, &si); @@ -588,6 +592,8 @@ static void test_SetScrollInfo(void) EnableScrollBar(hScroll, SB_CTL, ESB_ENABLE_BOTH); ok(IsWindowEnabled(hScroll), "expected enabled scrollbar\n"); + ret = IsWindowVisible(hScroll); + ok(!ret, "Unexpected visible state.\n"); si.fMask = SIF_POS|SIF_RANGE|SIF_PAGE|SIF_DISABLENOSCROLL; si.nMax = 10; @@ -597,6 +603,86 @@ static void test_SetScrollInfo(void) SetScrollInfo(hScroll, SB_CTL, &si, TRUE); ret = IsWindowEnabled(hScroll); ok(ret, "scroll bar disabled\n"); + ret = IsWindowVisible(hScroll); + ok(!ret, "Unexpected visible state.\n"); + + /* With visible window. */ + ShowWindow(mainwnd, SW_SHOW); + + ret = IsWindowVisible(hScroll); + ok(ret, "Unexpected visible state.\n"); + + EnableScrollBar(hScroll, SB_CTL, ESB_DISABLE_BOTH); + ret = IsWindowEnabled(hScroll); + ok(!ret, "Unexpected enabled state.\n"); + + /* Enabled state is changed only for visible windows, and only with redraw flag. */ + si.fMask = SIF_POS|SIF_RANGE|SIF_PAGE|SIF_DISABLENOSCROLL; + si.nMax = 100; + si.nMin = 10; + si.nPos = 0; + si.nPage = 50; + SetScrollInfo(hScroll, SB_CTL, &si, FALSE); + ret = IsWindowEnabled(hScroll); + ok(!ret, "Unexpected enabled state.\n"); + + /* State changes when called with same arguments too. */ + si.fMask = SIF_POS|SIF_RANGE|SIF_PAGE|SIF_DISABLENOSCROLL; + si.nMax = 100; + si.nMin = 10; + si.nPos = 0; + si.nPage = 50; + SetScrollInfo(hScroll, SB_CTL, &si, TRUE); + ret = IsWindowEnabled(hScroll); + ok(ret, "Unexpected enabled state.\n"); + + si.fMask = SIF_POS|SIF_RANGE|SIF_PAGE|SIF_DISABLENOSCROLL; + si.nMax = 100; + si.nMin = 10; + si.nPos = 0; + si.nPage = 100; + SetScrollInfo(hScroll, SB_CTL, &si, TRUE); + ret = IsWindowEnabled(hScroll); + ok(!ret, "Unexpected enabled state.\n"); + + EnableScrollBar(hScroll, SB_CTL, ESB_ENABLE_BOTH); + ret = IsWindowEnabled(hScroll); + ok(ret, "Unexpected enabled state.\n"); + + si.fMask = SIF_POS|SIF_RANGE|SIF_PAGE|SIF_DISABLENOSCROLL; + si.nMax = 100; + si.nMin = 10; + si.nPos = 0; + si.nPage = 100; + SetScrollInfo(hScroll, SB_CTL, &si, TRUE); + ret = IsWindowEnabled(hScroll); + ok(!ret, "Unexpected enabled state.\n"); + + EnableScrollBar(hScroll, SB_CTL, ESB_DISABLE_BOTH); + ret = IsWindowEnabled(hScroll); + ok(!ret, "Unexpected enabled state.\n"); + + si.fMask = SIF_POS|SIF_RANGE|SIF_PAGE|SIF_DISABLENOSCROLL; + si.nMax = 41; + si.nMin = 0; + si.nPos = 0; + si.nPage = 41; + SetScrollInfo(hScroll, SB_CTL, &si, TRUE); + ret = IsWindowEnabled(hScroll); + ok(ret, "Unexpected enabled state.\n"); + + EnableScrollBar(mainwnd, SB_CTL, ESB_ENABLE_BOTH); + + si.fMask = SIF_POS; + si.nPos = 3; + ret = SetScrollInfo(mainwnd, SB_HORZ, &si, FALSE); + ok(ret == 3, "SetScrollInfo returned %d\n", ret); + + /* undocumented flag making SetScrollInfo return previous position */ + si.fMask = SIF_POS | 0x1000; + si.nPos = 4; + ret = SetScrollInfo(mainwnd, SB_HORZ, &si, FALSE); + ok(ret == 3, "SetScrollInfo returned %d\n", ret); DestroyWindow(hScroll); DestroyWindow(mainwnd); @@ -627,7 +713,7 @@ static void test_subclass(void) BOOL r; r = GetClassInfoExA(GetModuleHandleA(NULL), "SCROLLBAR", &class_info); - ok(r, "GetClassInfoEx failed: %u\n", GetLastError()); + ok(r, "GetClassInfoEx failed: %lu\n", GetLastError()); scrollbar_wndproc = class_info.lpfnWndProc; memset(&wc, 0, sizeof(wc)); @@ -636,42 +722,41 @@ static void test_subclass(void) wc.lpszClassName = "MyTestSubclass"; wc.lpfnWndProc = subclass_proc; r = RegisterClassA(&wc); - ok(r, "RegisterClass failed: %u\n", GetLastError()); + ok(r, "RegisterClass failed: %lu\n", GetLastError()); hwnd = CreateWindowExA( 0, "MyTestSubclass", "Scroll", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0 ); - ok(hwnd != NULL, "Failed to create window: %u\n", GetLastError()); + ok(hwnd != NULL, "Failed to create window: %lu\n", GetLastError()); r = SetScrollRange(hwnd, SB_CTL, 0, 100, TRUE); - ok(r, "SetScrollRange failed: %u\n", GetLastError()); + ok(r, "SetScrollRange failed: %lu\n", GetLastError()); res = SetScrollPos(hwnd, SB_CTL, 2, FALSE); - ok(!res, "SetScrollPos returned %lu\n", res); + ok(!res, "SetScrollPos returned %Iu\n", res); memset(&set_scrollinfo, 0xcc, sizeof(set_scrollinfo)); res = SetScrollPos(hwnd, SB_CTL, 1, FALSE); - ok(res == 2, "SetScrollPos returned %lu\n", res); + ok(res == 2, "SetScrollPos returned %Iu\n", res); ok(set_scrollinfo.cbSize == sizeof(SCROLLINFO), "cbSize = %u\n", set_scrollinfo.cbSize); - todo_wine ok(set_scrollinfo.fMask == (0x1000 | SIF_POS), "fMask = %x\n", set_scrollinfo.fMask); ok(set_scrollinfo.nPos == 1, "nPos = %x\n", set_scrollinfo.nPos); memset(&scroll_info, 0xcc, sizeof(scroll_info)); scroll_info.cbSize = sizeof(scroll_info); res = SendMessageA(hwnd, SBM_GETSCROLLBARINFO, 0, (LPARAM)&scroll_info); - ok(res == 1, "SBM_GETSCROLLBARINFO returned %lu\n", res); + ok(res == 1, "SBM_GETSCROLLBARINFO returned %Iu\n", res); DestroyWindow(hwnd); /* if we skip calling wndproc for WM_CREATE, window is not considered a scrollbar */ hwnd = CreateWindowExA( 0, "MyTestSubclass", "Scroll", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, NULL, NULL, GetModuleHandleA(NULL), (void *)1 ); - ok(hwnd != NULL, "Failed to create window: %u\n", GetLastError()); + ok(hwnd != NULL, "Failed to create window: %lu\n", GetLastError()); memset(&scroll_info, 0xcc, sizeof(scroll_info)); scroll_info.cbSize = sizeof(scroll_info); res = SendMessageA(hwnd, SBM_GETSCROLLBARINFO, 0, (LPARAM)&scroll_info); - ok(!res, "SBM_GETSCROLLBARINFO returned %lu\n", res); + ok(!res, "SBM_GETSCROLLBARINFO returned %Iu\n", res); DestroyWindow(hwnd); @@ -679,34 +764,274 @@ static void test_subclass(void) wc.cbWndExtra = class_info.cbWndExtra - 1; wc.lpszClassName = "MyTestSubclass2"; r = RegisterClassA(&wc); - ok(r, "RegisterClass failed: %u\n", GetLastError()); + ok(r, "RegisterClass failed: %lu\n", GetLastError()); hwnd = CreateWindowExA( 0, "MyTestSubclass2", "Scroll", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0 ); - ok(hwnd != NULL, "Failed to create window: %u\n", GetLastError()); + ok(hwnd != NULL, "Failed to create window: %lu\n", GetLastError()); memset(&scroll_info, 0xcc, sizeof(scroll_info)); scroll_info.cbSize = sizeof(scroll_info); res = SendMessageA(hwnd, SBM_GETSCROLLBARINFO, 0, (LPARAM)&scroll_info); - ok(!res, "SBM_GETSCROLLBARINFO returned %lu\n", res); + ok(!res, "SBM_GETSCROLLBARINFO returned %Iu\n", res); memset(&set_scrollinfo, 0xcc, sizeof(set_scrollinfo)); res = SetScrollPos(hwnd, SB_CTL, 1, FALSE); - ok(res == 0, "SetScrollPos returned %lu\n", res); + ok(res == 0, "SetScrollPos returned %Iu\n", res); ok(set_scrollinfo.cbSize == sizeof(SCROLLINFO), "cbSize = %u\n", set_scrollinfo.cbSize); - todo_wine ok(set_scrollinfo.fMask == (0x1000 | SIF_POS), "fMask = %x\n", set_scrollinfo.fMask); ok(set_scrollinfo.nPos == 1, "nPos = %x\n", set_scrollinfo.nPos); DestroyWindow(hwnd); } +static void read_process(HWND hMainWnd) +{ + SCROLLBARINFO sbi = {0}; + SCROLLINFO si; + BOOL ret; + RECT rect, intersection; + BOOL (WINAPI *pGetScrollBarInfo)(HWND, LONG, LPSCROLLBARINFO); + + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE|SIF_POS|SIF_RANGE; + si.nMin = si.nMax = si.nPos = (int)0xdeadbeef; + si.nPage = 0xdeadbeef; + ret = GetScrollInfo( hMainWnd, SB_HORZ, &si ); + todo_wine ok( ret, "GetScrollInfo should succeed\n" ); + + todo_wine ok( si.nMin == 1, "unexpected nMin %i\n", si.nMin ); + todo_wine ok( si.nMax == 10, "unexpected nMax %i\n", si.nMax ); + todo_wine ok( si.nPage == 3, "unexpected nPage %u\n", si.nPage ); + todo_wine ok( si.nPos == 4, "unexpected nPos %i\n", si.nPos ); + + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE|SIF_POS|SIF_RANGE; + si.nMin = si.nMax = si.nPos = (int)0xdeadbeef; + si.nPage = 0xdeadbeef; + ret = GetScrollInfo( hMainWnd, SB_VERT, &si ); + todo_wine ok( ret, "GetScrollInfo should succeed\n" ); + + todo_wine ok( si.nMin == 201, "unexpected nMin %i\n", si.nMin ); + todo_wine ok( si.nMax == 210, "unexpected nMax %i\n", si.nMax ); + todo_wine ok( si.nPage == 2, "unexpected nPage %u\n", si.nPage ); + todo_wine ok( si.nPos == 204, "unexpected nPos %i\n", si.nPos ); + + pGetScrollBarInfo = (void*)GetProcAddress(GetModuleHandleA("user32.dll"), "GetScrollBarInfo"); + if (!pGetScrollBarInfo) + { + win_skip("GetScrollBarInfo is not available\n"); + return; + } + + ret = GetWindowRect( hMainWnd, &rect ); + ok( ret, "The GetWindowRect() call should not fail.\n" ); + + sbi.cbSize = sizeof(sbi); + sbi.rgstate[0] = 0xdeadbeef; + ret = pGetScrollBarInfo( hMainWnd, OBJID_HSCROLL, &sbi ); + todo_wine ok( ret, "The GetScrollBarInfo() call should not fail.\n" ); + + if (ret) + { + IntersectRect( &intersection, &sbi.rcScrollBar, &rect ); + ok( EqualRect( &intersection, &sbi.rcScrollBar ), "hscroll rect %s outside window rect %s\n", + wine_dbgstr_rect( &sbi.rcScrollBar ), wine_dbgstr_rect( &rect )); + ok( sbi.rcScrollBar.right - sbi.rcScrollBar.left > sbi.rcScrollBar.bottom - sbi.rcScrollBar.top, + "hscroll rect %s should have width > height\n", wine_dbgstr_rect( &rect )); + ok( sbi.rgstate[0] == 0, "unexpected hscroll state %#lx\n", sbi.rgstate[0] ); + } + + sbi.cbSize = sizeof(sbi); + sbi.rgstate[0] = 0xdeadbeef; + ret = pGetScrollBarInfo( hMainWnd, OBJID_VSCROLL, &sbi ); + todo_wine ok( ret, "The GetScrollBarInfo() call should not fail.\n" ); + + if (ret) + { + IntersectRect( &intersection, &sbi.rcScrollBar, &rect ); + ok( EqualRect( &intersection, &sbi.rcScrollBar ), "vscroll rect %s outside window rect %s\n", + wine_dbgstr_rect( &sbi.rcScrollBar ), wine_dbgstr_rect( &rect )); + ok( sbi.rcScrollBar.right - sbi.rcScrollBar.left < sbi.rcScrollBar.bottom - sbi.rcScrollBar.top, + "vscroll rect %s should have width < height\n", wine_dbgstr_rect( &rect )); + ok( sbi.rgstate[0] == 0, "unexpected vscroll state %#lx\n", sbi.rgstate[0] ); + } +} + +static DWORD WINAPI write_process(HWND hMainWnd) +{ + SCROLLBARINFO sbi; + SCROLLINFO si; + BOOL ret; + BOOL (WINAPI *pGetScrollBarInfo)(HWND, LONG, LPSCROLLBARINFO); + + si.cbSize = sizeof(si); + si.fMask = SIF_POS; + si.nPos = 6; + ret = SetScrollInfo( hMainWnd, SB_HORZ, &si, FALSE ); + todo_wine ok( ret, "SetScrollInfo should succeed\n" ); + + si.nPos = 206; + ret = SetScrollInfo( hMainWnd, SB_VERT, &si, FALSE ); + todo_wine ok( ret, "SetScrollInfo should succeed\n" ); + + si.nPos = 0xdeadbeef; + ret = GetScrollInfo( hMainWnd, SB_HORZ, &si ); + todo_wine ok( ret, "GetScrollInfo should succeed\n" ); + todo_wine ok( si.nPos == 6, "unexpected nPos %i\n", si.nPos ); + + si.nPos = 0xdeadbeef; + ret = GetScrollInfo( hMainWnd, SB_VERT, &si ); + todo_wine ok( ret, "GetScrollInfo should succeed\n" ); + todo_wine ok( si.nPos == 206, "unexpected nPos %i\n", si.nPos ); + + pGetScrollBarInfo = (void*)GetProcAddress(GetModuleHandleA("user32.dll"), "GetScrollBarInfo"); + if (!pGetScrollBarInfo) + { + win_skip("GetScrollBarInfo is not available\n"); + return 0; + } + + ret = EnableScrollBar( hMainWnd, SB_HORZ, ESB_DISABLE_BOTH ); + todo_wine ok( ret, "EnableScrollBar should succeed\n" ); + + ret = ShowScrollBar( hMainWnd, SB_VERT, FALSE ); + ok( ret, "ShowScrollBar should succeed\n" ); + + sbi.cbSize = sizeof(sbi); + sbi.rgstate[0] = 0xdeadbeef; + ret = pGetScrollBarInfo( hMainWnd, OBJID_HSCROLL, &sbi ); + todo_wine ok( ret, "The GetScrollBarInfo() call should not fail.\n" ); + todo_wine ok( sbi.rgstate[0] == STATE_SYSTEM_UNAVAILABLE, "unexpected hscroll state %#lx\n", sbi.rgstate[0] ); + + sbi.cbSize = sizeof(sbi); + sbi.rgstate[0] = 0xdeadbeef; + ret = pGetScrollBarInfo( hMainWnd, OBJID_VSCROLL, &sbi ); + todo_wine ok( ret, "The GetScrollBarInfo() call should not fail.\n" ); + todo_wine ok( sbi.rgstate[0] == STATE_SYSTEM_INVISIBLE, "unexpected vscroll state %#lx\n", sbi.rgstate[0] ); + + return 0; +} + +static void test_cross_process(const char* argv0) +{ + HWND hMainWnd; + BOOL ret; + SCROLLINFO si; + STARTUPINFOA startup_info = {0}; + PROCESS_INFORMATION process_info; + char path[MAX_PATH]; + + hMainWnd = create_main_test_wnd(); + + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE|SIF_POS|SIF_RANGE; + si.nMin = 1; + si.nMax = 10; + si.nPage = 3; + si.nPos = 4; + SetScrollInfo( hMainWnd, SB_HORZ, &si, FALSE ); + + si.nMin = 201; + si.nMax = 210; + si.nPage = 2; + si.nPos = 204; + SetScrollInfo( hMainWnd, SB_VERT, &si, FALSE ); + + startup_info.cb = sizeof(startup_info); + sprintf( path, "%s scroll read_process %p", argv0, hMainWnd ); + ret = CreateProcessA( NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &startup_info, &process_info ); + ok(ret, "CreateProcess \"%s\" failed err %lu.\n", path, GetLastError()); + + /* Messages do not need to be processed to read info. */ + winetest_wait_child_process(process_info.hProcess); + CloseHandle(process_info.hProcess); + CloseHandle(process_info.hThread); + + sprintf( path, "%s scroll write_process %p", argv0, hMainWnd ); + ret = CreateProcessA( NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &startup_info, &process_info ); + ok(ret, "CreateProcess \"%s\" failed err %lu.\n", path, GetLastError()); + + /* Modifying info requires a message loop. */ + while (MsgWaitForMultipleObjects( 1, &process_info.hProcess, FALSE, 5000, QS_SENDMESSAGE ) == 1) + { + MSG msg; + while (PeekMessageA( &msg, NULL, 0, 0, PM_REMOVE )) + { + TranslateMessage( &msg ); + DispatchMessageA( &msg ); + } + } + + winetest_wait_child_process(process_info.hProcess); + CloseHandle(process_info.hProcess); + CloseHandle(process_info.hThread); + + DestroyWindow( hScroll ); + DestroyWindow( hMainWnd ); +} + +static void test_visual(void) +{ + static const int color_indices[] = {COLOR_SCROLLBAR, COLOR_BTNFACE}; + static const DWORD styles[] = {SBS_SIZEBOX, SBS_SIZEGRIP}; + COLORREF old_colors[2], colors[2], color; + HWND hwnd; + BOOL ret; + HDC hdc; + int i; + + old_colors[0] = GetSysColor(color_indices[0]); + old_colors[1] = GetSysColor(color_indices[1]); + colors[0] = RGB(0x11, 0x22, 0x33); + colors[1] = RGB(0xaa, 0xbb, 0xcc); + ret = SetSysColors(ARRAY_SIZE(color_indices), color_indices, colors); + ok(ret, "SetSysColors failed, error %lu.\n", GetLastError()); + + for (i = 0; i < ARRAY_SIZE(styles); ++i) + { + winetest_push_context("style %#lx", styles[i]); + + hwnd = CreateWindowA("ScrollBar", "", WS_POPUP | WS_VISIBLE | styles[i], 0, 0, 20, 20, 0, 0, + 0, 0); + ok(hwnd != NULL, "CreateWindowA failed, error %lu.\n", GetLastError()); + RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ERASENOW | RDW_FRAME); + + hdc = GetDC(hwnd); + color = GetPixel(hdc, 5, 5); + ok(color == colors[1], "Expected color %#lx, got %#lx.\n", colors[1], color); + + ReleaseDC(hwnd, hdc); + DestroyWindow(hwnd); + winetest_pop_context(); + } + + ret = SetSysColors(ARRAY_SIZE(color_indices), color_indices, old_colors); + ok(ret, "SetSysColors failed, error %lu.\n", GetLastError()); +} + START_TEST ( scroll ) { + char **argv; + int argc; WNDCLASSA wc; HMODULE hUxtheme; BOOL (WINAPI * pIsThemeActive)(VOID); + argc = winetest_get_mainargs(&argv); + if (argc >= 4 && (!strcmp( argv[2], "read_process" ) || !strcmp( argv[2], "write_process" ))) + { + long wnd_long = strtol( argv[3], NULL, 16 ); + HWND wnd = (HWND)(INT_PTR)wnd_long; + + if (!strcmp( argv[2], "read_process" )) + read_process( wnd ); + else + write_process( wnd ); + + return; + } + wc.style = CS_HREDRAW | CS_VREDRAW; wc.cbClsExtra = 0; wc.cbWndExtra = 0; @@ -726,6 +1051,7 @@ START_TEST ( scroll ) scrollbar_test_track(); test_SetScrollInfo(); test_subclass(); + test_cross_process( argv[0] ); /* Some test results vary depending of theming being active or not */ hUxtheme = LoadLibraryA("uxtheme.dll"); @@ -737,6 +1063,8 @@ START_TEST ( scroll ) FreeLibrary(hUxtheme); } + test_visual(); + scrollbar_test_default( 0); scrollbar_test_default( WS_HSCROLL); scrollbar_test_default( WS_VSCROLL); diff --git a/modules/rostests/winetests/user32/static.c b/modules/rostests/winetests/user32/static.c index 8776c3a9e07..c4171df2e10 100644 --- a/modules/rostests/winetests/user32/static.c +++ b/modules/rostests/winetests/user32/static.c @@ -20,20 +20,17 @@ #include #include -#define STRICT -#define WIN32_LEAN_AND_MEAN -#include +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#define OEMRESOURCE +#include "winuser.h" #include "wine/test.h" -#define TODO_COUNT 1 - #define CTRL_ID 1995 static HWND hMainWnd; - -#define expect_eq(expr, value, type, fmt) { type val = expr; ok(val == (value), #expr " expected " fmt " got " fmt "\n", (value), val); } - static int g_nReceivedColorStatic = 0; /* try to make sure pending X events have been processed before continuing */ @@ -76,14 +73,32 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara return DefWindowProcA(hwnd, msg, wparam, lparam); } -static void test_updates(int style, int flags) +static void test_updates(int style) { - RECT r1 = {20, 20, 30, 30}; + RECT r1 = {5, 5, 30, 30}, rcClient; HWND hStatic = build_static(style); int exp; + LONG exstyle; flush_events(); trace("Testing style 0x%x\n", style); + + exstyle = GetWindowLongW(hStatic, GWL_EXSTYLE); + if (style == SS_ETCHEDHORZ || style == SS_ETCHEDVERT || style == SS_SUNKEN) + ok(exstyle == WS_EX_STATICEDGE, "expected WS_EX_STATICEDGE, got %ld\n", exstyle); + else + ok(exstyle == 0, "expected 0, got %ld\n", exstyle); + + GetClientRect(hStatic, &rcClient); + if (style == SS_ETCHEDVERT) + ok(rcClient.right == 0, "expected zero width, got %ld\n", rcClient.right); + else + ok(rcClient.right > 0, "expected non-zero width, got %ld\n", rcClient.right); + if (style == SS_ETCHEDHORZ) + ok(rcClient.bottom == 0, "expected zero height, got %ld\n", rcClient.bottom); + else + ok(rcClient.bottom > 0, "expected non-zero height, got %ld\n", rcClient.bottom); + g_nReceivedColorStatic = 0; /* during each update parent WndProc will test the WM_CTLCOLORSTATIC message */ InvalidateRect(hMainWnd, NULL, FALSE); @@ -104,14 +119,9 @@ static void test_updates(int style, int flags) if (style != SS_ETCHEDHORZ && style != SS_ETCHEDVERT) exp = 4; else - exp = 1; /* SS_ETCHED* seems to send WM_CTLCOLORSTATIC only sometimes */ + exp = 2; /* SS_ETCHEDHORZ/SS_ETCHEDVERT have empty client rect so WM_CTLCOLORSTATIC is sent only when parent window is invalidated */ - if (flags & TODO_COUNT) - todo_wine { expect_eq(g_nReceivedColorStatic, exp, int, "%d"); } - else if ((style & SS_TYPEMASK) == SS_ICON || (style & SS_TYPEMASK) == SS_BITMAP) - ok( g_nReceivedColorStatic == exp, "expected %u got %u\n", exp, g_nReceivedColorStatic ); - else - expect_eq(g_nReceivedColorStatic, exp, int, "%d"); + ok( g_nReceivedColorStatic == exp, "expected %u, got %u\n", exp, g_nReceivedColorStatic ); DestroyWindow(hStatic); } @@ -130,6 +140,211 @@ static void test_set_text(void) DestroyWindow(hStatic); } +static void test_image(HBITMAP image) +{ + BITMAP bm; + HDC hdc; + BITMAPINFO info; + BYTE bits[4]; +#ifdef __REACTOS__ + UINT display_bpp; + + hdc = GetDC(0); + display_bpp = GetDeviceCaps(hdc, BITSPIXEL); + ReleaseDC(0, hdc); +#endif + + GetObjectW(image, sizeof(bm), &bm); + ok(bm.bmWidth == 1, "got %d\n", bm.bmWidth); + ok(bm.bmHeight == 1, "got %d\n", bm.bmHeight); +#ifdef __REACTOS__ + ok(bm.bmBitsPixel == display_bpp, "got %d\n", bm.bmBitsPixel); +#else + ok(bm.bmBitsPixel == 32, "got %d\n", bm.bmBitsPixel); +#endif + ok(bm.bmBits == NULL, "bmBits is not NULL\n"); + + info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + info.bmiHeader.biWidth = bm.bmWidth; + info.bmiHeader.biHeight = bm.bmHeight; + info.bmiHeader.biPlanes = 1; + info.bmiHeader.biBitCount = 32; + info.bmiHeader.biCompression = BI_RGB; + info.bmiHeader.biSizeImage = 4; + info.bmiHeader.biXPelsPerMeter = 0; + info.bmiHeader.biYPelsPerMeter = 0; + info.bmiHeader.biClrUsed = 0; + info.bmiHeader.biClrImportant = 0; + + hdc = CreateCompatibleDC(0); + GetDIBits(hdc, image, 0, bm.bmHeight, bits, &info, DIB_RGB_COLORS); + DeleteDC(hdc); + +#ifdef __REACTOS__ + ok(bits[0] == 0x11 && bits[1] == 0x22 && bits[2] == 0x33 && (display_bpp == 32 ? bits[3] == 0x44 : bits[3] == 0x00), + "bits: %02x %02x %02x %02x\n", bits[0], bits[1], bits[2], bits[3]); +#else + ok(bits[0] == 0x11 && bits[1] == 0x22 && bits[2] == 0x33 && bits[3] == 0x44, + "bits: %02x %02x %02x %02x\n", bits[0], bits[1], bits[2], bits[3]); +#endif +} + +static void test_set_image(void) +{ + HWND hwnd = build_static(SS_BITMAP); + HBITMAP bmp, image; + + image = LoadImageW(GetModuleHandleW(NULL), MAKEINTRESOURCEW(101), IMAGE_BITMAP, 0, 0, 0); + ok(image != NULL, "LoadImage failed\n"); + + test_image(image); + + bmp = (HBITMAP)SendMessageW(hwnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)image); + ok(bmp == NULL, "got not NULL\n"); + + bmp = (HBITMAP)SendMessageW(hwnd, STM_GETIMAGE, IMAGE_BITMAP, 0); + ok(bmp != NULL, "got NULL\n"); + ok(bmp == image, "bmp != image\n"); + + bmp = (HBITMAP)SendMessageW(hwnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)image); + ok(bmp != NULL, "got NULL\n"); + ok(bmp == image, "bmp != image\n"); + test_image(image); + + DestroyWindow(hwnd); + DeleteObject(image); + + hwnd = CreateWindowW(L"static", L"\uffff\x65", WS_VISIBLE|WS_CHILD|SS_BITMAP, 5, 5, 100, 100, + hMainWnd, (HMENU)CTRL_ID, GetModuleHandleW(NULL), 0); + + bmp = (HBITMAP)SendMessageW(hwnd, STM_GETIMAGE, IMAGE_BITMAP, 0); + ok(bmp != NULL, "got NULL\n"); + test_image(bmp); + + DestroyWindow(hwnd); + + hwnd = CreateWindowA("static", "\xff\x65\0", WS_VISIBLE|WS_CHILD|SS_BITMAP, 5, 5, 100, 100, + hMainWnd, (HMENU)CTRL_ID, GetModuleHandleW(NULL), 0); + + bmp = (HBITMAP)SendMessageW(hwnd, STM_GETIMAGE, IMAGE_BITMAP, 0); + ok(bmp != NULL, "got NULL\n"); + test_image(bmp); + + DestroyWindow(hwnd); +} + +static void test_STM_SETIMAGE(void) +{ + DWORD type; + HWND hwnd; + HICON icon, old_image; + HBITMAP bmp; + HENHMETAFILE emf; + HDC dc; + + icon = LoadIconW(0, (LPCWSTR)IDI_APPLICATION); + bmp = LoadBitmapW(0, (LPCWSTR)OBM_CLOSE); + dc = CreateEnhMetaFileW(0, NULL, NULL, NULL); + LineTo(dc, 1, 1); + emf = CloseEnhMetaFile(dc); + DeleteDC(dc); + + for (type = SS_LEFT; type < SS_ETCHEDFRAME; type++) + { + winetest_push_context("%lu", type); + + hwnd = build_static(type); + ok(hwnd != 0, "failed to create static type %#lx\n", type); + + /* set icon */ + g_nReceivedColorStatic = 0; + old_image = (HICON)SendMessageW(hwnd, STM_SETIMAGE, IMAGE_ICON, (LPARAM)icon); + ok(!old_image, "got %p\n", old_image); + if (type == SS_ICON) + ok(g_nReceivedColorStatic, "Unexpected WM_CTLCOLORSTATIC value %d\n", g_nReceivedColorStatic); + else + ok(!g_nReceivedColorStatic, "Unexpected WM_CTLCOLORSTATIC value %d\n", g_nReceivedColorStatic); + + g_nReceivedColorStatic = 0; + old_image = (HICON)SendMessageW(hwnd, STM_SETIMAGE, IMAGE_ICON, (LPARAM)icon); + if (type == SS_ICON) + { + ok(old_image != 0, "got %p\n", old_image); + ok(g_nReceivedColorStatic, "Unexpected WM_CTLCOLORSTATIC value %d\n", g_nReceivedColorStatic); + } + else + { + ok(!old_image, "got %p\n", old_image); + ok(!g_nReceivedColorStatic, "Unexpected WM_CTLCOLORSTATIC value %d\n", g_nReceivedColorStatic); + } + + g_nReceivedColorStatic = 0; + old_image = (HICON)SendMessageW(hwnd, STM_SETICON, (WPARAM)icon, 0); + if (type == SS_ICON) + { + ok(old_image != 0, "got %p\n", old_image); + ok(g_nReceivedColorStatic, "Unexpected WM_CTLCOLORSTATIC value %d\n", g_nReceivedColorStatic); + } + else + { + ok(!old_image, "got %p\n", old_image); + ok(!g_nReceivedColorStatic, "Unexpected WM_CTLCOLORSTATIC value %d\n", g_nReceivedColorStatic); + } + + /* set bitmap */ + g_nReceivedColorStatic = 0; + old_image = (HICON)SendMessageW(hwnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)bmp); + ok(!old_image, "got %p\n", old_image); + if (type == SS_BITMAP) + ok(g_nReceivedColorStatic, "Unexpected WM_CTLCOLORSTATIC value %d\n", g_nReceivedColorStatic); + else + ok(!g_nReceivedColorStatic, "Unexpected WM_CTLCOLORSTATIC value %d\n", g_nReceivedColorStatic); + + g_nReceivedColorStatic = 0; + old_image = (HICON)SendMessageW(hwnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)bmp); + if (type == SS_BITMAP) + { + ok(old_image != 0, "got %p\n", old_image); + ok(g_nReceivedColorStatic, "Unexpected WM_CTLCOLORSTATIC value %d\n", g_nReceivedColorStatic); + } + else + { + ok(!old_image, "got %p\n", old_image); + ok(!g_nReceivedColorStatic, "Unexpected WM_CTLCOLORSTATIC value %d\n", g_nReceivedColorStatic); + } + + /* set EMF */ + g_nReceivedColorStatic = 0; + old_image = (HICON)SendMessageW(hwnd, STM_SETIMAGE, IMAGE_ENHMETAFILE, (LPARAM)emf); + ok(!old_image, "got %p\n", old_image); + if (type == SS_ENHMETAFILE) + ok(g_nReceivedColorStatic, "Unexpected WM_CTLCOLORSTATIC value %d\n", g_nReceivedColorStatic); + else + ok(!g_nReceivedColorStatic, "Unexpected WM_CTLCOLORSTATIC value %d\n", g_nReceivedColorStatic); + + g_nReceivedColorStatic = 0; + old_image = (HICON)SendMessageW(hwnd, STM_SETIMAGE, IMAGE_ENHMETAFILE, (LPARAM)emf); + if (type == SS_ENHMETAFILE) + { + ok(old_image != 0, "got %p\n", old_image); + ok(g_nReceivedColorStatic, "Unexpected WM_CTLCOLORSTATIC value %d\n", g_nReceivedColorStatic); + } + else + { + ok(!old_image, "got %p\n", old_image); + ok(!g_nReceivedColorStatic, "Unexpected WM_CTLCOLORSTATIC value %d\n", g_nReceivedColorStatic); + } + + DestroyWindow(hwnd); + + winetest_pop_context(); + } + + DestroyIcon(icon); + DeleteObject(bmp); + DeleteEnhMetaFile(emf); +} + START_TEST(static) { static const char szClassName[] = "testclass"; @@ -152,16 +367,24 @@ START_TEST(static) hMainWnd = CreateWindowA(szClassName, "Test", WS_OVERLAPPEDWINDOW, 0, 0, 500, 500, NULL, NULL, GetModuleHandleA(NULL), NULL); ShowWindow(hMainWnd, SW_SHOW); - test_updates(0, 0); - test_updates(SS_SIMPLE, 0); - test_updates(SS_ICON, 0); - test_updates(SS_BITMAP, 0); - test_updates(SS_BITMAP | SS_CENTERIMAGE, 0); - test_updates(SS_BLACKRECT, TODO_COUNT); - test_updates(SS_WHITERECT, TODO_COUNT); - test_updates(SS_ETCHEDHORZ, TODO_COUNT); - test_updates(SS_ETCHEDVERT, TODO_COUNT); + test_updates(0); + test_updates(SS_ICON); + test_updates(SS_BLACKRECT); + test_updates(SS_WHITERECT); + test_updates(SS_BLACKFRAME); + test_updates(SS_WHITEFRAME); + test_updates(SS_USERITEM); + test_updates(SS_SIMPLE); + test_updates(SS_OWNERDRAW); + test_updates(SS_BITMAP); + test_updates(SS_BITMAP | SS_CENTERIMAGE); + test_updates(SS_ETCHEDHORZ); + test_updates(SS_ETCHEDVERT); + test_updates(SS_ETCHEDFRAME); + test_updates(SS_SUNKEN); test_set_text(); + test_set_image(); + test_STM_SETIMAGE(); DestroyWindow(hMainWnd); } diff --git a/modules/rostests/winetests/user32/sysparams.c b/modules/rostests/winetests/user32/sysparams.c index 6f8e66f2868..2e0aed0be2b 100644 --- a/modules/rostests/winetests/user32/sysparams.c +++ b/modules/rostests/winetests/user32/sysparams.c @@ -30,11 +30,6 @@ #include "winuser.h" #include "winnls.h" -#ifndef SPI_GETDESKWALLPAPER -# define SPI_GETDESKWALLPAPER 0x0073 -#endif - -static LONG (WINAPI *pChangeDisplaySettingsExA)(LPCSTR, LPDEVMODEA, HWND, DWORD, LPVOID); static BOOL (WINAPI *pIsProcessDPIAware)(void); static BOOL (WINAPI *pSetProcessDPIAware)(void); static BOOL (WINAPI *pSetProcessDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); @@ -54,6 +49,8 @@ static BOOL (WINAPI *pAdjustWindowRectExForDpi)(LPRECT,DWORD,BOOL,DWORD,UINT); static BOOL (WINAPI *pLogicalToPhysicalPointForPerMonitorDPI)(HWND,POINT*); static BOOL (WINAPI *pPhysicalToLogicalPointForPerMonitorDPI)(HWND,POINT*); static LONG (WINAPI *pGetAutoRotationState)(PAR_STATE); +static BOOL (WINAPI *pAreDpiAwarenessContextsEqual)(DPI_AWARENESS_CONTEXT,DPI_AWARENESS_CONTEXT); +static LONG (WINAPI *pGetDpiFromDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); static BOOL strict; static int dpi, real_dpi; @@ -172,12 +169,29 @@ static DWORD WINAPI SysParamsThreadFunc( LPVOID lpParam ); static LRESULT CALLBACK SysParamsTestWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ); static int change_counter; -static int change_setworkarea_param, change_iconverticalspacing_param; static int change_last_param; static int last_bpp; static BOOL displaychange_ok = FALSE, displaychange_test_active = FALSE; static HANDLE displaychange_sem = 0; +#define run_in_process( a, b ) run_in_process_( __FILE__, __LINE__, a, b ) +static void run_in_process_( const char *file, int line, char **argv, const char *args ) +{ + STARTUPINFOA startup = {.cb = sizeof(STARTUPINFOA)}; + PROCESS_INFORMATION info = {0}; + char cmdline[MAX_PATH * 2]; + DWORD ret; + + sprintf( cmdline, "%s %s %s", argv[0], argv[1], args ); + ret = CreateProcessA( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info ); + ok_(file, line)( ret, "CreateProcessA failed, error %lu\n", GetLastError() ); + if (!ret) return; + + wait_child_process( info.hProcess ); + CloseHandle( info.hThread ); + CloseHandle( info.hProcess ); +} + static BOOL get_reg_dword(HKEY base, const char *key_name, const char *value_name, DWORD *value) { HKEY key; @@ -199,13 +213,18 @@ static BOOL get_reg_dword(HKEY base, const char *key_name, const char *value_nam static DWORD get_real_dpi(void) { + DPI_AWARENESS_CONTEXT ctx; DWORD dpi; if (pSetThreadDpiAwarenessContext) { - DPI_AWARENESS_CONTEXT context = pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ); + ctx = pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ); + ok( ctx == (DPI_AWARENESS_CONTEXT)0x80006010, "got %p\n", ctx ); dpi = pGetDpiForSystem(); - pSetThreadDpiAwarenessContext( context ); + ok( dpi, "GetDpiForSystem failed\n" ); + /* restore process-wide DPI awareness context */ + ctx = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x80006010 ); + ok( ctx == (DPI_AWARENESS_CONTEXT)((UINT_PTR)0x11 | (dpi << 8)), "got %p\n", ctx ); return dpi; } if (get_reg_dword(HKEY_CURRENT_USER, "Control Panel\\Desktop", "LogPixels", &dpi)) @@ -228,34 +247,27 @@ static LRESULT CALLBACK SysParamsTestWndProc( HWND hWnd, UINT msg, WPARAM wParam break; case WM_SETTINGCHANGE: - if (change_counter>0) { - /* ignore these messages caused by resizing of toolbars */ - if( wParam == SPI_SETWORKAREA){ - change_setworkarea_param = 1; + if (wParam == SPI_SETHANDEDNESS) break; /* ignore */ + if (!change_counter++) change_last_param = 0; + if (displaychange_test_active) break; + if (!change_last_param) change_last_param = wParam; + else if (change_last_param != wParam) + { + switch (wParam) + { + /* ignore these messages when caused by other actions */ + case SPI_ICONVERTICALSPACING: + case SPI_SETWORKAREA: +#ifdef __REACTOS__ + case SPI_SETBORDER: /* WS03 */ + case SPI_SETNONCLIENTMETRICS: /* WS03 */ +#endif break; - } else if( wParam == SPI_ICONVERTICALSPACING) { - change_iconverticalspacing_param = 1; - break; - } else if( displaychange_test_active) - break; - if( !change_last_param){ - change_last_param = wParam; + default: + ok( 0, "too many changes counter=%d last change=%Iu\n", change_counter, wParam ); break; } - ok(0,"too many changes counter=%d last change=%d\n", - change_counter,change_last_param); - change_counter++; - change_last_param = wParam; - break; } - change_counter++; - change_last_param = change_setworkarea_param = change_iconverticalspacing_param =0; - if( wParam == SPI_SETWORKAREA) - change_setworkarea_param = 1; - else if( wParam == SPI_ICONVERTICALSPACING) - change_iconverticalspacing_param = 1; - else - change_last_param = wParam; break; case WM_DESTROY: @@ -278,18 +290,26 @@ params: */ static void test_change_message( int action, int optional ) { + SendMessageA( ghTestWnd, WM_NULL, 0, 0 ); if (change_counter==0 && optional==1) return; - ok( 1 == change_counter, - "Missed a message: change_counter=%d\n", change_counter ); + ok( change_counter >= 1, "Missed a message: change_counter=%d\n", change_counter ); change_counter = 0; - ok( action == change_last_param || - ( change_setworkarea_param && action == SPI_SETWORKAREA) || - ( change_iconverticalspacing_param && action == SPI_ICONVERTICALSPACING), - "Wrong action got %d expected %d\n", change_last_param, action ); +#ifdef __REACTOS__ + ok( action == change_last_param || broken(action == SPI_SETBORDER) || broken(action == SPI_SETNONCLIENTMETRICS), "Wrong action got %d expected %d\n", change_last_param, action ); +#else + ok( action == change_last_param, "Wrong action got %d expected %d\n", change_last_param, action ); +#endif change_last_param = 0; } +static void flush_change_messages(void) +{ + change_counter = 0; + SendMessageA( ghTestWnd, WM_NULL, 0, 0 ); + change_counter = 0; +} + static BOOL test_error_msg ( int rc, const char *name ) { DWORD last_error = GetLastError(); @@ -306,14 +326,14 @@ static BOOL test_error_msg ( int rc, const char *name ) } else { - trace("%s failed for reason: %d. Indicating test failure and skipping remainder of test\n",name,last_error); - ok(rc!=0,"SystemParametersInfoA: rc=%d err=%d\n",rc,last_error); + trace("%s failed for reason: %ld. Indicating test failure and skipping remainder of test\n",name,last_error); + ok(rc!=0,"SystemParametersInfoA: rc=%d err=%ld\n",rc,last_error); } return FALSE; } else { - ok(rc!=0,"SystemParametersInfoA: rc=%d err=%d\n",rc,last_error); + ok(rc!=0,"SystemParametersInfoA: rc=%d err=%ld\n",rc,last_error); return TRUE; } } @@ -339,12 +359,12 @@ static void _test_reg_key( LPCSTR subKey1, LPCSTR subKey2, LPCSTR valName1, LPCS RegCloseKey( hKey ); if (rc==ERROR_SUCCESS) { - ok( type == exp_type, "wrong type %u/%u\n", type, exp_type ); + ok( type == exp_type, "wrong type %lu/%lu\n", type, exp_type ); switch (exp_type) { case REG_DWORD: ok( *(DWORD *)value == *(DWORD *)exp_value, - "Wrong value in registry: %s %s %08x/%08x\n", + "Wrong value in registry: %s %s %08lx/%08lx\n", subKey1, valName1, *(DWORD *)value, *(DWORD *)exp_value ); break; case REG_SZ: @@ -369,12 +389,12 @@ static void _test_reg_key( LPCSTR subKey1, LPCSTR subKey2, LPCSTR valName1, LPCS RegCloseKey( hKey ); if (rc==ERROR_SUCCESS) { - ok( type == exp_type, "wrong type %u/%u\n", type, exp_type ); + ok( type == exp_type, "wrong type %lu/%lu\n", type, exp_type ); switch (exp_type) { case REG_DWORD: ok( *(DWORD *)value == *(DWORD *)exp_value, - "Wrong value in registry: %s %s %08x/%08x\n", + "Wrong value in registry: %s %s %08lx/%08lx\n", subKey1, valName1, *(DWORD *)value, *(DWORD *)exp_value ); break; case REG_SZ: @@ -400,12 +420,12 @@ static void _test_reg_key( LPCSTR subKey1, LPCSTR subKey2, LPCSTR valName1, LPCS RegCloseKey( hKey ); if (rc==ERROR_SUCCESS) { - ok( type == exp_type, "wrong type %u/%u\n", type, exp_type ); + ok( type == exp_type, "wrong type %lu/%lu\n", type, exp_type ); switch (exp_type) { case REG_DWORD: ok( *(DWORD *)value == *(DWORD *)exp_value, - "Wrong value in registry: %s %s %08x/%08x\n", + "Wrong value in registry: %s %s %08lx/%08lx\n", subKey1, valName1, *(DWORD *)value, *(DWORD *)exp_value ); break; case REG_SZ: @@ -430,12 +450,12 @@ static void _test_reg_key( LPCSTR subKey1, LPCSTR subKey2, LPCSTR valName1, LPCS RegCloseKey( hKey ); if (rc==ERROR_SUCCESS) { - ok( type == exp_type, "wrong type %u/%u\n", type, exp_type ); + ok( type == exp_type, "wrong type %lu/%lu\n", type, exp_type ); switch (exp_type) { case REG_DWORD: ok( *(DWORD *)value == *(DWORD *)exp_value, - "Wrong value in registry: %s %s %08x/%08x\n", + "Wrong value in registry: %s %s %08lx/%08lx\n", subKey1, valName1, *(DWORD *)value, *(DWORD *)exp_value ); break; case REG_SZ: @@ -579,48 +599,48 @@ static void test_SPI_SETBEEP( void ) /* 2 */ curr_val = TRUE; rc=SystemParametersInfoA( SPI_SETBEEP, curr_val, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); if (!test_error_msg(rc,"SPI_SETBEEP")) return; - ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "SystemParametersInfoA: rc=%d err=%ld\n", rc, GetLastError()); test_change_message( SPI_SETBEEP, 0 ); test_reg_key( SPI_SETBEEP_REGKEY, SPI_SETBEEP_VALNAME, curr_val ? "Yes" : "No" ); rc=SystemParametersInfoA( SPI_GETBEEP, 0, &b, 0 ); - ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "SystemParametersInfoA: rc=%d err=%ld\n", rc, GetLastError()); eq( b, curr_val, "SPI_{GET,SET}BEEP", "%d" ); rc=SystemParametersInfoW( SPI_GETBEEP, 0, &b, 0 ); if (rc || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) { - ok(rc, "SystemParametersInfoW: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "SystemParametersInfoW: rc=%d err=%ld\n", rc, GetLastError()); eq( b, curr_val, "SystemParametersInfoW", "%d" ); } /* is a message sent for the second change? */ rc=SystemParametersInfoA( SPI_SETBEEP, curr_val, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); - ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "SystemParametersInfoA: rc=%d err=%ld\n", rc, GetLastError()); test_change_message( SPI_SETBEEP, 0 ); curr_val = FALSE; rc=SystemParametersInfoW( SPI_SETBEEP, curr_val, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); if (rc == FALSE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) rc=SystemParametersInfoA( SPI_SETBEEP, curr_val, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); - ok(rc, "SystemParametersInfo: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "SystemParametersInfo: rc=%d err=%ld\n", rc, GetLastError()); test_change_message( SPI_SETBEEP, 0 ); test_reg_key( SPI_SETBEEP_REGKEY, SPI_SETBEEP_VALNAME, curr_val ? "Yes" : "No" ); rc=SystemParametersInfoA( SPI_GETBEEP, 0, &b, 0 ); - ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "SystemParametersInfoA: rc=%d err=%ld\n", rc, GetLastError()); eq( b, curr_val, "SPI_{GET,SET}BEEP", "%d" ); rc=SystemParametersInfoW( SPI_GETBEEP, 0, &b, 0 ); if (rc || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) { - ok(rc, "SystemParametersInfoW: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "SystemParametersInfoW: rc=%d err=%ld\n", rc, GetLastError()); eq( b, curr_val, "SystemParametersInfoW", "%d" ); } ok( MessageBeep( MB_OK ), "Return value of MessageBeep when sound is disabled\n" ); rc=SystemParametersInfoA( SPI_SETBEEP, old_b, 0, SPIF_UPDATEINIFILE ); - ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "***warning*** failed to restore the original value: rc=%d err=%ld\n", rc, GetLastError()); } static const char *setmouse_valuenames[3] = { @@ -650,7 +670,7 @@ static BOOL run_spi_setmouse_test( int curr_val[], POINT *req_change, POINT *pro rc=SystemParametersInfoA( SPI_SETMOUSE, 0, curr_val, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); if (!test_error_msg(rc,"SPI_SETMOUSE")) return FALSE; - ok(rc, "SystemParametersInfo: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "SystemParametersInfo: rc=%d err=%ld\n", rc, GetLastError()); test_change_message( SPI_SETMOUSE, 0 ); for (i = 0; i < 3; i++) { @@ -659,20 +679,18 @@ static BOOL run_spi_setmouse_test( int curr_val[], POINT *req_change, POINT *pro } rc=SystemParametersInfoA( SPI_GETMOUSE, 0, mi, 0 ); - ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError()); - for (i = 0; i < 3; i++) - { - ok(mi[i] == curr_val[i], - "incorrect value for %d: %d != %d\n", i, mi[i], curr_val[i]); - } + ok(rc, "SystemParametersInfoA: rc=%d err=%ld\n", rc, GetLastError()); + ok(mi[0] == curr_val[0], "expected X threshold %d, got %d\n", curr_val[0], mi[0]); + ok(mi[1] == curr_val[1], "expected Y threshold %d, got %d\n", curr_val[1], mi[1]); + ok(mi[2] == curr_val[2] || broken(mi[2] == 1) /* Win10 1709+ */, + "expected acceleration %d, got %d\n", curr_val[2], mi[2]); rc=SystemParametersInfoW( SPI_GETMOUSE, 0, mi, 0 ); - ok(rc, "SystemParametersInfoW: rc=%d err=%d\n", rc, GetLastError()); - for (i = 0; i < 3; i++) - { - ok(mi[i] == curr_val[i], - "incorrect value for %d: %d != %d\n", i, mi[i], curr_val[i]); - } + ok(rc, "SystemParametersInfoW: rc=%d err=%ld\n", rc, GetLastError()); + ok(mi[0] == curr_val[0], "expected X threshold %d, got %d\n", curr_val[0], mi[0]); + ok(mi[1] == curr_val[1], "expected Y threshold %d, got %d\n", curr_val[1], mi[1]); + ok(mi[2] == curr_val[2] || broken(mi[2] == 1) /* Win10 1709+ */, + "expected acceleration %d, got %d\n", curr_val[2], mi[2]); if (0) { @@ -751,7 +769,7 @@ static void test_SPI_SETMOUSE( void ) /* 4 */ run_spi_setmouse_test( curr_val, req_change, proj_change8, nchange ); rc=SystemParametersInfoA( SPI_SETMOUSE, 0, old_mi, SPIF_UPDATEINIFILE ); - ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "***warning*** failed to restore the original value: rc=%d err=%ld\n", rc, GetLastError()); } static BOOL test_setborder(UINT curr_val, int usesetborder, int dpi) @@ -763,18 +781,18 @@ static BOOL test_setborder(UINT curr_val, int usesetborder, int dpi) ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth); rc=SystemParametersInfoA( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0); - ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "SystemParametersInfoA: rc=%d err=%ld\n", rc, GetLastError()); if( usesetborder) { rc=SystemParametersInfoA( SPI_SETBORDER, curr_val, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); if (!test_error_msg(rc,"SPI_SETBORDER")) return FALSE; - ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "SystemParametersInfoA: rc=%d err=%ld\n", rc, GetLastError()); test_change_message( SPI_SETBORDER, 1 ); } else { /* set non client metrics */ ncm.iBorderWidth = curr_val; rc=SystemParametersInfoA( SPI_SETNONCLIENTMETRICS, 0, &ncm, SPIF_UPDATEINIFILE| SPIF_SENDCHANGE); if (!test_error_msg(rc,"SPI_SETNONCLIENTMETRICS")) return FALSE; - ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "SystemParametersInfoA: rc=%d err=%ld\n", rc, GetLastError()); test_change_message( SPI_SETNONCLIENTMETRICS, 1 ); } if( curr_val) { /* skip if 0, some windows versions return 0 others 1 */ @@ -787,11 +805,11 @@ static BOOL test_setborder(UINT curr_val, int usesetborder, int dpi) if (curr_val == 0) curr_val = 1; /* should be the same as the non client metrics */ rc=SystemParametersInfoA( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0); - ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "SystemParametersInfoA: rc=%d err=%ld\n", rc, GetLastError()); eq( (UINT)ncm.iBorderWidth, curr_val, "NonClientMetric.iBorderWidth", "%d"); /* and from SPI_GETBORDER */ rc=SystemParametersInfoA( SPI_GETBORDER, 0, &border, 0 ); - ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "SystemParametersInfoA: rc=%d err=%ld\n", rc, GetLastError()); eq( border, curr_val, "SPI_{GET,SET}BORDER", "%d"); /* test some SystemMetrics */ frame = curr_val + GetSystemMetrics( SM_CXDLGFRAME ); @@ -823,13 +841,6 @@ static void test_SPI_SETBORDER( void ) /* 6 */ "Control Panel\\Desktop\\WindowMetrics","CaptionWidth", dpi); ncmsave.iCaptionWidth = CaptionWidth; - /* These tests hang when XFree86 4.0 for Windows is running (tested on - * WinNT, SP2, Cygwin/XFree 4.1.0. Skip the test when XFree86 is - * running. - */ - if (FindWindowA( NULL, "Cygwin/XFree86" )) - return; - trace("testing SPI_{GET,SET}BORDER\n"); SetLastError(0xdeadbeef); @@ -858,7 +869,7 @@ static void test_SPI_SETBORDER( void ) /* 6 */ rc=SystemParametersInfoA( SPI_SETNONCLIENTMETRICS, 0, &ncmsave, SPIF_UPDATEINIFILE| SPIF_SENDCHANGE); test_change_message( SPI_SETNONCLIENTMETRICS, 1 ); - ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "***warning*** failed to restore the original value: rc=%d err=%ld\n", rc, GetLastError()); } static void test_SPI_SETKEYBOARDSPEED( void ) /* 10 */ @@ -882,18 +893,18 @@ static void test_SPI_SETKEYBOARDSPEED( void ) /* 10 */ rc=SystemParametersInfoA( SPI_SETKEYBOARDSPEED, vals[i], 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); if (!test_error_msg(rc,"SPI_SETKEYBOARDSPEED")) return; - ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError()); + ok(rc, "%d: rc=%d err=%ld\n", i, rc, GetLastError()); test_change_message( SPI_SETKEYBOARDSPEED, 0 ); sprintf( buf, "%d", vals[i] ); test_reg_key( SPI_SETKEYBOARDSPEED_REGKEY, SPI_SETKEYBOARDSPEED_VALNAME, buf ); rc=SystemParametersInfoA( SPI_GETKEYBOARDSPEED, 0, &v, 0 ); - ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError()); + ok(rc, "%d: rc=%d err=%ld\n", i, rc, GetLastError()); eq( v, vals[i], "SPI_{GET,SET}KEYBOARDSPEED", "%d" ); } rc=SystemParametersInfoA( SPI_SETKEYBOARDSPEED, old_speed, 0, SPIF_UPDATEINIFILE ); - ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "***warning*** failed to restore the original value: rc=%d err=%ld\n", rc, GetLastError()); } /* test_SPI_ICONHORIZONTALSPACING helper */ @@ -906,7 +917,7 @@ static BOOL dotest_spi_iconhorizontalspacing( INT curr_val) rc=SystemParametersInfoA( SPI_ICONHORIZONTALSPACING, curr_val, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE); if (!test_error_msg(rc,"SPI_ICONHORIZONTALSPACING")) return FALSE; - ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "SystemParametersInfoA: rc=%d err=%ld\n", rc, GetLastError()); test_change_message( SPI_ICONHORIZONTALSPACING, 0 ); curr_val = max( curr_val, min_val ); /* The registry keys depend on the Windows version and the values too @@ -919,14 +930,14 @@ static BOOL dotest_spi_iconhorizontalspacing( INT curr_val) "wrong value in registry %d, expected %d\n", regval, curr_val); /* compare with what SPI_ICONHORIZONTALSPACING returns */ rc=SystemParametersInfoA( SPI_ICONHORIZONTALSPACING, 0, &spacing, 0 ); - ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "SystemParametersInfoA: rc=%d err=%ld\n", rc, GetLastError()); eq( spacing, curr_val, "ICONHORIZONTALSPACING", "%d"); /* and with a system metrics */ eq( GetSystemMetrics( SM_CXICONSPACING ), curr_val, "SM_CXICONSPACING", "%d" ); /* and with what SPI_GETICONMETRICS returns */ im.cbSize = sizeof(ICONMETRICSA); rc=SystemParametersInfoA( SPI_GETICONMETRICS, sizeof(ICONMETRICSA), &im, FALSE ); - ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "SystemParametersInfoA: rc=%d err=%ld\n", rc, GetLastError()); eq( im.iHorzSpacing, curr_val, "SPI_GETICONMETRICS", "%d" ); return TRUE; } @@ -947,7 +958,7 @@ static void test_SPI_ICONHORIZONTALSPACING( void ) /* 13 */ dotest_spi_iconhorizontalspacing( 10); /* minimum is 32 */ /* restore */ rc=SystemParametersInfoA( SPI_ICONHORIZONTALSPACING, old_spacing, 0, SPIF_UPDATEINIFILE ); - ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "***warning*** failed to restore the original value: rc=%d err=%ld\n", rc, GetLastError()); } static void test_SPI_SETSCREENSAVETIMEOUT( void ) /* 14 */ @@ -971,20 +982,20 @@ static void test_SPI_SETSCREENSAVETIMEOUT( void ) /* 14 */ rc=SystemParametersInfoA( SPI_SETSCREENSAVETIMEOUT, vals[i], 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); if (!test_error_msg(rc,"SPI_SETSCREENSAVETIMEOUT")) return; - ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError()); + ok(rc, "%d: rc=%d err=%ld\n", i, rc, GetLastError()); test_change_message( SPI_SETSCREENSAVETIMEOUT, 0 ); sprintf( buf, "%d", vals[i] ); test_reg_key( SPI_SETSCREENSAVETIMEOUT_REGKEY, SPI_SETSCREENSAVETIMEOUT_VALNAME, buf ); rc = SystemParametersInfoA( SPI_GETSCREENSAVETIMEOUT, 0, &v, 0 ); - ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError()); + ok(rc, "%d: rc=%d err=%ld\n", i, rc, GetLastError()); eq( v, vals[i], "SPI_{GET,SET}SCREENSAVETIMEOUT", "%d" ); } rc=SystemParametersInfoA( SPI_SETSCREENSAVETIMEOUT, old_timeout, 0, SPIF_UPDATEINIFILE ); - ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "***warning*** failed to restore the original value: rc=%d err=%ld\n", rc, GetLastError()); } static void test_SPI_SETSCREENSAVEACTIVE( void ) /* 17 */ @@ -1007,20 +1018,20 @@ static void test_SPI_SETSCREENSAVEACTIVE( void ) /* 17 */ rc=SystemParametersInfoA( SPI_SETSCREENSAVEACTIVE, vals[i], 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); if (!test_error_msg(rc,"SPI_SETSCREENSAVEACTIVE")) return; - ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError()); + ok(rc, "%d: rc=%d err=%ld\n", i, rc, GetLastError()); test_change_message( SPI_SETSCREENSAVEACTIVE, 0 ); test_reg_key( SPI_SETSCREENSAVEACTIVE_REGKEY, SPI_SETSCREENSAVEACTIVE_VALNAME, vals[i] ? "1" : "0" ); rc=SystemParametersInfoA( SPI_GETSCREENSAVEACTIVE, 0, &v, 0 ); - ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError()); + ok(rc, "%d: rc=%d err=%ld\n", i, rc, GetLastError()); ok(v == vals[i] || broken(! v) /* Win 7 */, "SPI_{GET,SET}SCREENSAVEACTIVE: got %d instead of %d\n", v, vals[i]); } rc=SystemParametersInfoA( SPI_SETSCREENSAVEACTIVE, old_b, 0, SPIF_UPDATEINIFILE ); - ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "***warning*** failed to restore the original value: rc=%d err=%ld\n", rc, GetLastError()); } static void test_SPI_SETGRIDGRANULARITY( void ) /* 19 */ @@ -1049,19 +1060,19 @@ static void test_SPI_SETKEYBOARDDELAY( void ) /* 23 */ rc=SystemParametersInfoA( SPI_SETKEYBOARDDELAY, vals[i], 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); if (!test_error_msg(rc,"SPI_SETKEYBOARDDELAY")) return; - ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError()); + ok(rc, "%d: rc=%d err=%ld\n", i, rc, GetLastError()); test_change_message( SPI_SETKEYBOARDDELAY, 0 ); sprintf( buf, "%d", vals[i] ); test_reg_key( SPI_SETKEYBOARDDELAY_REGKEY, SPI_SETKEYBOARDDELAY_VALNAME, buf ); rc=SystemParametersInfoA( SPI_GETKEYBOARDDELAY, 0, &delay, 0 ); - ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError()); + ok(rc, "%d: rc=%d err=%ld\n", i, rc, GetLastError()); eq( delay, vals[i], "SPI_{GET,SET}KEYBOARDDELAY", "%d" ); } rc=SystemParametersInfoA( SPI_SETKEYBOARDDELAY, old_delay, 0, SPIF_UPDATEINIFILE ); - ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "***warning*** failed to restore the original value: rc=%d err=%ld\n", rc, GetLastError()); } @@ -1075,7 +1086,7 @@ static BOOL dotest_spi_iconverticalspacing( INT curr_val) rc=SystemParametersInfoA( SPI_ICONVERTICALSPACING, curr_val, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE); if (!test_error_msg(rc,"SPI_ICONVERTICALSPACING")) return FALSE; - ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "SystemParametersInfoA: rc=%d err=%ld\n", rc, GetLastError()); test_change_message( SPI_ICONVERTICALSPACING, 0 ); curr_val = max( curr_val, min_val ); /* The registry keys depend on the Windows version and the values too @@ -1088,14 +1099,14 @@ static BOOL dotest_spi_iconverticalspacing( INT curr_val) "wrong value in registry %d, expected %d\n", regval, curr_val); /* compare with what SPI_ICONVERTICALSPACING returns */ rc=SystemParametersInfoA( SPI_ICONVERTICALSPACING, 0, &spacing, 0 ); - ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "SystemParametersInfoA: rc=%d err=%ld\n", rc, GetLastError()); eq( spacing, curr_val, "ICONVERTICALSPACING", "%d" ); /* and with a system metrics */ eq( GetSystemMetrics( SM_CYICONSPACING ), curr_val, "SM_CYICONSPACING", "%d" ); /* and with what SPI_GETICONMETRICS returns */ im.cbSize = sizeof(ICONMETRICSA); rc=SystemParametersInfoA( SPI_GETICONMETRICS, sizeof(ICONMETRICSA), &im, FALSE ); - ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "SystemParametersInfoA: rc=%d err=%ld\n", rc, GetLastError()); eq( im.iVertSpacing, curr_val, "SPI_GETICONMETRICS", "%d" ); return TRUE; } @@ -1118,7 +1129,7 @@ static void test_SPI_ICONVERTICALSPACING( void ) /* 24 */ /* restore */ rc=SystemParametersInfoA( SPI_ICONVERTICALSPACING, old_spacing, 0, SPIF_UPDATEINIFILE ); - ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "***warning*** failed to restore the original value: rc=%d err=%ld\n", rc, GetLastError()); } static void test_SPI_SETICONTITLEWRAP( void ) /* 26 */ @@ -1129,13 +1140,6 @@ static void test_SPI_SETICONTITLEWRAP( void ) /* 26 */ unsigned int i; ICONMETRICSA im; - /* These tests hang when XFree86 4.0 for Windows is running (tested on - * WinNT, SP2, Cygwin/XFree 4.1.0. Skip the test when XFree86 is - * running. - */ - if (FindWindowA( NULL, "Cygwin/XFree86" )) - return; - trace("testing SPI_{GET,SET}ICONTITLEWRAP\n"); SetLastError(0xdeadbeef); rc=SystemParametersInfoA( SPI_GETICONTITLEWRAP, 0, &old_b, 0 ); @@ -1150,7 +1154,7 @@ static void test_SPI_SETICONTITLEWRAP( void ) /* 26 */ rc=SystemParametersInfoA( SPI_SETICONTITLEWRAP, vals[i], 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); if (!test_error_msg(rc,"SPI_SETICONTITLEWRAP")) return; - ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError()); + ok(rc, "%d: rc=%d err=%ld\n", i, rc, GetLastError()); test_change_message( SPI_SETICONTITLEWRAP, 1 ); regval = metricfromreg( SPI_SETICONTITLEWRAP_REGKEY2, SPI_SETICONTITLEWRAP_VALNAME, dpi); @@ -1160,17 +1164,17 @@ static void test_SPI_SETICONTITLEWRAP( void ) /* 26 */ ok( regval == vals[i], "wrong value in registry %d, expected %d\n", regval, vals[i] ); rc=SystemParametersInfoA( SPI_GETICONTITLEWRAP, 0, &v, 0 ); - ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError()); + ok(rc, "%d: rc=%d err=%ld\n", i, rc, GetLastError()); eq( v, vals[i], "SPI_{GET,SET}ICONTITLEWRAP", "%d" ); /* and test with what SPI_GETICONMETRICS returns */ im.cbSize = sizeof(ICONMETRICSA); rc=SystemParametersInfoA( SPI_GETICONMETRICS, sizeof(ICONMETRICSA), &im, FALSE ); - ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "SystemParametersInfoA: rc=%d err=%ld\n", rc, GetLastError()); eq( im.iTitleWrap, (BOOL)vals[i], "SPI_GETICONMETRICS", "%d" ); } rc=SystemParametersInfoA( SPI_SETICONTITLEWRAP, old_b, 0, SPIF_UPDATEINIFILE ); - ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "***warning*** failed to restore the original value: rc=%d err=%ld\n", rc, GetLastError()); } static void test_SPI_SETMENUDROPALIGNMENT( void ) /* 28 */ @@ -1193,7 +1197,7 @@ static void test_SPI_SETMENUDROPALIGNMENT( void ) /* 28 */ rc=SystemParametersInfoA( SPI_SETMENUDROPALIGNMENT, vals[i], 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); if (!test_error_msg(rc,"SPI_SETMENUDROPALIGNMENT")) return; - ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError()); + ok(rc, "%d: rc=%d err=%ld\n", i, rc, GetLastError()); test_change_message( SPI_SETMENUDROPALIGNMENT, 0 ); test_reg_key_ex( SPI_SETMENUDROPALIGNMENT_REGKEY1, SPI_SETMENUDROPALIGNMENT_REGKEY2, @@ -1201,7 +1205,7 @@ static void test_SPI_SETMENUDROPALIGNMENT( void ) /* 28 */ vals[i] ? "1" : "0" ); rc=SystemParametersInfoA( SPI_GETMENUDROPALIGNMENT, 0, &v, 0 ); - ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError()); + ok(rc, "%d: rc=%d err=%ld\n", i, rc, GetLastError()); eq( v, vals[i], "SPI_{GET,SET}MENUDROPALIGNMENT", "%d" ); eq( GetSystemMetrics( SM_MENUDROPALIGNMENT ), (int)vals[i], "SM_MENUDROPALIGNMENT", "%d" ); @@ -1209,7 +1213,8 @@ static void test_SPI_SETMENUDROPALIGNMENT( void ) /* 28 */ rc=SystemParametersInfoA( SPI_SETMENUDROPALIGNMENT, old_b, 0, SPIF_UPDATEINIFILE ); - ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "***warning*** failed to restore the original value: rc=%d err=%ld\n", rc, GetLastError()); + flush_change_messages(); } static void test_SPI_SETDOUBLECLKWIDTH( void ) /* 29 */ @@ -1243,7 +1248,7 @@ static void test_SPI_SETDOUBLECLKWIDTH( void ) /* 29 */ rc=SystemParametersInfoA( SPI_SETDOUBLECLKWIDTH, old_width, 0, SPIF_UPDATEINIFILE ); - ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "***warning*** failed to restore the original value: rc=%d err=%ld\n", rc, GetLastError()); } static void test_SPI_SETDOUBLECLKHEIGHT( void ) /* 30 */ @@ -1277,7 +1282,8 @@ static void test_SPI_SETDOUBLECLKHEIGHT( void ) /* 30 */ rc=SystemParametersInfoA( SPI_SETDOUBLECLKHEIGHT, old_height, 0, SPIF_UPDATEINIFILE ); - ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "***warning*** failed to restore the original value: rc=%d err=%ld\n", rc, GetLastError()); + flush_change_messages(); } static void test_SPI_SETDOUBLECLICKTIME( void ) /* 32 */ @@ -1308,7 +1314,7 @@ static void test_SPI_SETDOUBLECLICKTIME( void ) /* 32 */ curr_val = 1000; rc=SystemParametersInfoA( SPI_SETDOUBLECLICKTIME, curr_val, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); - ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "SystemParametersInfoA: rc=%d err=%ld\n", rc, GetLastError()); test_change_message( SPI_SETDOUBLECLICKTIME, 0 ); sprintf( buf, "%d", curr_val ); test_reg_key( SPI_SETDOUBLECLICKTIME_REGKEY, @@ -1333,25 +1339,26 @@ static void test_SPI_SETDOUBLECLICKTIME( void ) /* 32 */ eq( GetDoubleClickTime(), curr_val, "GetDoubleClickTime", "%d" ); rc=SystemParametersInfoA(SPI_SETDOUBLECLICKTIME, old_time, 0, SPIF_UPDATEINIFILE); - ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "***warning*** failed to restore the original value: rc=%d err=%ld\n", rc, GetLastError()); + flush_change_messages(); } static void test_SPI_SETMOUSEBUTTONSWAP( void ) /* 33 */ { BOOL rc; - BOOL old_b; - const UINT vals[]={TRUE,FALSE}; + BOOL vals[2]; unsigned int i; trace("testing SPI_{GET,SET}MOUSEBUTTONSWAP\n"); - old_b = GetSystemMetrics( SM_SWAPBUTTON ); + vals[1] = GetSystemMetrics( SM_SWAPBUTTON ); + vals[0] = !vals[1]; for (i=0;i SETICONMETRICS */ eq( im_new.iHorzSpacing, im_cur.iHorzSpacing, "iHorzSpacing", "%d" ); eq( im_new.iVertSpacing, im_cur.iVertSpacing, "iVertSpacing", "%d" ); eq( im_new.iTitleWrap, im_cur.iTitleWrap, "iTitleWrap", "%d" ); - eq( im_new.lfFont.lfHeight, im_cur.lfFont.lfHeight, "lfHeight", "%d" ); - eq( im_new.lfFont.lfWidth, im_cur.lfFont.lfWidth, "lfWidth", "%d" ); - eq( im_new.lfFont.lfEscapement, im_cur.lfFont.lfEscapement, "lfEscapement", "%d" ); - eq( im_new.lfFont.lfWeight, im_cur.lfFont.lfWeight, "lfWeight", "%d" ); + eq( im_new.lfFont.lfHeight, im_cur.lfFont.lfHeight, "lfHeight", "%ld" ); + eq( im_new.lfFont.lfWidth, im_cur.lfFont.lfWidth, "lfWidth", "%ld" ); + eq( im_new.lfFont.lfEscapement, im_cur.lfFont.lfEscapement, "lfEscapement", "%ld" ); + eq( im_new.lfFont.lfWeight, im_cur.lfFont.lfWeight, "lfWeight", "%ld" ); eq( im_new.lfFont.lfItalic, im_cur.lfFont.lfItalic, "lfItalic", "%d" ); eq( im_new.lfFont.lfStrikeOut, im_cur.lfFont.lfStrikeOut, "lfStrikeOut", "%d" ); eq( im_new.lfFont.lfUnderline, im_cur.lfFont.lfUnderline, "lfUnderline", "%d" ); @@ -1849,10 +1861,11 @@ static void test_SPI_SETICONMETRICS( void ) /* 46 */ wrap, im_cur.iTitleWrap); /* restore old values */ rc=SystemParametersInfoA( SPI_SETICONMETRICS, sizeof(ICONMETRICSA), &im_orig,SPIF_UPDATEINIFILE ); - ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "***warning*** failed to restore the original value: rc=%d err=%ld\n", rc, GetLastError()); + flush_change_messages(); rc=SystemParametersInfoA( SPI_GETICONMETRICS, sizeof(ICONMETRICSA), &im_new, FALSE ); - ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "SystemParametersInfoA: rc=%d err=%ld\n", rc, GetLastError()); eq( im_new.iHorzSpacing, im_orig.iHorzSpacing, "iHorzSpacing", "%d" ); eq( im_new.iVertSpacing, im_orig.iVertSpacing, "iVertSpacing", "%d" ); @@ -1882,33 +1895,34 @@ static void test_SPI_SETWORKAREA( void ) /* 47 */ rc=SystemParametersInfoA( SPI_SETWORKAREA, 0, &curr_val, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); if (!test_error_msg(rc,"SPI_SETWORKAREA")) return; - ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "SystemParametersInfoA: rc=%d err=%ld\n", rc, GetLastError()); rc=SystemParametersInfoA( SPI_GETWORKAREA, 0, &area, 0 ); - ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "SystemParametersInfoA: rc=%d err=%ld\n", rc, GetLastError()); if( !EqualRect( &area, &curr_val)) /* no message if rect has not changed */ test_change_message( SPI_SETWORKAREA, 0); - eq( area.left, curr_val.left, "left", "%d" ); - eq( area.top, curr_val.top, "top", "%d" ); + eq( area.left, curr_val.left, "left", "%ld" ); + eq( area.top, curr_val.top, "top", "%ld" ); /* size may be rounded */ ok( area.right >= curr_val.right - 16 && area.right < curr_val.right + 16, - "right: got %d instead of %d\n", area.right, curr_val.right ); + "right: got %ld instead of %ld\n", area.right, curr_val.right ); ok( area.bottom >= curr_val.bottom - 16 && area.bottom < curr_val.bottom + 16, - "bottom: got %d instead of %d\n", area.bottom, curr_val.bottom ); + "bottom: got %ld instead of %ld\n", area.bottom, curr_val.bottom ); curr_val = area; rc=SystemParametersInfoA( SPI_SETWORKAREA, 0, &old_area, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); - ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "***warning*** failed to restore the original value: rc=%d err=%ld\n", rc, GetLastError()); rc=SystemParametersInfoA( SPI_GETWORKAREA, 0, &area, 0 ); - ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "SystemParametersInfoA: rc=%d err=%ld\n", rc, GetLastError()); if( !EqualRect( &area, &curr_val)) /* no message if rect has not changed */ test_change_message( SPI_SETWORKAREA, 0 ); - eq( area.left, old_area.left, "left", "%d" ); - eq( area.top, old_area.top, "top", "%d" ); + eq( area.left, old_area.left, "left", "%ld" ); + eq( area.top, old_area.top, "top", "%ld" ); /* size may be rounded */ ok( area.right >= old_area.right - 16 && area.right < old_area.right + 16, - "right: got %d instead of %d\n", area.right, old_area.right ); + "right: got %ld instead of %ld\n", area.right, old_area.right ); ok( area.bottom >= old_area.bottom - 16 && area.bottom < old_area.bottom + 16, - "bottom: got %d instead of %d\n", area.bottom, old_area.bottom ); + "bottom: got %ld instead of %ld\n", area.bottom, old_area.bottom ); + flush_change_messages(); } static void test_SPI_SETSHOWSOUNDS( void ) /* 57 */ @@ -1931,35 +1945,36 @@ static void test_SPI_SETSHOWSOUNDS( void ) /* 57 */ rc=SystemParametersInfoA( SPI_SETSHOWSOUNDS, vals[i], 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); if (!test_error_msg(rc,"SPI_SETSHOWSOUNDS")) return; - ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError()); + ok(rc, "%d: rc=%d err=%ld\n", i, rc, GetLastError()); test_change_message( SPI_SETSHOWSOUNDS, 1 ); test_reg_key( SPI_SETSHOWSOUNDS_REGKEY, SPI_SETSHOWSOUNDS_VALNAME, vals[i] ? "1" : "0" ); rc=SystemParametersInfoA( SPI_GETSHOWSOUNDS, 0, &v, 0 ); - ok(rc, "%d: rc=%d err=%d\n", i, rc, GetLastError()); + ok(rc, "%d: rc=%d err=%ld\n", i, rc, GetLastError()); eq( v, vals[i], "SPI_GETSHOWSOUNDS", "%d" ); eq( GetSystemMetrics( SM_SHOWSOUNDS ), (int)vals[i], "SM_SHOWSOUNDS", "%d" ); } rc=SystemParametersInfoA( SPI_SETSHOWSOUNDS, old_b, 0, SPIF_UPDATEINIFILE ); - ok(rc, "***warning*** failed to restore the original value: rc=%d err=%d\n", rc, GetLastError()); + ok(rc, "***warning*** failed to restore the original value: rc=%d err=%ld\n", rc, GetLastError()); + flush_change_messages(); } static void test_SPI_SETKEYBOARDPREF( void ) /* 69 */ { BOOL rc; - BOOL old_b; - const UINT vals[]={TRUE,FALSE}; + BOOL vals[2]; unsigned int i; trace("testing SPI_{GET,SET}KEYBOARDPREF\n"); SetLastError(0xdeadbeef); - rc=SystemParametersInfoA( SPI_GETKEYBOARDPREF, 0, &old_b, 0 ); + rc=SystemParametersInfoA( SPI_GETKEYBOARDPREF, 0, &vals[1], 0 ); if (!test_error_msg(rc,"SPI_{GET,SET}KEYBOARDPREF")) return; + vals[0] = !vals[1]; for (i=0;i 0 ? CaptionWidthfromreg : ncm.iCaptionWidth; if (!pIsProcessDPIAware || pIsProcessDPIAware()) - smicon = max( min( smicon, CaptionWidthfromreg - 2), 4 ) & ~1; + smicon = max( min( smicon, width - 2), 4 ) & ~1; todo_wine_if( real_dpi == dpi && smicon != (MulDiv( 16, dpi, USER_DEFAULT_SCREEN_DPI) & ~1) ) { - broken_val = (min( ncm.iCaptionHeight, CaptionWidthfromreg ) - 2) & ~1; + broken_val = (min( ncm.iCaptionHeight, width ) - 2) & ~1; broken_val = min( broken_val, 20 ); if (smicon == 4) @@ -2833,16 +2878,11 @@ static void test_GetSystemMetrics( void) ok_gsm_2( SM_CXSMICON, smicon, 6 ); ok_gsm_2( SM_CYSMICON, smicon, 6 ); } - else if (smicon < broken_val) + else { ok_gsm_2( SM_CXSMICON, smicon, broken_val ); ok_gsm_2( SM_CYSMICON, smicon, broken_val ); } - else - { - ok_gsm( SM_CXSMICON, smicon ); - ok_gsm( SM_CYSMICON, smicon ); - } } ok_gsm( SM_CYSMCAPTION, ncm.iSmCaptionHeight + 1); @@ -2908,7 +2948,7 @@ static void test_GetSystemMetrics( void) ncm.iBorderWidth, ncm.iCaptionWidth, ncm.iCaptionHeight, IconSpacing, IconVerticalSpacing); trace( "MenuHeight %d MenuWidth %d ScrollHeight %d ScrollWidth %d SmCaptionHeight %d SmCaptionWidth %d\n", ncm.iMenuHeight, ncm.iMenuWidth, ncm.iScrollHeight, ncm.iScrollWidth, ncm.iSmCaptionHeight, ncm.iSmCaptionWidth); - trace( "Captionfontchar width %d MenuFont %d,%d CaptionWidth from registry: %d screen %d,%d\n", + trace( "Captionfontchar width %d MenuFont %ld,%ld CaptionWidth from registry: %d screen %ld,%ld\n", avcwCaption, tmMenuFont.tmHeight, tmMenuFont.tmExternalLeading, CaptionWidthfromreg, screen.cx, screen.cy); } @@ -2917,10 +2957,10 @@ static void test_GetSystemMetrics( void) static void compare_font( const LOGFONTW *lf1, const LOGFONTW *lf2, int dpi, int custom_dpi, int line ) { - ok_(__FILE__,line)( lf1->lfHeight == MulDiv( lf2->lfHeight, dpi, custom_dpi ), - "wrong lfHeight %d vs %d\n", lf1->lfHeight, lf2->lfHeight ); + ok_(__FILE__,line)( lf2->lfHeight == (dpi == custom_dpi) ? lf1->lfHeight : MulDiv( lf1->lfHeight, custom_dpi, 2 * dpi ), + "wrong lfHeight %ld vs %ld\n", lf1->lfHeight, lf2->lfHeight ); ok_(__FILE__,line)( abs( lf1->lfWidth - MulDiv( lf2->lfWidth, dpi, custom_dpi )) <= 1, - "wrong lfWidth %d vs %d\n", lf1->lfWidth, lf2->lfWidth ); + "wrong lfWidth %ld vs %ld\n", lf1->lfWidth, lf2->lfWidth ); ok_(__FILE__,line)( !memcmp( &lf1->lfEscapement, &lf2->lfEscapement, offsetof( LOGFONTW, lfFaceName ) - offsetof( LOGFONTW, lfEscapement )), "font differs\n" ); @@ -2944,10 +2984,10 @@ static void test_metrics_for_dpi( int custom_dpi ) ncm1.cbSize = sizeof(ncm1); ret = SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, sizeof(ncm1), &ncm1, FALSE ); - ok( ret, "SystemParametersInfoW failed err %u\n", GetLastError() ); + ok( ret, "SystemParametersInfoW failed err %lu\n", GetLastError() ); ncm2.cbSize = sizeof(ncm2); ret = pSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, sizeof(ncm2), &ncm2, FALSE, custom_dpi ); - ok( ret, "SystemParametersInfoForDpi failed err %u\n", GetLastError() ); + ok( ret, "SystemParametersInfoForDpi failed err %lu\n", GetLastError() ); for (i = 0; i < 92; i++) { @@ -3011,6 +3051,19 @@ static void test_metrics_for_dpi( int custom_dpi ) "%u: wrong value %u vs %u font %u vs %u\n", i, ret1, ret2, get_tmheightW( &ncm1.lfMenuFont, 1 ), get_tmheightW( &ncm2.lfMenuFont, 1 )); break; + case SM_CYMIN: + case SM_CYMINTRACK: + val = pGetSystemMetricsForDpi( SM_CYCAPTION, custom_dpi ); + val += 2 * pGetSystemMetricsForDpi( SM_CYFRAME, custom_dpi ); + val += 2 * ncm2.iPaddedBorderWidth; + ok( ret1 == ret2 || ret2 == val /* Win10 1709+ */, "%u: expected %u or %u, got %u\n", i, ret1, val, ret2 ); + break; + case SM_CXMIN: + case SM_CXMINTRACK: + val = MulDiv( ret1 - 7, custom_dpi, dpi ); + ok( ret1 == ret2 || (ret2 >= val - 10 && ret2 <= val + 10) /* Win10 1709+ */, + "%u: expected %u or %u, got %u\n", i, ret1, val, ret2 ); + break; default: ok( ret1 == ret2, "%u: wrong value %u vs %u\n", i, ret1, ret2 ); break; @@ -3018,10 +3071,10 @@ static void test_metrics_for_dpi( int custom_dpi ) } im1.cbSize = sizeof(im1); ret = SystemParametersInfoW( SPI_GETICONMETRICS, sizeof(im1), &im1, FALSE ); - ok( ret, "SystemParametersInfoW failed err %u\n", GetLastError() ); + ok( ret, "SystemParametersInfoW failed err %lu\n", GetLastError() ); im2.cbSize = sizeof(im2); ret = pSystemParametersInfoForDpi( SPI_GETICONMETRICS, sizeof(im2), &im2, FALSE, custom_dpi ); - ok( ret, "SystemParametersInfoForDpi failed err %u\n", GetLastError() ); + ok( ret, "SystemParametersInfoForDpi failed err %lu\n", GetLastError() ); ok( im1.iHorzSpacing == MulDiv( im2.iHorzSpacing, dpi, custom_dpi ), "wrong iHorzSpacing %u vs %u\n", im1.iHorzSpacing, im2.iHorzSpacing ); ok( im1.iVertSpacing == MulDiv( im2.iVertSpacing, dpi, custom_dpi ), "wrong iVertSpacing %u vs %u\n", @@ -3031,9 +3084,9 @@ static void test_metrics_for_dpi( int custom_dpi ) compare_font( &im1.lfFont, &im2.lfFont, dpi, custom_dpi, __LINE__ ); ret = SystemParametersInfoW( SPI_GETICONTITLELOGFONT, sizeof(lf1), &lf1, FALSE ); - ok( ret, "SystemParametersInfoW failed err %u\n", GetLastError() ); + ok( ret, "SystemParametersInfoW failed err %lu\n", GetLastError() ); ret = pSystemParametersInfoForDpi( SPI_GETICONTITLELOGFONT, sizeof(lf2), &lf2, FALSE, custom_dpi ); - ok( ret, "SystemParametersInfoForDpi failed err %u\n", GetLastError() ); + ok( ret, "SystemParametersInfoForDpi failed err %lu\n", GetLastError() ); compare_font( &lf1, &lf2, dpi, custom_dpi, __LINE__ ); /* on high-dpi iPaddedBorderWidth is used in addition to iBorderWidth */ @@ -3070,47 +3123,273 @@ static void test_metrics_for_dpi( int custom_dpi ) SetLastError( 0xdeadbeef ); ret = pSystemParametersInfoForDpi( i, 0, &val, 0, custom_dpi ); ok( !ret, "%u: SystemParametersInfoForDpi succeeded\n", i ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "%u: wrong error %u\n", i, GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "%u: wrong error %lu\n", i, GetLastError() ); } } +static BOOL get_primary_adapter_name(CHAR *name) +{ + DISPLAY_DEVICEA dd; + DWORD adapter; + + dd.cb = sizeof(dd); + for (adapter = 0; EnumDisplayDevicesA(NULL, adapter, &dd, 0); ++adapter) + { + if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) + { + lstrcpyA(name, dd.DeviceName); + return TRUE; + } + } + + return FALSE; +} + +static BOOL CALLBACK test_enum_display_settings(HMONITOR hmonitor, HDC hdc, LPRECT rect, LPARAM lparam) +{ + INT width, height; + MONITORINFOEXA mi; + DEVMODEA dm; + BOOL ret; + + memset(&mi, 0, sizeof(mi)); + mi.cbSize = sizeof(mi); + ret = GetMonitorInfoA(hmonitor, (MONITORINFO *)&mi); + ok(ret, "GetMonitorInfoA failed, error %#lx\n", GetLastError()); + + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + ret = EnumDisplaySettingsA(mi.szDevice, ENUM_CURRENT_SETTINGS, &dm); + ok(ret, "EnumDisplaySettingsA failed, error %#lx\n", GetLastError()); + + ok((dm.dmFields & (DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT)) == (DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT), + "Unexpected dmFields %#lx.\n", dm.dmFields); + ok(dm.dmPosition.x == mi.rcMonitor.left, "Expect dmPosition.x %ld, got %ld\n", mi.rcMonitor.left, dm.dmPosition.x); + ok(dm.dmPosition.y == mi.rcMonitor.top, "Expect dmPosition.y %ld, got %ld\n", mi.rcMonitor.top, dm.dmPosition.y); + width = mi.rcMonitor.right - mi.rcMonitor.left; + ok(dm.dmPelsWidth == width, "Expect dmPelsWidth %d, got %ld\n", width, dm.dmPelsWidth); + height = mi.rcMonitor.bottom - mi.rcMonitor.top; + ok(dm.dmPelsHeight == height, "Expect dmPelsHeight %d, got %ld\n", height, dm.dmPelsHeight); + + return TRUE; +} + static void test_EnumDisplaySettings(void) { - DEVMODEA devmode; - DWORD val; + static const DWORD mode_fields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | + DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY; + static const DWORD setting_fields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | + DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION; + CHAR primary_adapter[CCHDEVICENAME]; + DPI_AWARENESS_CONTEXT ctx = NULL; + DWORD err, val, device, mode; + BOOL attached, ret; + DISPLAY_DEVICEA dd; + DEVMODEA dm, dm2; + DEVMODEW dmW; HDC hdc; - DWORD num; - memset(&devmode, 0, sizeof(devmode)); - EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &devmode); + /* Test invalid device names */ + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + SetLastError(0xdeadbeef); + ret = EnumDisplaySettingsA("invalid", ENUM_CURRENT_SETTINGS, &dm); + ok(!ret, "EnumDisplaySettingsA succeeded\n"); + ok(GetLastError() == 0xdeadbeef, "Expect error 0xdeadbeef, got %#lx\n", GetLastError()); + ok(dm.dmFields == 0, "Expect dmFields unchanged, got %#lx\n", dm.dmFields); + /* Monitor device names are invalid */ + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + SetLastError(0xdeadbeef); + ret = EnumDisplaySettingsA("\\\\.\\DISPLAY1\\Monitor0", ENUM_CURRENT_SETTINGS, &dm); + ok(!ret, "EnumDisplaySettingsA succeeded\n"); + ok(GetLastError() == 0xdeadbeef, "Expect error 0xdeadbeef, got %#lx\n", GetLastError()); + ok(dm.dmFields == 0, "Expect dmFields unchanged, got %#lx\n", dm.dmFields); + + /* Test that passing NULL to device name parameter means to use the primary adapter */ + memset(&dm, 0, sizeof(dm)); + memset(&dm2, 0, sizeof(dm2)); + dm.dmSize = sizeof(dm); + dm2.dmSize = sizeof(dm2); + ret = get_primary_adapter_name(primary_adapter); + ok(ret, "get_primary_adapter_name failed\n"); + ret = EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &dm); + ok(ret, "EnumDisplaySettingsA failed, error %#lx\n", GetLastError()); + ret = EnumDisplaySettingsA(primary_adapter, ENUM_CURRENT_SETTINGS, &dm2); + ok(ret, "EnumDisplaySettingsA failed, error %#lx\n", GetLastError()); + ok(!memcmp(&dm, &dm2, sizeof(dm)), "Expect NULL device is the primary device.\n"); + + /* Test dmSize */ + /* EnumDisplaySettingsA/W modify dmSize and don't check for insufficient dmSize */ + memset(&dm, 0, sizeof(dm)); + ret = EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &dm); + ok(ret, "EnumDisplaySettingsA failed, error %#lx\n", GetLastError()); + ok(dm.dmSize == FIELD_OFFSET(DEVMODEA, dmICMMethod), "Expect dmSize %lu, got %u\n", + FIELD_OFFSET(DEVMODEA, dmICMMethod), dm.dmSize); + ok((dm.dmFields & setting_fields) == setting_fields, "Expect dmFields to contain %#lx, got %#lx\n", + setting_fields, dm.dmFields); + + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + ret = EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &dm); + ok(ret, "EnumDisplaySettingsA failed, error %#lx\n", GetLastError()); + ok(dm.dmSize == FIELD_OFFSET(DEVMODEA, dmICMMethod), "Expect dmSize %lu, got %u\n", + FIELD_OFFSET(DEVMODEA, dmICMMethod), dm.dmSize); + ok((dm.dmFields & setting_fields) == setting_fields, "Expect dmFields to contain %#lx, got %#lx\n", + setting_fields, dm.dmFields); + + memset(&dmW, 0, sizeof(dmW)); + ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &dmW); + ok(ret, "EnumDisplaySettingsW failed, error %#lx\n", GetLastError()); + ok(dmW.dmSize == FIELD_OFFSET(DEVMODEW, dmICMMethod), "Expect dmSize %lu, got %u\n", + FIELD_OFFSET(DEVMODEW, dmICMMethod), dmW.dmSize); + ok((dmW.dmFields & setting_fields) == setting_fields, "Expect dmFields to contain %#lx, got %#lx\n", + setting_fields, dmW.dmFields); + + memset(&dmW, 0, sizeof(dmW)); + dmW.dmSize = sizeof(dmW); + ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &dmW); + ok(ret, "EnumDisplaySettingsW failed, error %#lx\n", GetLastError()); + ok(dmW.dmSize == FIELD_OFFSET(DEVMODEW, dmICMMethod), "Expect dmSize %lu, got %u\n", + FIELD_OFFSET(DEVMODEW, dmICMMethod), dmW.dmSize); + ok((dmW.dmFields & setting_fields) == setting_fields, "Expect dmFields to contain %#lx, got %#lx\n", + setting_fields, dmW.dmFields); + + /* EnumDisplaySettingsExA/W need dmSize to be at least FIELD_OFFSET(DEVMODEA/W, dmFields) + 1 to have valid dmFields */ + /* Crash on Windows when dmSize is zero */ + if (0) + { + memset(&dm, 0, sizeof(dm)); + ret = EnumDisplaySettingsExA(NULL, ENUM_CURRENT_SETTINGS, &dm, 0); + ok(!ret, "EnumDisplaySettingsExA succeed\n"); + + memset(&dmW, 0, sizeof(dmW)); + ret = EnumDisplaySettingsExW(NULL, ENUM_CURRENT_SETTINGS, &dmW, 0); + ok(!ret, "EnumDisplaySettingsExA succeed\n"); + } + + memset(&dm, 0, sizeof(dm)); + dm.dmSize = FIELD_OFFSET(DEVMODEA, dmFields); + ret = EnumDisplaySettingsExA(NULL, ENUM_CURRENT_SETTINGS, &dm, 0); + ok(ret, "EnumDisplaySettingsExA failed, error %#lx\n", GetLastError()); + todo_wine ok(dm.dmSize == FIELD_OFFSET(DEVMODEA, dmFields), "Expect dmSize unchanged, got %u\n", dm.dmSize); + todo_wine ok(dm.dmFields == 0, "Expect dmFields unchanged, got %#lx\n", dm.dmFields); + + memset(&dm, 0, sizeof(dm)); + dm.dmSize = FIELD_OFFSET(DEVMODEA, dmFields) + 1; + ret = EnumDisplaySettingsExA(NULL, ENUM_CURRENT_SETTINGS, &dm, 0); + ok(ret, "EnumDisplaySettingsExA failed, error %#lx\n", GetLastError()); + todo_wine ok(dm.dmSize == FIELD_OFFSET(DEVMODEA, dmFields) + 1, "Expect dmSize unchanged, got %u\n", dm.dmSize); + todo_wine ok((dm.dmFields & setting_fields) == (DM_POSITION | DM_DISPLAYORIENTATION), + "Expect dmFields to contain %#lx, got %#lx\n", DM_POSITION | DM_DISPLAYORIENTATION, dm.dmFields); + /* Fields beyond dmSize don't get written */ + todo_wine ok(dm.dmPelsWidth == 0, "Expect dmPelsWidth unwritten\n"); + + memset(&dmW, 0, sizeof(dmW)); + dmW.dmSize = FIELD_OFFSET(DEVMODEW, dmFields); + ret = EnumDisplaySettingsExW(NULL, ENUM_CURRENT_SETTINGS, &dmW, 0); + ok(ret, "EnumDisplaySettingsExW failed, error %#lx\n", GetLastError()); + todo_wine ok(dmW.dmSize == FIELD_OFFSET(DEVMODEW, dmFields), "Expect dmSize unchanged, got %u\n", dmW.dmSize); + todo_wine ok(dmW.dmFields == 0, "Expect dmFields unchanged, got %#lx\n", dmW.dmFields); + + memset(&dmW, 0, sizeof(dmW)); + dmW.dmSize = FIELD_OFFSET(DEVMODEW, dmFields) + 1; + ret = EnumDisplaySettingsExW(NULL, ENUM_CURRENT_SETTINGS, &dmW, 0); + ok(ret, "EnumDisplaySettingsExW failed, error %#lx\n", GetLastError()); + todo_wine ok(dmW.dmSize == FIELD_OFFSET(DEVMODEW, dmFields) + 1, "Expect dmSize unchanged, got %u\n", dmW.dmSize); + todo_wine ok((dmW.dmFields & setting_fields) == (DM_POSITION | DM_DISPLAYORIENTATION), + "Expect dmFields to contain %#lx, got %#lx\n", DM_POSITION | DM_DISPLAYORIENTATION, dmW.dmFields); + /* Fields beyond dmSize don't get written */ + todo_wine ok(dmW.dmPelsWidth == 0, "Expect dmPelsWidth unwritten\n"); + + /* Test dmBitsPerPel */ hdc = GetDC(0); val = GetDeviceCaps(hdc, BITSPIXEL); - ok(devmode.dmBitsPerPel == val, - "GetDeviceCaps(BITSPIXEL) returned %d, EnumDisplaySettings returned %d\n", - val, devmode.dmBitsPerPel); + + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + ret = EnumDisplaySettingsExA(NULL, ENUM_CURRENT_SETTINGS, &dm, 0); + ok(ret, "EnumDisplaySettingsExA failed, error %#lx\n", GetLastError()); + ok((dm.dmFields & setting_fields) == setting_fields, "Expect dmFields to contain %#lx, got %#lx\n", + setting_fields, dm.dmFields); + ok(dm.dmBitsPerPel == val, "Expect dmBitsPerPel %ld, got %ld\n", val, dm.dmBitsPerPel); val = GetDeviceCaps(hdc, NUMCOLORS); - if(devmode.dmBitsPerPel <= 8) { - ok(val == 256, "Screen bpp is %d, NUMCOLORS returned %d\n", devmode.dmBitsPerPel, val); - } else { - ok(val == -1, "Screen bpp is %d, NUMCOLORS returned %d\n", devmode.dmBitsPerPel, val); + if (dm.dmBitsPerPel <= 8) + { + ok(val == 256, "Screen bpp is %ld, NUMCOLORS returned %ld\n", dm.dmBitsPerPel, val); + } + else + { + ok(val == -1, "Screen bpp is %ld, NUMCOLORS returned %ld\n", dm.dmBitsPerPel, val); } ReleaseDC(0, hdc); - num = 1; - while (1) { - SetLastError (0xdeadbeef); - if (!EnumDisplaySettingsA(NULL, num, &devmode)) { - DWORD le = GetLastError(); - ok(le == ERROR_NO_MORE_FILES || - le == ERROR_MOD_NOT_FOUND /* Win8 */ || - le == 0xdeadbeef, /* XP, 2003 */ - "Expected ERROR_NO_MORE_FILES, ERROR_MOD_NOT_FOUND or 0xdeadbeef, got %d for %d\n", le, num); - break; - } - num++; + /* Test dmPosition, dmPelsWidth and dmPelsHeight */ + /* Set DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE so that GetMonitorInfo() returns physical pixels */ + if (pSetThreadDpiAwarenessContext) + ctx = pSetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE); + EnumDisplayMonitors(NULL, NULL, test_enum_display_settings, 0); + if (pSetThreadDpiAwarenessContext && ctx) + pSetThreadDpiAwarenessContext(ctx); + + /* Test mode enumeration and other fields */ + dd.cb = sizeof(dd); + for (device = 0; EnumDisplayDevicesA(NULL, device, &dd, 0); ++device) + { + INT number; + + /* Skip software devices */ + if (sscanf(dd.DeviceName, "\\\\.\\DISPLAY%d", &number) != 1) + continue; + + attached = dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP; + + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + SetLastError(0xdeadbeef); + for (mode = ENUM_REGISTRY_SETTINGS; EnumDisplaySettingsA(dd.DeviceName, mode, &dm); ++mode) + { + if (mode == ENUM_CURRENT_SETTINGS) + { + ok((dm.dmFields & setting_fields) == setting_fields, + "Expect dmFields to contain %#lx, got %#lx\n", setting_fields, dm.dmFields); + } + else + { + ok((dm.dmFields & mode_fields) == mode_fields, "Expect dmFields to contain %#lx, got %#lx\n", + mode_fields, dm.dmFields); + } + + ok(dm.dmDisplayOrientation == DMDO_DEFAULT, "Expect dmDisplayOrientation DMDO_DEFAULT, got %#lx\n", + dm.dmDisplayOrientation); + ok(dm.dmDisplayFlags == 0, "Expect dmDisplayFlags zero\n"); + + if (mode == ENUM_CURRENT_SETTINGS && !attached) + { + ok(dm.dmBitsPerPel == 0, "Expect dmBitsPerPel zero, got %lu\n", dm.dmBitsPerPel); + ok(dm.dmPelsWidth == 0, "Expect dmPelsWidth zero, got %lu\n", dm.dmPelsWidth); + ok(dm.dmPelsHeight == 0, "Expect dmPelsHeight zero, got %lu\n", dm.dmPelsHeight); + ok(dm.dmDisplayFrequency == 0, "Expect dmDisplayFrequency zero, got %lu\n", dm.dmDisplayFrequency); + } + else if (mode != ENUM_REGISTRY_SETTINGS) + { + ok(dm.dmBitsPerPel, "Expect dmBitsPerPel not zero\n"); + ok(dm.dmPelsWidth, "Expect dmPelsWidth not zero\n"); + ok(dm.dmPelsHeight, "Expect dmPelsHeight not zero\n"); + ok(dm.dmDisplayFrequency, "Expect dmDisplayFrequency not zero\n"); + } + } + + ok(mode >= 1, "Expect at least one valid mode gets enumerated.\n"); + + err = GetLastError(); + ok(err == ERROR_NO_MORE_FILES || + err == ERROR_MOD_NOT_FOUND /* Win8 */ || + err == 0xdeadbeef, /* XP, 2003 */ + "Expected ERROR_NO_MORE_FILES, ERROR_MOD_NOT_FOUND or 0xdeadbeef, got %#lx\n", err); } } @@ -3121,7 +3400,7 @@ static void test_GetSysColorBrush(void) SetLastError(0xdeadbeef); hbr = GetSysColorBrush(-1); ok(hbr == NULL, "Expected NULL brush\n"); - ok(GetLastError() == 0xdeadbeef, "Expected last error not set, got %x\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "Expected last error not set, got %lx\n", GetLastError()); /* greater than max index */ hbr = GetSysColorBrush(COLOR_MENUBAR); if (hbr) @@ -3129,7 +3408,7 @@ static void test_GetSysColorBrush(void) SetLastError(0xdeadbeef); hbr = GetSysColorBrush(COLOR_MENUBAR + 1); ok(hbr == NULL, "Expected NULL brush\n"); - ok(GetLastError() == 0xdeadbeef, "Expected last error not set, got %x\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "Expected last error not set, got %lx\n", GetLastError()); } else win_skip("COLOR_MENUBAR unsupported\n"); @@ -3168,7 +3447,7 @@ static void test_dpi_stock_objects( HDC hdc ) GetObjectW( obj[i], sizeof(lf), &lf ); GetObjectW( obj2[i], sizeof(lf2), &lf2 ); ok( lf.lfHeight == MulDiv( lf2.lfHeight, USER_DEFAULT_SCREEN_DPI, real_dpi ), - "%u: wrong height %d / %d\n", i, lf.lfHeight, lf2.lfHeight ); + "%u: wrong height %ld / %ld\n", i, lf.lfHeight, lf2.lfHeight ); break; default: ok( obj[i] == obj2[i], "%u: different object\n", i ); @@ -3221,6 +3500,7 @@ static void test_dpi_mapping(void) ULONG_PTR i, j, k; WINDOWPLACEMENT wpl_orig, wpl; HMONITOR monitor; + INT monitor_count; MONITORINFO mon_info; DPI_AWARENESS_CONTEXT context; @@ -3231,6 +3511,7 @@ static void test_dpi_mapping(void) } context = pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ); GetWindowRect( GetDesktopWindow(), &desktop ); + monitor_count = GetSystemMetrics( SM_CMONITORS ); for (i = DPI_AWARENESS_UNAWARE; i <= DPI_AWARENESS_PER_MONITOR_AWARE; i++) { pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~i ); @@ -3238,27 +3519,31 @@ static void test_dpi_mapping(void) GetWindowRect( GetDesktopWindow(), &rect ); expect = desktop; if (i == DPI_AWARENESS_UNAWARE) scale_rect_dpi( &expect, real_dpi, USER_DEFAULT_SCREEN_DPI ); - ok( EqualRect( &expect, &rect ), "%lu: wrong desktop rect %s expected %s\n", + ok( EqualRect( &expect, &rect ), "%Iu: wrong desktop rect %s expected %s\n", i, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); SetRect( &rect, 0, 0, GetSystemMetrics( SM_CXSCREEN ), GetSystemMetrics( SM_CYSCREEN )); - ok( EqualRect( &expect, &rect ), "%lu: wrong desktop rect %s expected %s\n", - i, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); - SetRect( &rect, 0, 0, GetSystemMetrics( SM_CXVIRTUALSCREEN ), GetSystemMetrics( SM_CYVIRTUALSCREEN )); - ok( EqualRect( &expect, &rect ), "%lu: wrong virt desktop rect %s expected %s\n", + ok( EqualRect( &expect, &rect ), "%Iu: wrong desktop rect %s expected %s\n", i, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); + if (monitor_count < 2) + { + SetRect( &rect, 0, 0, GetSystemMetrics( SM_CXVIRTUALSCREEN ), GetSystemMetrics( SM_CYVIRTUALSCREEN )); + ok( EqualRect( &expect, &rect ), "%Iu: wrong virt desktop rect %s expected %s\n", + i, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); + } SetRect( &rect, 0, 0, 1, 1 ); monitor = MonitorFromRect( &rect, MONITOR_DEFAULTTOPRIMARY ); ok( monitor != 0, "failed to get monitor\n" ); mon_info.cbSize = sizeof(mon_info); ok( GetMonitorInfoW( monitor, &mon_info ), "GetMonitorInfoExW failed\n" ); - ok( EqualRect( &expect, &mon_info.rcMonitor ), "%lu: wrong monitor rect %s expected %s\n", + ok( EqualRect( &expect, &mon_info.rcMonitor ), "%Iu: wrong monitor rect %s expected %s\n", i, wine_dbgstr_rect(&mon_info.rcMonitor), wine_dbgstr_rect(&expect) ); hdc = CreateDCA( "display", NULL, NULL, NULL ); SetRect( &rect, 0, 0, GetDeviceCaps( hdc, HORZRES ), GetDeviceCaps( hdc, VERTRES )); - ok( EqualRect( &expect, &rect ), "%lu: wrong caps desktop rect %s expected %s\n", + ok( EqualRect( &expect, &rect ), "%Iu: wrong caps desktop rect %s expected %s\n", i, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); SetRect( &rect, 0, 0, GetDeviceCaps( hdc, DESKTOPHORZRES ), GetDeviceCaps( hdc, DESKTOPVERTRES )); - ok( EqualRect( &desktop, &rect ), "%lu: wrong caps virt desktop rect %s expected %s\n", + todo_wine_if(monitor_count > 1) + ok( EqualRect( &desktop, &rect ), "%Iu: wrong caps virt desktop rect %s expected %s\n", i, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&desktop) ); DeleteDC( hdc ); /* test message window rect */ @@ -3267,7 +3552,7 @@ static void test_dpi_mapping(void) GetWindowRect( GetAncestor( hwnd, GA_PARENT ), &rect ); SetRect( &expect, 0, 0, 100, 100 ); if (i == DPI_AWARENESS_UNAWARE) scale_rect_dpi( &expect, real_dpi, USER_DEFAULT_SCREEN_DPI ); - ok( EqualRect( &expect, &rect ), "%lu: wrong message rect %s expected %s\n", + ok( EqualRect( &expect, &rect ), "%Iu: wrong message rect %s expected %s\n", i, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); DestroyWindow( hwnd ); } @@ -3276,10 +3561,10 @@ static void test_dpi_mapping(void) pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~i ); hwnd = CreateWindowA( "SysParamsTestClass", "test", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 193, 177, 295, 303, 0, 0, GetModuleHandleA(0), NULL ); - ok( hwnd != 0, "creating window failed err %u\n", GetLastError()); + ok( hwnd != 0, "creating window failed err %lu\n", GetLastError()); child = CreateWindowA( "SysParamsTestClass", "child", WS_CHILD | WS_VISIBLE, 50, 60, 70, 80, hwnd, 0, GetModuleHandleA(0), NULL ); - ok( child != 0, "creating child failed err %u\n", GetLastError()); + ok( child != 0, "creating child failed err %lu\n", GetLastError()); GetWindowRect( hwnd, &orig ); SetRect( &rect, 0, 0, 0, 0 ); pAdjustWindowRectExForDpi( &rect, WS_OVERLAPPEDWINDOW, FALSE, 0, pGetDpiForWindow( hwnd )); @@ -3297,46 +3582,47 @@ static void test_dpi_mapping(void) GetWindowRect( hwnd, &rect ); expect = orig; scale_rect_dpi_aware( &expect, i, j ); - ok( EqualRect( &expect, &rect ), "%lu/%lu: wrong window rect %s expected %s\n", + ok( EqualRect( &expect, &rect ), "%Iu/%Iu: wrong window rect %s expected %s\n", i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); /* test client rect */ GetClientRect( hwnd, &rect ); expect = client; OffsetRect( &expect, -expect.left, -expect.top ); scale_rect_dpi_aware( &expect, i, j ); - ok( EqualRect( &expect, &rect ), "%lu/%lu: wrong client rect %s expected %s\n", + ok( EqualRect( &expect, &rect ), "%Iu/%Iu: wrong client rect %s expected %s\n", i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); /* test window placement */ GetWindowPlacement( hwnd, &wpl ); point = wpl_orig.ptMinPosition; if (point.x != -1 || point.y != -1) scale_point_dpi_aware( &point, i, j ); ok( wpl.ptMinPosition.x == point.x && wpl.ptMinPosition.y == point.y, - "%lu/%lu: wrong placement min pos %d,%d expected %d,%d\n", i, j, + "%Iu/%Iu: wrong placement min pos %ld,%ld expected %ld,%ld\n", i, j, wpl.ptMinPosition.x, wpl.ptMinPosition.y, point.x, point.y ); point = wpl_orig.ptMaxPosition; if (point.x != -1 || point.y != -1) scale_point_dpi_aware( &point, i, j ); ok( wpl.ptMaxPosition.x == point.x && wpl.ptMaxPosition.y == point.y, - "%lu/%lu: wrong placement max pos %d,%d expected %d,%d\n", i, j, + "%Iu/%Iu: wrong placement max pos %ld,%ld expected %ld,%ld\n", i, j, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, point.x, point.y ); expect = wpl_orig.rcNormalPosition; scale_rect_dpi_aware( &expect, i, j ); ok( EqualRect( &wpl.rcNormalPosition, &expect ), - "%lu/%lu: wrong placement rect %s expect %s\n", i, j, + "%Iu/%Iu: wrong placement rect %s expect %s\n", i, j, wine_dbgstr_rect(&wpl.rcNormalPosition), wine_dbgstr_rect(&expect)); /* test DC rect */ hdc = GetDC( hwnd ); GetClipBox( hdc, &rect ); SetRect( &expect, 0, 0, client.right - client.left, client.bottom - client.top ); - ok( EqualRect( &expect, &rect ), "%lu/%lu: wrong clip box %s expected %s\n", + ok( EqualRect( &expect, &rect ), "%Iu/%Iu: wrong clip box %s expected %s\n", i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); /* test DC resolution */ SetRect( &rect, 0, 0, GetDeviceCaps( hdc, HORZRES ), GetDeviceCaps( hdc, VERTRES )); expect = desktop; if (j == DPI_AWARENESS_UNAWARE) scale_rect_dpi( &expect, real_dpi, USER_DEFAULT_SCREEN_DPI ); - ok( EqualRect( &expect, &rect ), "%lu/%lu: wrong DC resolution %s expected %s\n", + ok( EqualRect( &expect, &rect ), "%Iu/%Iu: wrong DC resolution %s expected %s\n", i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); SetRect( &rect, 0, 0, GetDeviceCaps( hdc, DESKTOPHORZRES ), GetDeviceCaps( hdc, DESKTOPVERTRES )); - ok( EqualRect( &desktop, &rect ), "%lu/%lu: wrong desktop resolution %s expected %s\n", + todo_wine_if(monitor_count > 1) + ok( EqualRect( &desktop, &rect ), "%Iu/%Iu: wrong desktop resolution %s expected %s\n", i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&desktop) ); ReleaseDC( hwnd, hdc ); /* test DC win rect */ @@ -3344,7 +3630,7 @@ static void test_dpi_mapping(void) GetClipBox( hdc, &rect ); SetRect( &expect, 0, 0, 295, 303 ); todo_wine - ok( EqualRect( &expect, &rect ), "%lu/%lu: wrong clip box win DC %s expected %s\n", + ok( EqualRect( &expect, &rect ), "%Iu/%Iu: wrong clip box win DC %s expected %s\n", i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); ReleaseDC( hwnd, hdc ); /* test window invalidation */ @@ -3361,11 +3647,11 @@ static void test_dpi_mapping(void) GetUpdateRgn( hwnd, update, FALSE ); GetRgnBox( update, &rect ); SetRect( &expect, 20, 20, 25, 25 ); - ok( EqualRect( &expect, &rect ), "%lu/%lu/%lu: wrong update region %s expected %s\n", + ok( EqualRect( &expect, &rect ), "%Iu/%Iu/%Iu: wrong update region %s expected %s\n", i, j, k, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); GetUpdateRect( hwnd, &rect, FALSE ); scale_rect_dpi_aware( &expect, i, j ); - ok( EqualRect( &expect, &rect ), "%lu/%lu/%lu: wrong update rect %s expected %s\n", + ok( EqualRect( &expect, &rect ), "%Iu/%Iu/%Iu: wrong update rect %s expected %s\n", i, j, k, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); UpdateWindow( hwnd ); } @@ -3377,11 +3663,11 @@ static void test_dpi_mapping(void) pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~j ); GetRgnBox( update, &rect ); SetRect( &expect, 20, 20, 25, 25 ); - ok( EqualRect( &expect, &rect ), "%lu/%lu/%lu: wrong update region %s expected %s\n", + ok( EqualRect( &expect, &rect ), "%Iu/%Iu/%Iu: wrong update region %s expected %s\n", i, j, k, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); GetUpdateRect( hwnd, &rect, FALSE ); scale_rect_dpi_aware( &expect, i, j ); - ok( EqualRect( &expect, &rect ), "%lu/%lu/%lu: wrong update rect %s expected %s\n", + ok( EqualRect( &expect, &rect ), "%Iu/%Iu/%Iu: wrong update rect %s expected %s\n", i, j, k, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); UpdateWindow( hwnd ); } @@ -3396,11 +3682,11 @@ static void test_dpi_mapping(void) GetUpdateRgn( hwnd, update, TRUE ); GetRgnBox( update, &rect ); if (i == DPI_AWARENESS_UNAWARE) scale_rect_dpi( &expect, real_dpi, USER_DEFAULT_SCREEN_DPI ); - ok( EqualRect( &expect, &rect ), "%lu/%lu: wrong update region %s expected %s\n", + ok( EqualRect( &expect, &rect ), "%Iu/%Iu: wrong update region %s expected %s\n", i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); GetUpdateRect( hwnd, &rect, FALSE ); scale_rect_dpi_aware( &expect, i, j ); - ok( EqualRect( &expect, &rect ), "%lu/%lu: wrong update rect %s expected %s\n", + ok( EqualRect( &expect, &rect ), "%Iu/%Iu: wrong update rect %s expected %s\n", i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); UpdateWindow( hwnd ); DeleteObject( update ); @@ -3409,7 +3695,7 @@ static void test_dpi_mapping(void) point.x = LOWORD( units ); point.y = HIWORD( units ); scale_point_dpi_aware( &point, i, j ); - ok( LOWORD(ret) == point.x && HIWORD(ret) == point.y, "%lu/%lu: wrong units %d,%d / %d,%d\n", + ok( LOWORD(ret) == point.x && HIWORD(ret) == point.y, "%Iu/%Iu: wrong units %d,%d / %ld,%ld\n", i, j, LOWORD(ret), HIWORD(ret), point.x, point.y ); /* test window points mapping */ SetRect( &rect, 0, 0, 100, 100 ); @@ -3420,7 +3706,7 @@ static void test_dpi_mapping(void) scale_rect_dpi_aware( &expect, i, j ); expect.right = expect.left + 100; expect.bottom = expect.top + 100; - ok( EqualRect( &expect, &rect ), "%lu/%lu: wrong MapWindowPoints rect %s expected %s\n", + ok( EqualRect( &expect, &rect ), "%Iu/%Iu: wrong MapWindowPoints rect %s expected %s\n", i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); SetRect( &rect, 50, 60, 70, 80 ); scale_rect_dpi_aware( &rect, i, j ); @@ -3428,7 +3714,7 @@ static void test_dpi_mapping(void) OffsetRect( &expect, -rect.left, -rect.top ); SetRect( &rect, 40, 30, 60, 80 ); MapWindowPoints( hwnd, child, (POINT *)&rect, 2 ); - ok( EqualRect( &expect, &rect ), "%lu/%lu: wrong MapWindowPoints child rect %s expected %s\n", + ok( EqualRect( &expect, &rect ), "%Iu/%Iu: wrong MapWindowPoints child rect %s expected %s\n", i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); /* test logical<->physical coords mapping */ win_dpi = pGetDpiForWindow( hwnd ); @@ -3439,42 +3725,42 @@ static void test_dpi_mapping(void) point.x = 373; point.y = 377; ret = pLogicalToPhysicalPointForPerMonitorDPI( hwnd, &point ); - ok( ret, "%lu/%lu: LogicalToPhysicalPointForPerMonitorDPI failed\n", i, j ); + ok( ret, "%Iu/%Iu: LogicalToPhysicalPointForPerMonitorDPI failed\n", i, j ); ok( point.x == MulDiv( 373, real_dpi, win_dpi ) && point.y == MulDiv( 377, real_dpi, win_dpi ), - "%lu/%lu: wrong pos %d,%d dpi %u\n", i, j, point.x, point.y, win_dpi ); + "%Iu/%Iu: wrong pos %ld,%ld dpi %u\n", i, j, point.x, point.y, win_dpi ); point.x = 405; point.y = 423; ret = pPhysicalToLogicalPointForPerMonitorDPI( hwnd, &point ); - ok( ret, "%lu/%lu: PhysicalToLogicalPointForPerMonitorDPI failed\n", i, j ); + ok( ret, "%Iu/%Iu: PhysicalToLogicalPointForPerMonitorDPI failed\n", i, j ); ok( point.x == MulDiv( 405, win_dpi, real_dpi ) && point.y == MulDiv( 423, win_dpi, real_dpi ), - "%lu/%lu: wrong pos %d,%d dpi %u\n", i, j, point.x, point.y, win_dpi ); + "%Iu/%Iu: wrong pos %ld,%ld dpi %u\n", i, j, point.x, point.y, win_dpi ); /* point outside the window fails, but note that Windows (wrongly) checks against the * window rect transformed relative to the thread's awareness */ GetWindowRect( hwnd, &rect ); point.x = rect.left - 1; point.y = rect.top; ret = pLogicalToPhysicalPointForPerMonitorDPI( hwnd, &point ); - ok( !ret, "%lu/%lu: LogicalToPhysicalPointForPerMonitorDPI succeeded\n", i, j ); + ok( !ret, "%Iu/%Iu: LogicalToPhysicalPointForPerMonitorDPI succeeded\n", i, j ); point.x++; point.y--; ret = pLogicalToPhysicalPointForPerMonitorDPI( hwnd, &point ); - ok( !ret, "%lu/%lu: LogicalToPhysicalPointForPerMonitorDPI succeeded\n", i, j ); + ok( !ret, "%Iu/%Iu: LogicalToPhysicalPointForPerMonitorDPI succeeded\n", i, j ); point.y++; ret = pLogicalToPhysicalPointForPerMonitorDPI( hwnd, &point ); - ok( ret, "%lu/%lu: LogicalToPhysicalPointForPerMonitorDPI failed\n", i, j ); + ok( ret, "%Iu/%Iu: LogicalToPhysicalPointForPerMonitorDPI failed\n", i, j ); point.x = rect.right; point.y = rect.bottom + 1; ret = pLogicalToPhysicalPointForPerMonitorDPI( hwnd, &point ); - ok( !ret, "%lu/%lu: LogicalToPhysicalPointForPerMonitorDPI succeeded\n", i, j ); + ok( !ret, "%Iu/%Iu: LogicalToPhysicalPointForPerMonitorDPI succeeded\n", i, j ); point.x++; point.y--; ret = pLogicalToPhysicalPointForPerMonitorDPI( hwnd, &point ); - ok( !ret, "%lu/%lu: LogicalToPhysicalPointForPerMonitorDPI succeeded\n", i, j ); + ok( !ret, "%Iu/%Iu: LogicalToPhysicalPointForPerMonitorDPI succeeded\n", i, j ); point.x--; ret = pLogicalToPhysicalPointForPerMonitorDPI( hwnd, &point ); - ok( ret, "%lu/%lu: LogicalToPhysicalPointForPerMonitorDPI failed\n", i, j ); + ok( ret, "%Iu/%Iu: LogicalToPhysicalPointForPerMonitorDPI failed\n", i, j ); /* get physical window rect */ pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ); GetWindowRect( hwnd, &rect ); @@ -3482,25 +3768,25 @@ static void test_dpi_mapping(void) point.x = rect.left - 1; point.y = rect.top; ret = pPhysicalToLogicalPointForPerMonitorDPI( hwnd, &point ); - ok( !ret, "%lu/%lu: PhysicalToLogicalPointForPerMonitorDPI succeeded\n", i, j ); + ok( !ret, "%Iu/%Iu: PhysicalToLogicalPointForPerMonitorDPI succeeded\n", i, j ); point.x++; point.y--; ret = pPhysicalToLogicalPointForPerMonitorDPI( hwnd, &point ); - ok( !ret, "%lu/%lu: PhysicalToLogicalPointForPerMonitorDPI succeeded\n", i, j ); + ok( !ret, "%Iu/%Iu: PhysicalToLogicalPointForPerMonitorDPI succeeded\n", i, j ); point.y++; ret = pPhysicalToLogicalPointForPerMonitorDPI( hwnd, &point ); - ok( ret, "%lu/%lu: PhysicalToLogicalPointForPerMonitorDPI failed\n", i, j ); + ok( ret, "%Iu/%Iu: PhysicalToLogicalPointForPerMonitorDPI failed\n", i, j ); point.x = rect.right; point.y = rect.bottom + 1; ret = pPhysicalToLogicalPointForPerMonitorDPI( hwnd, &point ); - ok( !ret, "%lu/%lu: PhysicalToLogicalPointForPerMonitorDPI succeeded\n", i, j ); + ok( !ret, "%Iu/%Iu: PhysicalToLogicalPointForPerMonitorDPI succeeded\n", i, j ); point.x++; point.y--; ret = pPhysicalToLogicalPointForPerMonitorDPI( hwnd, &point ); - ok( !ret, "%lu/%lu: PhysicalToLogicalPointForPerMonitorDPI succeeded\n", i, j ); + ok( !ret, "%Iu/%Iu: PhysicalToLogicalPointForPerMonitorDPI succeeded\n", i, j ); point.x--; ret = pPhysicalToLogicalPointForPerMonitorDPI( hwnd, &point ); - ok( ret, "%lu/%lu: PhysicalToLogicalPointForPerMonitorDPI failed\n", i, j ); + ok( ret, "%Iu/%Iu: PhysicalToLogicalPointForPerMonitorDPI failed\n", i, j ); } DestroyWindow( hwnd ); } @@ -3529,25 +3815,488 @@ static void test_dpi_aware(void) test_metrics_for_dpi( 192 ); } +static void test_SetProcessDpiAwarenessContext( ULONG arg ) +{ + DPI_AWARENESS_CONTEXT contexts[] = + { + (DPI_AWARENESS_CONTEXT)0x6010, + (DPI_AWARENESS_CONTEXT)0x40006010, + (DPI_AWARENESS_CONTEXT)((UINT_PTR)0x11 | (real_dpi << 8)), + (DPI_AWARENESS_CONTEXT)0x12, + (DPI_AWARENESS_CONTEXT)0x22, + }; + DPI_AWARENESS_CONTEXT context, ctx, old_ctx, expect_ctx; + UINT ret, i; + + /* 0x11 is system aware DPI and only works with the current system DPI */ + if (arg == 0x11) context = contexts[2]; + else context = LongToHandle( arg ) /* sign-extend */; + + if (context == DPI_AWARENESS_CONTEXT_UNAWARE) expect_ctx = contexts[0]; + else if (context == DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED) expect_ctx = contexts[1]; + else if (context == DPI_AWARENESS_CONTEXT_SYSTEM_AWARE) expect_ctx = contexts[2]; + else if (context == DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE) expect_ctx = contexts[3]; + else if (context == DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) expect_ctx = contexts[4]; + else if ((arg & 0xff000000) == 0x80000000) expect_ctx = ULongToHandle( arg ) /* no sign-extend */; + else expect_ctx = context; + + winetest_push_context( "%#lx", arg ); + + ctx = pGetThreadDpiAwarenessContext(); + ok( ctx == (DPI_AWARENESS_CONTEXT)0x6010, "got %p\n", ctx ); + + SetLastError( 0xdeadbeef ); + ret = pSetProcessDpiAwarenessContext( 0 ); + ok( !ret, "SetProcessDpiAwarenessContext succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got %#lx\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = pSetProcessDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x11 ); + ok( !ret, "SetProcessDpiAwarenessContext succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_ACCESS_DENIED, "got %#lx\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = pSetProcessDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x21 ); + ok( !ret, "SetProcessDpiAwarenessContext succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got %#lx\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = pSetProcessDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x32 ); + ok( !ret, "SetProcessDpiAwarenessContext succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got %#lx\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = pSetProcessDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x6012 ); + ok( !ret, "SetProcessDpiAwarenessContext succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got %#lx\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = pSetProcessDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x6022 ); + ok( !ret, "SetProcessDpiAwarenessContext succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got %#lx\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = pSetProcessDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x40006011 ); + ok( !ret, "SetProcessDpiAwarenessContext succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got %#lx\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = pSetProcessDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x40000012 ); + ok( !ret, "SetProcessDpiAwarenessContext succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got %#lx\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = pSetProcessDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x7810 ); + ok( !ret, "SetProcessDpiAwarenessContext succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got %#lx\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = pSetProcessDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x1ff11 ); + ok( !ret, "SetProcessDpiAwarenessContext succeeded\n" ); + todo_wine ok( GetLastError() == ERROR_ACCESS_DENIED, "got %#lx\n", GetLastError() ); + ctx = pGetThreadDpiAwarenessContext(); + ok( ctx == (DPI_AWARENESS_CONTEXT)0x6010, "got %p\n", ctx ); + + SetLastError( 0xdeadbeef ); + ret = pSetProcessDpiAwarenessContext( context ); + ok( ret, "SetProcessDpiAwarenessContext failed, error %lu\n", GetLastError() ); + ok( GetLastError() == 0xdeadbeef, "got %#lx\n", GetLastError() ); + ctx = pGetThreadDpiAwarenessContext(); + ok( ctx == expect_ctx, "got %p\n", ctx ); + + for (i = 0; i < ARRAY_SIZE(contexts); i++) + { + SetLastError( 0xdeadbeef ); + ret = pSetProcessDpiAwarenessContext( contexts[i] ); + ok( !ret, "SetProcessDpiAwarenessContext succeeded\n" ); + ok( GetLastError() == ERROR_ACCESS_DENIED, "got %#lx\n", GetLastError() ); + ctx = pGetThreadDpiAwarenessContext(); + ok( ctx == expect_ctx, "got %p\n", ctx ); + } + + /* thread DPI context overrides process DPI context */ + ctx = pGetThreadDpiAwarenessContext(); + ok( ctx == expect_ctx, "got %p\n", ctx ); + old_ctx = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x12 ); + ok( old_ctx == (DPI_AWARENESS_CONTEXT)ULongToHandle( 0x80000000 | (UINT_PTR)expect_ctx ), "got %p\n", old_ctx ); + ctx = pGetThreadDpiAwarenessContext(); + ok( ctx == (DPI_AWARENESS_CONTEXT)0x12, "got %p\n", ctx ); + old_ctx = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x22 ); + ok( old_ctx == ctx, "got %p\n", old_ctx ); + ctx = pGetThreadDpiAwarenessContext(); + ok( ctx == (DPI_AWARENESS_CONTEXT)0x22, "got %p\n", ctx ); + + /* thread DPI context can be reset to process DPI context with 0x80000000, but needs to be valid */ + SetLastError( 0xdeadbeef ); + old_ctx = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x80000000 ); + ok( !old_ctx, "SetThreadDpiAwarenessContext succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got %#lx\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + old_ctx = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x80000010 ); + ok( !old_ctx, "SetThreadDpiAwarenessContext succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got %#lx\n", GetLastError() ); + + old_ctx = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x80006010 ); + ok( old_ctx == ctx, "got %p\n", old_ctx ); + ctx = pGetThreadDpiAwarenessContext(); + ok( ctx == expect_ctx, "got %p\n", ctx ); + old_ctx = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)((UINT_PTR)0x80000011 | (real_dpi << 8)) ); + ok( old_ctx == ULongToHandle( 0x80000000 | (UINT_PTR)expect_ctx ), "got %p\n", old_ctx ); + ctx = pGetThreadDpiAwarenessContext(); + ok( ctx == expect_ctx, "got %p\n", ctx ); + old_ctx = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x80000012 ); + ok( old_ctx == ULongToHandle( 0x80000000 | (UINT_PTR)expect_ctx ), "got %p\n", old_ctx ); + ctx = pGetThreadDpiAwarenessContext(); + ok( ctx == expect_ctx, "got %p\n", ctx ); + old_ctx = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x80000022 ); + ok( old_ctx == ULongToHandle( 0x80000000 | (UINT_PTR)expect_ctx ), "got %p\n", old_ctx ); + ctx = pGetThreadDpiAwarenessContext(); + ok( ctx == expect_ctx, "got %p\n", ctx ); + + winetest_pop_context(); +} + +static void test_SetThreadDpiAwarenessContext(void) +{ + DPI_AWARENESS_CONTEXT ctx, old_ctx; + + if (!pSetThreadDpiAwarenessContext || !pGetThreadDpiAwarenessContext) + { + win_skip( "(Set|Get)ThreadDpiAwarenessContext missing, skipping tests\n" ); + return; + } + + ctx = pGetThreadDpiAwarenessContext(); + ok( ctx == (DPI_AWARENESS_CONTEXT)0x6010, "got %p\n", ctx ); + + old_ctx = pSetThreadDpiAwarenessContext( 0 ); + ok( !old_ctx, "SetThreadDpiAwarenessContext succeeded\n" ); + old_ctx = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x11 ); + ok( !old_ctx, "SetThreadDpiAwarenessContext succeeded\n" ); + + old_ctx = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x12 ); + ok( old_ctx == (DPI_AWARENESS_CONTEXT)0x80006010, "got %p\n", old_ctx ); + ctx = pGetThreadDpiAwarenessContext(); + ok( ctx == (DPI_AWARENESS_CONTEXT)0x12, "got %p\n", ctx ); + old_ctx = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x22 ); + ok( old_ctx == ctx, "got %p\n", old_ctx ); + ctx = pGetThreadDpiAwarenessContext(); + ok( ctx == (DPI_AWARENESS_CONTEXT)0x22, "got %p\n", ctx ); + + old_ctx = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x7810 ); + ok( !old_ctx, "SetThreadDpiAwarenessContext succeeded\n" ); + old_ctx = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x6010 ); + ok( old_ctx == ctx, "got %p\n", old_ctx ); + ctx = pGetThreadDpiAwarenessContext(); + ok( ctx == (DPI_AWARENESS_CONTEXT)0x6010, "got %p\n", ctx ); + + old_ctx = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)((UINT_PTR)0x11 | ((real_dpi + 1) << 8)) ); + ok( !old_ctx, "SetThreadDpiAwarenessContext succeeded\n" ); + old_ctx = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)((UINT_PTR)0x11 | (real_dpi << 8)) ); + ok( old_ctx == ctx, "got %p\n", old_ctx ); + ctx = pGetThreadDpiAwarenessContext(); + ok( ctx == (DPI_AWARENESS_CONTEXT)((UINT_PTR)0x11 | (real_dpi << 8)), "got %p\n", ctx ); + + old_ctx = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x40006010 ); + ok( old_ctx == ctx, "got %p\n", old_ctx ); + ctx = pGetThreadDpiAwarenessContext(); + ok( ctx == (DPI_AWARENESS_CONTEXT)0x40006010, "got %p\n", ctx ); + + old_ctx = pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_UNAWARE ); + ok( old_ctx == ctx, "got %p\n", old_ctx ); + ctx = pGetThreadDpiAwarenessContext(); + ok( ctx == (DPI_AWARENESS_CONTEXT)0x6010, "got %p\n", ctx ); + old_ctx = pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ); + ok( old_ctx == ctx, "got %p\n", old_ctx ); + ctx = pGetThreadDpiAwarenessContext(); + ok( ctx == (DPI_AWARENESS_CONTEXT)((UINT_PTR)0x11 | (real_dpi << 8)), "got %p\n", ctx ); + old_ctx = pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ); + ok( old_ctx == ctx, "got %p\n", old_ctx ); + ctx = pGetThreadDpiAwarenessContext(); + ok( ctx == (DPI_AWARENESS_CONTEXT)0x12, "got %p\n", ctx ); + old_ctx = pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ); + ok( old_ctx == ctx, "got %p\n", old_ctx ); + ctx = pGetThreadDpiAwarenessContext(); + ok( ctx == (DPI_AWARENESS_CONTEXT)0x22, "got %p\n", ctx ); + old_ctx = pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED ); + ok( old_ctx == ctx, "got %p\n", old_ctx ); + ctx = pGetThreadDpiAwarenessContext(); + ok( ctx == (DPI_AWARENESS_CONTEXT)0x40006010, "got %p\n", ctx ); + + /* restore process-wide DPI awareness context */ + ctx = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x80006010 ); + ok( ctx == (DPI_AWARENESS_CONTEXT)0x40006010, "got %p\n", ctx ); +} + +static void test_IsValidDpiAwarenessContext(void) +{ + UINT_PTR i; + BOOL ret; + + if (!pIsValidDpiAwarenessContext) + { + win_skip( "IsValidDpiAwarenessContext missing, skipping tests\n" ); + return; + } + + ret = pIsValidDpiAwarenessContext( 0 ); + ok( !ret, "IsValidDpiAwarenessContext returned %u\n", ret ); + + /* commonly seen dpi awareness contexts */ + ret = pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x12 ); + ok( ret, "IsValidDpiAwarenessContext returned %u\n", ret ); + ret = pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x22 ); + ok( ret, "IsValidDpiAwarenessContext returned %u\n", ret ); + ret = pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x6010 ); + ok( ret, "IsValidDpiAwarenessContext returned %u\n", ret ); + ret = pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x6011 ); + ok( ret, "IsValidDpiAwarenessContext returned %u\n", ret ); + ret = pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x40006010 ); + ok( ret, "IsValidDpiAwarenessContext returned %u\n", ret ); + + ret = pIsValidDpiAwarenessContext( DPI_AWARENESS_CONTEXT_UNAWARE ); + ok( ret, "IsValidDpiAwarenessContext returned %u\n", ret ); + ret = pIsValidDpiAwarenessContext( DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ); + ok( ret, "IsValidDpiAwarenessContext returned %u\n", ret ); + ret = pIsValidDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ); + ok( ret, "IsValidDpiAwarenessContext returned %u\n", ret ); + ret = pIsValidDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ); + ok( ret, "IsValidDpiAwarenessContext returned %u\n", ret ); + ret = pIsValidDpiAwarenessContext( DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED ); + ok( ret, "IsValidDpiAwarenessContext returned %u\n", ret ); + ret = pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)-6 ); + ok( !ret, "IsValidDpiAwarenessContext returned %u\n", ret ); + + for (i = 1; i < 0xff; i++) + { + ret = pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)i ); + if (i == 0x12 || i == 0x22) ok( ret, "IsValidDpiAwarenessContext %#Ix failed\n", i ); + /* 0x0011 is rejected on win11 */ + else if (i != 0x11) ok( !ret, "IsValidDpiAwarenessContext %#Ix succeeded\n", i ); + + ret = pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)(i | 0x6000) ); + if (i == 0x10 || i == 0x11) ok( ret, "IsValidDpiAwarenessContext %#Ix failed\n", (i | 0x6000) ); + /* 0x6013 is accepted on win11 */ + else if (i != 0x13) ok( !ret, "IsValidDpiAwarenessContext %#Ix succeeded\n", (i | 0x6000) ); + + ret = pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)((i << 8) | 0x10) ); + if (i == 0x60) ok( ret, "IsValidDpiAwarenessContext %#Ix failed\n", ((i << 8) | 0x10) ); + else ok( !ret, "IsValidDpiAwarenessContext %#Ix succeeded\n", ((i << 8) | 0x10) ); + ret = pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)((i << 8) | 0x11) ); + if (i != 0xff) ok( ret, "IsValidDpiAwarenessContext %#Ix failed\n", ((i << 8) | 0x11) ); + else ok( !ret, "IsValidDpiAwarenessContext %#Ix succeeded\n", ((i << 8) | 0x11) ); + ret = pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)((i << 8) | 0x12) ); + ok( !ret, "IsValidDpiAwarenessContext %#Ix succeeded\n", ((i << 8) | 0x12) ); + ret = pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)((i << 8) | 0x22) ); + ok( !ret, "IsValidDpiAwarenessContext %#Ix succeeded\n", ((i << 8) | 0x22) ); + + ret = pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)((i << 16) | 0x6010) ); + ok( !ret, "IsValidDpiAwarenessContext %#Ix succeeded\n", ((i << 16) | 0x6010) ); + ret = pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)((i << 16) | (real_dpi << 8) | 0x11) ); + if (i == 1) ok( ret, "IsValidDpiAwarenessContext %#Ix succeeded\n", ((i << 16) | (real_dpi << 8) | 0x11) ); + else ok( !ret, "IsValidDpiAwarenessContext %#Ix succeeded\n", ((i << 16) | (real_dpi << 8) | 0x11) ); + ret = pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)((i << 16) | 0x12) ); + ok( !ret, "IsValidDpiAwarenessContext %#Ix succeeded\n", ((i << 16) | 0x12) ); + ret = pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)((i << 16) | 0x22) ); + ok( !ret, "IsValidDpiAwarenessContext %#Ix succeeded\n", ((i << 16) | 0x22) ); + + ret = pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)((i << 24) | 0x6010) ); + if (i & 0x1f) ok( !ret, "IsValidDpiAwarenessContext %#Ix succeeded\n", ((i << 24) | 0x6010) ); + /* 0x20000000 is rejected on win11 */ + else if (!(i & 0x20)) ok( ret, "IsValidDpiAwarenessContext %#Ix failed\n", ((i << 24) | 0x6010) ); + ret = pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)((i << 24) | (real_dpi << 8) | 0x11) ); + if (i & 0x5f) ok( !ret, "IsValidDpiAwarenessContext %#Ix succeeded\n", ((i << 24) | (real_dpi << 8) | 0x11) ); + /* 0x20000000 is rejected on win11 */ + else if (!(i & 0x20)) ok( ret, "IsValidDpiAwarenessContext %#Ix failed\n", ((i << 24) | (real_dpi << 8) | 0x11) ); + ret = pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)((i << 24) | 0x12) ); + if (i & 0x5f) ok( !ret, "IsValidDpiAwarenessContext %#Ix succeeded\n", ((i << 24) | 0x12) ); + /* 0x20000000 is rejected on win11 */ + else if (!(i & 0x20)) ok( ret, "IsValidDpiAwarenessContext %#Ix failed\n", ((i << 24) | 0x12) ); + ret = pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)((i << 24) | 0x22) ); + if (i & 0x5f) ok( !ret, "IsValidDpiAwarenessContext %#Ix succeeded\n", ((i << 24) | 0x22) ); + /* 0x20000000 is rejected on win11 */ + else if (!(i & 0x20)) ok( ret, "IsValidDpiAwarenessContext %#Ix failed\n", ((i << 24) | 0x22) ); + } +} + +static void test_GetDpiFromDpiAwarenessContext(void) +{ + UINT ret; + + if (!pGetDpiFromDpiAwarenessContext) + { + win_skip( "GetDpiFromDpiAwarenessContext missing, skipping tests\n" ); + return; + } + + ret = pGetDpiFromDpiAwarenessContext( 0 ); + ok( !ret, "GetDpiFromDpiAwarenessContext returned %u\n", ret ); + + ret = pGetDpiFromDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x11 ); + ok( ret == 0, "GetDpiFromDpiAwarenessContext returned %u\n", ret ); + ret = pGetDpiFromDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x12 ); + ok( ret == 0, "GetDpiFromDpiAwarenessContext returned %u\n", ret ); + ret = pGetDpiFromDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x22 ); + ok( ret == 0, "GetDpiFromDpiAwarenessContext returned %u\n", ret ); + ret = pGetDpiFromDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x6010 ); + ok( ret == 96, "GetDpiFromDpiAwarenessContext returned %u\n", ret ); + ret = pGetDpiFromDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x6011 ); + ok( ret == 96, "GetDpiFromDpiAwarenessContext returned %u\n", ret ); + ret = pGetDpiFromDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x6111 ); + ok( ret == 97, "GetDpiFromDpiAwarenessContext returned %u\n", ret ); + ret = pGetDpiFromDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x7811 ); + ok( ret == 120, "GetDpiFromDpiAwarenessContext returned %u\n", ret ); + ret = pGetDpiFromDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x10011 ); + ok( ret == 256, "GetDpiFromDpiAwarenessContext returned %u\n", ret ); + ret = pGetDpiFromDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x40006010 ); + ok( ret == 96, "GetDpiFromDpiAwarenessContext returned %u\n", ret ); + + ret = pGetDpiFromDpiAwarenessContext( DPI_AWARENESS_CONTEXT_UNAWARE ); + ok( ret == 96, "GetDpiFromDpiAwarenessContext returned %u\n", ret ); + ret = pGetDpiFromDpiAwarenessContext( DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ); + ok( ret == real_dpi, "GetDpiFromDpiAwarenessContext returned %u\n", ret ); + ret = pGetDpiFromDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ); + ok( ret == 0, "GetDpiFromDpiAwarenessContext returned %u\n", ret ); + ret = pGetDpiFromDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ); + ok( ret == 0, "GetDpiFromDpiAwarenessContext returned %u\n", ret ); + ret = pGetDpiFromDpiAwarenessContext( DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED ); + ok( ret == 96, "GetDpiFromDpiAwarenessContext returned %u\n", ret ); +} + +static void test_AreDpiAwarenessContextsEqual(void) +{ + BOOL ret; + + if (!pAreDpiAwarenessContextsEqual) + { + win_skip( "AreDpiAwarenessContextsEqual missing, skipping tests\n" ); + return; + } + + ret = pAreDpiAwarenessContextsEqual( 0, 0 ); + ok( !ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + + ret = pAreDpiAwarenessContextsEqual( (DPI_AWARENESS_CONTEXT)0x12, (DPI_AWARENESS_CONTEXT)0x12 ); + ok( ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( (DPI_AWARENESS_CONTEXT)0x22, (DPI_AWARENESS_CONTEXT)0x22 ); + ok( ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( (DPI_AWARENESS_CONTEXT)0x6010, (DPI_AWARENESS_CONTEXT)0x6010 ); + ok( ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( (DPI_AWARENESS_CONTEXT)0x6011, (DPI_AWARENESS_CONTEXT)0x6011 ); + ok( ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( (DPI_AWARENESS_CONTEXT)0x6111, (DPI_AWARENESS_CONTEXT)0x6111 ); + ok( ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( (DPI_AWARENESS_CONTEXT)0x7811, (DPI_AWARENESS_CONTEXT)0x7811 ); + ok( ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( (DPI_AWARENESS_CONTEXT)0x40006010, (DPI_AWARENESS_CONTEXT)0x40006010 ); + ok( ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + + ret = pAreDpiAwarenessContextsEqual( DPI_AWARENESS_CONTEXT_UNAWARE, DPI_AWARENESS_CONTEXT_UNAWARE ); + ok( ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( DPI_AWARENESS_CONTEXT_SYSTEM_AWARE, DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ); + ok( ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ); + ok( ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ); + ok( ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED, DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED ); + ok( ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + + ret = pAreDpiAwarenessContextsEqual( DPI_AWARENESS_CONTEXT_UNAWARE, (DPI_AWARENESS_CONTEXT)0x6010 ); + ok( ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( (DPI_AWARENESS_CONTEXT)0x6010, DPI_AWARENESS_CONTEXT_UNAWARE ); + ok( ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( DPI_AWARENESS_CONTEXT_UNAWARE, (DPI_AWARENESS_CONTEXT)0x10 ); + ok( !ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + + ret = pAreDpiAwarenessContextsEqual( DPI_AWARENESS_CONTEXT_SYSTEM_AWARE, (DPI_AWARENESS_CONTEXT)((UINT_PTR)0x11 | (real_dpi << 8)) ); + ok( ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( (DPI_AWARENESS_CONTEXT)((UINT_PTR)0x11 | (real_dpi << 8)), DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ); + ok( ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( DPI_AWARENESS_CONTEXT_SYSTEM_AWARE, (DPI_AWARENESS_CONTEXT)0x11 ); + ok( !ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + + ret = pAreDpiAwarenessContextsEqual( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE, (DPI_AWARENESS_CONTEXT)0x12 ); + ok( ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( (DPI_AWARENESS_CONTEXT)0x12, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ); + ok( ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2, (DPI_AWARENESS_CONTEXT)0x22 ); + ok( ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( (DPI_AWARENESS_CONTEXT)0x22, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ); + ok( ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED, (DPI_AWARENESS_CONTEXT)0x40006010 ); + ok( ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( (DPI_AWARENESS_CONTEXT)0x40006010, DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED ); + ok( ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED, (DPI_AWARENESS_CONTEXT)0x40000010 ); + ok( !ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + + ret = pAreDpiAwarenessContextsEqual( (DPI_AWARENESS_CONTEXT)0x10, (DPI_AWARENESS_CONTEXT)0x6010 ); + ok( !ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( (DPI_AWARENESS_CONTEXT)0x11, (DPI_AWARENESS_CONTEXT)0x6011 ); + ok( !ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( (DPI_AWARENESS_CONTEXT)0x12, (DPI_AWARENESS_CONTEXT)0x6012 ); + ok( !ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( (DPI_AWARENESS_CONTEXT)0x22, (DPI_AWARENESS_CONTEXT)0x6022 ); + ok( !ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( (DPI_AWARENESS_CONTEXT)0x20006010, (DPI_AWARENESS_CONTEXT)0x6010 ); + ok( !ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( (DPI_AWARENESS_CONTEXT)0x40006010, (DPI_AWARENESS_CONTEXT)0x6010 ); + ok( !ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); + ret = pAreDpiAwarenessContextsEqual( (DPI_AWARENESS_CONTEXT)0x80006010, (DPI_AWARENESS_CONTEXT)0x6010 ); + ok( ret, "AreDpiAwarenessContextsEqual returned %u\n", ret ); +} + +static void test_GetAwarenessFromDpiAwarenessContext(void) +{ + DPI_AWARENESS ret; + + if (!pGetAwarenessFromDpiAwarenessContext) + { + win_skip( "GetAwarenessFromDpiAwarenessContext missing, skipping tests\n" ); + return; + } + + ret = pGetAwarenessFromDpiAwarenessContext( 0 ); + ok( ret == -1, "got %u\n", ret ); + + ret = pGetAwarenessFromDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x12 ); + ok( ret == DPI_AWARENESS_PER_MONITOR_AWARE, "got %u\n", ret ); + ret = pGetAwarenessFromDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x22 ); + ok( ret == DPI_AWARENESS_PER_MONITOR_AWARE, "got %u\n", ret ); + ret = pGetAwarenessFromDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x6010 ); + ok( ret == DPI_AWARENESS_UNAWARE, "got %u\n", ret ); + ret = pGetAwarenessFromDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x6011 ); + ok( ret == DPI_AWARENESS_SYSTEM_AWARE, "got %u\n", ret ); + ret = pGetAwarenessFromDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x6111 ); + ok( ret == DPI_AWARENESS_SYSTEM_AWARE, "got %u\n", ret ); + ret = pGetAwarenessFromDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x7811 ); + ok( ret == DPI_AWARENESS_SYSTEM_AWARE, "got %u\n", ret ); + ret = pGetAwarenessFromDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x10011 ); + ok( ret == DPI_AWARENESS_SYSTEM_AWARE, "got %u\n", ret ); + ret = pGetAwarenessFromDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x40006010 ); + ok( ret == DPI_AWARENESS_UNAWARE, "got %u\n", ret ); + ret = pGetAwarenessFromDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x80000012 ); + ok( ret == DPI_AWARENESS_PER_MONITOR_AWARE, "got %u\n", ret ); + ret = pGetAwarenessFromDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x80006010 ); + ok( ret == DPI_AWARENESS_UNAWARE, "got %u\n", ret ); + + ret = pGetAwarenessFromDpiAwarenessContext( DPI_AWARENESS_CONTEXT_UNAWARE ); + ok( ret == DPI_AWARENESS_UNAWARE, "got %u\n", ret ); + ret = pGetAwarenessFromDpiAwarenessContext( DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ); + ok( ret == DPI_AWARENESS_SYSTEM_AWARE, "got %u\n", ret ); + ret = pGetAwarenessFromDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ); + ok( ret == DPI_AWARENESS_PER_MONITOR_AWARE, "got %u\n", ret ); + ret = pGetAwarenessFromDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ); + ok( ret == DPI_AWARENESS_PER_MONITOR_AWARE, "got %u\n", ret ); + ret = pGetAwarenessFromDpiAwarenessContext( DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED ); + ok( ret == DPI_AWARENESS_UNAWARE, "got %u\n", ret ); +} + static void test_dpi_context(void) { DPI_AWARENESS awareness; DPI_AWARENESS_CONTEXT context; - ULONG_PTR i, flags; BOOL ret; UINT dpi; HDC hdc = GetDC( 0 ); context = pGetThreadDpiAwarenessContext(); - /* Windows 10 >= 1709 adds extra 0x6000 flags */ - flags = (ULONG_PTR)context & 0x6000; - todo_wine - ok( context == (DPI_AWARENESS_CONTEXT)(0x10 | flags), "wrong context %p\n", context ); + ok( context == (DPI_AWARENESS_CONTEXT)0x6010, "wrong context %p\n", context ); awareness = pGetAwarenessFromDpiAwarenessContext( context ); - todo_wine - ok( awareness == DPI_AWARENESS_UNAWARE, "wrong awareness %u\n", awareness ); - todo_wine - ok( !pIsProcessDPIAware(), "already aware\n" ); + ok( awareness == DPI_AWARENESS_UNAWARE, "wrong awareness %u\n", awareness ); + ok( !pIsProcessDPIAware(), "already aware\n" ); dpi = pGetDpiForSystem(); todo_wine_if (real_dpi != USER_DEFAULT_SCREEN_DPI) ok( dpi == USER_DEFAULT_SCREEN_DPI, "wrong dpi %u\n", dpi ); @@ -3557,64 +4306,64 @@ static void test_dpi_context(void) SetLastError( 0xdeadbeef ); ret = pSetProcessDpiAwarenessContext( NULL ); ok( !ret, "got %d\n", ret ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); ret = pSetProcessDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)-6 ); ok( !ret, "got %d\n", ret ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); ret = pSetProcessDpiAwarenessContext( DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ); - todo_wine ok( ret, "got %d\n", ret ); ok( pIsProcessDPIAware(), "not aware\n" ); real_dpi = pGetDpiForSystem(); SetLastError( 0xdeadbeef ); ret = pSetProcessDpiAwarenessContext( DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ); ok( !ret, "got %d\n", ret ); - ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); ret = pSetProcessDpiAwarenessContext( DPI_AWARENESS_CONTEXT_UNAWARE ); ok( !ret, "got %d\n", ret ); - ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %lu\n", GetLastError() ); ret = pSetProcessDpiAwarenessInternal( DPI_AWARENESS_INVALID ); ok( !ret, "got %d\n", ret ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); ret = pSetProcessDpiAwarenessInternal( DPI_AWARENESS_UNAWARE ); ok( !ret, "got %d\n", ret ); - ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %lu\n", GetLastError() ); ret = pGetProcessDpiAwarenessInternal( 0, &awareness ); ok( ret, "got %d\n", ret ); - todo_wine ok( awareness == DPI_AWARENESS_SYSTEM_AWARE, "wrong value %d\n", awareness ); ret = pGetProcessDpiAwarenessInternal( GetCurrentProcess(), &awareness ); ok( ret, "got %d\n", ret ); - todo_wine ok( awareness == DPI_AWARENESS_SYSTEM_AWARE, "wrong value %d\n", awareness ); + SetLastError(0xdeadbeef); ret = pGetProcessDpiAwarenessInternal( (HANDLE)0xdeadbeef, &awareness ); - ok( ret, "got %d\n", ret ); - ok( awareness == DPI_AWARENESS_UNAWARE, "wrong value %d\n", awareness ); + todo_wine + ok( !ret || broken(ret) /* <= win10 1709 */, "got %d\n", ret ); + if (!ret) + { + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError() ); + ok( awareness == DPI_AWARENESS_INVALID, "wrong value %d\n", awareness ); + } + else ok( awareness == DPI_AWARENESS_UNAWARE, "wrong value %d\n", awareness ); ret = pIsProcessDPIAware(); ok(ret, "got %d\n", ret); context = pGetThreadDpiAwarenessContext(); - todo_wine - ok( context == (DPI_AWARENESS_CONTEXT)(0x11 | flags), "wrong context %p\n", context ); + ok( context == (DPI_AWARENESS_CONTEXT)0x6011, "wrong context %p\n", context ); awareness = pGetAwarenessFromDpiAwarenessContext( context ); - todo_wine ok( awareness == DPI_AWARENESS_SYSTEM_AWARE, "wrong awareness %u\n", awareness ); SetLastError( 0xdeadbeef ); context = pSetThreadDpiAwarenessContext( 0 ); ok( !context, "got %p\n", context ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); context = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)-6 ); ok( !context, "got %p\n", context ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); context = pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_UNAWARE ); - todo_wine - ok( context == (DPI_AWARENESS_CONTEXT)(0x80000011 | flags), "wrong context %p\n", context ); + ok( context == (DPI_AWARENESS_CONTEXT)0x80006011, "wrong context %p\n", context ); awareness = pGetAwarenessFromDpiAwarenessContext( context ); - todo_wine ok( awareness == DPI_AWARENESS_SYSTEM_AWARE, "wrong awareness %u\n", awareness ); dpi = pGetDpiForSystem(); ok( dpi == USER_DEFAULT_SCREEN_DPI, "wrong dpi %u\n", dpi ); @@ -3622,11 +4371,11 @@ static void test_dpi_context(void) ok( dpi == USER_DEFAULT_SCREEN_DPI, "wrong dpi %u\n", dpi ); ok( !pIsProcessDPIAware(), "still aware\n" ); context = pGetThreadDpiAwarenessContext(); - ok( context == (DPI_AWARENESS_CONTEXT)(0x10 | flags), "wrong context %p\n", context ); + ok( context == (DPI_AWARENESS_CONTEXT)0x6010, "wrong context %p\n", context ); awareness = pGetAwarenessFromDpiAwarenessContext( context ); ok( awareness == DPI_AWARENESS_UNAWARE, "wrong awareness %u\n", awareness ); context = pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ); - ok( context == (DPI_AWARENESS_CONTEXT)(0x10 | flags), "wrong context %p\n", context ); + ok( context == (DPI_AWARENESS_CONTEXT)0x6010, "wrong context %p\n", context ); awareness = pGetAwarenessFromDpiAwarenessContext( context ); ok( awareness == DPI_AWARENESS_UNAWARE, "wrong awareness %u\n", awareness ); dpi = pGetDpiForSystem(); @@ -3647,85 +4396,22 @@ static void test_dpi_context(void) ok( dpi == real_dpi, "wrong dpi %u\n", dpi ); ok( pIsProcessDPIAware(), "not aware\n" ); context = pGetThreadDpiAwarenessContext(); - ok( context == (DPI_AWARENESS_CONTEXT)(0x11 | flags), "wrong context %p\n", context ); - context = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)(0x80000010 | flags) ); - ok( context == (DPI_AWARENESS_CONTEXT)(0x11 | flags), "wrong context %p\n", context ); + ok( context == (DPI_AWARENESS_CONTEXT)0x6011, "wrong context %p\n", context ); + context = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x80006010 ); + ok( context == (DPI_AWARENESS_CONTEXT)0x6011, "wrong context %p\n", context ); context = pGetThreadDpiAwarenessContext(); - todo_wine - ok( context == (DPI_AWARENESS_CONTEXT)(0x11 | flags), "wrong context %p\n", context ); - context = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)(0x80000011 | flags) ); - todo_wine - ok( context == (DPI_AWARENESS_CONTEXT)(0x80000011 | flags), "wrong context %p\n", context ); + ok( context == (DPI_AWARENESS_CONTEXT)0x6011, "wrong context %p\n", context ); + context = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x80006011 ); + ok( context == (DPI_AWARENESS_CONTEXT)0x80006011, "wrong context %p\n", context ); context = pGetThreadDpiAwarenessContext(); - todo_wine - ok( context == (DPI_AWARENESS_CONTEXT)(0x11 | flags), "wrong context %p\n", context ); + ok( context == (DPI_AWARENESS_CONTEXT)0x6011, "wrong context %p\n", context ); context = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)0x12 ); - todo_wine - ok( context == (DPI_AWARENESS_CONTEXT)(0x80000011 | flags), "wrong context %p\n", context ); + ok( context == (DPI_AWARENESS_CONTEXT)0x80006011, "wrong context %p\n", context ); context = pSetThreadDpiAwarenessContext( context ); - ok( context == (DPI_AWARENESS_CONTEXT)(0x12), "wrong context %p\n", context ); + ok( context == (DPI_AWARENESS_CONTEXT)0x12, "wrong context %p\n", context ); context = pGetThreadDpiAwarenessContext(); - todo_wine - ok( context == (DPI_AWARENESS_CONTEXT)(0x11 | flags), "wrong context %p\n", context ); - for (i = 0; i < 0x100; i++) - { - awareness = pGetAwarenessFromDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)i ); - switch (i) - { - case 0x10: - case 0x11: - case 0x12: - ok( awareness == (i & ~0x10), "%lx: wrong value %u\n", i, awareness ); - ok( pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)i ), "%lx: not valid\n", i ); - break; - default: - ok( awareness == DPI_AWARENESS_INVALID, "%lx: wrong value %u\n", i, awareness ); - ok( !pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)i ), "%lx: valid\n", i ); - break; - } - awareness = pGetAwarenessFromDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)(i | 0x80000000) ); - switch (i) - { - case 0x10: - case 0x11: - case 0x12: - ok( awareness == (i & ~0x10), "%lx: wrong value %u\n", i | 0x80000000, awareness ); - ok( pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)(i | 0x80000000) ), - "%lx: not valid\n", i | 0x80000000 ); - break; - default: - ok( awareness == DPI_AWARENESS_INVALID, "%lx: wrong value %u\n", i | 0x80000000, awareness ); - ok( !pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)(i | 0x80000000) ), - "%lx: valid\n", i | 0x80000000 ); - break; - } - awareness = pGetAwarenessFromDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~i ); - switch (~i) - { - case (ULONG_PTR)DPI_AWARENESS_CONTEXT_UNAWARE: - case (ULONG_PTR)DPI_AWARENESS_CONTEXT_SYSTEM_AWARE: - case (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE: - ok( awareness == i, "%lx: wrong value %u\n", ~i, awareness ); - ok( pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~i ), "%lx: not valid\n", ~i ); - break; - case (ULONG_PTR)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2: - if (pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~i )) - ok( awareness == DPI_AWARENESS_PER_MONITOR_AWARE, "%lx: wrong value %u\n", ~i, awareness ); - else - ok( awareness == DPI_AWARENESS_INVALID, "%lx: wrong value %u\n", ~i, awareness ); - break; - case (ULONG_PTR)DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED: - if (pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~i )) - ok( awareness == DPI_AWARENESS_UNAWARE, "%lx: wrong value %u\n", ~i, awareness ); - else - ok( awareness == DPI_AWARENESS_INVALID, "%lx: wrong value %u\n", ~i, awareness ); - break; - default: - ok( awareness == DPI_AWARENESS_INVALID, "%lx: wrong value %u\n", ~i, awareness ); - ok( !pIsValidDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~i ), "%lx: valid\n", ~i ); - break; - } - } + ok( context == (DPI_AWARENESS_CONTEXT)0x6011, "wrong context %p\n", context ); + if (real_dpi != USER_DEFAULT_SCREEN_DPI) test_dpi_stock_objects( hdc ); ReleaseDC( 0, hdc ); } @@ -3742,7 +4428,7 @@ static LRESULT CALLBACK dpi_winproc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) pos = GetMessagePos(); pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ); pos2 = GetMessagePos(); - ok( pos == pos2, "wrong pos %08x / %08x\n", pos, pos2 ); + ok( pos == pos2, "wrong pos %08lx / %08lx\n", pos, pos2 ); pSetThreadDpiAwarenessContext( ctx2 ); return DefWindowProcA( hwnd, msg, wp, lp ); } @@ -3770,29 +4456,29 @@ static void test_dpi_window(void) ok( hwnd != 0, "failed to create window\n" ); context = pGetWindowDpiAwarenessContext( hwnd ); awareness = pGetAwarenessFromDpiAwarenessContext( context ); - ok( awareness == i, "%lu: wrong awareness %u\n", i, awareness ); + ok( awareness == i, "%Iu: wrong awareness %u\n", i, awareness ); dpi = pGetDpiForWindow( hwnd ); ok( dpi == (i == DPI_AWARENESS_UNAWARE ? USER_DEFAULT_SCREEN_DPI : real_dpi), - "%lu: got %u / %u\n", i, dpi, real_dpi ); + "%Iu: got %u / %u\n", i, dpi, real_dpi ); if (pGetDpiForMonitorInternal) { BOOL res; SetLastError( 0xdeadbeef ); res = pGetDpiForMonitorInternal( MonitorFromWindow( hwnd, 0 ), 0, &dpi, NULL ); ok( !res, "succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_ADDRESS, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_ADDRESS, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); res = pGetDpiForMonitorInternal( MonitorFromWindow( hwnd, 0 ), 3, &dpi, &dpi ); ok( !res, "succeeded\n" ); - ok( GetLastError() == ERROR_BAD_ARGUMENTS, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_BAD_ARGUMENTS, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); res = pGetDpiForMonitorInternal( MonitorFromWindow( hwnd, 0 ), 3, &dpi, NULL ); ok( !res, "succeeded\n" ); - ok( GetLastError() == ERROR_BAD_ARGUMENTS, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_BAD_ARGUMENTS, "wrong error %lu\n", GetLastError() ); res = pGetDpiForMonitorInternal( MonitorFromWindow( hwnd, 0 ), 0, &dpi, &dpi ); - ok( res, "failed err %u\n", GetLastError() ); + ok( res, "failed err %lu\n", GetLastError() ); ok( dpi == (i == DPI_AWARENESS_UNAWARE ? USER_DEFAULT_SCREEN_DPI : real_dpi), - "%lu: got %u / %u\n", i, dpi, real_dpi ); + "%Iu: got %u / %u\n", i, dpi, real_dpi ); } msg.hwnd = hwnd; for (j = DPI_AWARENESS_UNAWARE; j <= DPI_AWARENESS_PER_MONITOR_AWARE; j++) @@ -3805,36 +4491,36 @@ static void test_dpi_window(void) WS_CHILD, 0, 0, 100, 100, hwnd, 0, GetModuleHandleA(0), NULL ); context = pGetWindowDpiAwarenessContext( child ); awareness = pGetAwarenessFromDpiAwarenessContext( context ); - ok( awareness == i, "%lu/%lu: wrong awareness %u\n", i, j, awareness ); + ok( awareness == i, "%Iu/%Iu: wrong awareness %u\n", i, j, awareness ); dpi = pGetDpiForWindow( child ); ok( dpi == (i == DPI_AWARENESS_UNAWARE ? USER_DEFAULT_SCREEN_DPI : real_dpi), - "%lu/%lu: got %u / %u\n", i, j, dpi, real_dpi ); + "%Iu/%Iu: got %u / %u\n", i, j, dpi, real_dpi ); ret = SetParent( child, NULL ); - ok( ret != 0, "SetParent failed err %u\n", GetLastError() ); + ok( ret != 0, "SetParent failed err %lu\n", GetLastError() ); context = pGetWindowDpiAwarenessContext( child ); awareness = pGetAwarenessFromDpiAwarenessContext( context ); - ok( awareness == i, "%lu/%lu: wrong awareness %u\n", i, j, awareness ); + ok( awareness == i, "%Iu/%Iu: wrong awareness %u\n", i, j, awareness ); dpi = pGetDpiForWindow( child ); ok( dpi == (i == DPI_AWARENESS_UNAWARE ? USER_DEFAULT_SCREEN_DPI : real_dpi), - "%lu/%lu: got %u / %u\n", i, j, dpi, real_dpi ); + "%Iu/%Iu: got %u / %u\n", i, j, dpi, real_dpi ); DestroyWindow( child ); child = CreateWindowA( "DpiTestClass", "Test", WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL ); context = pGetWindowDpiAwarenessContext( child ); awareness = pGetAwarenessFromDpiAwarenessContext( context ); - ok( awareness == j, "%lu/%lu: wrong awareness %u\n", i, j, awareness ); + ok( awareness == j, "%Iu/%Iu: wrong awareness %u\n", i, j, awareness ); dpi = pGetDpiForWindow( child ); ok( dpi == (j == DPI_AWARENESS_UNAWARE ? USER_DEFAULT_SCREEN_DPI : real_dpi), - "%lu/%lu: got %u / %u\n", i, j, dpi, real_dpi ); + "%Iu/%Iu: got %u / %u\n", i, j, dpi, real_dpi ); ret = SetParent( child, hwnd ); ok( ret != 0 || GetLastError() == ERROR_INVALID_STATE, - "SetParent failed err %u\n", GetLastError() ); + "SetParent failed err %lu\n", GetLastError() ); context = pGetWindowDpiAwarenessContext( child ); awareness = pGetAwarenessFromDpiAwarenessContext( context ); - ok( awareness == (ret ? i : j), "%lu/%lu: wrong awareness %u\n", i, j, awareness ); + ok( awareness == (ret ? i : j), "%Iu/%Iu: wrong awareness %u\n", i, j, awareness ); dpi = pGetDpiForWindow( child ); ok( dpi == (i == DPI_AWARENESS_UNAWARE ? USER_DEFAULT_SCREEN_DPI : real_dpi), - "%lu/%lu: got %u / %u\n", i, j, dpi, real_dpi ); + "%Iu/%Iu: got %u / %u\n", i, j, dpi, real_dpi ); DestroyWindow( child ); } DestroyWindow( hwnd ); @@ -3843,12 +4529,12 @@ static void test_dpi_window(void) SetLastError( 0xdeadbeef ); context = pGetWindowDpiAwarenessContext( (HWND)0xdeadbeef ); ok( !context, "got %p\n", context ); - ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); dpi = pGetDpiForWindow( (HWND)0xdeadbeef ); ok( !dpi, "got %u\n", dpi ); ok( GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_INVALID_WINDOW_HANDLE, - "wrong error %u\n", GetLastError() ); + "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); context = pGetWindowDpiAwarenessContext( GetDesktopWindow() ); @@ -3882,11 +4568,35 @@ static void test_GetAutoRotationState(void) SetLastError(0xdeadbeef); ret = pGetAutoRotationState(NULL); ok(!ret, "Expected GetAutoRotationState to 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()); state = 0; ret = pGetAutoRotationState(&state); - ok(ret, "Expected GetAutoRotationState to succeed, error %d\n", GetLastError()); + ok(ret, "Expected GetAutoRotationState to succeed, error %ld\n", GetLastError()); +} + +static void test_LOGFONT_charset(void) +{ + CHARSETINFO csi; + LOGFONTA lf; + NONCLIENTMETRICSA ncm; + BOOL ret; + + ret = TranslateCharsetInfo(ULongToPtr(GetACP()), &csi, TCI_SRCCODEPAGE); + ok(ret, "TranslateCharsetInfo(%d) error %lu\n", GetACP(), GetLastError()); + + GetObjectA(GetStockObject(DEFAULT_GUI_FONT), sizeof(lf), &lf); + ok(lf.lfCharSet == csi.ciCharset, "got %d, expected %d\n", lf.lfCharSet, csi.ciCharset); + + ret = SystemParametersInfoA(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, FALSE); + ok(ret, "SystemParametersInfoW error %lu\n", GetLastError()); + ok(lf.lfCharSet == DEFAULT_CHARSET, "got %d\n", lf.lfCharSet); + + ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICSA, iPaddedBorderWidth); + ret = SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0); + ok(ret, "SystemParametersInfoW error %lu\n", GetLastError()); + ok(ncm.lfCaptionFont.lfCharSet == DEFAULT_CHARSET, "got %d\n", ncm.lfCaptionFont.lfCharSet); + ok(ncm.lfSmCaptionFont.lfCharSet == DEFAULT_CHARSET, "got %d\n", ncm.lfSmCaptionFont.lfCharSet); } START_TEST(sysparams) @@ -3901,7 +4611,6 @@ START_TEST(sysparams) HANDLE hInstance, hdll; hdll = GetModuleHandleA("user32.dll"); - pChangeDisplaySettingsExA = (void*)GetProcAddress(hdll, "ChangeDisplaySettingsExA"); pIsProcessDPIAware = (void*)GetProcAddress(hdll, "IsProcessDPIAware"); pSetProcessDPIAware = (void*)GetProcAddress(hdll, "SetProcessDPIAware"); pGetDpiForSystem = (void*)GetProcAddress(hdll, "GetDpiForSystem"); @@ -3921,12 +4630,13 @@ START_TEST(sysparams) pLogicalToPhysicalPointForPerMonitorDPI = (void*)GetProcAddress(hdll, "LogicalToPhysicalPointForPerMonitorDPI"); pPhysicalToLogicalPointForPerMonitorDPI = (void*)GetProcAddress(hdll, "PhysicalToLogicalPointForPerMonitorDPI"); pGetAutoRotationState = (void*)GetProcAddress(hdll, "GetAutoRotationState"); + pAreDpiAwarenessContextsEqual = (void*)GetProcAddress(hdll, "AreDpiAwarenessContextsEqual"); + pGetDpiFromDpiAwarenessContext = (void*)GetProcAddress(hdll, "GetDpiFromDpiAwarenessContext"); hInstance = GetModuleHandleA( NULL ); hdc = GetDC(0); dpi = GetDeviceCaps( hdc, LOGPIXELSY); real_dpi = get_real_dpi(); - trace("dpi %d real_dpi %d\n", dpi, real_dpi); ReleaseDC( 0, hdc); /* This test requires interactivity, if we don't have it, give up */ @@ -3935,7 +4645,16 @@ START_TEST(sysparams) argc = winetest_get_mainargs(&argv); strict=(argc >= 3 && strcmp(argv[2],"strict")==0); - trace("strict=%d\n",strict); + + if (argc > 3 && !strcmp( argv[2], "SetProcessDpiAwarenessContext" )) + { + test_SetProcessDpiAwarenessContext( strtoul( argv[3], NULL, 16 ) ); + return; + } + + trace("dpi %d real_dpi %d, strict %d\n", dpi, real_dpi, strict); + + test_LOGFONT_charset(); trace("testing GetSystemMetrics with your current desktop settings\n"); test_GetSystemMetrics( ); @@ -3943,6 +4662,11 @@ START_TEST(sysparams) test_EnumDisplaySettings( ); test_GetSysColorBrush( ); test_GetAutoRotationState( ); + test_SetThreadDpiAwarenessContext(); + test_IsValidDpiAwarenessContext(); + test_GetDpiFromDpiAwarenessContext(); + test_AreDpiAwarenessContextsEqual(); + test_GetAwarenessFromDpiAwarenessContext(); change_counter = 0; change_last_param = 0; @@ -3983,4 +4707,25 @@ START_TEST(sysparams) else win_skip( "SetThreadDpiAwarenessContext not supported\n" ); test_dpi_aware(); + + if (!pSetProcessDpiAwarenessContext || !pSetThreadDpiAwarenessContext || !pGetThreadDpiAwarenessContext) + win_skip( "SetProcessDpiAwarenessContext not supported\n" ); + else + { + run_in_process( argv, "SetProcessDpiAwarenessContext 0x6010" ); + run_in_process( argv, "SetProcessDpiAwarenessContext 0x11" ); + run_in_process( argv, "SetProcessDpiAwarenessContext 0x12" ); + run_in_process( argv, "SetProcessDpiAwarenessContext 0x22" ); + run_in_process( argv, "SetProcessDpiAwarenessContext 0x40006010" ); + run_in_process( argv, "SetProcessDpiAwarenessContext 0x80006010" ); + run_in_process( argv, "SetProcessDpiAwarenessContext 0x80000012" ); + run_in_process( argv, "SetProcessDpiAwarenessContext 0x80000022" ); + + /* user32 allows abstract DPI contexts to be used */ + run_in_process( argv, "SetProcessDpiAwarenessContext 0xffffffff" ); + run_in_process( argv, "SetProcessDpiAwarenessContext 0xfffffffe" ); + run_in_process( argv, "SetProcessDpiAwarenessContext 0xfffffffd" ); + run_in_process( argv, "SetProcessDpiAwarenessContext 0xfffffffc" ); + run_in_process( argv, "SetProcessDpiAwarenessContext 0xfffffffb" ); + } } diff --git a/modules/rostests/winetests/user32/testdll.c b/modules/rostests/winetests/user32/testdll.c new file mode 100644 index 00000000000..52ca93fc340 --- /dev/null +++ b/modules/rostests/winetests/user32/testdll.c @@ -0,0 +1,32 @@ +/* + * Copyright 2023 Zhiyi Zhang for CodeWeavers + * + * 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 + +#include +#include +#include + +LRESULT CALLBACK dummy_hook_proc(int code, WPARAM wp, LPARAM lp) +{ + return CallNextHookEx(0, code, wp, lp); +} diff --git a/modules/rostests/winetests/user32/testdll.spec b/modules/rostests/winetests/user32/testdll.spec new file mode 100644 index 00000000000..80834cbc21a --- /dev/null +++ b/modules/rostests/winetests/user32/testdll.spec @@ -0,0 +1 @@ +@ stdcall dummy_hook_proc(long ptr ptr) diff --git a/modules/rostests/winetests/user32/testlist.c b/modules/rostests/winetests/user32/testlist.c index d3d99a72d1a..25d66071eec 100644 --- a/modules/rostests/winetests/user32/testlist.c +++ b/modules/rostests/winetests/user32/testlist.c @@ -12,27 +12,12 @@ extern void func_dce(void); extern void func_dde(void); extern void func_dialog(void); extern void func_edit(void); -//extern void func_generated(void); +extern void func_generated(void); extern void func_input(void); extern void func_listbox(void); extern void func_menu(void); extern void func_monitor(void); -//extern void func_msg(void); -extern void func_msg_queue(void); -extern void func_msg_messages(void); -extern void func_msg_focus(void); -extern void func_msg_winpos(void); -extern void func_msg_paint(void); -extern void func_msg_input(void); -extern void func_msg_timer(void); -extern void func_msg_hook(void); -extern void func_msg_menu(void); -extern void func_msg_mdi(void); -extern void func_msg_controls(void); -extern void func_msg_layered_window(void); -extern void func_msg_dialog(void); -extern void func_msg_clipboard(void); -extern void func_rawinput(void); +extern void func_msg(void); extern void func_resource(void); extern void func_scroll(void); extern void func_static(void); @@ -54,26 +39,12 @@ const struct test winetest_testlist[] = { "dde", func_dde }, { "dialog", func_dialog }, { "edit", func_edit }, - //{ "generated", func_generated }, + { "generated", func_generated }, { "input", func_input }, { "listbox", func_listbox }, { "menu", func_menu }, { "monitor", func_monitor }, - { "msg_queue", func_msg_queue}, - { "msg_messages", func_msg_messages}, - { "msg_focus", func_msg_focus}, - { "msg_winpos", func_msg_winpos}, - { "msg_paint", func_msg_paint}, - { "msg_input", func_msg_input}, - { "msg_timer", func_msg_timer}, - { "msg_hook", func_msg_hook}, - { "msg_menu", func_msg_menu}, - { "msg_mdi", func_msg_mdi}, - { "msg_controls", func_msg_controls}, - { "msg_layered_window", func_msg_layered_window}, - { "msg_dialog", func_msg_dialog}, - { "msg_clipboard", func_msg_clipboard}, - { "rawinput", func_rawinput }, + { "msg", func_msg }, { "resource", func_resource }, { "scroll", func_scroll }, { "static", func_static }, diff --git a/modules/rostests/winetests/user32/text.c b/modules/rostests/winetests/user32/text.c index 359721fcd91..d796ef4f441 100644 --- a/modules/rostests/winetests/user32/text.c +++ b/modules/rostests/winetests/user32/text.c @@ -45,6 +45,8 @@ static void test_DrawTextCalcRect(void) static WCHAR emptystringW[] = { 0 }; static CHAR wordbreak_text[] = "line1 line2"; static WCHAR wordbreak_textW[] = {'l','i','n','e','1',' ','l','i','n','e','2',0}; + static WCHAR wordbreak_text_colonW[] = {'l','i','n','e','1',' ','l','i','n','e','2',' ',':',0}; + static WCHAR wordbreak_text_csbW[] = {'l','i','n','e','1',' ','l','i','n','e','2',' ',']',0}; static char tabstring[] = "one\ttwo"; INT textlen, textheight, heightcheck; RECT rect = { 0, 0, 100, 0 }, rect2; @@ -55,9 +57,9 @@ static void test_DrawTextCalcRect(void) /* Initialization */ hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 200, 200, 0, 0, 0, NULL); - ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError()); + ok(hwnd != 0, "CreateWindowExA error %lu\n", GetLastError()); hdc = GetDC(hwnd); - ok(hdc != 0, "GetDC error %u\n", GetLastError()); + ok(hdc != 0, "GetDC error %lu\n", GetLastError()); trace("hdc %p\n", hdc); textlen = lstrlenA(text); @@ -74,23 +76,23 @@ static void test_DrawTextCalcRect(void) SetMapMode(hdc, MM_HIENGLISH); lf.lfHeight = 100 * 9 / 72; /* 9 point */ hFont = CreateFontIndirectA(&lf); - ok(hFont != 0, "CreateFontIndirectA error %u\n", + ok(hFont != 0, "CreateFontIndirectA error %lu\n", GetLastError()); hOldFont = SelectObject(hdc, hFont); textheight = DrawTextA(hdc, text, textlen, &rect, DT_CALCRECT | DT_EXTERNALLEADING | DT_WORDBREAK | DT_NOCLIP | DT_LEFT | DT_NOPREFIX); - ok( textheight, "DrawTextA error %u\n", GetLastError()); + ok( textheight, "DrawTextA error %lu\n", GetLastError()); - trace("MM_HIENGLISH rect.bottom %d\n", rect.bottom); + trace("MM_HIENGLISH rect.bottom %ld\n", rect.bottom); ok(rect.bottom < 0, "In MM_HIENGLISH, DrawText with " "DT_CALCRECT should return a negative rectangle bottom. " - "(bot=%d)\n", rect.bottom); + "(bot=%ld)\n", rect.bottom); SelectObject(hdc, hOldFont); ret = DeleteObject(hFont); - ok( ret, "DeleteObject error %u\n", GetLastError()); + ok( ret, "DeleteObject error %lu\n", GetLastError()); /* DrawText in MM_TEXT with DT_CALCRECT */ @@ -98,18 +100,18 @@ static void test_DrawTextCalcRect(void) lf.lfHeight = -MulDiv(9, GetDeviceCaps(hdc, LOGPIXELSY), 72); /* 9 point */ hFont = CreateFontIndirectA(&lf); - ok(hFont != 0, "CreateFontIndirectA error %u\n", + ok(hFont != 0, "CreateFontIndirectA error %lu\n", GetLastError()); hOldFont = SelectObject(hdc, hFont); textheight = DrawTextA(hdc, text, textlen, &rect, DT_CALCRECT | DT_EXTERNALLEADING | DT_WORDBREAK | DT_NOCLIP | DT_LEFT | DT_NOPREFIX); - ok( textheight, "DrawTextA error %u\n", GetLastError()); + ok( textheight, "DrawTextA error %lu\n", GetLastError()); - trace("MM_TEXT rect.bottom %d\n", rect.bottom); + trace("MM_TEXT rect.bottom %ld\n", rect.bottom); ok(rect.bottom > 0, "In MM_TEXT, DrawText with DT_CALCRECT " - "should return a positive rectangle bottom. (bot=%d)\n", + "should return a positive rectangle bottom. (bot=%ld)\n", rect.bottom); /* empty or null text should in some cases calc an empty rectangle */ @@ -326,12 +328,12 @@ static void test_DrawTextCalcRect(void) dtp.iLeftMargin = 8; SetRectEmpty(&rect); DrawTextExA(hdc, text, -1, &rect, DT_CALCRECT, &dtp); - ok(rect.right==dtp.iLeftMargin+textlen ,"Incorrect left margin calculated rc(%d,%d)\n", rect.left, rect.right); + ok(rect.right==dtp.iLeftMargin+textlen ,"Incorrect left margin calculated rc(%ld,%ld)\n", rect.left, rect.right); dtp.iLeftMargin = 0; dtp.iRightMargin = 8; SetRectEmpty(&rect); DrawTextExA(hdc, text, -1, &rect, DT_CALCRECT, &dtp); - ok(rect.right==dtp.iRightMargin+textlen ,"Incorrect right margin calculated rc(%d,%d)\n", rect.left, rect.right); + ok(rect.right==dtp.iRightMargin+textlen ,"Incorrect right margin calculated rc(%ld,%ld)\n", rect.left, rect.right); /* Wide char versions */ SetRect( &rect, 10,10, 100, 100); @@ -519,15 +521,46 @@ static void test_DrawTextCalcRect(void) ok(textheight==0,"Got textheight from DrawTextExW\n"); ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn); } + + /* When passing invalid DC, other parameters must be ignored - no crashes on invalid pointers */ + +#ifdef __REACTOS__ + if (is_reactos()) { + ok(FALSE, "FIXME: invalid pointer tests crash on ReactOS.\n"); + } else { +#endif + SetLastError(0xdeadbeef); + textheight = DrawTextExW((HDC)0xdeadbeef, (LPWSTR)0xdeadbeef, 100000, &rect, 0, 0); + ok(textheight == 0, "Got textheight from DrawTextExW\n"); + ok(GetLastError() == 0xdeadbeef,"Got error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + textheight = DrawTextExW((HDC)0xdeadbeef, 0, -1, (LPRECT)0xdeadbeef, DT_CALCRECT, 0); + ok(textheight == 0, "Got textheight from DrawTextExW\n"); + ok(GetLastError() == 0xdeadbeef,"Got error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + textheight = DrawTextExA((HDC)0xdeadbeef, 0, -1, (LPRECT)0xdeadbeef, DT_CALCRECT, 0); + ok(textheight == 0, "Got textheight from DrawTextExA\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_INVALID_HANDLE,"Got error %lu\n", GetLastError()); +#ifdef __REACTOS__ + } +#endif + + if (0) + { + /* Crashes */ + textheight = DrawTextExA((HDC)0xdeadbeef, (LPSTR)0xdeadbeef, 100, &rect, 0, 0); + } } /* More test cases from bug 12226 */ SetRectEmpty(&rect); textheight = DrawTextA(hdc, emptystring, -1, &rect, DT_CALCRECT | DT_LEFT | DT_SINGLELINE); - ok(textheight, "DrawTextA error %u\n", GetLastError()); - ok(0 == rect.left, "expected 0, got %d\n", rect.left); - ok(0 == rect.right, "expected 0, got %d\n", rect.right); - ok(0 == rect.top, "expected 0, got %d\n", rect.top); + ok(textheight, "DrawTextA error %lu\n", GetLastError()); + ok(0 == rect.left, "expected 0, got %ld\n", rect.left); + ok(0 == rect.right, "expected 0, got %ld\n", rect.right); + ok(0 == rect.top, "expected 0, got %ld\n", rect.top); ok(rect.bottom, "rect.bottom should not be 0\n"); SetRectEmpty(&rect); @@ -538,10 +571,10 @@ static void test_DrawTextCalcRect(void) } else { - ok(textheight, "DrawTextW error %u\n", GetLastError()); - ok(0 == rect.left, "expected 0, got %d\n", rect.left); - ok(0 == rect.right, "expected 0, got %d\n", rect.right); - ok(0 == rect.top, "expected 0, got %d\n", rect.top); + ok(textheight, "DrawTextW error %lu\n", GetLastError()); + ok(0 == rect.left, "expected 0, got %ld\n", rect.left); + ok(0 == rect.right, "expected 0, got %ld\n", rect.right); + ok(0 == rect.top, "expected 0, got %ld\n", rect.top); ok(rect.bottom, "rect.bottom should not be 0\n"); } @@ -567,6 +600,36 @@ static void test_DrawTextCalcRect(void) ok(textheight >= heightcheck * 6, "Got unexpected textheight %d, expected at least %d.\n", textheight, heightcheck * 6); + /* Word break tests with space before punctuation */ + SetRect(&rect, 0, 0, 200, 1); + textheight = DrawTextW(hdc, wordbreak_text_colonW, -1, &rect, DT_CALCRECT | DT_WORDBREAK); + ok(textheight == heightcheck, "Got unexpected textheight %d, expected %d.\n", + textheight, heightcheck); + + rect2 = rect; + rect.right--; + + textheight = DrawTextW(hdc, wordbreak_text_colonW, -1, &rect, DT_CALCRECT | DT_WORDBREAK); + ok(textheight == heightcheck * 2, "Got unexpected textheight %d, expected %d.\n", + textheight, heightcheck * 2); + ok(rect.right > rect2.right - 10, "Got unexpected textwdith %ld, expected larger than %ld.\n", + rect.right, rect2.right - 10); + + SetRect(&rect, 0, 0, 200, 1); + textheight = DrawTextW(hdc, wordbreak_text_csbW, -1, &rect, DT_CALCRECT | DT_WORDBREAK); + ok(textheight == heightcheck, "Got unexpected textheight %d, expected %d.\n", + textheight, heightcheck); + + rect2 = rect; + rect.right--; + + textheight = DrawTextW(hdc, wordbreak_text_csbW, -1, &rect, DT_CALCRECT | DT_WORDBREAK); + ok(textheight == heightcheck * 2, "Got unexpected textheight %d, expected %d.\n", + textheight, heightcheck * 2); + ok(rect.right > rect2.right - 10, "Got unexpected textwdith %ld, expected larger than %ld.\n", + rect.right, rect2.right - 10); + + /* DT_TABSTOP | DT_EXPANDTABS tests */ SetRect( &rect, 0,0, 10, 10); textheight = DrawTextA(hdc, tabstring, -1, &rect, DT_TABSTOP | DT_EXPANDTABS ); @@ -595,22 +658,22 @@ static void test_DrawTextCalcRect(void) textheight = DrawTextExA(hdc, tabstring, -1, &rect, DT_CALCRECT | DT_TABSTOP | DT_EXPANDTABS, &dtp); ok(textheight >= heightcheck, "Got unexpected textheight %d\n", textheight); ok(dtp.iTabLength == 8, "invalid dtp.iTabLength = %i\n",dtp.iTabLength); - ok(rect.left == rect2.left, "unexpected value %d, got %d\n", rect.left, rect2.left); + ok(rect.left == rect2.left, "unexpected value %ld, got %ld\n", rect.left, rect2.left); /* XP, 2003 appear to not give the same values. */ - ok(rect.right == rect2.right || broken(rect.right > rect2.right), "unexpected value %d, got %d\n",rect.right, rect2.right); - ok(rect.top == rect2.top, "unexpected value %d, got %d\n", rect.top, rect2.top); - ok(rect.bottom == rect2.bottom , "unexpected value %d, got %d\n", rect.bottom, rect2.bottom); + ok(rect.right == rect2.right || broken(rect.right > rect2.right), "unexpected value %ld, got %ld\n",rect.right, rect2.right); + ok(rect.top == rect2.top, "unexpected value %ld, got %ld\n", rect.top, rect2.top); + ok(rect.bottom == rect2.bottom , "unexpected value %ld, got %ld\n", rect.bottom, rect2.bottom); SelectObject(hdc, hOldFont); ret = DeleteObject(hFont); - ok( ret, "DeleteObject error %u\n", GetLastError()); + ok( ret, "DeleteObject error %lu\n", GetLastError()); /* Clean up */ ret = ReleaseDC(hwnd, hdc); - ok( ret, "ReleaseDC error %u\n", GetLastError()); + ok( ret, "ReleaseDC error %lu\n", GetLastError()); ret = DestroyWindow(hwnd); - ok( ret, "DestroyWindow error %u\n", GetLastError()); + ok( ret, "DestroyWindow error %lu\n", GetLastError()); } /* replace tabs by \t */ @@ -631,7 +694,7 @@ static void strfmt( const char *str, char *strout) extent = GetTabbedTextExtentA( hdc, string, strlen( string), (tabcount), tabs); \ strfmt( string, strdisp); \ /* trace( "Extent is %08lx\n", extent); */\ - ok( extent == _exp, "Test case \"%s\". Text extent is 0x%x, expected 0x%x tab %d tabcount %d\n", \ + ok( extent == _exp, "Test case \"%s\". Text extent is 0x%lx, expected 0x%lx tab %d tabcount %d\n", \ strdisp, extent, _exp, tabval, tabcount); \ } \ @@ -648,12 +711,12 @@ static void test_TabbedText(void) /* Initialization */ hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 200, 200, 0, 0, 0, NULL); - ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError()); + ok(hwnd != 0, "CreateWindowExA error %lu\n", GetLastError()); hdc = GetDC(hwnd); - ok(hdc != 0, "GetDC error %u\n", GetLastError()); + ok(hdc != 0, "GetDC error %lu\n", GetLastError()); ret = GetTextMetricsA( hdc, &tm); - ok( ret, "GetTextMetrics error %u\n", GetLastError()); + ok( ret, "GetTextMetrics error %lu\n", GetLastError()); extent = GetTabbedTextExtentA( hdc, "x", 0, 1, tabs); ok( extent == 0, "GetTabbedTextExtentA returned non-zero on nCount == 0\n"); @@ -721,24 +784,24 @@ static void test_DrawState(void) SetLastError(0xdeadbeef); ret = DrawStateA(hdc, GetStockObject(DKGRAY_BRUSH), NULL, (LPARAM)text, strlen(text), 0, 0, 10, 10, DST_TEXT); - ok(ret, "DrawState error %u\n", GetLastError()); + ok(ret, "DrawState error %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = DrawStateA(hdc, GetStockObject(DKGRAY_BRUSH), NULL, (LPARAM)text, 0, 0, 0, 10, 10, DST_TEXT); - ok(ret, "DrawState error %u\n", GetLastError()); + ok(ret, "DrawState error %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = DrawStateA(hdc, GetStockObject(DKGRAY_BRUSH), NULL, 0, strlen(text), 0, 0, 10, 10, DST_TEXT); ok(!ret || broken(ret) /* win98 */, "DrawState succeeded\n"); - ok(GetLastError() == 0xdeadbeef, "not expected error %u\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "not expected error %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = DrawStateA(hdc, GetStockObject(DKGRAY_BRUSH), NULL, 0, 0, 0, 0, 10, 10, DST_TEXT); ok(!ret || broken(ret) /* win98 */, "DrawState succeeded\n"); - ok(GetLastError() == 0xdeadbeef, "not expected error %u\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "not expected error %lu\n", GetLastError()); ReleaseDC(hwnd, hdc); DestroyWindow(hwnd); diff --git a/modules/rostests/winetests/user32/uitools.c b/modules/rostests/winetests/user32/uitools.c index 07cf776a952..a3067c518ea 100644 --- a/modules/rostests/winetests/user32/uitools.c +++ b/modules/rostests/winetests/user32/uitools.c @@ -46,7 +46,7 @@ static void test_FillRect(void) oldhbmp = SelectObject(hdcmem, hbmp); ok(oldhbmp != NULL, "SelectObject returned NULL\n"); /* a memdc always has a bitmap selected */ col = GetPixel(hdcmem, 0, 0); - ok( col == 0xffffff, "GetPixel returned %08x, expected 0xffffff\n", col); + ok( col == 0xffffff, "GetPixel returned %08lx, expected 0xffffff\n", col); /* select black brush */ old_brush = SelectObject(hdcmem, GetStockObject(BLACK_BRUSH)); @@ -55,7 +55,7 @@ static void test_FillRect(void) SelectObject(hdcmem, old_brush); /* bitmap filled with last selected brush */ col = GetPixel(hdcmem, 0, 0); - ok(col == 0, "GetPixel returned %08x, expected 0\n", col); + ok(col == 0, "GetPixel returned %08lx, expected 0\n", col); SelectObject(hdcmem, oldhbmp); DeleteObject(hbmp); diff --git a/modules/rostests/winetests/user32/win.c b/modules/rostests/winetests/user32/win.c index b5ec3889005..ef761f4d955 100644 --- a/modules/rostests/winetests/user32/win.c +++ b/modules/rostests/winetests/user32/win.c @@ -20,11 +20,19 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "precomp.h" +#include +#include +#include +#include +#include -#ifndef SPI_GETDESKWALLPAPER -#define SPI_GETDESKWALLPAPER 0x0073 -#endif +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winreg.h" + +#include "wine/test.h" #ifndef WM_SYSTIMER #define WM_SYSTIMER 0x0118 @@ -32,27 +40,31 @@ #define LONG_PTR INT_PTR #define ULONG_PTR UINT_PTR +#ifdef __REACTOS__ +/* Not in Windows SDK, but is in Wine headers */ +#define DCX_USESTYLE 0x00010000 +#endif void dump_region(HRGN hrgn); -static HWND (WINAPI *pGetAncestor)(HWND,UINT); static BOOL (WINAPI *pGetWindowInfo)(HWND,WINDOWINFO*); static UINT (WINAPI *pGetWindowModuleFileNameA)(HWND,LPSTR,UINT); static BOOL (WINAPI *pGetLayeredWindowAttributes)(HWND,COLORREF*,BYTE*,DWORD*); static BOOL (WINAPI *pSetLayeredWindowAttributes)(HWND,COLORREF,BYTE,DWORD); static BOOL (WINAPI *pUpdateLayeredWindow)(HWND,HDC,POINT*,SIZE*,HDC,POINT*,COLORREF,BLENDFUNCTION*,DWORD); static BOOL (WINAPI *pUpdateLayeredWindowIndirect)(HWND,const UPDATELAYEREDWINDOWINFO*); -static BOOL (WINAPI *pGetMonitorInfoA)(HMONITOR,LPMONITORINFO); -static HMONITOR (WINAPI *pMonitorFromPoint)(POINT,DWORD); static int (WINAPI *pGetWindowRgnBox)(HWND,LPRECT); static BOOL (WINAPI *pGetGUIThreadInfo)(DWORD, GUITHREADINFO*); static BOOL (WINAPI *pGetProcessDefaultLayout)( DWORD *layout ); static BOOL (WINAPI *pSetProcessDefaultLayout)( DWORD layout ); static BOOL (WINAPI *pFlashWindow)( HWND hwnd, BOOL bInvert ); static BOOL (WINAPI *pFlashWindowEx)( PFLASHWINFO pfwi ); -static DWORD (WINAPI *pSetLayout)(HDC hdc, DWORD layout); -static DWORD (WINAPI *pGetLayout)(HDC hdc); static BOOL (WINAPI *pMirrorRgn)(HWND hwnd, HRGN hrgn); +static BOOL (WINAPI *pGetWindowDisplayAffinity)(HWND hwnd, DWORD *affinity); +static BOOL (WINAPI *pSetWindowDisplayAffinity)(HWND hwnd, DWORD affinity); +static BOOL (WINAPI *pAdjustWindowRectExForDpi)(LPRECT,DWORD,BOOL,DWORD,UINT); +static BOOL (WINAPI *pSystemParametersInfoForDpi)(UINT,UINT,void*,UINT,UINT); +static HICON (WINAPI *pInternalGetWindowIcon)(HWND window, UINT type); static BOOL test_lbuttondown_flag; static DWORD num_gettext_msgs; @@ -66,13 +78,33 @@ static const char* szAWRClass = "Winsize"; static HMENU hmenu; static DWORD our_pid; -static BOOL is_win9x = FALSE; +static void hold_key( int vk ) +{ + BYTE kstate[256]; + BOOL res; -#define COUNTOF(arr) (sizeof(arr)/sizeof(arr[0])) + res = GetKeyboardState( kstate ); + ok(res, "GetKeyboardState failed.\n"); + kstate[vk] |= 0x80; + res = SetKeyboardState( kstate ); + ok(res, "SetKeyboardState failed.\n"); +} + +static void release_key( int vk ) +{ + BYTE kstate[256]; + BOOL res; + + res = GetKeyboardState( kstate ); + ok(res, "GetKeyboardState failed.\n"); + kstate[vk] &= ~0x80; + res = SetKeyboardState( kstate ); + ok(res, "SetKeyboardState failed.\n"); +} static void dump_minmax_info( const MINMAXINFO *minmax ) { - trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n", + trace("Reserved=%ld,%ld MaxSize=%ld,%ld MaxPos=%ld,%ld MinTrack=%ld,%ld MaxTrack=%ld,%ld\n", minmax->ptReserved.x, minmax->ptReserved.y, minmax->ptMaxSize.x, minmax->ptMaxSize.y, minmax->ptMaxPosition.x, minmax->ptMaxPosition.y, @@ -98,46 +130,24 @@ static void flush_events( BOOL remove_messages ) } } -static BOOL wait_for_event(HANDLE event, int timeout) -{ - DWORD end_time = GetTickCount() + timeout; - MSG msg; - - do { - if(MsgWaitForMultipleObjects(1, &event, FALSE, timeout, QS_ALLINPUT) == WAIT_OBJECT_0) - return TRUE; - while(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) - DispatchMessageA(&msg); - timeout = end_time - GetTickCount(); - }while(timeout > 0); - - return FALSE; -} - /* check the values returned by the various parent/owner functions on a given window */ static void check_parents( HWND hwnd, HWND ga_parent, HWND gwl_parent, HWND get_parent, HWND gw_owner, HWND ga_root, HWND ga_root_owner ) { HWND res; - if (pGetAncestor) - { - res = pGetAncestor( hwnd, GA_PARENT ); - ok( res == ga_parent, "Wrong result for GA_PARENT %p expected %p\n", res, ga_parent ); - } + res = GetAncestor( hwnd, GA_PARENT ); + ok( res == ga_parent, "Wrong result for GA_PARENT %p expected %p\n", res, ga_parent ); res = (HWND)GetWindowLongPtrA( hwnd, GWLP_HWNDPARENT ); ok( res == gwl_parent, "Wrong result for GWL_HWNDPARENT %p expected %p\n", res, gwl_parent ); res = GetParent( hwnd ); ok( res == get_parent, "Wrong result for GetParent %p expected %p\n", res, get_parent ); res = GetWindow( hwnd, GW_OWNER ); ok( res == gw_owner, "Wrong result for GW_OWNER %p expected %p\n", res, gw_owner ); - if (pGetAncestor) - { - res = pGetAncestor( hwnd, GA_ROOT ); - ok( res == ga_root, "Wrong result for GA_ROOT %p expected %p\n", res, ga_root ); - res = pGetAncestor( hwnd, GA_ROOTOWNER ); - ok( res == ga_root_owner, "Wrong result for GA_ROOTOWNER %p expected %p\n", res, ga_root_owner ); - } + res = GetAncestor( hwnd, GA_ROOT ); + ok( res == ga_root, "Wrong result for GA_ROOT %p expected %p\n", res, ga_root ); + res = GetAncestor( hwnd, GA_ROOTOWNER ); + ok( res == ga_root_owner, "Wrong result for GA_ROOTOWNER %p expected %p\n", res, ga_root_owner ); } #define check_wnd_state(a,b,c,d) check_wnd_state_(__FILE__,__LINE__,a,b,c,d) @@ -149,7 +159,6 @@ static void check_wnd_state_(const char *file, int line, /* foreground can be moved to a different app pretty much at any time */ if (foreground && GetForegroundWindow() && GetWindowThreadProcessId(GetForegroundWindow(), NULL) == GetCurrentThreadId()) - disable_success_count ok_(file, line)(foreground == GetForegroundWindow(), "GetForegroundWindow() = %p\n", GetForegroundWindow()); ok_(file, line)(focus == GetFocus(), "GetFocus() = %p\n", GetFocus()); ok_(file, line)(capture == GetCapture(), "GetCapture() = %p\n", GetCapture()); @@ -165,15 +174,21 @@ static void check_active_state_(const char *file, int line, /* foreground can be moved to a different app pretty much at any time */ if (foreground && GetForegroundWindow() && GetWindowThreadProcessId(GetForegroundWindow(), NULL) == GetCurrentThreadId()) - disable_success_count ok_(file, line)(foreground == GetForegroundWindow(), "GetForegroundWindow() = %p\n", GetForegroundWindow()); ok_(file, line)(focus == GetFocus(), "GetFocus() = %p\n", GetFocus()); } -static BOOL ignore_message( UINT message ) +static BOOL ignore_message( UINT message, HWND hwnd ) { + WCHAR buffer[256]; + + if (GetClassNameW( hwnd, buffer, ARRAY_SIZE(buffer) ) == 22 && + !wcscmp( buffer, L"UserAdapterWindowClass" )) + return TRUE; + /* these are always ignored */ return (message >= 0xc000 || + message == 0x0060 || /* Internal undocumented message introduced by Win11 */ message == WM_GETICON || message == WM_GETOBJECT || message == WM_TIMER || @@ -182,10 +197,31 @@ static BOOL ignore_message( UINT message ) message == WM_DEVICECHANGE); } +static DWORD wait_for_events( DWORD count, HANDLE *events, DWORD timeout ) +{ + DWORD ret, end = GetTickCount() + timeout; + MSG msg; + + while ((ret = MsgWaitForMultipleObjects( count, events, FALSE, timeout, QS_ALLINPUT )) <= count) + { + while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) + { + TranslateMessage( &msg ); + DispatchMessageA( &msg ); + } + if (ret < count) return ret; + if (timeout == INFINITE) continue; + if (end <= GetTickCount()) timeout = 0; + else timeout = end - GetTickCount(); + } + + ok( ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %#lx\n", ret ); + return ret; +} + static BOOL CALLBACK EnumChildProc( HWND hwndChild, LPARAM lParam) { (*(LPINT)lParam)++; - trace("EnumChildProc on %p\n", hwndChild); if (*(LPINT)lParam > 1) return FALSE; return TRUE; } @@ -193,7 +229,6 @@ static BOOL CALLBACK EnumChildProc( HWND hwndChild, LPARAM lParam) /* will search for the given window */ static BOOL CALLBACK EnumChildProc1( HWND hwndChild, LPARAM lParam) { - trace("EnumChildProc1 on %p\n", hwndChild); if ((HWND)lParam == hwndChild) return FALSE; return TRUE; } @@ -215,16 +250,15 @@ static void test_parent_owner(void) HWND child = create_tool_window( WS_CHILD, hwndMain ); INT numChildren; - trace( "main window %p main2 %p desktop %p child %p\n", hwndMain, hwndMain2, desktop, child ); + if (winetest_debug > 1) + trace( "main window %p main2 %p desktop %p child %p\n", hwndMain, hwndMain2, desktop, child ); /* child without parent, should fail */ SetLastError(0xdeadbeef); test = CreateWindowExA(0, "ToolWindowClass", "Tool window 1", WS_CHILD, 0, 0, 100, 100, 0, 0, 0, NULL ); ok( !test, "WS_CHILD without parent created\n" ); - ok( GetLastError() == ERROR_TLW_WITH_WSCHILD || - broken(GetLastError() == 0xdeadbeef), /* win9x */ - "CreateWindowExA error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_TLW_WITH_WSCHILD, "CreateWindowExA error %lu\n", GetLastError() ); /* desktop window */ check_parents( desktop, 0, 0, 0, 0, 0, 0 ); @@ -235,7 +269,7 @@ static void test_parent_owner(void) /* normal child window */ test = create_tool_window( WS_CHILD, hwndMain ); - trace( "created child %p\n", test ); + if (winetest_debug > 1) trace( "created child %p\n", test ); check_parents( test, hwndMain, hwndMain, hwndMain, 0, hwndMain, hwndMain ); SetWindowLongA( test, GWL_STYLE, 0 ); check_parents( test, hwndMain, hwndMain, 0, 0, hwndMain, test ); @@ -260,7 +294,7 @@ static void test_parent_owner(void) /* child of desktop */ test = create_tool_window( WS_CHILD, desktop ); - trace( "created child of desktop %p\n", test ); + if (winetest_debug > 1) trace( "created child of desktop %p\n", test ); check_parents( test, desktop, 0, desktop, 0, test, desktop ); SetWindowLongA( test, GWL_STYLE, WS_POPUP ); check_parents( test, desktop, 0, 0, 0, test, test ); @@ -278,7 +312,7 @@ static void test_parent_owner(void) /* child of child */ test = create_tool_window( WS_CHILD, child ); - trace( "created child of child %p\n", test ); + if (winetest_debug > 1) trace( "created child of child %p\n", test ); check_parents( test, child, child, child, 0, hwndMain, hwndMain ); SetWindowLongA( test, GWL_STYLE, 0 ); check_parents( test, child, child, 0, 0, hwndMain, test ); @@ -296,7 +330,7 @@ static void test_parent_owner(void) /* not owned top-level window */ test = create_tool_window( 0, 0 ); - trace( "created top-level %p\n", test ); + if (winetest_debug > 1) trace( "created top-level %p\n", test ); check_parents( test, desktop, 0, 0, 0, test, test ); SetWindowLongA( test, GWL_STYLE, WS_POPUP ); check_parents( test, desktop, 0, 0, 0, test, test ); @@ -310,7 +344,7 @@ static void test_parent_owner(void) /* owned top-level window */ test = create_tool_window( 0, hwndMain ); - trace( "created owned top-level %p\n", test ); + if (winetest_debug > 1) trace( "created owned top-level %p\n", test ); check_parents( test, desktop, hwndMain, 0, hwndMain, test, test ); SetWindowLongA( test, GWL_STYLE, WS_POPUP ); check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain ); @@ -324,7 +358,7 @@ static void test_parent_owner(void) /* not owned popup */ test = create_tool_window( WS_POPUP, 0 ); - trace( "created popup %p\n", test ); + if (winetest_debug > 1) trace( "created popup %p\n", test ); check_parents( test, desktop, 0, 0, 0, test, test ); SetWindowLongA( test, GWL_STYLE, WS_CHILD ); check_parents( test, desktop, 0, desktop, 0, test, desktop ); @@ -338,7 +372,7 @@ static void test_parent_owner(void) /* owned popup */ test = create_tool_window( WS_POPUP, hwndMain ); - trace( "created owned popup %p\n", test ); + if (winetest_debug > 1) trace( "created owned popup %p\n", test ); check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain ); SetWindowLongA( test, GWL_STYLE, WS_CHILD ); check_parents( test, desktop, hwndMain, desktop, hwndMain, test, desktop ); @@ -352,7 +386,7 @@ static void test_parent_owner(void) /* top-level window owned by child (same as owned by top-level) */ test = create_tool_window( 0, child ); - trace( "created top-level owned by child %p\n", test ); + if (winetest_debug > 1) trace( "created top-level owned by child %p\n", test ); check_parents( test, desktop, hwndMain, 0, hwndMain, test, test ); DestroyWindow( test ); @@ -362,7 +396,7 @@ static void test_parent_owner(void) /* popup owned by desktop (same as not owned) */ test = create_tool_window( WS_POPUP, desktop ); - trace( "created popup owned by desktop %p\n", test ); + if (winetest_debug > 1) trace( "created popup owned by desktop %p\n", test ); check_parents( test, desktop, 0, 0, 0, test, test ); DestroyWindow( test ); @@ -372,7 +406,7 @@ static void test_parent_owner(void) /* popup owned by child (same as owned by top-level) */ test = create_tool_window( WS_POPUP, child ); - trace( "created popup owned by child %p\n", test ); + if (winetest_debug > 1) trace( "created popup owned by child %p\n", test ); check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain ); DestroyWindow( test ); @@ -382,7 +416,7 @@ static void test_parent_owner(void) /* not owned popup with WS_CHILD (same as WS_POPUP only) */ test = create_tool_window( WS_POPUP | WS_CHILD, 0 ); - trace( "created WS_CHILD popup %p\n", test ); + if (winetest_debug > 1) trace( "created WS_CHILD popup %p\n", test ); check_parents( test, desktop, 0, 0, 0, test, test ); DestroyWindow( test ); @@ -392,7 +426,7 @@ static void test_parent_owner(void) /* owned popup with WS_CHILD (same as WS_POPUP only) */ test = create_tool_window( WS_POPUP | WS_CHILD, hwndMain ); - trace( "created owned WS_CHILD popup %p\n", test ); + if (winetest_debug > 1) trace( "created owned WS_CHILD popup %p\n", test ); check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain ); DestroyWindow( test ); @@ -401,22 +435,17 @@ static void test_parent_owner(void) DestroyWindow( test ); /******************** parent changes *************************/ - trace( "testing parent changes\n" ); /* desktop window */ check_parents( desktop, 0, 0, 0, 0, 0, 0 ); - if (0) - { - /* this test succeeds on NT but crashes on win9x systems */ ret = (HWND)SetWindowLongPtrA( test, GWLP_HWNDPARENT, (LONG_PTR)hwndMain2 ); ok( !ret, "Set GWL_HWNDPARENT succeeded on desktop\n" ); check_parents( desktop, 0, 0, 0, 0, 0, 0 ); ok( !SetParent( desktop, hwndMain ), "SetParent succeeded on desktop\n" ); check_parents( desktop, 0, 0, 0, 0, 0, 0 ); - } /* normal child window */ test = create_tool_window( WS_CHILD, hwndMain ); - trace( "created child %p\n", test ); + if (winetest_debug > 1) trace( "created child %p\n", test ); ret = (HWND)SetWindowLongPtrA( test, GWLP_HWNDPARENT, (LONG_PTR)hwndMain2 ); ok( ret == hwndMain, "GWL_HWNDPARENT return value %p expected %p\n", ret, hwndMain ); @@ -431,14 +460,9 @@ static void test_parent_owner(void) check_parents( test, desktop, 0, desktop, 0, test, desktop ); /* window is now child of desktop so GWLP_HWNDPARENT changes owner from now on */ - if (!is_win9x) - { - ret = (HWND)SetWindowLongPtrA( test, GWLP_HWNDPARENT, (LONG_PTR)test ); - ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0\n", ret ); - check_parents( test, desktop, 0, desktop, 0, test, desktop ); - } - else - win_skip("Test creates circular window tree under Win9x/WinMe\n" ); + ret = (HWND)SetWindowLongPtrA( test, GWLP_HWNDPARENT, (LONG_PTR)test ); + ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0\n", ret ); + check_parents( test, desktop, 0, desktop, 0, test, desktop ); ret = (HWND)SetWindowLongPtrA( test, GWLP_HWNDPARENT, (LONG_PTR)child ); ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0\n", ret ); @@ -451,7 +475,7 @@ static void test_parent_owner(void) /* not owned top-level window */ test = create_tool_window( 0, 0 ); - trace( "created top-level %p\n", test ); + if (winetest_debug > 1) trace( "created top-level %p\n", test ); ret = (HWND)SetWindowLongPtrA( test, GWLP_HWNDPARENT, (LONG_PTR)hwndMain2 ); ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0\n", ret ); @@ -468,7 +492,7 @@ static void test_parent_owner(void) /* not owned popup */ test = create_tool_window( WS_POPUP, 0 ); - trace( "created popup %p\n", test ); + if (winetest_debug > 1) trace( "created popup %p\n", test ); ret = (HWND)SetWindowLongPtrA( test, GWLP_HWNDPARENT, (LONG_PTR)hwndMain2 ); ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0\n", ret ); @@ -485,7 +509,7 @@ static void test_parent_owner(void) /* normal child window */ test = create_tool_window( WS_CHILD, hwndMain ); - trace( "created child %p\n", test ); + if (winetest_debug > 1) trace( "created child %p\n", test ); ret = SetParent( test, desktop ); ok( ret == hwndMain, "SetParent return value %p expected %p\n", ret, hwndMain ); @@ -502,27 +526,22 @@ static void test_parent_owner(void) /* not owned top-level window */ test = create_tool_window( 0, 0 ); - trace( "created top-level %p\n", test ); + if (winetest_debug > 1) trace( "created top-level %p\n", test ); ret = SetParent( test, child ); ok( ret == desktop, "SetParent return value %p expected %p\n", ret, desktop ); check_parents( test, child, child, 0, 0, hwndMain, test ); - if (!is_win9x) - { - ShowWindow( test, SW_SHOW ); - ret = SetParent( test, test ); - ok( ret == NULL, "SetParent return value %p expected %p\n", ret, NULL ); - ok( GetWindowLongA( test, GWL_STYLE ) & WS_VISIBLE, "window is not visible after SetParent\n" ); - check_parents( test, child, child, 0, 0, hwndMain, test ); - } - else - win_skip( "Test crashes on Win9x/WinMe\n" ); + ShowWindow( test, SW_SHOW ); + ret = SetParent( test, test ); + ok( ret == NULL, "SetParent return value %p expected %p\n", ret, NULL ); + ok( GetWindowLongA( test, GWL_STYLE ) & WS_VISIBLE, "window is not visible after SetParent\n" ); + check_parents( test, child, child, 0, 0, hwndMain, test ); DestroyWindow( test ); /* owned popup */ test = create_tool_window( WS_POPUP, hwndMain2 ); - trace( "created owned popup %p\n", test ); + if (winetest_debug > 1) trace( "created owned popup %p\n", test ); ret = SetParent( test, child ); ok( ret == desktop, "SetParent return value %p expected %p\n", ret, desktop ); @@ -538,7 +557,7 @@ static void test_parent_owner(void) /* owned child popup */ owner = create_tool_window( 0, 0 ); test = create_tool_window( WS_POPUP, owner ); - trace( "created owner %p and popup %p\n", owner, test ); + if (winetest_debug > 1) trace( "created owner %p and popup %p\n", owner, test ); ret = SetParent( test, child ); ok( ret == desktop, "SetParent return value %p expected %p\n", ret, desktop ); check_parents( test, child, child, owner, owner, hwndMain, owner ); @@ -555,7 +574,7 @@ static void test_parent_owner(void) /* owned top-level popup */ owner = create_tool_window( 0, 0 ); test = create_tool_window( WS_POPUP, owner ); - trace( "created owner %p and popup %p\n", owner, test ); + if (winetest_debug > 1) trace( "created owner %p and popup %p\n", owner, test ); check_parents( test, desktop, owner, owner, owner, test, owner ); DestroyWindow( owner ); ok( !IsWindow(test), "Window %p not destroyed by owner destruction\n", test ); @@ -563,7 +582,7 @@ static void test_parent_owner(void) /* top-level popup owned by child */ owner = create_tool_window( WS_CHILD, hwndMain2 ); test = create_tool_window( WS_POPUP, 0 ); - trace( "created owner %p and popup %p\n", owner, test ); + if (winetest_debug > 1) trace( "created owner %p and popup %p\n", owner, test ); ret = (HWND)SetWindowLongPtrA( test, GWLP_HWNDPARENT, (ULONG_PTR)owner ); ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0\n", ret ); check_parents( test, desktop, owner, owner, owner, test, hwndMain2 ); @@ -686,15 +705,12 @@ static DWORD CALLBACK enum_thread( void *arg ) GUITHREADINFO info; info.cbSize = sizeof(info); ret = pGetGUIThreadInfo( GetCurrentThreadId(), &info ); - ok( ret || broken(!ret), /* win9x */ - "GetGUIThreadInfo failed without message queue\n" ); + ok( ret, "GetGUIThreadInfo failed without message queue\n" ); SetLastError( 0xdeadbeef ); info.cbSize = sizeof(info) + 1; ret = pGetGUIThreadInfo( GetCurrentThreadId(), &info ); ok( !ret, "GetGUIThreadInfo succeeded with wrong size\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER || - broken(GetLastError() == 0xdeadbeef), /* win9x */ - "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); } PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ); /* make sure we have a message queue */ @@ -739,9 +755,279 @@ static void test_enum_thread_windows(void) CloseHandle( handle ); } +struct test_thread_exit_parent_params +{ + HWND hwnd; + HANDLE created_event; + HANDLE stop_event; +}; + +static DWORD CALLBACK test_thread_exit_parent_thread( void *args ) +{ + struct test_thread_exit_parent_params *params = args; + DWORD ret; + MSG msg; + + params->hwnd = CreateWindowW( L"static", L"parent", WS_OVERLAPPEDWINDOW|WS_VISIBLE, + 100, 100, 200, 200, 0, 0, 0, NULL ); + ok( params->hwnd != 0, "CreateWindowExW failed, error %lu\n", GetLastError() ); + flush_events( TRUE ); + SetEvent( params->created_event ); + + do + { + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + ret = MsgWaitForMultipleObjects( 1, ¶ms->stop_event, FALSE, INFINITE, QS_ALLINPUT ); + } + while (ret != WAIT_OBJECT_0); + + return 0; +} + +static LRESULT CALLBACK test_thread_exit_wnd_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) +{ + if (msg == WM_USER) return 0xdeadbeef; + if (msg == WM_USER + 1) return 0xfeedcafe; + return DefWindowProcW( hwnd, msg, wp, lp ); +} + +static void test_thread_exit_destroy(void) +{ + struct test_thread_exit_parent_params params; + HWND adopter, child1, child2, child3, child; + WNDPROC old_wndproc, wndproc; + WCHAR buffer[MAX_PATH]; + HANDLE thread; + DWORD ret; + HRGN rgn; + HWND tmp; + MSG msg; + + params.created_event = CreateEventW( NULL, FALSE, FALSE, NULL ); + params.stop_event = CreateEventW( NULL, FALSE, FALSE, NULL ); + + adopter = CreateWindowW( L"static", L"adopter", WS_OVERLAPPEDWINDOW|WS_VISIBLE, + 300, 100, 200, 200, 0, 0, 0, NULL ); + ok( adopter != 0, "CreateWindowExW failed, error %lu\n", GetLastError() ); + flush_events( TRUE ); + + thread = CreateThread( NULL, 0, test_thread_exit_parent_thread, ¶ms, 0, NULL ); + ok( thread != 0, "CreateThread failed, error %lu\n", GetLastError() ); + WaitForSingleObject( params.created_event, INFINITE ); + + child1 = CreateWindowW( L"static", L"child1", WS_CHILD|WS_VISIBLE, + 50, 50, 50, 50, params.hwnd, 0, 0, NULL ); + ok( child1 != 0, "CreateWindowExW failed, error %lu\n", GetLastError() ); + child2 = CreateWindowW( L"static", L"child2", WS_CHILD|WS_VISIBLE, + 100, 50, 50, 50, params.hwnd, 0, 0, NULL ); + ok( child2 != 0, "CreateWindowExW failed, error %lu\n", GetLastError() ); + child3 = CreateWindowW( L"static", L"child3", WS_CHILD|WS_VISIBLE, + 50, 100, 50, 50, params.hwnd, 0, 0, NULL ); + ok( child3 != 0, "CreateWindowExW failed, error %lu\n", GetLastError() ); + flush_events( TRUE ); + + trace("parent %p adopter %p child1 %p child2 %p child3 %p\n", params.hwnd, adopter, child1, child2, child3); + + SetActiveWindow( child1 ); + SetFocus( child1 ); + SetCapture( child1 ); + + ok( GetActiveWindow() == params.hwnd, "GetActiveWindow %p, expected %p\n", GetActiveWindow(), params.hwnd ); + ok( GetFocus() == child1, "GetFocus %p, expected %p\n", GetFocus(), child1 ); + ok( GetCapture() == child1, "GetCapture %p, expected %p\n", GetCapture(), child1 ); + + ret = SetPropW( child1, L"myprop", UlongToHandle(0xdeadbeef) ); + ok( ret, "SetPropW failed, error %lu\n", GetLastError() ); + ret = SetPropW( child2, L"myprop", UlongToHandle(0xdeadbeef) ); + ok( ret, "SetPropW failed, error %lu\n", GetLastError() ); + + old_wndproc = (WNDPROC)GetWindowLongPtrW( child1, GWLP_WNDPROC ); + ok( old_wndproc != NULL, "GetWindowLongPtrW GWLP_WNDPROC failed, error %lu\n", GetLastError() ); + + ret = GetWindowLongW( child1, GWL_STYLE ); + ok( ret == (WS_CHILD|WS_VISIBLE), "GetWindowLongW returned %#lx\n", ret ); + + SetEvent( params.stop_event ); + ret = WaitForSingleObject( thread, INFINITE ); + ok( ret == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", ret ); + CloseHandle( thread ); + + /* child windows should all still be alive but hidden */ + ret = IsWindow( child1 ); + ok( ret, "IsWindow returned %lu\n", ret ); + ret = IsWindow( child2 ); + ok( ret, "IsWindow returned %lu\n", ret ); + ret = IsWindow( child3 ); + ok( ret, "IsWindow returned %lu\n", ret ); + + todo_wine + ok( GetActiveWindow() == adopter, "GetActiveWindow %p, expected %p\n", GetActiveWindow(), adopter ); + todo_wine + ok( GetFocus() == adopter, "GetFocus %p, expected %p\n", GetFocus(), adopter ); + ok( GetCapture() == child1, "GetCapture %p, expected %p\n", GetCapture(), child1 ); + + SetActiveWindow( child1 ); + SetFocus( child1 ); + SetCapture( child1 ); + + todo_wine + ok( GetActiveWindow() == adopter, "GetActiveWindow %p, expected %p\n", GetActiveWindow(), adopter ); + todo_wine + ok( GetFocus() == adopter, "GetFocus %p, expected %p\n", GetFocus(), adopter ); + ok( GetCapture() == child1, "GetCapture %p, expected %p\n", GetCapture(), child1 ); + + SetLastError( 0xdeadbeef ); + ret = GetWindowLongW( child1, GWL_STYLE ); + todo_wine + ok( ret == WS_CHILD, "GetWindowLongW returned %#lx\n", ret ); + ok( GetLastError() == 0xdeadbeef, "GetWindowLongW error %lu\n", GetLastError() ); + ret = SetWindowLongW( child1, GWL_STYLE, WS_CHILD|WS_VISIBLE ); + ok( ret, "SetWindowLongW failed, error %lu\n", GetLastError() ); + ret = GetWindowLongW( child1, GWL_STYLE ); + ok( ret == (WS_CHILD|WS_VISIBLE), "GetWindowLongW returned %#lx\n", ret ); + + /* and cannot be adopted */ + SetLastError( 0xdeadbeef ); + tmp = GetParent( child1 ); + ok( tmp == params.hwnd, "GetParent returned %p, error %lu\n", tmp, GetLastError() ); + ok( GetLastError() == 0xdeadbeef, "GetWindowLongW error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + tmp = SetParent( child1, adopter ); + ok( tmp == 0, "SetParent returned %p\n", tmp ); +#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 ); + tmp = SetParent( child3, adopter ); + ok( tmp == 0, "SetParent returned %p\n", tmp ); +#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 ); + tmp = GetParent( child1 ); + ok( tmp == params.hwnd, "GetParent returned %p, error %lu\n", tmp, GetLastError() ); + ok( GetLastError() == 0xdeadbeef, "GetWindowLongW error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + ret = GetWindowLongW( params.hwnd, GWL_STYLE ); + ok( ret == 0, "GetWindowLongW returned %#lx\n", ret ); + ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "GetWindowLongW error %lu\n", GetLastError() ); + + wndproc = (WNDPROC)GetWindowLongPtrW( child1, GWLP_WNDPROC ); + ok( wndproc != NULL, "GetWindowLongPtrW GWLP_WNDPROC failed, error %lu\n", GetLastError() ); + ok( wndproc == old_wndproc, "GetWindowLongPtrW GWLP_WNDPROC returned %p\n", wndproc ); + + tmp = GetPropW( child1, L"myprop" ); + ok( HandleToULong(tmp) == 0xdeadbeef, "GetPropW returned %p\n", tmp ); + tmp = GetPropW( child2, L"myprop" ); + ok( HandleToULong(tmp) == 0xdeadbeef, "GetPropW returned %p\n", tmp ); + + child = CreateWindowExA( 0, "ToolWindowClass", "Tool window 1", WS_CHILD, + 0, 0, 100, 100, child1, 0, 0, NULL ); +#ifdef __REACTOS__ + ok( GetLastError() == ERROR_INVALID_PARAMETER /* MSVC test builds return child, GCC test builds don't on Windows */ + || broken(child && GetLastError() == ERROR_SUCCESS) /* WS03 */, + "CreateWindowExA returned %p %lu\n", child, GetLastError() ); +#else + ok( !child && GetLastError() == ERROR_INVALID_PARAMETER, + "CreateWindowExA returned %p %lu\n", child, GetLastError() ); +#endif + + ret = MoveWindow( child1, 5, 5, 10, 10, FALSE ); + ok( ret, "MoveWindow failed: %lu\n", GetLastError() ); + + /* destroying child1 ourselves succeeds */ + ret = DestroyWindow( child1 ); + ok( ret, "DestroyWindow returned %lu\n", ret ); + ret = DestroyWindow( child1 ); + ok( !ret, "DestroyWindow returned %lu\n", ret ); + ret = IsWindow( child1 ); + ok( !ret, "IsWindow returned %lu\n", ret ); + + tmp = GetPropW( child1, L"myprop" ); + ok( HandleToULong(tmp) == 0, "GetPropW returned %p\n", tmp ); + + /* child2 is still alive, for now */ + ret = IsWindow( child2 ); + ok( ret, "IsWindow returned %lu\n", ret ); + + SetLastError( 0xdeadbeef ); + ret = SetWindowPos( child2, HWND_TOPMOST, 0, 0, 100, 100, SWP_NOSIZE|SWP_NOMOVE ); + todo_wine +#ifdef __REACTOS__ + ok( !ret || broken(ret) /* WS03 */, "SetWindowPos succeeded\n" ); +#else + ok( !ret, "SetWindowPos succeeded\n" ); +#endif + todo_wine +#ifdef __REACTOS__ + ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef) /* WS03 */, "SetWindowPos returned error %lu\n", GetLastError() ); +#else + ok( GetLastError() == ERROR_INVALID_PARAMETER, "SetWindowPos returned error %lu\n", GetLastError() ); +#endif + SetLastError( 0xdeadbeef ); + ret = SetWindowPos( child2, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE ); + todo_wine +#ifdef __REACTOS__ + ok( !ret || broken(ret) /* WS03 */, "SetWindowPos succeeded\n" ); +#else + ok( !ret, "SetWindowPos succeeded\n" ); +#endif + todo_wine +#ifdef __REACTOS__ + ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef) /* WS03 */, "SetWindowPos returned error %lu\n", GetLastError() ); +#else + ok( GetLastError() == ERROR_INVALID_PARAMETER, "SetWindowPos returned error %lu\n", GetLastError() ); +#endif + + rgn = CreateRectRgn( 5, 5, 15, 15 ); + SetLastError( 0xdeadbeef ); + ret = SetWindowRgn( child2, rgn, TRUE ); + ok( ret, "SetWindowRgn failed, error %lu\n", GetLastError() ); + DeleteObject( rgn ); + + wndproc = (WNDPROC)SetWindowLongPtrW( child2, GWLP_WNDPROC, (LONG_PTR)test_thread_exit_wnd_proc ); + ret = SendMessageW( child2, WM_USER, 0, 0 ); + ok( ret == 0xdeadbeef, "SendMessageW returned %lu, error %lu\n", ret, GetLastError() ); + ret = SendMessageW( child2, WM_USER + 1, 0, 0 ); + ok( ret == 0xfeedcafe, "SendMessageW returned %lu, error %lu\n", ret, GetLastError() ); + ret = SendMessageW( child2, WM_USER + 2, 0, 0 ); + ok( ret == 0, "SendMessageW returned %lu, error %lu\n", ret, GetLastError() ); + + ret = GetWindowTextW( child2, buffer, ARRAY_SIZE(buffer) ); + ok( ret == 6, "GetWindowTextW returned %lu\n", ret ); + ok( !wcscmp( buffer, L"child2" ), "GetWindowTextW returned %s\n", debugstr_w( buffer ) ); + ret = IsWindow( child2 ); + ok( ret, "IsWindow returned %lu\n", ret ); + + /* but peeking any message should reap them all */ + PeekMessageW( &msg, child2, 0, 0, PM_REMOVE ); + + tmp = GetPropW( child2, L"myprop" ); + ok( HandleToULong(tmp) == 0, "GetPropW returned %p\n", tmp ); + + ret = IsWindow( child2 ); + ok( !ret, "IsWindow returned %lu\n", ret ); + ret = IsWindow( child3 ); + todo_wine + ok( !ret, "IsWindow returned %lu\n", ret ); + ret = DestroyWindow( child2 ); + ok( !ret, "DestroyWindow returned %lu\n", ret ); + + DestroyWindow( adopter ); + + CloseHandle( params.created_event ); + CloseHandle( params.stop_event ); +} + static struct wm_gettext_override_data { BOOL enabled; /* when 1 bypasses default procedure */ + BOOL dont_terminate; /* don't null terminate returned string in WM_GETTEXT handler */ char *buff; /* expected text buffer pointer */ WCHAR *buffW; /* same, for W test */ } g_wm_gettext_override; @@ -763,8 +1049,7 @@ static LRESULT WINAPI main_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPAR ok(winpos->x >= -32768 && winpos->x <= 32767, "bad winpos->x %d\n", winpos->x); ok(winpos->y >= -32768 && winpos->y <= 32767, "bad winpos->y %d\n", winpos->y); } - /* Win9x does not fixup cx/xy for WM_WINDOWPOSCHANGING */ - if (!(winpos->flags & SWP_NOSIZE) && !is_win9x) + if (!(winpos->flags & SWP_NOSIZE)) { ok((winpos->cx >= 0 && winpos->cx <= 32767) || winpos->cx == 32768, /* win7 doesn't truncate */ @@ -776,8 +1061,8 @@ static LRESULT WINAPI main_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPAR break; } case WM_WINDOWPOSCHANGED: - disable_success_count { + LRESULT ret; RECT rc1, rc2; WINDOWPOS *winpos = (WINDOWPOS *)lparam; ok(winpos->x >= -32768 && winpos->x <= 32767, "bad winpos->x %d\n", winpos->x); @@ -793,19 +1078,16 @@ static LRESULT WINAPI main_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPAR GetWindowRect(hwnd, &rc1); SetRect(&rc2, winpos->x, winpos->y, winpos->x + winpos->cx, winpos->y + winpos->cy); /* note: winpos coordinates are relative to parent */ - MapWindowPoints(GetParent(hwnd), 0, (LPPOINT)&rc2, 2); - if (0) - { - /* Uncomment this once the test succeeds in all cases */ + MapWindowPoints(GetAncestor(hwnd,GA_PARENT), 0, (LPPOINT)&rc2, 2); ok(EqualRect(&rc1, &rc2), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc1), wine_dbgstr_rect(&rc2)); GetClientRect(hwnd, &rc2); - DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc1); + ret = DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc1); + ok(!ret, "got %08Ix\n", ret); MapWindowPoints(0, hwnd, (LPPOINT)&rc1, 2); ok(EqualRect(&rc1, &rc2), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc1), wine_dbgstr_rect(&rc2)); - } break; } case WM_NCCREATE: @@ -835,6 +1117,16 @@ static LRESULT WINAPI main_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPAR ok(*text == 0, "expected empty string buffer %x\n", *text); return 0; } + else if (g_wm_gettext_override.dont_terminate) + { + char *text = (char *)lparam; + if (text) + { + memcpy(text, "text", 4); + return 4; + } + return 0; + } break; case WM_SETTEXT: num_settext_msgs++; @@ -843,6 +1135,15 @@ static LRESULT WINAPI main_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPAR if (wparam) app_activated = TRUE; else app_deactivated = TRUE; break; + case WM_MOUSEACTIVATE: + return MA_ACTIVATE; + + case WM_NCCALCSIZE: + { + LRESULT ret = DefWindowProcA(hwnd, WM_NCCALCSIZE, wparam, lparam); + ok(!ret, "got %08Ix (%08Ix %08Ix)\n", ret, wparam, lparam); + return ret; + } } return DefWindowProcA(hwnd, msg, wparam, lparam); @@ -861,7 +1162,25 @@ static LRESULT WINAPI main_window_procW(HWND hwnd, UINT msg, WPARAM wparam, LPAR ok(*text == 0, "expected empty string buffer %x\n", *text); return 0; } + else if (g_wm_gettext_override.dont_terminate) + { + static const WCHAR textW[] = {'t','e','x','t'}; + WCHAR *text = (WCHAR *)lparam; + if (text) + { + memcpy(text, textW, sizeof(textW)); + return 4; + } + return 0; + } break; + + case WM_NCCALCSIZE: + { + LRESULT ret = DefWindowProcA(hwnd, WM_NCCALCSIZE, wparam, lparam); + ok(!ret, "got %08Ix (%08Ix %08Ix)\n", ret, wparam, lparam); + return ret; + } } return DefWindowProcA(hwnd, msg, wparam, lparam); @@ -887,6 +1206,13 @@ static LRESULT WINAPI tool_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPAR ok(!got_getminmaxinfo, "tool: WM_GETMINMAXINFO should NOT have been received before WM_NCCREATE\n"); break; } + + case WM_NCCALCSIZE: + { + LRESULT ret = DefWindowProcA(hwnd, WM_NCCALCSIZE, wparam, lparam); + ok(!ret, "got %08Ix (%08Ix %08Ix)\n", ret, wparam, lparam); + return ret; + } } return DefWindowProcA(hwnd, msg, wparam, lparam); @@ -957,20 +1283,18 @@ static void verify_window_info(const char *hook, HWND hwnd, const WINDOWINFO *in ok(EqualRect(&rcClient, &info->rcClient), "wrong rcClient for %p in hook %s\n", hwnd, hook); ok(info->dwStyle == (DWORD)GetWindowLongA(hwnd, GWL_STYLE), - "wrong dwStyle: %08x != %08x for %p in hook %s\n", + "wrong dwStyle: %08lx != %08lx for %p in hook %s\n", info->dwStyle, GetWindowLongA(hwnd, GWL_STYLE), hwnd, hook); /* Windows reports some undocumented exstyles in WINDOWINFO, but * doesn't return them in GetWindowLong(hwnd, GWL_EXSTYLE). */ ok((info->dwExStyle & ~0xe0000800) == (DWORD)GetWindowLongA(hwnd, GWL_EXSTYLE), - "wrong dwExStyle: %08x != %08x for %p in hook %s\n", + "wrong dwExStyle: %08lx != %08lx for %p in hook %s\n", info->dwExStyle, GetWindowLongA(hwnd, GWL_EXSTYLE), hwnd, hook); status = (GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0; if (GetForegroundWindow()) - ok(info->dwWindowStatus == status, "wrong dwWindowStatus: %04x != %04x active %p fg %p in hook %s\n", + ok(info->dwWindowStatus == status, "wrong dwWindowStatus: %04lx != %04lx active %p fg %p in hook %s\n", info->dwWindowStatus, status, GetActiveWindow(), GetForegroundWindow(), hook); - else - ok(1, "Just counting"); /* win2k and XP return broken border info in GetWindowInfo most of * the time, so there is no point in testing it. @@ -979,7 +1303,7 @@ if (0) { UINT border; ok(info->cxWindowBorders == (unsigned)(rcClient.left - rcWindow.left), - "wrong cxWindowBorders %d != %d\n", info->cxWindowBorders, rcClient.left - rcWindow.left); + "wrong cxWindowBorders %d != %ld\n", info->cxWindowBorders, rcClient.left - rcWindow.left); border = min(rcWindow.bottom - rcClient.bottom, rcClient.top - rcWindow.top); ok(info->cyWindowBorders == border, "wrong cyWindowBorders %d != %d\n", info->cyWindowBorders, border); @@ -991,6 +1315,61 @@ if (0) "wrong wCreatorVersion %04x for %p in hook %s\n", info->wCreatorVersion, hwnd, hook); } +static void test_window_info(const char *hook, HWND hwnd) +{ + WINDOWINFO info, info2; + + if (0) /* crashes on Win10 */ + ok(!pGetWindowInfo(hwnd, NULL), "GetWindowInfo should fail\n"); + + if (0) { /* crashes on XP, 2003 */ + SetLastError(0xdeadbeef); + ok(!pGetWindowInfo(0, NULL), "GetWindowInfo should fail\n"); + ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, + "got error %ld expected ERROR_INVALID_WINDOW_HANDLE\n", GetLastError()); + } + + SetLastError(0xdeadbeef); + ok(!pGetWindowInfo(0, &info), "GetWindowInfo should fail\n"); + ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, + "got error %ld expected ERROR_INVALID_WINDOW_HANDLE\n", GetLastError()); + + info.cbSize = sizeof(WINDOWINFO); + ok(pGetWindowInfo(hwnd, &info), "GetWindowInfo should not fail\n"); + verify_window_info(hook, hwnd, &info); + + /* test different cbSize values. + * Windows ignores it (except for Win98, according to an old comment). + */ + memset(&info, 0xcc, sizeof(WINDOWINFO)); + memset(&info2, 0xcc, sizeof(WINDOWINFO)); + + info.cbSize = sizeof(WINDOWINFO); + info2.cbSize = sizeof(WINDOWINFO); + + ok(pGetWindowInfo(hwnd, &info), "GetWindowInfo should not fail\n"); + ok(pGetWindowInfo(hwnd, &info2), "GetWindowInfo should not fail\n"); + ok(memcmp(&info, &info2, sizeof(WINDOWINFO)) == 0, "identical GetWindowInfo calls produce different result\n"); + + memset(&info2, 0xcc, sizeof(WINDOWINFO)); + info2.cbSize = 0; + ok(pGetWindowInfo(hwnd, &info2), "GetWindowInfo should not fail\n"); + info2.cbSize = sizeof(WINDOWINFO); + ok(memcmp(&info, &info2, sizeof(WINDOWINFO)) == 0, "GetWindowInfo cbSize should be ignored\n"); + + memset(&info2, 0xcc, sizeof(WINDOWINFO)); + info2.cbSize = sizeof(WINDOWINFO)/2; + ok(pGetWindowInfo(hwnd, &info2), "GetWindowInfo should not fail\n"); + info2.cbSize = sizeof(WINDOWINFO); + ok(memcmp(&info, &info2, sizeof(WINDOWINFO)) == 0, "GetWindowInfo cbSize should be ignored\n"); + + memset(&info2, 0xcc, sizeof(WINDOWINFO)); + info2.cbSize = UINT_MAX; + ok(pGetWindowInfo(hwnd, &info2), "GetWindowInfo should not fail\n"); + info2.cbSize = sizeof(WINDOWINFO); + ok(memcmp(&info, &info2, sizeof(WINDOWINFO)) == 0, "GetWindowInfo cbSize should be ignored\n"); +} + static void FixedAdjustWindowRectEx(RECT* rc, LONG style, BOOL menu, LONG exstyle) { AdjustWindowRectEx(rc, style, menu, exstyle); @@ -1009,23 +1388,19 @@ static void FixedAdjustWindowRectEx(RECT* rc, LONG style, BOOL menu, LONG exstyl /* reimplement it to check that the Wine algorithm gives the correct result */ static void wine_AdjustWindowRectEx( RECT *rect, LONG style, BOOL menu, LONG exStyle ) { - int adjust; + NONCLIENTMETRICSW ncm; + int adjust = 0; - if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == - WS_EX_STATICEDGE) - { + ncm.cbSize = offsetof( NONCLIENTMETRICSW, iPaddedBorderWidth ); + SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 ); + + if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) adjust = 1; /* for the outer frame always present */ - } - else - { - adjust = 0; - if ((exStyle & WS_EX_DLGMODALFRAME) || - (style & (WS_THICKFRAME|WS_DLGFRAME))) adjust = 2; /* outer */ - } - if (style & WS_THICKFRAME) - adjust += GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME); /* The resize border */ - if ((style & (WS_BORDER|WS_DLGFRAME)) || - (exStyle & WS_EX_DLGMODALFRAME)) + else if ((exStyle & WS_EX_DLGMODALFRAME) || (style & (WS_THICKFRAME|WS_DLGFRAME))) + adjust = 2; /* outer */ + + if (style & WS_THICKFRAME) adjust += ncm.iBorderWidth; /* The resize border */ + if ((style & (WS_BORDER|WS_DLGFRAME)) || (exStyle & WS_EX_DLGMODALFRAME)) adjust++; /* The other border */ InflateRect (rect, adjust, adjust); @@ -1033,11 +1408,11 @@ static void wine_AdjustWindowRectEx( RECT *rect, LONG style, BOOL menu, LONG exS if ((style & WS_CAPTION) == WS_CAPTION) { if (exStyle & WS_EX_TOOLWINDOW) - rect->top -= GetSystemMetrics(SM_CYSMCAPTION); + rect->top -= ncm.iSmCaptionHeight + 1; else - rect->top -= GetSystemMetrics(SM_CYCAPTION); + rect->top -= ncm.iCaptionHeight + 1; } - if (menu) rect->top -= GetSystemMetrics(SM_CYMENU); + if (menu) rect->top -= ncm.iMenuHeight + 1; if (exStyle & WS_EX_CLIENTEDGE) InflateRect(rect, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE)); @@ -1052,12 +1427,83 @@ static void wine_AdjustWindowRectEx( RECT *rect, LONG style, BOOL menu, LONG exS if (style & WS_HSCROLL) rect->bottom += GetSystemMetrics(SM_CYHSCROLL); } +static void wine_AdjustWindowRectExForDpi( RECT *rect, LONG style, BOOL menu, LONG exStyle, UINT dpi ) +{ + NONCLIENTMETRICSW ncm; + int adjust = 0; + + ncm.cbSize = sizeof(ncm); + pSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0, dpi ); + + if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) + adjust = 1; /* for the outer frame always present */ + else if ((exStyle & WS_EX_DLGMODALFRAME) || (style & (WS_THICKFRAME|WS_DLGFRAME))) + adjust = 2; /* outer */ + + if (style & WS_THICKFRAME) adjust += ncm.iBorderWidth + ncm.iPaddedBorderWidth; + + if ((style & (WS_BORDER|WS_DLGFRAME)) || (exStyle & WS_EX_DLGMODALFRAME)) + adjust++; /* The other border */ + + InflateRect (rect, adjust, adjust); + + if ((style & WS_CAPTION) == WS_CAPTION) + { + if (exStyle & WS_EX_TOOLWINDOW) + rect->top -= ncm.iSmCaptionHeight + 1; + else + rect->top -= ncm.iCaptionHeight + 1; + } + if (menu) rect->top -= ncm.iMenuHeight + 1; + + if (exStyle & WS_EX_CLIENTEDGE) + InflateRect(rect, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE)); +} + +static int offset; + +static LRESULT CALLBACK test_standard_scrollbar_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) +{ + switch (msg) + { + case WM_NCPAINT: + { + HRGN region; + RECT rect; + + GetWindowRect(hwnd, &rect); + region = CreateRectRgn(rect.left, rect.top, rect.right, rect.bottom - offset); + DefWindowProcA(hwnd, msg, (WPARAM)region, lp); + DeleteObject(region); + return 0; + } + + case WM_NCCALCSIZE: + { + LRESULT ret = DefWindowProcA(hwnd, WM_NCCALCSIZE, wp, lp); + ok(!ret, "got %08Ix (%08Ix %08Ix)\n", ret, wp, lp); + return ret; + } + + default: + return DefWindowProcA(hwnd, msg, wp, lp); + } +} + static void test_nonclient_area(HWND hwnd) { + BOOL (WINAPI *pIsThemeActive)(void); + POINT point, old_cursor_pos; + COLORREF color, old_color; + BOOL is_theme_active; DWORD style, exstyle; RECT rc_window, rc_client, rc; + HWND child, parent; + HMODULE uxtheme; + WNDCLASSA cls; BOOL menu; LRESULT ret; + HDC hdc; style = GetWindowLongA(hwnd, GWL_STYLE); exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE); @@ -1075,31 +1521,28 @@ static void test_nonclient_area(HWND hwnd) FixedAdjustWindowRectEx(&rc, style, menu, exstyle); ok(EqualRect(&rc, &rc_window), - "window rect does not match: style:exstyle=0x%08x:0x%08x, menu=%d, win=%s, calc=%s\n", + "window rect does not match: style:exstyle=0x%08lx:0x%08lx, menu=%d, win=%s, calc=%s\n", style, exstyle, menu, wine_dbgstr_rect(&rc_window), wine_dbgstr_rect(&rc)); rc = rc_client; MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2); wine_AdjustWindowRectEx(&rc, style, menu, exstyle); ok(EqualRect(&rc, &rc_window), - "window rect does not match: style:exstyle=0x%08x:0x%08x, menu=%d, win=%s, calc=%s\n", + "window rect does not match: style:exstyle=0x%08lx:0x%08lx, menu=%d, win=%s, calc=%s\n", style, exstyle, menu, wine_dbgstr_rect(&rc_window), wine_dbgstr_rect(&rc)); rc = rc_window; - DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc); + ret = DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc); + ok(!ret, "got %08Ix\n", ret); MapWindowPoints(0, hwnd, (LPPOINT)&rc, 2); ok(EqualRect(&rc, &rc_client), - "client rect does not match: style:exstyle=0x%08x:0x%08x, menu=%d client=%s, calc=%s\n", + "client rect does not match: style:exstyle=0x%08lx:0x%08lx, menu=%d client=%s, calc=%s\n", style, exstyle, menu, wine_dbgstr_rect(&rc_client), wine_dbgstr_rect(&rc)); /* NULL rectangle shouldn't crash */ ret = DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, 0); - ok(ret == 0, "NULL rectangle returned %ld instead of 0\n", ret); - - /* Win9x doesn't like WM_NCCALCSIZE with synthetic data and crashes */; - if (is_win9x) - return; + ok(ret == 0, "NULL rectangle returned %Id instead of 0\n", ret); /* and now test AdjustWindowRectEx and WM_NCCALCSIZE on synthetic data */ SetRect(&rc_client, 0, 0, 250, 150); @@ -1108,11 +1551,103 @@ static void test_nonclient_area(HWND hwnd) FixedAdjustWindowRectEx(&rc_window, style, menu, exstyle); rc = rc_window; - DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc); + ret = DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc); + ok(!ret, "got %08Ix\n", ret); MapWindowPoints(0, hwnd, (LPPOINT)&rc, 2); ok(EqualRect(&rc, &rc_client), - "synthetic rect does not match: style:exstyle=0x%08x:0x%08x, menu=%d, client=%s, calc=%s\n", + "synthetic rect does not match: style:exstyle=0x%08lx:0x%08lx, menu=%d, client=%s, calc=%s\n", style, exstyle, menu, wine_dbgstr_rect(&rc_client), wine_dbgstr_rect(&rc)); + + /* Test standard scroll bars */ + uxtheme = LoadLibraryA("uxtheme.dll"); + ok(!!uxtheme, "Failed to load uxtheme.dll, error %lu.\n", GetLastError()); + pIsThemeActive = (void *)GetProcAddress(uxtheme, "IsThemeActive"); + ok(!!pIsThemeActive, "Failed to load IsThemeActive, error %lu.\n", GetLastError()); + is_theme_active = pIsThemeActive(); + + memset(&cls, 0, sizeof(cls)); + cls.lpfnWndProc = DefWindowProcA; + cls.hInstance = GetModuleHandleA(0); + cls.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW); + cls.hbrBackground = GetStockObject(LTGRAY_BRUSH); + cls.lpszClassName = "TestStandardScrollbarParentClass"; + RegisterClassA(&cls); + + cls.lpfnWndProc = test_standard_scrollbar_proc; + cls.hbrBackground = GetStockObject(GRAY_BRUSH); + cls.lpszClassName = "TestStandardScrollbarClass"; + RegisterClassA(&cls); + + parent = CreateWindowA("TestStandardScrollbarParentClass", "parent", WS_POPUP | WS_VISIBLE, 100, + 100, 100, 100, NULL, NULL, 0, NULL); + ok(!!parent, "Failed to create a parent window, error %lu.\n", GetLastError()); + GetCursorPos(&old_cursor_pos); + + /* Place the cursor on the standard scroll bar arrow button when not painting it at all. + * Expects the standard scroll bar not to appear before and after the cursor position change */ + offset = GetSystemMetrics(SM_CYHSCROLL); + child = CreateWindowA("TestStandardScrollbarClass", "test", WS_CHILD | WS_HSCROLL | WS_VISIBLE, + 0, 0, 50, 50, parent, NULL, 0, NULL); + ok(!!child, "Failed to create a test window, error %lu.\n", GetLastError()); + hdc = GetDC(parent); + ok(!!hdc, "GetDC failed, error %ld.\n", GetLastError()); + + SetCursorPos(0, 0); + flush_events(TRUE); + RedrawWindow(child, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ERASENOW | RDW_FRAME); + old_color = GetPixel(hdc, 50 - GetSystemMetrics(SM_CXVSCROLL) / 2, + 50 - GetSystemMetrics(SM_CYHSCROLL) / 2); + ok(old_color == 0xc0c0c0, "Expected color %#x, got %#lx.\n", 0xc0c0c0, old_color); + + point.x = 50 - GetSystemMetrics(SM_CXVSCROLL) / 2; + point.y = 50 - GetSystemMetrics(SM_CYHSCROLL) / 2; + ClientToScreen(child, &point); + SetCursorPos(point.x, point.y); + flush_events(TRUE); + RedrawWindow(child, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ERASENOW | RDW_FRAME); + color = GetPixel(hdc, 50 - GetSystemMetrics(SM_CXVSCROLL) / 2, + 50 - GetSystemMetrics(SM_CYHSCROLL) / 2); + ok(color == old_color, "Expected color %#lx, got %#lx.\n", old_color, color); + + ReleaseDC(parent, hdc); + DestroyWindow(child); + + /* Place the cursor on standard scroll bar arrow button when painting 1 pixel of the scroll bar. + * Expects the scroll bar to appear after the cursor position change */ + offset = GetSystemMetrics(SM_CYHSCROLL) - 1; + child = CreateWindowA("TestStandardScrollbarClass", "test", WS_CHILD | WS_HSCROLL | WS_VISIBLE, + 0, 0, 50, 50, parent, NULL, 0, NULL); + ok(!!child, "Failed to create a test window, error %lu.\n", GetLastError()); + hdc = GetDC(parent); + ok(!!hdc, "GetDC failed, error %ld.\n", GetLastError()); + + SetCursorPos(0, 0); + flush_events(TRUE); + RedrawWindow(child, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ERASENOW | RDW_FRAME); + old_color = GetPixel(hdc, 50 - GetSystemMetrics(SM_CXVSCROLL) / 2, + 50 - GetSystemMetrics(SM_CYHSCROLL) / 2); + + point.x = 50 - GetSystemMetrics(SM_CXVSCROLL) / 2; + point.y = 50 - GetSystemMetrics(SM_CYHSCROLL) / 2; + ClientToScreen(child, &point); + SetCursorPos(point.x, point.y); + flush_events(TRUE); + RedrawWindow(child, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ERASENOW | RDW_FRAME); + color = GetPixel(hdc, 50 - GetSystemMetrics(SM_CXVSCROLL) / 2, + 50 - GetSystemMetrics(SM_CYHSCROLL) / 2); + if (is_theme_active) + ok(color != old_color || broken(color == old_color), /* Win 10 1507 64-bit */ + "Got unexpected color %#lx.\n", color); + else + todo_wine + ok(color == old_color, "Expected color %#lx, got %#lx.\n", old_color, color); + + SetCursorPos(old_cursor_pos.x, old_cursor_pos.y); + ReleaseDC(parent, hdc); + DestroyWindow(parent); + UnregisterClassA("TestStandardScrollbarClass", GetModuleHandleA(0)); + UnregisterClassA("TestStandardScrollbarParentClass", GetModuleHandleA(0)); + FreeLibrary(uxtheme); } static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) @@ -1142,18 +1677,13 @@ static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) ok(createwnd->hwndInsertAfter == HWND_TOP, "hwndInsertAfter should be always HWND_TOP\n"); if (pGetWindowInfo) - { - WINDOWINFO info; - info.cbSize = sizeof(WINDOWINFO); - ok(pGetWindowInfo(hwnd, &info), "GetWindowInfo should not fail\n"); - verify_window_info(code_name, hwnd, &info); - } + test_window_info(code_name, hwnd); /* WS_VISIBLE should be turned off yet */ style = createwnd->lpcs->style & ~WS_VISIBLE; - ok(style == GetWindowLongA(hwnd, GWL_STYLE), - "style of hwnd and style in the CREATESTRUCT do not match: %08x != %08x\n", - GetWindowLongA(hwnd, GWL_STYLE), style); + ok(style == GetWindowLongA(hwnd, GWL_STYLE), + "style of hwnd and style in the CREATESTRUCT do not match: %08lx != %08lx\n", + GetWindowLongA(hwnd, GWL_STYLE), style); if (0) { @@ -1183,19 +1713,16 @@ static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) if (0) { /* Uncomment this once the test succeeds in all cases */ - if (pGetAncestor) - { - ok(pGetAncestor(hwnd, GA_PARENT) == hwndMessage, "GA_PARENT should be set to hwndMessage at this point\n"); - ok(pGetAncestor(hwnd, GA_ROOT) == hwnd, - "GA_ROOT is set to %p, expected %p\n", pGetAncestor(hwnd, GA_ROOT), hwnd); + ok(GetAncestor(hwnd, GA_PARENT) == hwndMessage, "GA_PARENT should be set to hwndMessage at this point\n"); + ok(GetAncestor(hwnd, GA_ROOT) == hwnd, + "GA_ROOT is set to %p, expected %p\n", GetAncestor(hwnd, GA_ROOT), hwnd); if ((style & (WS_CHILD|WS_POPUP)) == WS_CHILD) - ok(pGetAncestor(hwnd, GA_ROOTOWNER) == hwndMessage, + ok(GetAncestor(hwnd, GA_ROOTOWNER) == hwndMessage, "GA_ROOTOWNER should be set to hwndMessage at this point\n"); else - ok(pGetAncestor(hwnd, GA_ROOTOWNER) == hwnd, - "GA_ROOTOWNER is set to %p, expected %p\n", pGetAncestor(hwnd, GA_ROOTOWNER), hwnd); - } + ok(GetAncestor(hwnd, GA_ROOTOWNER) == hwnd, + "GA_ROOTOWNER is set to %p, expected %p\n", GetAncestor(hwnd, GA_ROOTOWNER), hwnd); ok(GetWindowRect(hwnd, &rc), "GetWindowRect failed\n"); ok(EqualRect(&rc, &rc_null), "window rect should be set to 0 HCBT_CREATEWND\n"); @@ -1208,17 +1735,7 @@ static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) case HCBT_MINMAX: case HCBT_ACTIVATE: if (pGetWindowInfo && IsWindow(hwnd)) - { - WINDOWINFO info; - - /* Win98 actually does check the info.cbSize and doesn't allow - * it to be anything except sizeof(WINDOWINFO), while Win95, Win2k, - * WinXP do not check it at all. - */ - info.cbSize = sizeof(WINDOWINFO); - ok(pGetWindowInfo(hwnd, &info), "GetWindowInfo should not fail\n"); - verify_window_info(code_name, hwnd, &info); - } + test_window_info(code_name, hwnd); break; /* window state is undefined */ case HCBT_SETFOCUS: @@ -1231,71 +1748,38 @@ static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) return CallNextHookEx(hhook, nCode, wParam, lParam); } -static void test_shell_window(void) +static DWORD WINAPI test_shell_window_thread(LPVOID param) { BOOL ret; - DWORD error; HMODULE hinst, hUser32; BOOL (WINAPI*SetShellWindow)(HWND); HWND hwnd1, hwnd2, hwnd3, hwnd4, hwnd5; HWND shellWindow, nextWnd; + HDESK testDesktop = (HDESK)param; - if (is_win9x) - { - win_skip("Skipping shell window test on Win9x\n"); - return; - } + SetThreadDesktop(testDesktop); shellWindow = GetShellWindow(); hinst = GetModuleHandleA(NULL); hUser32 = GetModuleHandleA("user32"); + ok(shellWindow == NULL, "Newly created desktop has a shell window %p\n", shellWindow); + SetShellWindow = (void *)GetProcAddress(hUser32, "SetShellWindow"); - trace("previous shell window: %p\n", shellWindow); - - if (shellWindow) { - DWORD pid; - HANDLE hProcess; - - GetWindowThreadProcessId(shellWindow, &pid); - hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); - if (!hProcess) - { - skip( "cannot get access to shell process\n" ); - return; - } - - SetLastError(0xdeadbeef); - ret = DestroyWindow(shellWindow); - error = GetLastError(); - - ok(!ret, "DestroyWindow(shellWindow)\n"); - /* passes on Win XP, but not on Win98 */ - ok(error==ERROR_ACCESS_DENIED || error == 0xdeadbeef, - "got %u after DestroyWindow(shellWindow)\n", error); - - /* close old shell instance */ - ret = TerminateProcess(hProcess, 0); - ok(ret, "termination of previous shell process failed: GetLastError()=%d\n", GetLastError()); - WaitForSingleObject(hProcess, INFINITE); /* wait for termination */ - CloseHandle(hProcess); - } - hwnd1 = CreateWindowExA(0, "#32770", "TEST1", WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 100, 100, 300, 200, 0, 0, hinst, 0); - trace("created window 1: %p\n", hwnd1); ret = SetShellWindow(hwnd1); ok(ret, "first call to SetShellWindow(hwnd1)\n"); shellWindow = GetShellWindow(); - ok(shellWindow==hwnd1, "wrong shell window: %p\n", shellWindow); + ok(shellWindow==hwnd1, "wrong shell window: %p/%p\n", shellWindow,hwnd1); ret = SetShellWindow(hwnd1); ok(!ret, "second call to SetShellWindow(hwnd1)\n"); ret = SetShellWindow(0); - error = GetLastError(); /* passes on Win XP, but not on Win98 + DWORD error = GetLastError(); ok(!ret, "reset shell window by SetShellWindow(0)\n"); ok(error==ERROR_INVALID_WINDOW_HANDLE, "ERROR_INVALID_WINDOW_HANDLE after SetShellWindow(0)\n"); */ @@ -1311,23 +1795,20 @@ static void test_shell_window(void) ok(ret, "DestroyWindow(hwnd1)\n"); hwnd2 = CreateWindowExA(WS_EX_TOPMOST, "#32770", "TEST2", WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 150, 250, 300, 200, 0, 0, hinst, 0); - trace("created window 2: %p\n", hwnd2); ret = SetShellWindow(hwnd2); - ok(!ret, "SetShellWindow(hwnd2) with WS_EX_TOPMOST\n"); + ok(!ret, "SetShellWindow(%p) with WS_EX_TOPMOST\n", hwnd2); hwnd3 = CreateWindowExA(0, "#32770", "TEST3", WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 200, 400, 300, 200, 0, 0, hinst, 0); - trace("created window 3: %p\n", hwnd3); hwnd4 = CreateWindowExA(0, "#32770", "TEST4", WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 250, 500, 300, 200, 0, 0, hinst, 0); - trace("created window 4: %p\n", hwnd4); nextWnd = GetWindow(hwnd4, GW_HWNDNEXT); - ok(nextWnd==hwnd3, "wrong next window for hwnd4: %p - expected hwnd3\n", nextWnd); + ok(nextWnd==hwnd3, "wrong next window for hwnd4 %p: %p - expected %p\n", hwnd4, nextWnd, hwnd3); ret = SetShellWindow(hwnd4); ok(ret, "SetShellWindow(hwnd4)\n"); shellWindow = GetShellWindow(); - ok(shellWindow==hwnd4, "wrong shell window: %p - expected hwnd4\n", shellWindow); + ok(shellWindow==hwnd4, "wrong shell window: %p - expected %p\n", shellWindow, hwnd4); nextWnd = GetWindow(hwnd4, GW_HWNDNEXT); ok(nextWnd==0, "wrong next window for hwnd4: %p - expected 0\n", nextWnd); @@ -1341,10 +1822,9 @@ static void test_shell_window(void) ret = SetShellWindow(hwnd3); ok(!ret, "SetShellWindow(hwnd3)\n"); shellWindow = GetShellWindow(); - ok(shellWindow==hwnd4, "wrong shell window: %p - expected hwnd4\n", shellWindow); + ok(shellWindow==hwnd4, "wrong shell window: %p - expected %p\n", shellWindow, hwnd4); hwnd5 = CreateWindowExA(0, "#32770", "TEST5", WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 300, 600, 300, 200, 0, 0, hinst, 0); - trace("created window 5: %p\n", hwnd5); ret = SetWindowPos(hwnd4, hwnd5, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); ok(ret, "SetWindowPos(hwnd4, hwnd5)\n"); @@ -1359,6 +1839,33 @@ static void test_shell_window(void) DestroyWindow(hwnd3); DestroyWindow(hwnd4); DestroyWindow(hwnd5); + + return 0; +} + +static void test_shell_window(void) +{ + HDESK hdesk; + HWND orig_shell_window; + HANDLE hthread; + + orig_shell_window = GetShellWindow(); + ok(orig_shell_window != NULL, "default desktop doesn't have a shell window\n"); + + hdesk = CreateDesktopA("winetest", NULL, NULL, 0, GENERIC_ALL, NULL); + + hthread = CreateThread(NULL, 0, test_shell_window_thread, (LPVOID)hdesk, 0, NULL); + + WaitForSingleObject(hthread, INFINITE); + + CloseHandle(hthread); + + CloseDesktop(hdesk); + + if (!orig_shell_window) + skip("no shell window on default desktop\n"); + else + ok(GetShellWindow() == orig_shell_window, "changing shell window on another desktop effected the default\n"); } /************** MDI test ****************/ @@ -1372,7 +1879,6 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) INT_PTR id; static const WCHAR classW[] = {'M','D','I','_','c','h','i','l','d','_','C','l','a','s','s','_','1',0}; static const WCHAR titleW[] = {'M','D','I',' ','c','h','i','l','d',0}; - BOOL isWin9x = FALSE; HMENU frame_menu = GetMenu(parent); ok(frame_menu != NULL, "Frame window didn't have a menu\n"); @@ -1389,7 +1895,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs); ok(mdi_child != 0, "MDI child creation failed\n"); id = GetWindowLongPtrA(mdi_child, GWLP_ID); - ok(id == first_id, "wrong child id %ld\n", id); + ok(id == first_id, "wrong child id %Id\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); exp_hwnd = (GetWindowLongW(mdi_child, GWL_STYLE) & WS_VISIBLE) ? mdi_child : 0; ok(hwnd == exp_hwnd, "WM_MDIGETACTIVE should return %p, got %p\n", exp_hwnd, hwnd); @@ -1400,7 +1906,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs); ok(mdi_child != 0, "MDI child creation failed\n"); id = GetWindowLongPtrA(mdi_child, GWLP_ID); - ok(id == first_id, "wrong child id %ld\n", id); + ok(id == first_id, "wrong child id %Id\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); @@ -1416,7 +1922,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) { ok(mdi_child != 0, "MDI child creation failed\n"); id = GetWindowLongPtrA(mdi_child, GWLP_ID); - ok(id == first_id, "wrong child id %ld\n", id); + ok(id == first_id, "wrong child id %Id\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); @@ -1431,24 +1937,15 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) mdi_cs.szTitle = (LPCSTR)titleW; SetLastError(0xdeadbeef); mdi_child = (HWND)SendMessageW(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs); - if (!mdi_child) - { - if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) - isWin9x = TRUE; - else - ok(mdi_child != 0, "MDI child creation failed\n"); - } - else - { - id = GetWindowLongPtrA(mdi_child, GWLP_ID); - ok(id == first_id, "wrong child id %ld\n", id); - hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); - exp_hwnd = (GetWindowLongW(mdi_child, GWL_STYLE) & WS_VISIBLE) ? mdi_child : 0; - ok(hwnd == exp_hwnd, "WM_MDIGETACTIVE should return %p, got %p\n", exp_hwnd, hwnd); - ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); - SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); - ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); - } + ok(mdi_child != 0, "MDI child creation failed\n"); + id = GetWindowLongPtrA(mdi_child, GWLP_ID); + ok(id == first_id, "wrong child id %Id\n", id); + hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); + exp_hwnd = (GetWindowLongW(mdi_child, GWL_STYLE) & WS_VISIBLE) ? mdi_child : 0; + ok(hwnd == exp_hwnd, "WM_MDIGETACTIVE should return %p, got %p\n", exp_hwnd, hwnd); + ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); + SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); + ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); mdi_child = CreateMDIWindowA("MDI_child_Class_1", "MDI child", 0, @@ -1458,7 +1955,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) (LPARAM)mdi_lParam_test_message); ok(mdi_child != 0, "MDI child creation failed\n"); id = GetWindowLongPtrA(mdi_child, GWLP_ID); - ok(id == first_id, "wrong child id %ld\n", id); + ok(id == first_id, "wrong child id %Id\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); exp_hwnd = (GetWindowLongW(mdi_child, GWL_STYLE) & WS_VISIBLE) ? mdi_child : 0; ok(hwnd == exp_hwnd, "WM_MDIGETACTIVE should return %p, got %p\n", exp_hwnd, hwnd); @@ -1474,7 +1971,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) (LPARAM)mdi_lParam_test_message); ok(mdi_child != 0, "MDI child creation failed\n"); id = GetWindowLongPtrA(mdi_child, GWLP_ID); - ok(id == first_id, "wrong child id %ld\n", id); + ok(id == first_id, "wrong child id %Id\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); @@ -1495,7 +1992,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) { ok(mdi_child != 0, "MDI child creation failed\n"); id = GetWindowLongPtrA(mdi_child, GWLP_ID); - ok(id == first_id, "wrong child id %ld\n", id); + ok(id == first_id, "wrong child id %Id\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); @@ -1511,24 +2008,15 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) CW_USEDEFAULT, CW_USEDEFAULT, mdi_client, GetModuleHandleA(NULL), (LPARAM)mdi_lParam_test_message); - if (!mdi_child) - { - if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) - isWin9x = TRUE; - else - ok(mdi_child != 0, "MDI child creation failed\n"); - } - else - { - id = GetWindowLongPtrA(mdi_child, GWLP_ID); - ok(id == first_id, "wrong child id %ld\n", id); - hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); - exp_hwnd = (GetWindowLongW(mdi_child, GWL_STYLE) & WS_VISIBLE) ? mdi_child : 0; - ok(hwnd == exp_hwnd, "WM_MDIGETACTIVE should return %p, got %p\n", exp_hwnd, hwnd); - ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); - SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); - ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); - } + ok(mdi_child != 0, "MDI child creation failed\n"); + id = GetWindowLongPtrA(mdi_child, GWLP_ID); + ok(id == first_id, "wrong child id %Id\n", id); + hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); + exp_hwnd = (GetWindowLongW(mdi_child, GWL_STYLE) & WS_VISIBLE) ? mdi_child : 0; + ok(hwnd == exp_hwnd, "WM_MDIGETACTIVE should return %p, got %p\n", exp_hwnd, hwnd); + ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); + SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); + ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_1", "MDI child", 0, @@ -1538,7 +2026,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) mdi_lParam_test_message); ok(mdi_child != 0, "MDI child creation failed\n"); id = GetWindowLongPtrA(mdi_child, GWLP_ID); - ok(id == first_id, "wrong child id %ld\n", id); + ok(id == first_id, "wrong child id %Id\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); exp_hwnd = (GetWindowLongW(mdi_child, GWL_STYLE) & WS_VISIBLE) ? mdi_child : 0; ok(hwnd == exp_hwnd, "WM_MDIGETACTIVE should return %p, got %p\n", exp_hwnd, hwnd); @@ -1554,7 +2042,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) mdi_lParam_test_message); ok(mdi_child != 0, "MDI child creation failed\n"); id = GetWindowLongPtrA(mdi_child, GWLP_ID); - ok(id == first_id, "wrong child id %ld\n", id); + ok(id == first_id, "wrong child id %Id\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); exp_hwnd = (GetWindowLongW(mdi_child, GWL_STYLE) & WS_VISIBLE) ? mdi_child : 0; ok(hwnd == exp_hwnd, "WM_MDIGETACTIVE should return %p, got %p\n", exp_hwnd, hwnd); @@ -1573,7 +2061,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) mdi_lParam_test_message); ok(mdi_child != 0, "MDI child creation failed\n"); id = GetWindowLongPtrA(mdi_child, GWLP_ID); - ok(id == first_id, "wrong child id %ld\n", id); + ok(id == first_id, "wrong child id %Id\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); @@ -1594,7 +2082,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) { ok(mdi_child != 0, "MDI child creation failed\n"); id = GetWindowLongPtrA(mdi_child, GWLP_ID); - ok(id == first_id, "wrong child id %ld\n", id); + ok(id == first_id, "wrong child id %Id\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); @@ -1610,36 +2098,23 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) CW_USEDEFAULT, CW_USEDEFAULT, mdi_client, 0, GetModuleHandleA(NULL), mdi_lParam_test_message); - if (!mdi_child) - { - if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) - isWin9x = TRUE; - else - ok(mdi_child != 0, "MDI child creation failed\n"); - } - else - { - id = GetWindowLongPtrA(mdi_child, GWLP_ID); - ok(id == first_id, "wrong child id %ld\n", id); - hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); - exp_hwnd = (GetWindowLongW(mdi_child, GWL_STYLE) & WS_VISIBLE) ? mdi_child : 0; - ok(hwnd == exp_hwnd, "WM_MDIGETACTIVE should return %p, got %p\n", exp_hwnd, hwnd); - ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); - SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); - ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); - } + ok(mdi_child != 0, "MDI child creation failed\n"); + id = GetWindowLongPtrA(mdi_child, GWLP_ID); + ok(id == first_id, "wrong child id %Id\n", id); + hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); + exp_hwnd = (GetWindowLongW(mdi_child, GWL_STYLE) & WS_VISIBLE) ? mdi_child : 0; + ok(hwnd == exp_hwnd, "WM_MDIGETACTIVE should return %p, got %p\n", exp_hwnd, hwnd); + ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); + SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); + ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); - /* This test fails on Win9x */ - if (!isWin9x) - { - mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_2", "MDI child", + mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_2", "MDI child", WS_CHILD, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, parent, 0, GetModuleHandleA(NULL), mdi_lParam_test_message); - ok(!mdi_child, "WS_EX_MDICHILD with a not MDIClient parent should fail\n"); - } + ok(!mdi_child, "WS_EX_MDICHILD with a not MDIClient parent should fail\n"); mdi_child = CreateWindowExA(0, "MDI_child_Class_2", "MDI child", WS_CHILD, /* without WS_POPUP */ @@ -1649,7 +2124,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) mdi_lParam_test_message); ok(mdi_child != 0, "MDI child creation failed\n"); id = GetWindowLongPtrA(mdi_child, GWLP_ID); - ok(id == 0, "wrong child id %ld\n", id); + ok(id == 0, "wrong child id %Id\n", id); ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); @@ -1663,7 +2138,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) mdi_lParam_test_message); ok(mdi_child != 0, "MDI child creation failed\n"); id = GetWindowLongPtrA(mdi_child, GWLP_ID); - ok(id == 0, "wrong child id %ld\n", id); + ok(id == 0, "wrong child id %Id\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); @@ -1678,13 +2153,12 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) mdi_lParam_test_message); ok(mdi_child != 0, "MDI child creation failed\n"); id = GetWindowLongPtrA(mdi_child, GWLP_ID); - ok(id == 0, "wrong child id %ld\n", id); + ok(id == 0, "wrong child id %Id\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); DestroyWindow(mdi_child); - trace("Creating maximized child with a caption\n"); mdi_child = CreateWindowExA(0, "MDI_child_Class_2", "MDI child", WS_CHILD | WS_MAXIMIZE | WS_CAPTION, CW_USEDEFAULT, CW_USEDEFAULT, @@ -1693,13 +2167,12 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) mdi_lParam_test_message); ok(mdi_child != 0, "MDI child creation failed\n"); id = GetWindowLongPtrA(mdi_child, GWLP_ID); - ok(id == 0, "wrong child id %ld\n", id); + ok(id == 0, "wrong child id %Id\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); DestroyWindow(mdi_child); - trace("Creating maximized child with a caption and a thick frame\n"); mdi_child = CreateWindowExA(0, "MDI_child_Class_2", "MDI child", WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME, CW_USEDEFAULT, CW_USEDEFAULT, @@ -1708,7 +2181,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) mdi_lParam_test_message); ok(mdi_child != 0, "MDI child creation failed\n"); id = GetWindowLongPtrA(mdi_child, GWLP_ID); - ok(id == 0, "wrong child id %ld\n", id); + ok(id == 0, "wrong child id %Id\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); @@ -1744,13 +2217,11 @@ static void test_MDI_child_stack(HWND mdi_client) stack[1] = GetWindow(stack[0], GW_HWNDNEXT); stack[2] = GetWindow(stack[1], GW_HWNDNEXT); stack[3] = GetWindow(stack[2], GW_HWNDNEXT); - trace("Initial MDI child stack: %p->%p->%p->%p\n", stack[0], stack[1], stack[2], stack[3]); ok(stack[0] == child_4 && stack[1] == child_3 && stack[2] == child_2 && stack[3] == child_1, "Unexpected initial order, should be: %p->%p->%p->%p\n", child_4, child_3, child_2, child_1); - trace("Activate child next to %p\n", child_3); SendMessageA(mdi_client, WM_MDINEXT, (WPARAM)child_3, 0); stack[0] = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); @@ -1762,7 +2233,6 @@ static void test_MDI_child_stack(HWND mdi_client) "Broken MDI child stack:\nexpected: %p->%p->%p->%p, but got: %p->%p->%p->%p\n", child_2, child_4, child_1, child_3, stack[0], stack[1], stack[2], stack[3]); - trace("Activate child previous to %p\n", child_1); SendMessageA(mdi_client, WM_MDINEXT, (WPARAM)child_1, 1); stack[0] = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); @@ -1774,6 +2244,13 @@ static void test_MDI_child_stack(HWND mdi_client) "Broken MDI child stack:\nexpected: %p->%p->%p->%p, but got: %p->%p->%p->%p\n", child_4, child_2, child_1, child_3, stack[0], stack[1], stack[2], stack[3]); + ShowWindow(child_4, SW_MINIMIZE); + + stack[0] = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); + stack[1] = GetWindow(stack[0], GW_HWNDNEXT); + todo_wine ok(stack[0] == child_4, "Expected %p, got %p\n", child_4, stack[0]); + todo_wine ok(stack[1] == NULL, "Expected NULL, got %p\n", stack[1]); + DestroyWindow(child_1); DestroyWindow(child_2); DestroyWindow(child_3); @@ -1801,8 +2278,6 @@ static void MDI_ChildGetMinMaxInfo( HWND client, HWND hwnd, MINMAXINFO* lpMinMax lpMinMax->ptMaxPosition.x = rect.left; lpMinMax->ptMaxPosition.y = rect.top; - - trace("max rect %s\n", wine_dbgstr_rect(&rect)); } static LRESULT WINAPI mdi_child_wnd_proc_1(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) @@ -1826,7 +2301,7 @@ static LRESULT WINAPI mdi_child_wnd_proc_1(HWND hwnd, UINT msg, WPARAM wparam, L /* MDICREATESTRUCT should have original values */ ok(mdi_cs->style == 0 || mdi_cs->style == 0x7fffffff || mdi_cs->style == 0xffffffff || mdi_cs->style == WS_MAXIMIZE, - "mdi_cs->style does not match (%08x)\n", mdi_cs->style); + "mdi_cs->style does not match (%08lx)\n", mdi_cs->style); ok(mdi_cs->x == CW_USEDEFAULT, "%d != CW_USEDEFAULT\n", mdi_cs->x); ok(mdi_cs->y == CW_USEDEFAULT, "%d != CW_USEDEFAULT\n", mdi_cs->y); ok(mdi_cs->cx == CW_USEDEFAULT, "%d != CW_USEDEFAULT\n", mdi_cs->cx); @@ -1846,7 +2321,7 @@ static LRESULT WINAPI mdi_child_wnd_proc_1(HWND hwnd, UINT msg, WPARAM wparam, L { LONG style = mdi_cs->style | WS_CHILD | WS_CLIPSIBLINGS; ok(cs->style == style, - "cs->style does not match (%08x)\n", cs->style); + "cs->style does not match (%08lx)\n", cs->style); } else { @@ -1855,7 +2330,7 @@ static LRESULT WINAPI mdi_child_wnd_proc_1(HWND hwnd, UINT msg, WPARAM wparam, L style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; ok(cs->style == style, - "cs->style does not match (%08x)\n", cs->style); + "cs->style does not match (%08lx)\n", cs->style); } break; } @@ -1877,23 +2352,29 @@ static LRESULT WINAPI mdi_child_wnd_proc_1(HWND hwnd, UINT msg, WPARAM wparam, L if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */ AdjustWindowRectEx(&rc, style, 0, exstyle); - trace("MDI child: calculated max window size = (%d x %d)\n", rc.right-rc.left, rc.bottom-rc.top); - dump_minmax_info( minmax ); + if (winetest_debug > 1) + { + trace("MDI child: calculated max window size = (%ld x %ld)\n", rc.right-rc.left, rc.bottom-rc.top); + dump_minmax_info( minmax ); + } - ok(minmax->ptMaxSize.x == rc.right - rc.left, "default width of maximized child %d != %d\n", + ok(minmax->ptMaxSize.x == rc.right - rc.left, "default width of maximized child %ld != %ld\n", minmax->ptMaxSize.x, rc.right - rc.left); - ok(minmax->ptMaxSize.y == rc.bottom - rc.top, "default height of maximized child %d != %d\n", + ok(minmax->ptMaxSize.y == rc.bottom - rc.top, "default height of maximized child %ld != %ld\n", minmax->ptMaxSize.y, rc.bottom - rc.top); DefMDIChildProcA(hwnd, msg, wparam, lparam); - trace("DefMDIChildProc returned:\n"); - dump_minmax_info( minmax ); + if (winetest_debug > 1) + { + trace("DefMDIChildProc returned:\n"); + dump_minmax_info( minmax ); + } MDI_ChildGetMinMaxInfo(client, hwnd, &my_minmax); - ok(minmax->ptMaxSize.x == my_minmax.ptMaxSize.x, "default width of maximized child %d != %d\n", + ok(minmax->ptMaxSize.x == my_minmax.ptMaxSize.x, "default width of maximized child %ld != %ld\n", minmax->ptMaxSize.x, my_minmax.ptMaxSize.x); - ok(minmax->ptMaxSize.y == my_minmax.ptMaxSize.y, "default height of maximized child %d != %d\n", + ok(minmax->ptMaxSize.y == my_minmax.ptMaxSize.y, "default height of maximized child %ld != %ld\n", minmax->ptMaxSize.y, my_minmax.ptMaxSize.y); return 1; @@ -1923,8 +2404,9 @@ static LRESULT WINAPI mdi_child_wnd_proc_2(HWND hwnd, UINT msg, WPARAM wparam, L { CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam; - trace("%s: x %d, y %d, cx %d, cy %d\n", (msg == WM_NCCREATE) ? "WM_NCCREATE" : "WM_CREATE", - cs->x, cs->y, cs->cx, cs->cy); + if (winetest_debug > 1) + trace("%s: x %d, y %d, cx %d, cy %d\n", (msg == WM_NCCREATE) ? "WM_NCCREATE" : "WM_CREATE", + cs->x, cs->y, cs->cx, cs->cy); ok(!(cs->dwExStyle & WS_EX_MDICHILD), "WS_EX_MDICHILD should not be set\n"); ok(cs->lpCreateParams == mdi_lParam_test_message, "wrong cs->lpCreateParams\n"); @@ -1933,15 +2415,11 @@ static LRESULT WINAPI mdi_child_wnd_proc_2(HWND hwnd, UINT msg, WPARAM wparam, L ok(!lstrcmpA(cs->lpszName, "MDI child"), "wrong title\n"); /* CREATESTRUCT should have fixed values */ - /* For some reason Win9x doesn't translate cs->x from CW_USEDEFAULT, - while NT does. */ - /*ok(cs->x != CW_USEDEFAULT, "%d == CW_USEDEFAULT\n", cs->x);*/ + ok(cs->x != CW_USEDEFAULT, "%d == CW_USEDEFAULT\n", cs->x); ok(cs->y != CW_USEDEFAULT, "%d == CW_USEDEFAULT\n", cs->y); /* cx/cy == CW_USEDEFAULT are translated to 0 */ - /* For some reason Win98 doesn't translate cs->cx from CW_USEDEFAULT, - while Win95, Win2k, WinXP do. */ - /*ok(cs->cx == 0, "%d != 0\n", cs->cx);*/ + ok(cs->cx == 0, "%d != 0\n", cs->cx); ok(cs->cy == 0, "%d != 0\n", cs->cy); break; } @@ -1957,23 +2435,26 @@ static LRESULT WINAPI mdi_child_wnd_proc_2(HWND hwnd, UINT msg, WPARAM wparam, L exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE); GetClientRect(parent, &rc); - trace("WM_GETMINMAXINFO: parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom); - + if (winetest_debug > 1) + { + trace("WM_GETMINMAXINFO: parent %p client size = (%ld x %ld)\n", parent, rc.right, rc.bottom); + dump_minmax_info( minmax ); + } GetClientRect(parent, &rc); if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */ AdjustWindowRectEx(&rc, style, 0, exstyle); - dump_minmax_info( minmax ); - ok(minmax->ptMaxSize.x == rc.right - rc.left, "default width of maximized child %d != %d\n", + ok(minmax->ptMaxSize.x == rc.right - rc.left, "default width of maximized child %ld != %ld\n", minmax->ptMaxSize.x, rc.right - rc.left); - ok(minmax->ptMaxSize.y == rc.bottom - rc.top, "default height of maximized child %d != %d\n", + ok(minmax->ptMaxSize.y == rc.bottom - rc.top, "default height of maximized child %ld != %ld\n", minmax->ptMaxSize.y, rc.bottom - rc.top); break; } case WM_WINDOWPOSCHANGED: { + LRESULT ret; WINDOWPOS *winpos = (WINDOWPOS *)lparam; RECT rc1, rc2; @@ -1985,7 +2466,8 @@ static LRESULT WINAPI mdi_child_wnd_proc_2(HWND hwnd, UINT msg, WPARAM wparam, L wine_dbgstr_rect(&rc1), wine_dbgstr_rect(&rc2)); GetWindowRect(hwnd, &rc1); GetClientRect(hwnd, &rc2); - DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc1); + ret = DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc1); + ok(!ret, "got %08Ix\n", ret); MapWindowPoints(0, hwnd, (LPPOINT)&rc1, 2); ok(EqualRect(&rc1, &rc2), "rects do not match, window=%s client=%s\n", wine_dbgstr_rect(&rc1), wine_dbgstr_rect(&rc2)); @@ -1996,10 +2478,11 @@ static LRESULT WINAPI mdi_child_wnd_proc_2(HWND hwnd, UINT msg, WPARAM wparam, L WINDOWPOS *winpos = (WINDOWPOS *)lparam; WINDOWPOS my_winpos = *winpos; - trace("%s: %p after %p, x %d, y %d, cx %d, cy %d flags %08x\n", - (msg == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED", - winpos->hwnd, winpos->hwndInsertAfter, - winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags); + if (winetest_debug > 1) + trace("%s: %p after %p, x %d, y %d, cx %d, cy %d flags %08x\n", + (msg == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED", + winpos->hwnd, winpos->hwndInsertAfter, + winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags); DefWindowProcA(hwnd, msg, wparam, lparam); @@ -2010,7 +2493,15 @@ static LRESULT WINAPI mdi_child_wnd_proc_2(HWND hwnd, UINT msg, WPARAM wparam, L return 1; } + + case WM_NCCALCSIZE: + { + LRESULT ret = DefWindowProcA(hwnd, WM_NCCALCSIZE, wparam, lparam); + ok(!ret, "got %08Ix (%08Ix %08Ix)\n", ret, wparam, lparam); + return ret; + } } + return DefWindowProcA(hwnd, msg, wparam, lparam); } @@ -2029,12 +2520,11 @@ static LRESULT WINAPI mdi_main_wnd_procA(HWND hwnd, UINT msg, WPARAM wparam, LPA RECT rc1, rc2; GetWindowRect(hwnd, &rc1); - trace("window: %s\n", wine_dbgstr_rect(&rc1)); SetRect(&rc2, winpos->x, winpos->y, winpos->x + winpos->cx, winpos->y + winpos->cy); /* note: winpos coordinates are relative to parent */ MapWindowPoints(GetParent(hwnd), 0, (LPPOINT)&rc2, 2); - trace("pos: %s\n", wine_dbgstr_rect(&rc2)); - ok(EqualRect(&rc1, &rc2), "rects do not match\n"); + ok(EqualRect(&rc1, &rc2), "rects %s %s do not match\n", + wine_dbgstr_rect(&rc1), wine_dbgstr_rect(&rc2)); GetWindowRect(hwnd, &rc1); GetClientRect(hwnd, &rc2); @@ -2048,16 +2538,18 @@ static LRESULT WINAPI mdi_main_wnd_procA(HWND hwnd, UINT msg, WPARAM wparam, LPA WINDOWPOS *winpos = (WINDOWPOS *)lparam; WINDOWPOS my_winpos = *winpos; - trace("%s\n", (msg == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED"); - trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n", - winpos->hwnd, winpos->hwndInsertAfter, - winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags); + if (winetest_debug > 1) + trace("%s: %p after %p, x %d, y %d, cx %d, cy %d flags %08x\n", + (msg == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED", + winpos->hwnd, winpos->hwndInsertAfter, + winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags); DefWindowProcA(hwnd, msg, wparam, lparam); - trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n", - winpos->hwnd, winpos->hwndInsertAfter, - winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags); + if (winetest_debug > 1) + trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n", + winpos->hwnd, winpos->hwndInsertAfter, + winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags); ok(!memcmp(&my_winpos, winpos, sizeof(WINDOWPOS)), "DefWindowProc should not change WINDOWPOS values\n"); @@ -2065,6 +2557,13 @@ static LRESULT WINAPI mdi_main_wnd_procA(HWND hwnd, UINT msg, WPARAM wparam, LPA return 1; } + case WM_NCCALCSIZE: + { + LRESULT ret = DefFrameProcA(hwnd, mdi_client, WM_NCCALCSIZE, wparam, lparam); + ok(!ret, "got %08Ix (%08Ix %08Ix)\n", ret, wparam, lparam); + return ret; + } + case WM_CLOSE: PostQuitMessage(0); break; @@ -2126,11 +2625,12 @@ static void test_mdi(void) client_cs.hWindowMenu = 0; client_cs.idFirstChild = 1; - for (i = 0; i < sizeof(style)/sizeof(style[0]); i++) + for (i = 0; i < ARRAY_SIZE(style); i++) { SCROLLINFO si; BOOL ret, gotit; + winetest_push_context("style %#lx", style[i]); mdi_client = CreateWindowExA(0, "mdiclient", NULL, WS_CHILD | style[i], 0, 0, rc.right, rc.bottom, @@ -2169,7 +2669,7 @@ static void test_mdi(void) ret = GetScrollInfo(mdi_client, SB_HORZ, &si); if (style[i] & (WS_HSCROLL | WS_VSCROLL)) { - ok(ret, "style %#x: GetScrollInfo(SB_HORZ) failed\n", style[i]); + ok(ret, "GetScrollInfo(SB_HORZ) failed\n"); ok(si.nPage == 0, "expected 0\n"); ok(si.nPos == 0, "expected 0\n"); ok(si.nTrackPos == 0, "expected 0\n"); @@ -2177,12 +2677,12 @@ static void test_mdi(void) ok(si.nMax == 100, "expected 100\n"); } else - ok(!ret, "style %#x: GetScrollInfo(SB_HORZ) should fail\n", style[i]); + ok(!ret, "GetScrollInfo(SB_HORZ) should fail\n"); ret = GetScrollInfo(mdi_client, SB_VERT, &si); if (style[i] & (WS_HSCROLL | WS_VSCROLL)) { - ok(ret, "style %#x: GetScrollInfo(SB_VERT) failed\n", style[i]); + ok(ret, "GetScrollInfo(SB_VERT) failed\n"); ok(si.nPage == 0, "expected 0\n"); ok(si.nPos == 0, "expected 0\n"); ok(si.nTrackPos == 0, "expected 0\n"); @@ -2190,7 +2690,7 @@ static void test_mdi(void) ok(si.nMax == 100, "expected 100\n"); } else - ok(!ret, "style %#x: GetScrollInfo(SB_VERT) should fail\n", style[i]); + ok(!ret, "GetScrollInfo(SB_VERT) should fail\n"); SetWindowPos(mdi_child, 0, -100, -100, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE); @@ -2199,7 +2699,7 @@ static void test_mdi(void) ret = GetScrollInfo(mdi_client, SB_HORZ, &si); if (style[i] & (WS_HSCROLL | WS_VSCROLL)) { - ok(ret, "style %#x: GetScrollInfo(SB_HORZ) failed\n", style[i]); + ok(ret, "GetScrollInfo(SB_HORZ) failed\n"); ok(si.nPage == 0, "expected 0\n"); ok(si.nPos == 0, "expected 0\n"); ok(si.nTrackPos == 0, "expected 0\n"); @@ -2207,12 +2707,12 @@ static void test_mdi(void) ok(si.nMax == 100, "expected 100\n"); } else - ok(!ret, "style %#x: GetScrollInfo(SB_HORZ) should fail\n", style[i]); + ok(!ret, "GetScrollInfo(SB_HORZ) should fail\n"); ret = GetScrollInfo(mdi_client, SB_VERT, &si); if (style[i] & (WS_HSCROLL | WS_VSCROLL)) { - ok(ret, "style %#x: GetScrollInfo(SB_VERT) failed\n", style[i]); + ok(ret, "GetScrollInfo(SB_VERT) failed\n"); ok(si.nPage == 0, "expected 0\n"); ok(si.nPos == 0, "expected 0\n"); ok(si.nTrackPos == 0, "expected 0\n"); @@ -2220,7 +2720,7 @@ static void test_mdi(void) ok(si.nMax == 100, "expected 100\n"); } else - ok(!ret, "style %#x: GetScrollInfo(SB_VERT) should fail\n", style[i]); + ok(!ret, "GetScrollInfo(SB_VERT) should fail\n"); gotit = FALSE; while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) @@ -2247,8 +2747,8 @@ static void test_mdi(void) ret = GetScrollInfo(mdi_client, SB_HORZ, &si); if (style[i] & (WS_HSCROLL | WS_VSCROLL)) { - ok(ret, "style %#x: GetScrollInfo(SB_HORZ) failed\n", style[i]); -todo_wine + ok(ret, "GetScrollInfo(SB_HORZ) failed\n"); + todo_wine ok(si.nPage != 0, "expected !0\n"); ok(si.nPos == 0, "expected 0\n"); ok(si.nTrackPos == 0, "expected 0\n"); @@ -2256,13 +2756,13 @@ todo_wine ok(si.nMax != 100, "expected !100\n"); } else - ok(!ret, "style %#x: GetScrollInfo(SB_HORZ) should fail\n", style[i]); + ok(!ret, "GetScrollInfo(SB_HORZ) should fail\n"); ret = GetScrollInfo(mdi_client, SB_VERT, &si); if (style[i] & (WS_HSCROLL | WS_VSCROLL)) { - ok(ret, "style %#x: GetScrollInfo(SB_VERT) failed\n", style[i]); -todo_wine + ok(ret, "GetScrollInfo(SB_VERT) failed\n"); + todo_wine ok(si.nPage != 0, "expected !0\n"); ok(si.nPos == 0, "expected 0\n"); ok(si.nTrackPos == 0, "expected 0\n"); @@ -2270,11 +2770,12 @@ todo_wine ok(si.nMax != 100, "expected !100\n"); } else - ok(!ret, "style %#x: GetScrollInfo(SB_VERT) should fail\n", style[i]); + ok(!ret, "GetScrollInfo(SB_VERT) should fail\n"); DestroyMenu(child_menu); DestroyWindow(mdi_child); DestroyWindow(mdi_client); + winetest_pop_context(); } SetMenu(mdi_hwndMain, frame_menu); @@ -2356,68 +2857,276 @@ todo_wine DestroyWindow(mdi_hwndMain); } +#define check_icon_size(a, b, c) check_icon_size_(__LINE__, a, b, c) +static void check_icon_size_( int line, HICON icon, LONG width, LONG height ) +{ + ICONINFO info = {sizeof(info)}; + BITMAP bitmap; + BOOL ret; + + ret = GetIconInfo( icon, &info ); + ok_(__FILE__, line)(ret, "failed to get icon info, error %lu\n", GetLastError()); + ret = GetObjectW(info.hbmColor, sizeof(bitmap), &bitmap); + ok_(__FILE__, line)(ret, "failed to get bitmap, error %lu\n", GetLastError()); + ok_(__FILE__, line)(bitmap.bmWidth == width, "expected width %ld, got %d\n", width, bitmap.bmWidth); + ok_(__FILE__, line)(bitmap.bmHeight == height, "expected height %ld, got %d\n", height, bitmap.bmHeight); +} + +#define check_internal_icon_size(a, b, c, d) check_internal_icon_size_(__LINE__, a, b, c, d) +static void check_internal_icon_size_( int line, HANDLE window, UINT type, LONG width, LONG height ) +{ + HICON icon; + BOOL ret; + + icon = pInternalGetWindowIcon( window, type ); + ok_(__FILE__, line)(icon != 0, "expected nonzero icon\n"); + check_icon_size_( line, icon, width, height ); + ret = DestroyIcon( icon ); + ok_(__FILE__, line)(ret, "failed to destroy icon, error %lu\n", GetLastError()); +} + +static DWORD WINAPI internal_get_icon_thread(void *arg) +{ + HICON icon; + BOOL ret; + + icon = pInternalGetWindowIcon( arg, ICON_BIG ); + ok( icon != 0, "expected nonzero icon\n" ); + ret = DestroyIcon( icon ); + ok( ret, "got error %lu\n", GetLastError() ); + + return 0; +} + static void test_icons(void) { - WNDCLASSEXA cls; + static const BYTE bitmap_bits[50 * 50 * 4]; + HICON icon = CreateIcon( 0, 10, 10, 1, 32, bitmap_bits, bitmap_bits ); + HICON icon2 = CreateIcon( 0, 20, 20, 1, 32, bitmap_bits, bitmap_bits ); + HICON icon3 = CreateIcon( 0, 30, 30, 1, 32, bitmap_bits, bitmap_bits ); + HICON icon4 = CreateIcon( 0, 40, 40, 1, 32, bitmap_bits, bitmap_bits ); + HICON icon5 = CreateIcon( 0, 50, 50, 1, 32, bitmap_bits, bitmap_bits ); + LONG big_width = GetSystemMetrics( SM_CXICON ), big_height = GetSystemMetrics( SM_CYICON ); + LONG small_width = GetSystemMetrics( SM_CXSMICON ), small_height = GetSystemMetrics( SM_CYSMICON ); + WNDCLASSEXA cls = {sizeof(cls)}; + HICON res, res2; + HANDLE thread; HWND hwnd; - HICON icon = LoadIconA(0, (LPCSTR)IDI_APPLICATION); - HICON icon2 = LoadIconA(0, (LPCSTR)IDI_QUESTION); - HICON small_icon = LoadImageA(0, (LPCSTR)IDI_APPLICATION, IMAGE_ICON, - GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED ); - HICON res; + BOOL ret; - cls.cbSize = sizeof(cls); - cls.style = 0; +#ifdef __REACTOS__ + if (GetNTVersion() <= _WIN32_WINNT_WS03) { + skip("test_icons() crashes on Windows Server 2003 and ReactOS.\n"); + return; + } +#endif cls.lpfnWndProc = DefWindowProcA; - cls.cbClsExtra = 0; - cls.cbWndExtra = 0; - cls.hInstance = 0; - cls.hIcon = LoadIconA(0, (LPCSTR)IDI_HAND); - cls.hIconSm = small_icon; - cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); - cls.hbrBackground = GetStockObject(WHITE_BRUSH); - cls.lpszMenuName = NULL; + cls.hIcon = icon4; + cls.hIconSm = icon5; cls.lpszClassName = "IconWindowClass"; - RegisterClassExA(&cls); hwnd = CreateWindowExA(0, "IconWindowClass", "icon test", 0, 100, 100, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL); - assert( hwnd ); + ok( hwnd != NULL, "failed to create window\n" ); res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 ); ok( res == 0, "wrong big icon %p/0\n", res ); + SetLastError( 0xdeadbeef ); + res = pInternalGetWindowIcon( hwnd, ICON_BIG ); + ok( res != 0, "expected nonzero icon\n" ); + ok( GetLastError() == 0xdeadbeef, "got error %lu\n", GetLastError() ); + check_icon_size( res, 40, 40 ); + res2 = pInternalGetWindowIcon( hwnd, ICON_BIG ); + ok( res2 && res2 != res, "got %p\n", res2 ); + check_icon_size( res2, 40, 40 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %lu\n", GetLastError() ); + ret = DestroyIcon( res ); + ok( ret, "got error %lu\n", GetLastError() ); + + res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 ); + ok( !res, "wrong small icon %p\n", res ); + res = pInternalGetWindowIcon( hwnd, ICON_SMALL ); + ok( res != 0, "expected nonzero icon\n" ); + check_icon_size( res, 50, 50 ); + res2 = pInternalGetWindowIcon( hwnd, ICON_SMALL ); + ok( res2 && res2 != res, "got %p\n", res2 ); + check_icon_size( res2, 50, 50 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %lu\n", GetLastError() ); + ret = DestroyIcon( res ); + ok( ret, "got error %lu\n", GetLastError() ); + + res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 ); + ok( !res, "wrong small2 icon %p\n", res ); + res = pInternalGetWindowIcon( hwnd, ICON_SMALL2 ); + ok( res != 0, "expected nonzero icon\n" ); + check_icon_size( res, 50, 50 ); + res2 = pInternalGetWindowIcon( hwnd, ICON_SMALL2 ); + ok( res2 && res2 != res, "got %p\n", res2 ); + check_icon_size( res2, 50, 50 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %lu\n", GetLastError() ); + ret = DestroyIcon( res ); + ok( ret, "got error %lu\n", GetLastError() ); + res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_BIG, (LPARAM)icon ); ok( res == 0, "wrong previous big icon %p/0\n", res ); res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 ); ok( res == icon, "wrong big icon after set %p/%p\n", res, icon ); + res2 = pInternalGetWindowIcon( hwnd, ICON_BIG ); + ok( res2 && res2 != icon, "got %p\n", res2 ); + check_icon_size( res2, 10, 10 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %lu\n", GetLastError() ); + res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_BIG, (LPARAM)icon2 ); ok( res == icon, "wrong previous big icon %p/%p\n", res, icon ); res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 ); ok( res == icon2, "wrong big icon after set %p/%p\n", res, icon2 ); + res2 = pInternalGetWindowIcon( hwnd, ICON_BIG ); + ok( res2 && res2 != icon2, "got %p\n", res2 ); + check_icon_size( res2, 20, 20 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %lu\n", GetLastError() ); res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 ); ok( res == 0, "wrong small icon %p/0\n", res ); + res2 = pInternalGetWindowIcon( hwnd, ICON_SMALL ); + ok( res2 != 0, "expected nonzero icon\n" ); + check_icon_size( res2, small_width, small_height ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %lu\n", GetLastError() ); + res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 ); - ok( (res && res != small_icon && res != icon2) || broken(!res), "wrong small2 icon %p\n", res ); + ok( res && res != icon3 && res != icon2, "wrong small2 icon %p\n", res ); + res2 = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 ); + ok( res2 == res, "expected icon to match\n" ); + check_icon_size( res, small_width, small_height ); + res2 = pInternalGetWindowIcon( hwnd, ICON_SMALL2 ); + ok( res2 && res2 != icon3 && res2 != icon2 && res2 != res, "got %p\n", res2 ); + check_icon_size( res2, small_width, small_height ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %lu\n", GetLastError() ); + res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_SMALL, (LPARAM)icon ); ok( res == 0, "wrong previous small icon %p/0\n", res ); res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 ); ok( res == icon, "wrong small icon after set %p/%p\n", res, icon ); + res2 = pInternalGetWindowIcon( hwnd, ICON_SMALL ); + ok( res2 && res2 != icon, "got %p\n", res2 ); + check_icon_size( res2, 10, 10 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %lu\n", GetLastError() ); + res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 ); - ok( res == icon || broken(!res), "wrong small2 icon after set %p/%p\n", res, icon ); - res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_SMALL, (LPARAM)small_icon ); + ok( res == icon, "wrong small2 icon after set %p/%p\n", res, icon ); + res2 = pInternalGetWindowIcon( hwnd, ICON_SMALL2 ); + ok( res2 && res2 != icon && res2 != res, "got %p\n", res2 ); + check_icon_size( res2, 10, 10 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %lu\n", GetLastError() ); + + res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_SMALL, (LPARAM)icon3 ); ok( res == icon, "wrong previous small icon %p/%p\n", res, icon ); res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 ); - ok( res == small_icon, "wrong small icon after set %p/%p\n", res, small_icon ); + ok( res == icon3, "wrong small icon after set %p/%p\n", res, icon3 ); + res2 = pInternalGetWindowIcon( hwnd, ICON_SMALL ); + ok( res2 && res2 != icon3, "got %p\n", res2 ); + check_icon_size( res2, 30, 30 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %lu\n", GetLastError() ); + res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 ); - ok( res == small_icon || broken(!res), "wrong small2 icon after set %p/%p\n", res, small_icon ); + ok( res == icon3, "wrong small2 icon after set %p/%p\n", res, icon3 ); + res2 = pInternalGetWindowIcon( hwnd, ICON_SMALL2 ); + ok( res2 && res2 != icon3 && res2 != res, "got %p\n", res2 ); + check_icon_size( res2, 30, 30 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %lu\n", GetLastError() ); /* make sure the big icon hasn't changed */ res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 ); ok( res == icon2, "wrong big icon after set %p/%p\n", res, icon2 ); + res2 = pInternalGetWindowIcon( hwnd, ICON_BIG ); + ok( res2 && res2 != icon2, "got %p\n", res2 ); + check_icon_size( res2, 20, 20 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + res = pInternalGetWindowIcon( NULL, ICON_BIG ); + ok( !res, "got %p\n", res ); + ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "got error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + res = pInternalGetWindowIcon( hwnd, 0xdeadbeef ); + ok( !res, "got %p\n", res ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + + thread = CreateThread( NULL, 0, internal_get_icon_thread, hwnd, 0, NULL ); + ret = WaitForSingleObject( thread, 1000 ); + ok( !ret, "wait timed out\n" ); + CloseHandle( thread ); DestroyWindow( hwnd ); + UnregisterClassA( "IconWindowClass", GetModuleHandleA( NULL ) ); + + /* check when the big class icon is missing */ + + cls.hIcon = 0; + cls.hIconSm = icon5; + RegisterClassExA(&cls); + + hwnd = CreateWindowExA(0, "IconWindowClass", "icon test", 0, + 100, 100, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL); + ok( hwnd != NULL, "failed to create window\n" ); + + check_internal_icon_size( hwnd, ICON_BIG, big_width, big_height ); + check_internal_icon_size( hwnd, ICON_SMALL, 50, 50 ); + check_internal_icon_size( hwnd, ICON_SMALL2, 50, 50 ); + + DestroyWindow( hwnd ); + UnregisterClassA( "IconWindowClass", GetModuleHandleA( NULL ) ); + + /* and when the small class icon is missing */ + + cls.hIcon = icon4; + cls.hIconSm = 0; + RegisterClassExA(&cls); + hwnd = CreateWindowExA(0, "IconWindowClass", "icon test", 0, + 100, 100, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL); + ok( hwnd != NULL, "failed to create window\n" ); + + check_internal_icon_size( hwnd, ICON_BIG, 40, 40 ); + check_internal_icon_size( hwnd, ICON_SMALL, small_width, small_width ); + check_internal_icon_size( hwnd, ICON_SMALL2, small_width, small_width ); + + DestroyWindow( hwnd ); + UnregisterClassA( "IconWindowClass", GetModuleHandleA( NULL ) ); + + /* and when both are missing */ + + cls.hIcon = 0; + cls.hIconSm = 0; + RegisterClassExA(&cls); + hwnd = CreateWindowExA(0, "IconWindowClass", "icon test", 0, + 100, 100, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL); + ok( hwnd != NULL, "failed to create window\n" ); + + check_internal_icon_size( hwnd, ICON_BIG, big_width, big_height ); + check_internal_icon_size( hwnd, ICON_SMALL, big_width, big_height ); + check_internal_icon_size( hwnd, ICON_SMALL2, big_width, big_height ); + + DestroyWindow( hwnd ); + UnregisterClassA( "IconWindowClass", GetModuleHandleA( NULL ) ); + + DestroyIcon( icon ); + DestroyIcon( icon2 ); + DestroyIcon( icon3 ); + DestroyIcon( icon4 ); + DestroyIcon( icon5 ); } static LRESULT WINAPI nccalcsize_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) @@ -2439,6 +3148,7 @@ static void test_SetWindowPos(HWND hwnd, HWND hwnd2) LONG_PTR old_proc; HWND hwnd_grandchild, hwnd_child, hwnd_child2; HWND hwnd_desktop; + RECT rc_expected; RECT rc1, rc2; BOOL ret; @@ -2465,6 +3175,8 @@ static void test_SetWindowPos(HWND hwnd, HWND hwnd2) ok( rect.left == 90 && rect.top == 90 && rect.right == 110 && rect.bottom == 110, "invalid client rect %s\n", wine_dbgstr_rect(&rect)); + flush_events( TRUE ); /* needed by Win10 1709+ */ + ret = SetWindowPos(hwnd, 0, 200, 200, 0, 0, SWP_NOZORDER|SWP_FRAMECHANGED); ok(ret, "Got %d\n", ret); GetWindowRect( hwnd, &rect ); @@ -2480,43 +3192,28 @@ static void test_SetWindowPos(HWND hwnd, HWND hwnd2) ok(ret, "Got %d\n", ret); SetWindowLongPtrA( hwnd, GWLP_WNDPROC, old_proc ); - /* Win9x truncates coordinates to 16-bit irrespectively */ - if (!is_win9x) - { - ret = SetWindowPos(hwnd, 0, -32769, -40000, -32769, -90000, SWP_NOMOVE); - ok(ret, "Got %d\n", ret); - ret = SetWindowPos(hwnd, 0, 32768, 40000, 32768, 40000, SWP_NOMOVE); - ok(ret, "Got %d\n", ret); + ret = SetWindowPos(hwnd, 0, -32769, -40000, -32769, -90000, SWP_NOMOVE); + ok(ret, "Got %d\n", ret); + ret = SetWindowPos(hwnd, 0, 32768, 40000, 32768, 40000, SWP_NOMOVE); + ok(ret, "Got %d\n", ret); - ret = SetWindowPos(hwnd, 0, -32769, -40000, -32769, -90000, SWP_NOSIZE); - ok(ret, "Got %d\n", ret); - ret = SetWindowPos(hwnd, 0, 32768, 40000, 32768, 40000, SWP_NOSIZE); - ok(ret, "Got %d\n", ret); - } + ret = SetWindowPos(hwnd, 0, -32769, -40000, -32769, -90000, SWP_NOSIZE); + ok(ret, "Got %d\n", ret); + ret = SetWindowPos(hwnd, 0, 32768, 40000, 32768, 40000, SWP_NOSIZE); + ok(ret, "Got %d\n", ret); ret = SetWindowPos(hwnd, 0, orig_win_rc.left, orig_win_rc.top, orig_win_rc.right, orig_win_rc.bottom, 0); ok(ret, "Got %d\n", ret); - ok(!(GetWindowLongA(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST), "WS_EX_TOPMOST should not be set\n"); - ret = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); - ok(ret, "Got %d\n", ret); - ok(GetWindowLongA(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST, "WS_EX_TOPMOST should be set\n"); - ret = SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); - ok(ret, "Got %d\n", ret); - ok(GetWindowLongA(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST, "WS_EX_TOPMOST should be set\n"); - ret = SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); - ok(ret, "Got %d\n", ret); - ok(!(GetWindowLongA(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST), "WS_EX_TOPMOST should not be set\n"); - hwnd_desktop = GetDesktopWindow(); - ok(!!hwnd_desktop, "Failed to get hwnd_desktop window (%d).\n", GetLastError()); + ok(!!hwnd_desktop, "Failed to get hwnd_desktop window (%ld).\n", GetLastError()); hwnd_child = create_tool_window(WS_VISIBLE|WS_CHILD, hwnd); - ok(!!hwnd_child, "Failed to create child window (%d)\n", GetLastError()); + ok(!!hwnd_child, "Failed to create child window (%ld)\n", GetLastError()); hwnd_grandchild = create_tool_window(WS_VISIBLE|WS_CHILD, hwnd_child); - ok(!!hwnd_child, "Failed to create child window (%d)\n", GetLastError()); + ok(!!hwnd_child, "Failed to create child window (%ld)\n", GetLastError()); hwnd_child2 = create_tool_window(WS_VISIBLE|WS_CHILD, hwnd); - ok(!!hwnd_child2, "Failed to create second child window (%d)\n", GetLastError()); + ok(!!hwnd_child2, "Failed to create second child window (%ld)\n", GetLastError()); ret = SetWindowPos(hwnd, hwnd2, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); ok(ret, "Got %d\n", ret); @@ -2537,12 +3234,60 @@ static void test_SetWindowPos(HWND hwnd, HWND hwnd2) /* Does not seem to do anything even without passing flags, still returns TRUE */ GetWindowRect(hwnd_child, &rc1); - ret = SetWindowPos(hwnd_child, hwnd2 , 1, 2, 3, 4, 0); - ok(ret, "Got %d\n", ret); + ret = SetWindowPos(hwnd_child, hwnd2, 1, 2, 3, 4, 0); + ok(ret, "Got %d.\n", ret); GetWindowRect(hwnd_child, &rc2); - ok(EqualRect(&rc1, &rc2), "%s != %s\n", wine_dbgstr_rect(&rc1), wine_dbgstr_rect(&rc2)); + ok(EqualRect(&rc1, &rc2), "%s != %s.\n", wine_dbgstr_rect(&rc1), wine_dbgstr_rect(&rc2)); check_active_state(hwnd2, hwnd2, hwnd2); + GetWindowRect(hwnd_child, &rc1); + ret = SetWindowPos(hwnd_child, HWND_NOTOPMOST, 1, 2, 3, 4, 0); + ok(ret, "Got %d.\n", ret); + GetWindowRect(hwnd_child, &rc2); + todo_wine ok(EqualRect(&rc1, &rc2), "%s != %s.\n", wine_dbgstr_rect(&rc1), wine_dbgstr_rect(&rc2)); + check_active_state(hwnd2, hwnd2, hwnd2); + SetWindowPos(hwnd_child, HWND_NOTOPMOST, 0, 0, rc1.right - rc1.left, rc1.bottom - rc1.top, 0); + + GetWindowRect(hwnd_child, &rc1); + ret = SetWindowPos(hwnd_child, HWND_TOPMOST, 1, 2, 3, 4, 0); + ok(ret, "Got %d.\n", ret); + GetWindowRect(hwnd_child, &rc2); + todo_wine ok(EqualRect(&rc1, &rc2), "%s != %s.\n", wine_dbgstr_rect(&rc1), wine_dbgstr_rect(&rc2)); + check_active_state(hwnd2, hwnd2, hwnd2); + SetWindowPos(hwnd_child, HWND_TOPMOST, 0, 0, rc1.right - rc1.left, rc1.bottom - rc1.top, 0); + + /* HWND_TOP / HWND_BOTTOM are different. */ + GetWindowRect(hwnd_child, &rc1); + rc_expected.left = rc1.left + 1; + rc_expected.top = rc1.top + 2; + rc_expected.right = rc1.left + 4; + rc_expected.bottom = rc1.top + 6; + ret = SetWindowPos(hwnd_child, HWND_TOP, 1, 2, 3, 4, 0); + ok(ret, "Got %d.\n", ret); + GetWindowRect(hwnd_child, &rc2); + ok(EqualRect(&rc_expected, &rc2), "%s != %s.\n", + wine_dbgstr_rect(&rc_expected), wine_dbgstr_rect(&rc2)); + check_active_state(hwnd2, hwnd2, hwnd2); + SetWindowPos(hwnd_child, HWND_TOP, 0, 0, rc1.right - rc1.left, rc1.bottom - rc1.top, 0); + + GetWindowRect(hwnd_child, &rc1); + ret = SetWindowPos(hwnd_child, HWND_BOTTOM, 1, 2, 3, 4, 0); + ok(ret, "Got %d.\n", ret); + GetWindowRect(hwnd_child, &rc2); + ok(EqualRect(&rc_expected, &rc2), "%s != %s.\n", + wine_dbgstr_rect(&rc_expected), wine_dbgstr_rect(&rc2)); + check_active_state(hwnd2, hwnd2, hwnd2); + SetWindowPos(hwnd_child, HWND_BOTTOM, 0, 0, rc1.right - rc1.left, rc1.bottom - rc1.top, 0); + + GetWindowRect(hwnd_child, &rc1); + ret = SetWindowPos(hwnd_child, NULL, 1, 2, 3, 4, 0); + ok(ret, "Got %d.\n", ret); + GetWindowRect(hwnd_child, &rc2); + ok(EqualRect(&rc_expected, &rc2), "%s != %s.\n", + wine_dbgstr_rect(&rc_expected), wine_dbgstr_rect(&rc2)); + check_active_state(hwnd2, hwnd2, hwnd2); + SetWindowPos(hwnd_child, NULL, 0, 0, rc1.right - rc1.left, rc1.bottom - rc1.top, 0); + /* Same thing the other way around. */ GetWindowRect(hwnd2, &rc1); ret = SetWindowPos(hwnd2, hwnd_child, 1, 2, 3, 4, 0); @@ -2564,10 +3309,8 @@ static void test_SetWindowPos(HWND hwnd, HWND hwnd2) ret = SetWindowPos(hwnd_grandchild, hwnd_child2, 1, 2, 3, 4, SWP_NOZORDER); ok(ret, "Got %d\n", ret); GetWindowRect(hwnd_grandchild, &rc2); - ok((rc1.left+1) == rc2.left && (rc1.top+2) == rc2.top && - (rc1.left+4) == rc2.right && (rc1.top+6) == rc2.bottom, - "(%d,%d)-(%d,%d) != %s\n", rc1.left+1, rc1.top+2, rc1.left+4, rc1.top+6, - wine_dbgstr_rect(&rc2)); + ok(EqualRect(&rc_expected, &rc2), + "%s != %s.\n", wine_dbgstr_rect(&rc_expected), wine_dbgstr_rect(&rc2)); check_active_state(hwnd2, hwnd2, hwnd2); /* Given a sibling window, the window is properly resized. */ @@ -2575,10 +3318,8 @@ static void test_SetWindowPos(HWND hwnd, HWND hwnd2) ret = SetWindowPos(hwnd_child, hwnd_child2, 1, 2, 3, 4, 0); ok(ret, "Got %d\n", ret); GetWindowRect(hwnd_child, &rc2); - ok((rc1.left+1) == rc2.left && (rc1.top+2) == rc2.top && - (rc1.left+4) == rc2.right && (rc1.top+6) == rc2.bottom, - "(%d,%d)-(%d,%d) != %s\n", rc1.left+1, rc1.top+2, rc1.left+4, rc1.top+6, - wine_dbgstr_rect(&rc2)); + ok(EqualRect(&rc_expected, &rc2), + "%s != %s.\n", wine_dbgstr_rect(&rc_expected), wine_dbgstr_rect(&rc2)); check_active_state(hwnd2, hwnd2, hwnd2); /* Involving the desktop window changes things. */ @@ -2610,11 +3351,11 @@ static void test_SetWindowPos(HWND hwnd, HWND hwnd2) DestroyWindow(hwnd_child2); hwnd_child = create_tool_window(WS_CHILD|WS_POPUP|WS_SYSMENU, hwnd2); - ok(!!hwnd_child, "Failed to create child window (%d)\n", GetLastError()); + ok(!!hwnd_child, "Failed to create child window (%ld)\n", GetLastError()); ret = SetWindowPos(hwnd_child, NULL, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_SHOWWINDOW); ok(ret, "Got %d\n", ret); flush_events( TRUE ); - todo_wine check_active_state(hwnd2, hwnd2, hwnd2); + flaky todo_wine check_active_state(hwnd2, hwnd2, hwnd2); DestroyWindow(hwnd_child); } @@ -2638,13 +3379,11 @@ static void test_SetMenu(HWND parent) ok(ret == hMenu, "unexpected menu id %p\n", ret); /* test whether we can destroy a menu assigned to a window */ retok = DestroyMenu(hMenu); - ok( retok, "DestroyMenu error %d\n", GetLastError()); + ok( retok, "DestroyMenu error %ld\n", GetLastError()); retok = IsMenu(hMenu); - ok(!retok || broken(retok) /* nt4 */, "menu handle should be not valid after DestroyMenu\n"); + ok(!retok, "menu handle should be not valid after DestroyMenu\n"); ret = GetMenu(parent); - /* This test fails on Win9x */ - if (!is_win9x) - ok(ret == hMenu, "unexpected menu id %p\n", ret); + ok(ret == hMenu, "unexpected menu id %p\n", ret); ok(SetMenu(parent, 0), "SetMenu(0) on a top level window should not fail\n"); test_nonclient_area(parent); @@ -2734,7 +3473,6 @@ static void test_window_tree(HWND parent, const DWORD *style, const int *order, else child[i] = CreateWindowExA(0, "static", "", style[i], 0,0,10,10, parent, (HMENU)i, 0, NULL); - trace("child[%ld] = %p\n", i, child[i]); ok(child[i] != 0, "CreateWindowEx failed to create child window\n"); } @@ -2745,9 +3483,7 @@ static void test_window_tree(HWND parent, const DWORD *style, const int *order, for (i = 0; i < total; i++) { - trace("hwnd[%ld] = %p\n", i, hwnd); - ok(child[order[i]] == hwnd, "Z order of child #%ld is wrong\n", i); - + ok(child[order[i]] == hwnd, "Z order of child #%Id is wrong\n", i); hwnd = GetWindow(hwnd, GW_HWNDNEXT); } @@ -2805,7 +3541,6 @@ static void check_z_order_debug(HWND hwnd, HWND next, HWND prev, HWND owner, UlongToHandle(GetWindowLongPtrA(test, GWLP_HINSTANCE)) != GetModuleHandleA(NULL) || GetWindow(test, GW_OWNER) == next)) { - /*trace("skipping next %p (%p)\n", test, UlongToHandle(GetWindowLongPtr(test, GWLP_HINSTANCE)));*/ test = GetWindow(test, GW_HWNDNEXT); } ok_(file, line)(next == test, "%p: expected next %p, got %p\n", hwnd, next, test); @@ -2817,7 +3552,6 @@ static void check_z_order_debug(HWND hwnd, HWND next, HWND prev, HWND owner, UlongToHandle(GetWindowLongPtrA(test, GWLP_HINSTANCE)) != GetModuleHandleA(NULL) || GetWindow(test, GW_OWNER) == hwnd)) { - /*trace("skipping prev %p (%p)\n", test, UlongToHandle(GetWindowLongPtr(test, GWLP_HINSTANCE)));*/ test = GetWindow(test, GW_HWNDPREV); } ok_(file, line)(prev == test, "%p: expected prev %p, got %p\n", hwnd, prev, test); @@ -2834,7 +3568,12 @@ static void test_popup_zorder(HWND hwnd_D, HWND hwnd_E, DWORD style) { HWND hwnd_A, hwnd_B, hwnd_C, hwnd_F; - trace("hwnd_D %p, hwnd_E %p\n", hwnd_D, hwnd_E); + /* Give current thread foreground state otherwise the tests may fail. */ + if (!SetForegroundWindow(hwnd_D)) + { + skip("SetForegroundWindow not working\n"); + return; + } SetWindowPos(hwnd_E, hwnd_D, 0,0,0,0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE); @@ -2845,7 +3584,6 @@ static void test_popup_zorder(HWND hwnd_D, HWND hwnd_E, DWORD style) WS_OVERLAPPED | WS_CAPTION, 100, 100, 100, 100, 0, 0, GetModuleHandleA(NULL), NULL); - trace("hwnd_F %p\n", hwnd_F); check_z_order(hwnd_F, hwnd_D, 0, 0, FALSE); SetWindowPos(hwnd_F, hwnd_E, 0,0,0,0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE); @@ -2857,7 +3595,6 @@ static void test_popup_zorder(HWND hwnd_D, HWND hwnd_E, DWORD style) style, 100, 100, 100, 100, hwnd_F, 0, GetModuleHandleA(NULL), NULL); - trace("hwnd_C %p\n", hwnd_C); check_z_order(hwnd_F, 0, hwnd_E, 0, FALSE); check_z_order(hwnd_E, hwnd_F, hwnd_D, 0, FALSE); check_z_order(hwnd_D, hwnd_E, hwnd_C, 0, FALSE); @@ -2867,7 +3604,6 @@ static void test_popup_zorder(HWND hwnd_D, HWND hwnd_E, DWORD style) style, 100, 100, 100, 100, hwnd_F, 0, GetModuleHandleA(NULL), NULL); - trace("hwnd_B %p\n", hwnd_B); check_z_order(hwnd_F, 0, hwnd_E, 0, FALSE); check_z_order(hwnd_E, hwnd_F, hwnd_D, 0, FALSE); check_z_order(hwnd_D, hwnd_E, hwnd_C, 0, FALSE); @@ -2878,7 +3614,6 @@ static void test_popup_zorder(HWND hwnd_D, HWND hwnd_E, DWORD style) style, 100, 100, 100, 100, 0, 0, GetModuleHandleA(NULL), NULL); - trace("hwnd_A %p\n", hwnd_A); check_z_order(hwnd_F, 0, hwnd_E, 0, FALSE); check_z_order(hwnd_E, hwnd_F, hwnd_D, 0, FALSE); check_z_order(hwnd_D, hwnd_E, hwnd_C, 0, FALSE); @@ -2886,7 +3621,8 @@ static void test_popup_zorder(HWND hwnd_D, HWND hwnd_E, DWORD style) check_z_order(hwnd_B, hwnd_C, hwnd_A, hwnd_F, TRUE); check_z_order(hwnd_A, hwnd_B, 0, 0, TRUE); - trace("A %p B %p C %p D %p E %p F %p\n", hwnd_A, hwnd_B, hwnd_C, hwnd_D, hwnd_E, hwnd_F); + if (winetest_debug > 1) + trace("A %p B %p C %p D %p E %p F %p\n", hwnd_A, hwnd_B, hwnd_C, hwnd_D, hwnd_E, hwnd_F); /* move hwnd_F and its popups up */ SetWindowPos(hwnd_F, HWND_TOP, 0,0,0,0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE); @@ -2914,7 +3650,6 @@ static void test_popup_zorder(HWND hwnd_D, HWND hwnd_E, DWORD style) style, 100, 100, 100, 100, hwnd_A, 0, GetModuleHandleA(NULL), NULL); - trace("hwnd_C %p\n", hwnd_C); check_z_order(hwnd_E, 0, hwnd_D, 0, FALSE); check_z_order(hwnd_D, hwnd_E, hwnd_F, 0, FALSE); check_z_order(hwnd_F, hwnd_D, hwnd_B, 0, FALSE); @@ -2939,21 +3674,11 @@ static void test_vis_rgn( HWND hwnd ) ok( GetRandomRgn( hdc, hrgn, SYSRGN ) != 0, "GetRandomRgn failed\n" ); GetWindowRect( hwnd, &win_rect ); GetRgnBox( hrgn, &rgn_rect ); - if (is_win9x) - { - trace("win9x, mapping to screen coords\n"); - MapWindowPoints( hwnd, 0, (POINT *)&rgn_rect, 2 ); - } - trace("win: %s\n", wine_dbgstr_rect(&win_rect)); - trace("rgn: %s\n", wine_dbgstr_rect(&rgn_rect)); - ok( win_rect.left <= rgn_rect.left, "rgn left %d not inside win rect %d\n", - rgn_rect.left, win_rect.left ); - ok( win_rect.top <= rgn_rect.top, "rgn top %d not inside win rect %d\n", - rgn_rect.top, win_rect.top ); - ok( win_rect.right >= rgn_rect.right, "rgn right %d not inside win rect %d\n", - rgn_rect.right, win_rect.right ); - ok( win_rect.bottom >= rgn_rect.bottom, "rgn bottom %d not inside win rect %d\n", - rgn_rect.bottom, win_rect.bottom ); + ok( win_rect.left <= rgn_rect.left && + win_rect.top <= rgn_rect.top && + win_rect.right >= rgn_rect.right && + win_rect.bottom >= rgn_rect.bottom, + "rgn %s not inside win %s\n", wine_dbgstr_rect(&rgn_rect), wine_dbgstr_rect(&win_rect)); ReleaseDC( hwnd, hdc ); } @@ -3024,14 +3749,16 @@ static void test_SetFocus(HWND hwnd) ShowWindow(child, SW_SHOW); SetFocus(child); ok( GetFocus() == child, "Focus should be on child %p\n", child ); + SetLastError(0xdeadbeef); EnableWindow(hwnd, FALSE); + ok(GetLastError() == 0xdeadbeef, "got error %lu in EnableWindow call\n", GetLastError()); ok( GetFocus() == child, "Focus should still be on child %p\n", child ); EnableWindow(hwnd, TRUE); ok( GetActiveWindow() == hwnd, "parent window %p should be active\n", hwnd); ShowWindow(hwnd, SW_SHOWMINIMIZED); ok( GetActiveWindow() == hwnd, "parent window %p should be active\n", hwnd); -todo_wine + todo_wine ok( GetFocus() != child, "Focus should not be on child %p\n", child ); ok( GetFocus() != hwnd, "Focus should not be on parent %p\n", hwnd ); ShowWindow(hwnd, SW_RESTORE); @@ -3040,12 +3767,10 @@ todo_wine ShowWindow(hwnd, SW_SHOWMINIMIZED); ok( GetActiveWindow() == hwnd, "parent window %p should be active\n", hwnd); ok( GetFocus() != child, "Focus should not be on child %p\n", child ); -todo_wine ok( GetFocus() != hwnd, "Focus should not be on parent %p\n", hwnd ); old_wnd_proc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)set_focus_on_activate_proc); ShowWindow(hwnd, SW_RESTORE); ok( GetActiveWindow() == hwnd, "parent window %p should be active\n", hwnd); -todo_wine ok( GetFocus() == child, "Focus should be on child %p, not %p\n", child, GetFocus() ); SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)old_wnd_proc); @@ -3077,33 +3802,144 @@ todo_wine DestroyWindow( child ); } +static void test_SetActiveWindow_0_proc( char **argv ) +{ + HANDLE start_event, stop_event; + HWND hwnd, other, tmp; + BOOL ret; + + sscanf( argv[3], "%p", &other ); + start_event = CreateEventW( NULL, FALSE, FALSE, L"test_SetActiveWindow_0_start" ); + ok( start_event != 0, "CreateEventW failed, error %lu\n", GetLastError() ); + stop_event = CreateEventW( NULL, FALSE, FALSE, L"test_SetActiveWindow_0_stop" ); + ok( stop_event != 0, "CreateEventW failed, error %lu\n", GetLastError() ); + + hwnd = CreateWindowExA( 0, "static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 200, 200, 0, 0, NULL, NULL ); + ok( !!hwnd, "CreateWindowExA failed, error %lu\n", GetLastError() ); + flush_events( TRUE ); + + ret = SetForegroundWindow( hwnd ); + ok( ret, "SetForegroundWindow failed, error %lu\n", GetLastError() ); + + tmp = GetForegroundWindow(); + ok( tmp == hwnd, "GetForegroundWindow returned %p\n", tmp ); + tmp = GetActiveWindow(); + ok( tmp == hwnd, "GetActiveWindow returned %p\n", tmp ); + tmp = GetFocus(); + ok( tmp == hwnd, "GetFocus returned %p\n", tmp ); + + SetLastError( 0xdeadbeef ); + tmp = SetActiveWindow( 0 ); + if (!tmp) ok( GetLastError() == 0xdeadbeef, "got error %lu\n", GetLastError() ); + else /* < Win10 */ + { + ok( tmp == hwnd, "SetActiveWindow returned %p\n", tmp ); + ok( GetLastError() == 0, "got error %lu\n", GetLastError() ); + + tmp = GetForegroundWindow(); + ok( tmp == other || tmp == 0, "GetForegroundWindow returned %p\n", tmp ); + tmp = GetActiveWindow(); + ok( tmp == 0, "GetActiveWindow returned %p\n", tmp ); + tmp = GetFocus(); + ok( tmp == 0, "GetFocus returned %p\n", tmp ); + + SetEvent( start_event ); + wait_for_events( 1, &stop_event, INFINITE ); + + tmp = GetForegroundWindow(); + todo_wine + ok( tmp == other, "GetForegroundWindow returned %p\n", tmp ); + tmp = GetActiveWindow(); + ok( tmp == 0, "GetActiveWindow returned %p\n", tmp ); + tmp = GetFocus(); + ok( tmp == 0, "GetFocus returned %p\n", tmp ); + } + + tmp = SetActiveWindow( 0 ); + ok( tmp == 0, "SetActiveWindow returned %p\n", tmp ); + tmp = GetForegroundWindow(); + todo_wine + ok( tmp == hwnd, "GetForegroundWindow returned %p\n", tmp ); + tmp = GetActiveWindow(); + todo_wine + ok( tmp == hwnd, "GetActiveWindow returned %p\n", tmp ); + tmp = GetFocus(); + todo_wine + ok( tmp == hwnd, "GetFocus returned %p\n", tmp ); + + CloseHandle( start_event ); + CloseHandle( stop_event ); + DestroyWindow( hwnd ); +} + +static void test_SetActiveWindow_0( char **argv ) +{ + STARTUPINFOA startup = {.cb = sizeof(STARTUPINFOA)}; + PROCESS_INFORMATION info; + char cmdline[MAX_PATH]; + HANDLE events[3]; + HWND hwnd, tmp; + BOOL ret; + + hwnd = CreateWindowExA( 0, "static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 200, 200, 0, 0, NULL, NULL ); + ok( !!hwnd, "CreateWindowExA failed, error %lu\n", GetLastError() ); + SetWindowPos( hwnd, HWND_TOPMOST, 150, 150, 300, 300, SWP_FRAMECHANGED | SWP_SHOWWINDOW ); + flush_events( TRUE ); + + tmp = GetForegroundWindow(); + flaky_wine + ok( tmp == hwnd, "GetForegroundWindow returned %p\n", tmp ); + tmp = GetActiveWindow(); + flaky_wine + ok( tmp == hwnd, "GetActiveWindow returned %p\n", tmp ); + tmp = GetFocus(); + flaky_wine + ok( tmp == hwnd, "GetFocus returned %p\n", tmp ); + + events[1] = CreateEventW( NULL, FALSE, FALSE, L"test_SetActiveWindow_0_start" ); + ok( events[1] != 0, "CreateEventW failed, error %lu\n", GetLastError() ); + events[2] = CreateEventW( NULL, FALSE, FALSE, L"test_SetActiveWindow_0_stop" ); + ok( events[2] != 0, "CreateEventW failed, error %lu\n", GetLastError() ); + + sprintf( cmdline, "%s %s SetActiveWindow_0 %p", argv[0], argv[1], hwnd ); + ret = CreateProcessA( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info ); + ok( ret, "CreateProcessA failed, error %lu\n", GetLastError() ); + + events[0] = info.hProcess; + if (wait_for_events( 2, events, INFINITE ) == 1) + { + tmp = GetForegroundWindow(); + todo_wine + ok( tmp == hwnd, "GetForegroundWindow returned %p\n", tmp ); + tmp = GetActiveWindow(); + todo_wine + ok( tmp == hwnd, "GetActiveWindow returned %p\n", tmp ); + tmp = GetFocus(); + todo_wine + ok( tmp == hwnd, "GetFocus returned %p\n", tmp ); + SetEvent( events[2] ); + } + + wait_child_process( info.hProcess ); + CloseHandle( info.hProcess ); + CloseHandle( info.hThread ); + CloseHandle( events[1] ); + CloseHandle( events[2] ); + + DestroyWindow( hwnd ); +} + static void test_SetActiveWindow(HWND hwnd) { - HWND hwnd2; + HWND hwnd2, ret; flush_events( TRUE ); ShowWindow(hwnd, SW_HIDE); - SetFocus(0); - SetActiveWindow(0); check_wnd_state(0, 0, 0, 0); - /*trace("testing SetActiveWindow %p\n", hwnd);*/ - ShowWindow(hwnd, SW_SHOW); check_wnd_state(hwnd, hwnd, hwnd, 0); - hwnd2 = SetActiveWindow(0); - ok(hwnd2 == hwnd, "SetActiveWindow returned %p instead of %p\n", hwnd2, hwnd); - if (!GetActiveWindow()) /* doesn't always work on vista */ - { - ros_skip_flaky - check_wnd_state(0, 0, 0, 0); - hwnd2 = SetActiveWindow(hwnd); - ros_skip_flaky - ok(hwnd2 == 0, "SetActiveWindow returned %p instead of 0\n", hwnd2); - } - check_wnd_state(hwnd, hwnd, hwnd, 0); - SetWindowPos(hwnd,0,0,0,0,0,SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_HIDEWINDOW); check_wnd_state(hwnd, hwnd, hwnd, 0); @@ -3113,7 +3949,7 @@ static void test_SetActiveWindow(HWND hwnd) ShowWindow(hwnd, SW_HIDE); check_wnd_state(0, 0, 0, 0); - /*trace("testing SetActiveWindow on an invisible window %p\n", hwnd);*/ + /* Invisible window. */ SetActiveWindow(hwnd); check_wnd_state(hwnd, hwnd, hwnd, 0); @@ -3123,6 +3959,9 @@ static void test_SetActiveWindow(HWND hwnd) hwnd2 = CreateWindowExA(0, "static", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 0, 0, hwnd, 0, 0, NULL); check_wnd_state(hwnd2, hwnd2, hwnd2, 0); + SetActiveWindow(hwnd); + check_wnd_state(hwnd, hwnd, hwnd, 0); + DestroyWindow(hwnd2); check_wnd_state(hwnd, hwnd, hwnd, 0); @@ -3134,6 +3973,23 @@ static void test_SetActiveWindow(HWND hwnd) DestroyWindow(hwnd2); check_wnd_state(hwnd, hwnd, hwnd, 0); + + /* try to activate the desktop */ + SetLastError(0xdeadbeef); + ret = SetActiveWindow(GetDesktopWindow()); + ok(ret == NULL, "expected NULL, got %p\n", ret); + todo_wine + ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %lu\n", GetLastError()); + check_wnd_state(hwnd, hwnd, hwnd, 0); + + /* activating a child should activate the parent */ + hwnd2 = CreateWindowExA(0, "MainWindowClass", "Child window", WS_CHILD, 0, 0, 0, 0, hwnd, 0, GetModuleHandleA(NULL), NULL); + check_wnd_state(hwnd, hwnd, hwnd, 0); + ret = SetActiveWindow(hwnd2); + ok(ret == hwnd, "expected %p, got %p\n", hwnd, ret); + check_wnd_state(hwnd, hwnd, hwnd, 0); + + DestroyWindow(hwnd2); } struct create_window_thread_params @@ -3152,10 +4008,10 @@ static DWORD WINAPI create_window_thread(void *param) p->window = CreateWindowA("static", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 0, 0, 0, 0, 0, 0); ret = SetEvent(p->window_created); - ok(ret, "SetEvent failed, last error %#x.\n", GetLastError()); + ok(ret, "SetEvent failed, last error %#lx.\n", GetLastError()); res = WaitForSingleObject(p->test_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()); DestroyWindow(p->window); return 0; @@ -3173,22 +4029,11 @@ static void test_SetForegroundWindow(HWND hwnd) flush_events( TRUE ); ShowWindow(hwnd, SW_HIDE); - SetFocus(0); - SetActiveWindow(0); check_wnd_state(0, 0, 0, 0); - /*trace("testing SetForegroundWindow %p\n", hwnd);*/ - ShowWindow(hwnd, SW_SHOW); check_wnd_state(hwnd, hwnd, hwnd, 0); - hwnd2 = SetActiveWindow(0); - ok(hwnd2 == hwnd, "SetActiveWindow(0) returned %p instead of %p\n", hwnd2, hwnd); - if (GetActiveWindow() == hwnd) /* doesn't always work on vista */ - check_wnd_state(hwnd, hwnd, hwnd, 0); - else - check_wnd_state(0, 0, 0, 0); - ret = SetForegroundWindow(hwnd); if (!ret) { @@ -3200,9 +4045,8 @@ static void test_SetForegroundWindow(HWND hwnd) SetLastError(0xdeadbeef); ret = SetForegroundWindow(0); ok(!ret, "SetForegroundWindow returned TRUE instead of FALSE\n"); - ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || - broken(GetLastError() == 0xdeadbeef), /* win9x */ - "got error %d expected ERROR_INVALID_WINDOW_HANDLE\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, + "got error %ld expected ERROR_INVALID_WINDOW_HANDLE\n", GetLastError()); check_wnd_state(hwnd, hwnd, hwnd, 0); SetWindowPos(hwnd,0,0,0,0,0,SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_HIDEWINDOW); @@ -3214,16 +4058,16 @@ static void test_SetForegroundWindow(HWND hwnd) hwnd2 = GetForegroundWindow(); ok(hwnd2 == hwnd, "Wrong foreground window %p\n", hwnd2); ret = SetForegroundWindow( GetDesktopWindow() ); - ok(ret, "SetForegroundWindow(desktop) error: %d\n", GetLastError()); + ok(ret, "SetForegroundWindow(desktop) error: %ld\n", GetLastError()); hwnd2 = GetForegroundWindow(); ok(hwnd2 != hwnd, "Wrong foreground window %p\n", hwnd2); ShowWindow(hwnd, SW_HIDE); check_wnd_state(0, 0, 0, 0); - /*trace("testing SetForegroundWindow on an invisible window %p\n", hwnd);*/ + /* Invisible window. */ ret = SetForegroundWindow(hwnd); - ok(ret || broken(!ret), /* win98 */ "SetForegroundWindow returned FALSE instead of TRUE\n"); + ok(ret, "SetForegroundWindow returned FALSE instead of TRUE\n"); check_wnd_state(hwnd, hwnd, hwnd, 0); ShowWindow(hwnd, SW_SHOW); @@ -3248,13 +4092,13 @@ static void test_SetForegroundWindow(HWND hwnd) check_wnd_state(hwnd2, hwnd2, hwnd2, 0); thread_params.window_created = CreateEventW(NULL, FALSE, FALSE, NULL); - ok(!!thread_params.window_created, "CreateEvent failed, last error %#x.\n", GetLastError()); + ok(!!thread_params.window_created, "CreateEvent failed, last error %#lx.\n", GetLastError()); thread_params.test_finished = CreateEventW(NULL, FALSE, FALSE, NULL); - ok(!!thread_params.test_finished, "CreateEvent failed, last error %#x.\n", GetLastError()); + ok(!!thread_params.test_finished, "CreateEvent failed, last error %#lx.\n", GetLastError()); thread = CreateThread(NULL, 0, create_window_thread, &thread_params, 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(thread_params.window_created, 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()); check_wnd_state(hwnd2, thread_params.window, hwnd2, 0); SetForegroundWindow(hwnd2); @@ -3262,8 +4106,9 @@ static void test_SetForegroundWindow(HWND hwnd) while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); if (0) check_wnd_state(hwnd2, hwnd2, hwnd2, 0); - todo_wine ok(GetActiveWindow() == hwnd2, "Expected active window %p, got %p.\n", hwnd2, GetActiveWindow()); - todo_wine ok(GetFocus() == hwnd2, "Expected focus window %p, got %p.\n", hwnd2, GetFocus()); + + ok(GetActiveWindow() == hwnd2, "Expected active window %p, got %p.\n", hwnd2, GetActiveWindow()); + ok(GetFocus() == hwnd2, "Expected focus window %p, got %p.\n", hwnd2, GetFocus()); SetForegroundWindow(hwnd); check_wnd_state(hwnd, hwnd, hwnd, 0); @@ -3284,6 +4129,8 @@ static void test_SetForegroundWindow(HWND hwnd) CloseHandle(thread_params.window_created); CloseHandle(thread); DestroyWindow(hwnd2); + + flush_events(TRUE); } static WNDPROC old_button_proc; @@ -3306,7 +4153,6 @@ static LRESULT WINAPI button_hook_proc(HWND button, UINT msg, WPARAM wparam, LPA hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL); assert(hwnd); - trace("hwnd %p\n", hwnd); check_wnd_state(button, button, button, button); @@ -3318,7 +4164,6 @@ static LRESULT WINAPI button_hook_proc(HWND button, UINT msg, WPARAM wparam, LPA hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL); assert(hwnd); - trace("hwnd %p\n", hwnd); check_wnd_state(button, button, button, button); @@ -3353,7 +4198,6 @@ static void test_capture_1(void) button = CreateWindowExA(0, "button", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL); assert(button); - trace("button %p\n", button); old_button_proc = (WNDPROC)SetWindowLongPtrA(button, GWLP_WNDPROC, (LONG_PTR)button_hook_proc); @@ -3379,7 +4223,6 @@ static void test_capture_2(void) button = CreateWindowExA(0, "button", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL); assert(button); - trace("button %p\n", button); check_wnd_state(button, button, button, 0); @@ -3396,7 +4239,6 @@ static void test_capture_2(void) hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL); assert(hwnd); - trace("hwnd %p\n", hwnd); check_wnd_state(button, button, button, button); @@ -3408,7 +4250,6 @@ static void test_capture_2(void) hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL); assert(hwnd); - trace("hwnd %p\n", hwnd); check_wnd_state(button, button, button, button); @@ -3469,17 +4310,16 @@ static LRESULT CALLBACK test_capture_4_proc(HWND hWnd, UINT msg, WPARAM wParam, gti.cbSize = sizeof(GUITHREADINFO); status = pGetGUIThreadInfo(GetCurrentThreadId(), >i); ok(status, "GetGUIThreadInfo() failed!\n"); - ok(gti.flags & GUI_INMENUMODE, "Thread info incorrect (flags=%08X)!\n", gti.flags); + ok(gti.flags & GUI_INMENUMODE, "Thread info incorrect (flags=%08lX)!\n", gti.flags); } cap_wnd = GetCapture(); - ok(cap_wnd == (HWND)lParam, "capture window %p does not match lparam %lx\n", cap_wnd, lParam); + ok(cap_wnd == (HWND)lParam, "capture window %p does not match lparam %Ix\n", cap_wnd, lParam); todo_wine ok(cap_wnd == hWnd, "capture window %p does not match hwnd %p\n", cap_wnd, hWnd); /* check that re-setting the capture for the menu fails */ set_cap_wnd = SetCapture(cap_wnd); - ok(!set_cap_wnd || broken(set_cap_wnd == cap_wnd), /* nt4 */ - "SetCapture should have failed!\n"); + ok(!set_cap_wnd, "SetCapture should have failed!\n"); if (set_cap_wnd) { DestroyWindow(hWnd); @@ -3501,7 +4341,7 @@ static LRESULT CALLBACK test_capture_4_proc(HWND hWnd, UINT msg, WPARAM wParam, gti.cbSize = sizeof(GUITHREADINFO); status = pGetGUIThreadInfo(GetCurrentThreadId(), >i); ok(status, "GetGUIThreadInfo() failed!\n"); - ok(gti.flags & GUI_INMENUMODE, "Thread info incorrect (flags=%08X)!\n", gti.flags); + ok(gti.flags & GUI_INMENUMODE, "Thread info incorrect (flags=%08lX)!\n", gti.flags); } /* verify that no capture change took place */ @@ -3544,11 +4384,11 @@ static void test_capture_4(void) wclass.cbClsExtra = 0; wclass.cbWndExtra = 0; aclass = RegisterClassA( &wclass ); - ok( aclass, "RegisterClassA failed with error %d\n", GetLastError()); + ok( aclass, "RegisterClassA failed with error %ld\n", GetLastError()); hwnd = CreateWindowA( wclass.lpszClassName, "MenuTest", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 400, 200, NULL, NULL, hInstance, NULL); - ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); + ok(hwnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError()); if (!hwnd) return; hmenu = CreatePopupMenu(); @@ -3558,16 +4398,9 @@ static void test_capture_4(void) /* set main window to have initial capture */ SetCapture(hwnd); - if (is_win9x) - { - win_skip("TrackPopupMenu test crashes on Win9x/WinMe\n"); - } - else - { - /* create popup (it will self-destruct) */ - ret = TrackPopupMenu(hmenu, TPM_RETURNCMD, 100, 100, 0, hwnd, NULL); - ok( ret == 0, "TrackPopupMenu returned %d expected zero\n", ret); - } + /* create popup (it will self-destruct) */ + ret = TrackPopupMenu(hmenu, TPM_RETURNCMD, 100, 100, 0, hwnd, NULL); + ok( ret == 0, "TrackPopupMenu returned %d expected zero\n", ret); /* clean up */ DestroyMenu(hmenu); @@ -3581,7 +4414,7 @@ static BOOL peek_message( MSG *msg ) do { ret = PeekMessageA(msg, 0, 0, 0, PM_REMOVE); - } while (ret && ignore_message(msg->message)); + } while (ret && ignore_message(msg->message, msg->hwnd)); return ret; } @@ -3684,17 +4517,15 @@ static void test_mouse_input(HWND hwnd) RECT rc; POINT pt; int x, y; - HWND popup; + HWND popup, child = NULL; MSG msg; BOOL ret; - LRESULT res; ShowWindow(hwnd, SW_SHOWNORMAL); UpdateWindow(hwnd); SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE ); GetWindowRect(hwnd, &rc); - trace("main window %p: %s\n", hwnd, wine_dbgstr_rect(&rc)); popup = CreateWindowExA(0, "MainWindowClass", NULL, WS_POPUP, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, @@ -3705,11 +4536,9 @@ static void test_mouse_input(HWND hwnd) SetWindowPos( popup, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE ); GetWindowRect(popup, &rc); - trace("popup window %p: %s\n", popup, wine_dbgstr_rect(&rc)); x = rc.left + (rc.right - rc.left) / 2; y = rc.top + (rc.bottom - rc.top) / 2; - trace("setting cursor to (%d,%d)\n", x, y); SetCursorPos(x, y); GetCursorPos(&pt); @@ -3729,7 +4558,7 @@ static void test_mouse_input(HWND hwnd) { ok(msg.hwnd == popup && msg.message == WM_MOUSEMOVE, "hwnd %p message %04x\n", msg.hwnd, msg.message); - ok(msg.pt.x == x && msg.pt.y == y, "wrong message coords (%d,%d)/(%d,%d)\n", + ok(msg.pt.x == x && msg.pt.y == y, "wrong message coords (%d,%d)/(%ld,%ld)\n", x, y, msg.pt.x, msg.pt.y); } @@ -3745,7 +4574,7 @@ static void test_mouse_input(HWND hwnd) /* FIXME: SetCursorPos in Wine generates additional WM_MOUSEMOVE message */ while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) { - if (ignore_message(msg.message)) continue; + if (ignore_message(msg.message, msg.hwnd)) continue; ok(msg.hwnd == popup && msg.message == WM_MOUSEMOVE, "hwnd %p message %04x\n", msg.hwnd, msg.message); DispatchMessageA(&msg); @@ -3843,41 +4672,74 @@ static void test_mouse_input(HWND hwnd) msg.hwnd, popup, msg.message); ok(peek_message(&msg), "no message available\n"); - /* Test WM_MOUSEACTIVATE */ -#define TEST_MOUSEACTIVATE(A,B) \ - res = SendMessageA(hwnd, WM_MOUSEACTIVATE, (WPARAM)hwnd, (LPARAM)MAKELRESULT(A,0)); \ - ok(res == B, "WM_MOUSEACTIVATE for %s returned %ld\n", #A, res); - - TEST_MOUSEACTIVATE(HTERROR,MA_ACTIVATE); - TEST_MOUSEACTIVATE(HTTRANSPARENT,MA_ACTIVATE); - TEST_MOUSEACTIVATE(HTNOWHERE,MA_ACTIVATE); - TEST_MOUSEACTIVATE(HTCLIENT,MA_ACTIVATE); - TEST_MOUSEACTIVATE(HTCAPTION,MA_ACTIVATE); - TEST_MOUSEACTIVATE(HTSYSMENU,MA_ACTIVATE); - TEST_MOUSEACTIVATE(HTSIZE,MA_ACTIVATE); - TEST_MOUSEACTIVATE(HTMENU,MA_ACTIVATE); - TEST_MOUSEACTIVATE(HTHSCROLL,MA_ACTIVATE); - TEST_MOUSEACTIVATE(HTVSCROLL,MA_ACTIVATE); - TEST_MOUSEACTIVATE(HTMINBUTTON,MA_ACTIVATE); - TEST_MOUSEACTIVATE(HTMAXBUTTON,MA_ACTIVATE); - TEST_MOUSEACTIVATE(HTLEFT,MA_ACTIVATE); - TEST_MOUSEACTIVATE(HTRIGHT,MA_ACTIVATE); - TEST_MOUSEACTIVATE(HTTOP,MA_ACTIVATE); - TEST_MOUSEACTIVATE(HTTOPLEFT,MA_ACTIVATE); - TEST_MOUSEACTIVATE(HTTOPRIGHT,MA_ACTIVATE); - TEST_MOUSEACTIVATE(HTBOTTOM,MA_ACTIVATE); - TEST_MOUSEACTIVATE(HTBOTTOMLEFT,MA_ACTIVATE); - TEST_MOUSEACTIVATE(HTBOTTOMRIGHT,MA_ACTIVATE); - TEST_MOUSEACTIVATE(HTBORDER,MA_ACTIVATE); - TEST_MOUSEACTIVATE(HTOBJECT,MA_ACTIVATE); - TEST_MOUSEACTIVATE(HTCLOSE,MA_ACTIVATE); - TEST_MOUSEACTIVATE(HTHELP,MA_ACTIVATE); + ShowWindow(popup, SW_HIDE); -done: - /* Clear any messages left behind by WM_MOUSEACTIVATE tests */ + /* Test sending double click to the non-client area, while capturing the window after + the first click has been processed. Use a child window to ensure that Wine's graphics + driver isn't managing the non-client area. */ + + GetWindowRect(hwnd, &rc); + child = CreateWindowExA(0, "MainWindowClass", NULL, WS_CHILD | WS_CAPTION | WS_SYSMENU | WS_VISIBLE, + rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, + hwnd, 0, 0, NULL); + GetWindowRect(child, &rc); + + UpdateWindow(child); + SetCursorPos( rc.left + 5, rc.top + 5 ); flush_events( TRUE ); + mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); + mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0); + mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); + mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0); + + ret = wait_for_message( &msg ); + ok(ret, "no message available\n"); + if (msg.message == WM_NCMOUSEMOVE) /* not sent by Win10 1709+ */ + { + ok(msg.hwnd == child, "expected %p, got %p\n", child, msg.hwnd); + ret = wait_for_message( &msg ); + ok(ret, "no message available\n"); + } + ok(msg.hwnd == child && msg.message == WM_NCLBUTTONDOWN, "hwnd %p/%p message %04x\n", + msg.hwnd, child, msg.message); + ok(msg.wParam == HTSYSMENU, "wparam %Id\n", msg.wParam); + + ret = wait_for_message( &msg ); + ok(ret, "no message available\n"); + ok(msg.hwnd == child && msg.message == WM_NCLBUTTONUP, "hwnd %p/%p message %04x\n", + msg.hwnd, child, msg.message); + + SetCapture( child ); + + ret = wait_for_message( &msg ); + ok(ret, "no message available\n"); + ok(msg.hwnd == child && msg.message == WM_LBUTTONDBLCLK, "hwnd %p/%p message %04x\n", + msg.hwnd, child, msg.message); + ok(msg.wParam == MK_LBUTTON, "wparam %Id\n", msg.wParam); + + ret = wait_for_message( &msg ); + ok(ret, "no message available\n"); + todo_wine + ok(msg.hwnd == child && (msg.message == WM_NCMOUSELEAVE || broken(msg.message == WM_LBUTTONUP)), + "hwnd %p/%p message %04x\n", msg.hwnd, child, msg.message); + + if (msg.message == WM_NCMOUSELEAVE) + ret = wait_for_message( &msg ); + ok(ret, "no message available\n"); + ok(msg.hwnd == child && msg.message == WM_LBUTTONUP, "hwnd %p/%p message %04x\n", + msg.hwnd, child, msg.message); + + ret = peek_message(&msg); + ok(!ret, "message %04x available\n", msg.message); + +done: + flush_events( TRUE ); + + if (child) DestroyWindow(child); DestroyWindow(popup); + + SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); } static void test_validatergn(HWND hwnd) @@ -3920,12 +4782,15 @@ static void test_validatergn(HWND hwnd) static void nccalchelper(HWND hwnd, INT x, INT y, RECT *prc) { + LRESULT ret; RECT rc; MoveWindow( hwnd, 0, 0, x, y, 0); GetWindowRect( hwnd, prc); rc = *prc; - DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)prc); - trace("window rect is %s, nccalc rect is %s\n", wine_dbgstr_rect(&rc), wine_dbgstr_rect(prc)); + ret = DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)prc); + ok(!ret, "got %08Ix\n", ret); + if (winetest_debug > 1) + trace("window rect is %s, nccalc rect is %s\n", wine_dbgstr_rect(&rc), wine_dbgstr_rect(prc)); } static void test_nccalcscroll(HWND parent) @@ -4015,44 +4880,39 @@ static void test_SetParent(void) ok(!IsChild(child3, child4), "wrong parent/child %p/%p\n", child3, child4); ok(!IsChild(desktop, child4), "wrong parent/child %p/%p\n", desktop, child4); - if (!is_win9x) /* Win9x doesn't survive this test */ + ok(!SetParent(parent, child1), "SetParent should fail\n"); + ok(!SetParent(child2, child3), "SetParent should fail\n"); + ok(SetParent(child1, parent) != 0, "SetParent should not fail\n"); + ret = SetParent(parent, child2); + todo_wine ok( !ret || broken( ret != 0 ), "SetParent should fail\n"); + if (ret) /* nt4, win2k */ { - ok(!SetParent(parent, child1), "SetParent should fail\n"); - ok(!SetParent(child2, child3), "SetParent should fail\n"); - ok(SetParent(child1, parent) != 0, "SetParent should not fail\n"); - ret = SetParent(parent, child2); - todo_wine ok( !ret || broken( ret != 0 ), "SetParent should fail\n"); - if (ret) /* nt4, win2k */ - { - ret = SetParent(parent, child3); - ok(ret != 0, "SetParent should not fail\n"); - ret = SetParent(child2, parent); - ok(!ret, "SetParent should fail\n"); - ret = SetParent(parent, child4); - ok(ret != 0, "SetParent should not fail\n"); - check_parents(parent, child4, child4, 0, 0, child4, parent); - check_parents(child1, parent, parent, parent, 0, child4, parent); - check_parents(child2, desktop, parent, parent, parent, child2, parent); - check_parents(child3, child2, child2, child2, 0, child2, parent); - check_parents(child4, desktop, child2, child2, child2, child4, parent); - } - else - { - ret = SetParent(parent, child3); - ok(ret != 0, "SetParent should not fail\n"); - ret = SetParent(child2, parent); - ok(!ret, "SetParent should fail\n"); - ret = SetParent(parent, child4); - ok(!ret, "SetParent should fail\n"); - check_parents(parent, child3, child3, 0, 0, child2, parent); - check_parents(child1, parent, parent, parent, 0, child2, parent); - check_parents(child2, desktop, parent, parent, parent, child2, parent); - check_parents(child3, child2, child2, child2, 0, child2, parent); - check_parents(child4, desktop, child2, child2, child2, child4, parent); - } + ret = SetParent(parent, child3); + ok(ret != 0, "SetParent should not fail\n"); + ret = SetParent(child2, parent); + ok(!ret, "SetParent should fail\n"); + ret = SetParent(parent, child4); + ok(ret != 0, "SetParent should not fail\n"); + check_parents(parent, child4, child4, 0, 0, child4, parent); + check_parents(child1, parent, parent, parent, 0, child4, parent); + check_parents(child2, desktop, parent, parent, parent, child2, parent); + check_parents(child3, child2, child2, child2, 0, child2, parent); + check_parents(child4, desktop, child2, child2, child2, child4, parent); } else - skip("Win9x/WinMe crash\n"); + { + ret = SetParent(parent, child3); + ok(ret != 0, "SetParent should not fail\n"); + ret = SetParent(child2, parent); + ok(!ret, "SetParent should fail\n"); + ret = SetParent(parent, child4); + ok(!ret, "SetParent should fail\n"); + check_parents(parent, child3, child3, 0, 0, child2, parent); + check_parents(child1, parent, parent, parent, 0, child2, parent); + check_parents(child2, desktop, parent, parent, parent, child2, parent); + check_parents(child3, child2, child2, child2, 0, child2, parent); + check_parents(child4, desktop, child2, child2, child2, child4, parent); + } hMenu = CreateMenu(); sibling = CreateWindowExA(0, "static", NULL, WS_OVERLAPPEDWINDOW, @@ -4148,34 +5008,65 @@ static void test_SetParent(void) ok(!IsWindow(popup), "popup still exists\n"); } +typedef struct +{ + DWORD cs_style; + DWORD cs_exstyle; + DWORD style; + DWORD exstyle; +} test_style; + +static LRESULT WINAPI cbt_proc(int ncode, WPARAM wparam, LPARAM lparam) +{ + CBT_CREATEWNDW* c = (CBT_CREATEWNDW*)lparam; + HWND hwnd = (HWND)wparam; + test_style *ts; + DWORD style; + + if (ncode != HCBT_CREATEWND) + return CallNextHookEx(NULL, ncode, wparam, lparam); + + ts = c->lpcs->lpCreateParams; + ok(ts != NULL, "lpCreateParams not set\n"); + ok(c->lpcs->style == ts->cs_style, "style = 0x%08lx, expected 0x%08lx\n", + c->lpcs->style, ts->cs_style); + ok(c->lpcs->dwExStyle == ts->cs_exstyle, "exstyle = 0x%08lx, expected 0x%08lx\n", + c->lpcs->dwExStyle, ts->cs_exstyle); + + style = GetWindowLongW(hwnd, GWL_STYLE); + ok(style == ts->cs_style, "style = 0x%08lx, expected 0x%08lx\n", + style, ts->cs_style); + style = GetWindowLongW(hwnd, GWL_EXSTYLE); + ok(style == (ts->cs_exstyle & ~WS_EX_LAYERED), + "exstyle = 0x%08lx, expected 0x%08lx\n", style, ts->cs_exstyle); + return CallNextHookEx(NULL, ncode, wparam, lparam); +} + static LRESULT WINAPI StyleCheckProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { - LPCREATESTRUCTA lpcs; - LPSTYLESTRUCT lpss; + CREATESTRUCTA *cs; + test_style *ts; + DWORD style; switch (msg) { case WM_NCCREATE: case WM_CREATE: - lpcs = (LPCREATESTRUCTA)lparam; - lpss = lpcs->lpCreateParams; - if (lpss) - { - if ((lpcs->dwExStyle & WS_EX_DLGMODALFRAME) || - ((!(lpcs->dwExStyle & WS_EX_STATICEDGE)) && - (lpcs->style & (WS_DLGFRAME | WS_THICKFRAME)))) - ok(lpcs->dwExStyle & WS_EX_WINDOWEDGE, "Window should have WS_EX_WINDOWEDGE style\n"); - else - ok(!(lpcs->dwExStyle & WS_EX_WINDOWEDGE), "Window shouldn't have WS_EX_WINDOWEDGE style\n"); + cs = (LPCREATESTRUCTA)lparam; + ts = cs->lpCreateParams; - ok((lpss->styleOld & ~WS_EX_WINDOWEDGE) == (lpcs->dwExStyle & ~WS_EX_WINDOWEDGE), - "Ex style (0x%08x) should match what the caller passed to CreateWindowEx (0x%08x)\n", - lpss->styleOld, lpcs->dwExStyle); + ok(ts != NULL, "lpCreateParams not set\n"); + ok(cs->style == ts->cs_style, "style = 0x%08lx, expected 0x%08lx\n", + cs->style, ts->cs_style); + ok(cs->dwExStyle == ts->cs_exstyle, "exstyle = 0x%08lx, expected 0x%08lx\n", + cs->dwExStyle, ts->cs_exstyle); - ok(lpss->styleNew == lpcs->style, - "Style (0x%08x) should match what the caller passed to CreateWindowEx (0x%08x)\n", - lpss->styleNew, lpcs->style); - } + style = GetWindowLongW(hwnd, GWL_STYLE); + ok(style == ts->style, "style = 0x%08lx, expected 0x%08lx\n", + style, ts->style); + style = GetWindowLongW(hwnd, GWL_EXSTYLE); + ok(style == ts->exstyle, "exstyle = 0x%08lx, expected 0x%08lx\n", + style, ts->exstyle); break; } return DefWindowProcA(hwnd, msg, wparam, lparam); @@ -4207,29 +5098,41 @@ static void check_window_style(DWORD dwStyleIn, DWORD dwExStyleIn, DWORD dwStyle { DWORD dwActualStyle; DWORD dwActualExStyle; - STYLESTRUCT ss; + test_style ts; HWND hwnd; HWND hwndParent = NULL; + HHOOK hook; - ss.styleNew = dwStyleIn; - ss.styleOld = dwExStyleIn; + ts.cs_style = dwStyleIn; + ts.cs_exstyle = dwExStyleIn; + if ((dwExStyleIn & WS_EX_DLGMODALFRAME) || + ((!(dwExStyleIn & WS_EX_STATICEDGE)) && + (dwStyleIn & (WS_DLGFRAME | WS_THICKFRAME)))) + ts.cs_exstyle |= WS_EX_WINDOWEDGE; + else + ts.cs_exstyle &= ~WS_EX_WINDOWEDGE; + ts.style = dwStyleOut; + ts.exstyle = dwExStyleOut; if (dwStyleIn & WS_CHILD) { - hwndParent = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomStyleCheckClass), NULL, + hwndParent = CreateWindowExA(0, "static", NULL, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL, NULL, NULL); + ok(hwndParent != NULL, "CreateWindowExA failed\n"); } + hook = SetWindowsHookExW(WH_CBT, cbt_proc, 0, GetCurrentThreadId()); hwnd = CreateWindowExA(dwExStyleIn, (LPCSTR)MAKEINTATOM(atomStyleCheckClass), NULL, - dwStyleIn, 0, 0, 0, 0, hwndParent, NULL, NULL, &ss); - assert(hwnd); + dwStyleIn, 0, 0, 0, 0, hwndParent, NULL, NULL, &ts); + ok(hwnd != NULL, "CreateWindowExA failed\n"); + UnhookWindowsHookEx(hook); flush_events( TRUE ); dwActualStyle = GetWindowLongA(hwnd, GWL_STYLE); dwActualExStyle = GetWindowLongA(hwnd, GWL_EXSTYLE); - ok(dwActualStyle == dwStyleOut, "expected style %#x, got %#x\n", dwStyleOut, dwActualStyle); - ok(dwActualExStyle == dwExStyleOut, "expected ex_style %#x, got %#x\n", dwExStyleOut, dwActualExStyle); + ok(dwActualStyle == dwStyleOut, "expected style %#lx, got %#lx\n", dwStyleOut, dwActualStyle); + ok(dwActualExStyle == dwExStyleOut, "expected ex_style %#lx, got %#lx\n", dwExStyleOut, dwActualExStyle); /* try setting the styles explicitly */ SetWindowLongA( hwnd, GWL_EXSTYLE, dwExStyleIn ); @@ -4242,8 +5145,8 @@ static void check_window_style(DWORD dwStyleIn, DWORD dwExStyleIn, DWORD dwStyle dwExStyleOut = dwExStyleIn | WS_EX_WINDOWEDGE; else dwExStyleOut = dwExStyleIn & ~WS_EX_WINDOWEDGE; - ok(dwActualStyle == dwStyleOut, "expected style %#x, got %#x\n", dwStyleOut, dwActualStyle); - ok(dwActualExStyle == dwExStyleOut, "expected ex_style %#x, got %#x\n", dwExStyleOut, dwActualExStyle); + ok(dwActualStyle == dwStyleOut, "expected style %#lx, got %#lx\n", dwStyleOut, dwActualStyle); + ok(dwActualExStyle == dwExStyleOut, "expected ex_style %#lx, got %#lx\n", dwExStyleOut, dwActualExStyle); SetWindowLongA( hwnd, GWL_STYLE, dwStyleIn ); dwActualStyle = GetWindowLongA(hwnd, GWL_STYLE); @@ -4258,10 +5161,8 @@ static void check_window_style(DWORD dwStyleIn, DWORD dwExStyleIn, DWORD dwStyle dwExStyleOut = dwExStyleIn | WS_EX_WINDOWEDGE; else dwExStyleOut = dwExStyleIn & ~WS_EX_WINDOWEDGE; - ok(dwActualStyle == dwStyleOut, "expected style %#x, got %#x\n", dwStyleOut, dwActualStyle); - /* FIXME: Remove the condition below once Wine is fixed */ - todo_wine_if (dwActualExStyle != dwExStyleOut) - ok(dwActualExStyle == dwExStyleOut, "expected ex_style %#x, got %#x\n", dwExStyleOut, dwActualExStyle); + ok(dwActualStyle == dwStyleOut, "expected style %#lx, got %#lx\n", dwStyleOut, dwActualStyle); + ok(dwActualExStyle == dwExStyleOut, "expected ex_style %#lx, got %#lx\n", dwExStyleOut, dwActualExStyle); DestroyWindow(hwnd); if (hwndParent) DestroyWindow(hwndParent); @@ -4270,110 +5171,75 @@ static void check_window_style(DWORD dwStyleIn, DWORD dwExStyleIn, DWORD dwStyle /* tests what window styles the window manager automatically adds */ static void test_window_styles(void) { + static const struct + { + DWORD style_in; + DWORD exstyle_in; + DWORD style_out; + DWORD exstyle_out; + } tests[] = { + {0, 0, WS_CLIPSIBLINGS|WS_CAPTION, WS_EX_WINDOWEDGE}, + {WS_DLGFRAME, 0, WS_CLIPSIBLINGS|WS_CAPTION, WS_EX_WINDOWEDGE}, + {WS_THICKFRAME, 0, WS_THICKFRAME|WS_CLIPSIBLINGS|WS_CAPTION, WS_EX_WINDOWEDGE}, + {WS_DLGFRAME, WS_EX_STATICEDGE, WS_CLIPSIBLINGS|WS_CAPTION, WS_EX_WINDOWEDGE|WS_EX_STATICEDGE}, + {WS_THICKFRAME, WS_EX_STATICEDGE, WS_THICKFRAME|WS_CLIPSIBLINGS|WS_CAPTION, WS_EX_WINDOWEDGE|WS_EX_STATICEDGE}, + {WS_OVERLAPPEDWINDOW, 0, WS_CLIPSIBLINGS|WS_OVERLAPPEDWINDOW, WS_EX_WINDOWEDGE}, + {WS_CHILD, 0, WS_CHILD, 0}, + {WS_CHILD|WS_DLGFRAME, 0, WS_CHILD|WS_DLGFRAME, WS_EX_WINDOWEDGE}, + {WS_CHILD|WS_THICKFRAME, 0, WS_CHILD|WS_THICKFRAME, WS_EX_WINDOWEDGE}, + {WS_CHILD|WS_DLGFRAME, WS_EX_STATICEDGE, WS_CHILD|WS_DLGFRAME, WS_EX_STATICEDGE}, + {WS_CHILD|WS_THICKFRAME, WS_EX_STATICEDGE, WS_CHILD|WS_THICKFRAME, WS_EX_STATICEDGE}, + {WS_CHILD|WS_CAPTION, 0, WS_CHILD|WS_CAPTION, WS_EX_WINDOWEDGE}, + {WS_CHILD|WS_CAPTION|WS_SYSMENU, 0, WS_CHILD|WS_CAPTION|WS_SYSMENU, WS_EX_WINDOWEDGE}, + {WS_CHILD, WS_EX_WINDOWEDGE, WS_CHILD, 0}, + {WS_CHILD, WS_EX_DLGMODALFRAME, WS_CHILD, WS_EX_WINDOWEDGE|WS_EX_DLGMODALFRAME}, + {WS_CHILD, WS_EX_DLGMODALFRAME|WS_EX_STATICEDGE, WS_CHILD, WS_EX_STATICEDGE|WS_EX_WINDOWEDGE|WS_EX_DLGMODALFRAME}, + {WS_CHILD|WS_POPUP, 0, WS_CHILD|WS_POPUP|WS_CLIPSIBLINGS, 0}, + {WS_CHILD|WS_POPUP|WS_DLGFRAME, 0, WS_CHILD|WS_POPUP|WS_DLGFRAME|WS_CLIPSIBLINGS, WS_EX_WINDOWEDGE}, + {WS_CHILD|WS_POPUP|WS_THICKFRAME, 0, WS_CHILD|WS_POPUP|WS_THICKFRAME|WS_CLIPSIBLINGS, WS_EX_WINDOWEDGE}, + {WS_CHILD|WS_POPUP|WS_DLGFRAME, WS_EX_STATICEDGE, WS_CHILD|WS_POPUP|WS_DLGFRAME|WS_CLIPSIBLINGS, WS_EX_STATICEDGE}, + {WS_CHILD|WS_POPUP|WS_THICKFRAME, WS_EX_STATICEDGE, WS_CHILD|WS_POPUP|WS_THICKFRAME|WS_CLIPSIBLINGS, WS_EX_STATICEDGE}, + {WS_CHILD|WS_POPUP, WS_EX_APPWINDOW, WS_CHILD|WS_POPUP|WS_CLIPSIBLINGS, WS_EX_APPWINDOW}, + {WS_CHILD|WS_POPUP, WS_EX_WINDOWEDGE, WS_CHILD|WS_POPUP|WS_CLIPSIBLINGS, 0}, + {WS_CHILD, WS_EX_WINDOWEDGE, WS_CHILD, 0}, + {0, WS_EX_TOOLWINDOW, WS_CLIPSIBLINGS|WS_CAPTION, WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW}, + {WS_POPUP, 0, WS_POPUP|WS_CLIPSIBLINGS, 0}, + {WS_POPUP, WS_EX_WINDOWEDGE, WS_POPUP|WS_CLIPSIBLINGS, 0}, + {WS_POPUP|WS_DLGFRAME, 0, WS_POPUP|WS_DLGFRAME|WS_CLIPSIBLINGS, WS_EX_WINDOWEDGE}, + {WS_POPUP|WS_THICKFRAME, 0, WS_POPUP|WS_THICKFRAME|WS_CLIPSIBLINGS, WS_EX_WINDOWEDGE}, + {WS_POPUP|WS_DLGFRAME, WS_EX_STATICEDGE, WS_POPUP|WS_DLGFRAME|WS_CLIPSIBLINGS, WS_EX_STATICEDGE}, + {WS_POPUP|WS_THICKFRAME, WS_EX_STATICEDGE, WS_POPUP|WS_THICKFRAME|WS_CLIPSIBLINGS, WS_EX_STATICEDGE}, + {WS_CAPTION, WS_EX_STATICEDGE, WS_CLIPSIBLINGS|WS_CAPTION, WS_EX_STATICEDGE|WS_EX_WINDOWEDGE}, + {0, WS_EX_APPWINDOW, WS_CLIPSIBLINGS|WS_CAPTION, WS_EX_APPWINDOW|WS_EX_WINDOWEDGE}, + {0, WS_EX_LAYERED, WS_CLIPSIBLINGS|WS_CAPTION, WS_EX_LAYERED|WS_EX_WINDOWEDGE}, + {0, WS_EX_LAYERED|WS_EX_TRANSPARENT, WS_CLIPSIBLINGS|WS_CAPTION, WS_EX_LAYERED|WS_EX_TRANSPARENT|WS_EX_WINDOWEDGE}, + {0, WS_EX_LAYERED|WS_EX_TRANSPARENT|WS_EX_TOOLWINDOW, WS_CLIPSIBLINGS|WS_CAPTION, + WS_EX_LAYERED|WS_EX_TRANSPARENT|WS_EX_TOOLWINDOW|WS_EX_WINDOWEDGE}, + }; + int i; + register_style_check_class(); - check_window_style(0, 0, WS_CLIPSIBLINGS|WS_CAPTION, WS_EX_WINDOWEDGE); - check_window_style(WS_DLGFRAME, 0, WS_CLIPSIBLINGS|WS_CAPTION, WS_EX_WINDOWEDGE); - check_window_style(WS_THICKFRAME, 0, WS_THICKFRAME|WS_CLIPSIBLINGS|WS_CAPTION, WS_EX_WINDOWEDGE); - check_window_style(WS_DLGFRAME, WS_EX_STATICEDGE, WS_CLIPSIBLINGS|WS_CAPTION, WS_EX_WINDOWEDGE|WS_EX_STATICEDGE); - check_window_style(WS_THICKFRAME, WS_EX_STATICEDGE, WS_THICKFRAME|WS_CLIPSIBLINGS|WS_CAPTION, WS_EX_WINDOWEDGE|WS_EX_STATICEDGE); - check_window_style(WS_OVERLAPPEDWINDOW, 0, WS_CLIPSIBLINGS|WS_OVERLAPPEDWINDOW, WS_EX_WINDOWEDGE); - check_window_style(WS_CHILD, 0, WS_CHILD, 0); - check_window_style(WS_CHILD|WS_DLGFRAME, 0, WS_CHILD|WS_DLGFRAME, WS_EX_WINDOWEDGE); - check_window_style(WS_CHILD|WS_THICKFRAME, 0, WS_CHILD|WS_THICKFRAME, WS_EX_WINDOWEDGE); - check_window_style(WS_CHILD|WS_DLGFRAME, WS_EX_STATICEDGE, WS_CHILD|WS_DLGFRAME, WS_EX_STATICEDGE); - check_window_style(WS_CHILD|WS_THICKFRAME, WS_EX_STATICEDGE, WS_CHILD|WS_THICKFRAME, WS_EX_STATICEDGE); - check_window_style(WS_CHILD|WS_CAPTION, 0, WS_CHILD|WS_CAPTION, WS_EX_WINDOWEDGE); - check_window_style(WS_CHILD|WS_CAPTION|WS_SYSMENU, 0, WS_CHILD|WS_CAPTION|WS_SYSMENU, WS_EX_WINDOWEDGE); - check_window_style(WS_CHILD, WS_EX_WINDOWEDGE, WS_CHILD, 0); - check_window_style(WS_CHILD, WS_EX_DLGMODALFRAME, WS_CHILD, WS_EX_WINDOWEDGE|WS_EX_DLGMODALFRAME); - check_window_style(WS_CHILD, WS_EX_DLGMODALFRAME|WS_EX_STATICEDGE, WS_CHILD, WS_EX_STATICEDGE|WS_EX_WINDOWEDGE|WS_EX_DLGMODALFRAME); - check_window_style(WS_CHILD|WS_POPUP, 0, WS_CHILD|WS_POPUP|WS_CLIPSIBLINGS, 0); - check_window_style(WS_CHILD|WS_POPUP|WS_DLGFRAME, 0, WS_CHILD|WS_POPUP|WS_DLGFRAME|WS_CLIPSIBLINGS, WS_EX_WINDOWEDGE); - check_window_style(WS_CHILD|WS_POPUP|WS_THICKFRAME, 0, WS_CHILD|WS_POPUP|WS_THICKFRAME|WS_CLIPSIBLINGS, WS_EX_WINDOWEDGE); - check_window_style(WS_CHILD|WS_POPUP|WS_DLGFRAME, WS_EX_STATICEDGE, WS_CHILD|WS_POPUP|WS_DLGFRAME|WS_CLIPSIBLINGS, WS_EX_STATICEDGE); - check_window_style(WS_CHILD|WS_POPUP|WS_THICKFRAME, WS_EX_STATICEDGE, WS_CHILD|WS_POPUP|WS_THICKFRAME|WS_CLIPSIBLINGS, WS_EX_STATICEDGE); - check_window_style(WS_CHILD|WS_POPUP, WS_EX_APPWINDOW, WS_CHILD|WS_POPUP|WS_CLIPSIBLINGS, WS_EX_APPWINDOW); - check_window_style(WS_CHILD|WS_POPUP, WS_EX_WINDOWEDGE, WS_CHILD|WS_POPUP|WS_CLIPSIBLINGS, 0); - check_window_style(WS_CHILD, WS_EX_WINDOWEDGE, WS_CHILD, 0); - check_window_style(0, WS_EX_TOOLWINDOW, WS_CLIPSIBLINGS|WS_CAPTION, WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW); - check_window_style(WS_POPUP, 0, WS_POPUP|WS_CLIPSIBLINGS, 0); - check_window_style(WS_POPUP, WS_EX_WINDOWEDGE, WS_POPUP|WS_CLIPSIBLINGS, 0); - check_window_style(WS_POPUP|WS_DLGFRAME, 0, WS_POPUP|WS_DLGFRAME|WS_CLIPSIBLINGS, WS_EX_WINDOWEDGE); - check_window_style(WS_POPUP|WS_THICKFRAME, 0, WS_POPUP|WS_THICKFRAME|WS_CLIPSIBLINGS, WS_EX_WINDOWEDGE); - check_window_style(WS_POPUP|WS_DLGFRAME, WS_EX_STATICEDGE, WS_POPUP|WS_DLGFRAME|WS_CLIPSIBLINGS, WS_EX_STATICEDGE); - check_window_style(WS_POPUP|WS_THICKFRAME, WS_EX_STATICEDGE, WS_POPUP|WS_THICKFRAME|WS_CLIPSIBLINGS, WS_EX_STATICEDGE); - check_window_style(WS_CAPTION, WS_EX_STATICEDGE, WS_CLIPSIBLINGS|WS_CAPTION, WS_EX_STATICEDGE|WS_EX_WINDOWEDGE); - check_window_style(0, WS_EX_APPWINDOW, WS_CLIPSIBLINGS|WS_CAPTION, WS_EX_APPWINDOW|WS_EX_WINDOWEDGE); - - if (pGetLayeredWindowAttributes) + for (i = 0; i < ARRAY_SIZE(tests); i++) { - check_window_style(0, WS_EX_LAYERED, WS_CLIPSIBLINGS|WS_CAPTION, WS_EX_LAYERED|WS_EX_WINDOWEDGE); - check_window_style(0, WS_EX_LAYERED|WS_EX_TRANSPARENT, WS_CLIPSIBLINGS|WS_CAPTION, WS_EX_LAYERED|WS_EX_TRANSPARENT|WS_EX_WINDOWEDGE); - check_window_style(0, WS_EX_LAYERED|WS_EX_TRANSPARENT|WS_EX_TOOLWINDOW, WS_CLIPSIBLINGS|WS_CAPTION, - WS_EX_LAYERED|WS_EX_TRANSPARENT|WS_EX_TOOLWINDOW|WS_EX_WINDOWEDGE); + if ((tests[i].exstyle_in & WS_EX_LAYERED) && !pGetLayeredWindowAttributes) + continue; + + winetest_push_context("style %#lx exstyle %#lx", tests[i].style_in, tests[i].exstyle_in); + check_window_style(tests[i].style_in, tests[i].exstyle_in, tests[i].style_out, tests[i].exstyle_out); + winetest_pop_context(); } } -static HWND root_dialog(HWND hwnd) -{ - while ((GetWindowLongA(hwnd, GWL_EXSTYLE) & WS_EX_CONTROLPARENT) && - (GetWindowLongA(hwnd, GWL_STYLE) & (WS_CHILD|WS_POPUP)) == WS_CHILD) - { - HWND parent = GetParent(hwnd); - - /* simple detector for a window being a dialog */ - if (!DefDlgProcA(parent, DM_GETDEFID, 0, 0)) - break; - - hwnd = parent; - - if (!(GetWindowLongA(hwnd, GWL_STYLE) & DS_CONTROL)) - break; - } - - return hwnd; -} - static INT_PTR WINAPI empty_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { return 0; } -static LRESULT expected_id; - static INT_PTR WINAPI empty_dlg_proc3(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { if (msg == WM_INITDIALOG) - { - HWND parent = GetParent(hwnd); - LRESULT id, ret; - - id = DefDlgProcA(parent, DM_GETDEFID, 0, 0); - if (!id || root_dialog(hwnd) == hwnd) - parent = 0; - - id = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0); - if (!parent) - ok(id == MAKELONG(IDOK,DC_HASDEFID), "expected (IDOK,DC_HASDEFID), got %08lx\n", id); - else - ok(id == expected_id, "expected %08lx, got %08lx\n", expected_id, id); - - ret = DefDlgProcA(hwnd, DM_SETDEFID, 0x3333, 0); - ok(ret, "DefDlgProc(DM_SETDEFID) failed\n"); - id = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0); - ok(id == MAKELONG(0x3333,DC_HASDEFID), "expected (0x3333,DC_HASDEFID), got %08lx\n", id); - - if (parent) - { - id = DefDlgProcA(parent, DM_GETDEFID, 0, 0); - ok(id == MAKELONG(0x3333,DC_HASDEFID), "expected (0x3333,DC_HASDEFID), got %08lx\n", id); - - expected_id = MAKELONG(0x3333,DC_HASDEFID); - } - EndDialog(hwnd, 0); - } return 0; } @@ -4392,75 +5258,46 @@ static INT_PTR WINAPI empty_dlg_proc2(HWND hwnd, UINT msg, WPARAM wparam, LPARAM struct dialog_param *param = (struct dialog_param *)lparam; BOOL parent_is_child; HWND disabled_hwnd; - LRESULT id, ret; - - id = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0); - ok(id == MAKELONG(IDOK,DC_HASDEFID), "expected (IDOK,DC_HASDEFID), got %08lx\n", id); - ret = DefDlgProcA(hwnd, DM_SETDEFID, 0x2222, 0); - ok(ret, "DefDlgProc(DM_SETDEFID) failed\n"); - id = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0); - ok(id == MAKELONG(0x2222,DC_HASDEFID), "expected (0x2222,DC_HASDEFID), got %08lx\n", id); - - expected_id = MAKELONG(0x2222,DC_HASDEFID); parent_is_child = (GetWindowLongA(param->parent, GWL_STYLE) & (WS_POPUP | WS_CHILD)) == WS_CHILD; ok(IsWindowEnabled(hwnd), "wrong state for %p\n", hwnd); if (parent_is_child) { - ok(IsWindowEnabled(param->parent), "wrong state for %08x\n", style); + ok(IsWindowEnabled(param->parent), "wrong state for %08lx\n", style); disabled_hwnd = param->grand_parent; } else { - ok(!IsWindowEnabled(param->parent), "wrong state for %08x\n", style); + ok(!IsWindowEnabled(param->parent), "wrong state for %08lx\n", style); disabled_hwnd = param->parent; } if (param->grand_parent) { if (parent_is_child) - ok(!IsWindowEnabled(param->grand_parent), "wrong state for %08x\n", style); + ok(!IsWindowEnabled(param->grand_parent), "wrong state for %08lx\n", style); else - ok(IsWindowEnabled(param->grand_parent), "wrong state for %08x\n", style); + ok(IsWindowEnabled(param->grand_parent), "wrong state for %08lx\n", style); } DialogBoxIndirectParamA(GetModuleHandleA(NULL), param->dlg_data, disabled_hwnd, empty_dlg_proc3, 0); - ok(IsWindowEnabled(disabled_hwnd), "wrong state for %08x\n", style); + ok(IsWindowEnabled(disabled_hwnd), "wrong state for %08lx\n", style); ok(IsWindowEnabled(hwnd), "wrong state for %p\n", hwnd); ok(IsWindowEnabled(param->parent), "wrong state for %p\n", param->parent); if (param->grand_parent) - ok(IsWindowEnabled(param->grand_parent), "wrong state for %p (%08x)\n", param->grand_parent, style); + ok(IsWindowEnabled(param->grand_parent), "wrong state for %p (%08lx)\n", param->grand_parent, style); DialogBoxIndirectParamA(GetModuleHandleA(NULL), param->dlg_data, hwnd, empty_dlg_proc3, 0); ok(IsWindowEnabled(hwnd), "wrong state for %p\n", hwnd); ok(IsWindowEnabled(param->parent), "wrong state for %p\n", param->parent); if (param->grand_parent) - ok(IsWindowEnabled(param->grand_parent), "wrong state for %p (%08x)\n", param->grand_parent, style); + ok(IsWindowEnabled(param->grand_parent), "wrong state for %p (%08lx)\n", param->grand_parent, style); param->dlg_data->style |= WS_CHILD; DialogBoxIndirectParamA(GetModuleHandleA(NULL), param->dlg_data, hwnd, empty_dlg_proc3, 0); - ok(IsWindowEnabled(hwnd), "wrong state for %p (%08x)\n", hwnd, style); - - param->dlg_data->style |= DS_CONTROL; - DialogBoxIndirectParamA(GetModuleHandleA(NULL), param->dlg_data, hwnd, empty_dlg_proc3, 0); - ok(IsWindowEnabled(hwnd), "wrong state for %p (%08x)\n", hwnd, style); - - param->dlg_data->dwExtendedStyle |= WS_EX_CONTROLPARENT; - SetWindowLongA(hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_CONTROLPARENT); - SetWindowLongA(hwnd, GWL_STYLE, style & ~DS_CONTROL); - param->dlg_data->style &= ~DS_CONTROL; - DialogBoxIndirectParamA(GetModuleHandleA(NULL), param->dlg_data, hwnd, empty_dlg_proc3, 0); - ok(IsWindowEnabled(hwnd), "wrong state for %p (%08x)\n", hwnd, style); - - SetWindowLongA(hwnd, GWL_STYLE, style | DS_CONTROL); - DialogBoxIndirectParamA(GetModuleHandleA(NULL), param->dlg_data, hwnd, empty_dlg_proc3, 0); - ok(IsWindowEnabled(hwnd), "wrong state for %p (%08x)\n", hwnd, style); - - param->dlg_data->style |= DS_CONTROL; - DialogBoxIndirectParamA(GetModuleHandleA(NULL), param->dlg_data, hwnd, empty_dlg_proc3, 0); - ok(IsWindowEnabled(hwnd), "wrong state for %p (%08x)\n", hwnd, style); + ok(IsWindowEnabled(hwnd), "wrong state for %p (%08lx)\n", hwnd, style); EndDialog(hwnd, 0); } @@ -4480,7 +5317,6 @@ static void check_dialog_style(DWORD style_in, DWORD ex_style_in, DWORD style_ou DWORD style, ex_style; HWND hwnd, grand_parent = 0, parent = 0; struct dialog_param param; - LRESULT id, ret; if (style_in & WS_CHILD) { @@ -4491,7 +5327,7 @@ static void check_dialog_style(DWORD style_in, DWORD ex_style_in, DWORD style_ou parent = CreateWindowExA(0, "static", NULL, style_in, 0, 0, 0, 0, grand_parent, NULL, NULL, NULL); - ok(parent != 0, "parent creation failed, style %#x\n", style_in); + ok(parent != 0, "parent creation failed, style %#lx\n", style_in); dlg_data.dt.style = style_in; dlg_data.dt.dwExtendedStyle = ex_style_in; @@ -4506,29 +5342,22 @@ static void check_dialog_style(DWORD style_in, DWORD ex_style_in, DWORD style_ou dlg_data.caption[0] = 0; hwnd = CreateDialogIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, parent, empty_dlg_proc, 0); - ok(hwnd != 0, "dialog creation failed, style %#x, exstyle %#x\n", style_in, ex_style_in); - - id = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0); - ok(id == MAKELONG(IDOK,DC_HASDEFID), "expected (IDOK,DC_HASDEFID), got %08lx\n", id); - ret = DefDlgProcA(hwnd, DM_SETDEFID, 0x1111, 0); - ok(ret, "DefDlgProc(DM_SETDEFID) failed\n"); - id = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0); - ok(id == MAKELONG(0x1111,DC_HASDEFID), "expected (0x1111,DC_HASDEFID), got %08lx\n", id); + ok(hwnd != 0, "dialog creation failed, style %#lx, exstyle %#lx\n", style_in, ex_style_in); flush_events( TRUE ); style = GetWindowLongA(hwnd, GWL_STYLE); ex_style = GetWindowLongA(hwnd, GWL_EXSTYLE); - ok(style == (style_out | DS_3DLOOK), "got %#x\n", style); - ok(ex_style == ex_style_out, "expected ex_style %#x, got %#x\n", ex_style_out, ex_style); + ok(style == (style_out | DS_3DLOOK), "got %#lx\n", style); + ok(ex_style == ex_style_out, "expected ex_style %#lx, got %#lx\n", ex_style_out, ex_style); - ok(IsWindowEnabled(parent), "wrong parent state (dialog style %#x)\n", style_in); + ok(IsWindowEnabled(parent), "wrong parent state (dialog style %#lx)\n", style_in); /* try setting the styles explicitly */ SetWindowLongA(hwnd, GWL_EXSTYLE, ex_style_in); style = GetWindowLongA(hwnd, GWL_STYLE); ex_style = GetWindowLongA(hwnd, GWL_EXSTYLE); - ok(style == (style_out | DS_3DLOOK), "got %#x\n", style); + ok(style == (style_out | DS_3DLOOK), "got %#lx\n", style); /* WS_EX_WINDOWEDGE can't always be changed */ if (ex_style_in & WS_EX_DLGMODALFRAME) ex_style_out = ex_style_in | WS_EX_WINDOWEDGE; @@ -4536,7 +5365,7 @@ static void check_dialog_style(DWORD style_in, DWORD ex_style_in, DWORD style_ou ex_style_out = ex_style_in | WS_EX_WINDOWEDGE; else ex_style_out = ex_style_in & ~WS_EX_WINDOWEDGE; - ok(ex_style == ex_style_out, "expected ex_style %#x, got %#x\n", ex_style_out, ex_style); + ok(ex_style == ex_style_out, "expected ex_style %#lx, got %#lx\n", ex_style_out, ex_style); SetWindowLongA(hwnd, GWL_STYLE, style_in); style = GetWindowLongA(hwnd, GWL_STYLE); @@ -4544,7 +5373,7 @@ static void check_dialog_style(DWORD style_in, DWORD ex_style_in, DWORD style_ou /* WS_CLIPSIBLINGS can't be reset on top-level windows */ if ((style_in & (WS_CHILD | WS_POPUP)) == WS_CHILD) style_out = style_in; else style_out = style_in | WS_CLIPSIBLINGS; - ok(style == style_out, "expected style %#x, got %#x\n", style_out, style); + ok(style == style_out, "expected style %#lx, got %#lx\n", style_out, style); /* WS_EX_WINDOWEDGE can't always be changed */ if (ex_style_in & WS_EX_DLGMODALFRAME) ex_style_out = ex_style_in | WS_EX_WINDOWEDGE; @@ -4552,9 +5381,7 @@ static void check_dialog_style(DWORD style_in, DWORD ex_style_in, DWORD style_ou ex_style_out = ex_style_in | WS_EX_WINDOWEDGE; else ex_style_out = ex_style_in & ~WS_EX_WINDOWEDGE; - /* FIXME: Remove the condition below once Wine is fixed */ - todo_wine_if (ex_style != ex_style_out) - ok(ex_style == ex_style_out, "expected ex_style %#x, got %#x\n", ex_style_out, ex_style); + ok(ex_style == ex_style_out, "expected ex_style %#lx, got %#lx\n", ex_style_out, ex_style); DestroyWindow(hwnd); @@ -4563,9 +5390,9 @@ static void check_dialog_style(DWORD style_in, DWORD ex_style_in, DWORD style_ou param.dlg_data = &dlg_data.dt; DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, parent, empty_dlg_proc2, (LPARAM)¶m); - ok(IsWindowEnabled(parent), "wrong parent state (dialog style %#x)\n", style_in); + ok(IsWindowEnabled(parent), "wrong parent state (dialog style %#lx)\n", style_in); if (grand_parent) - ok(IsWindowEnabled(grand_parent), "wrong grand parent state (dialog style %#x)\n", style_in); + ok(IsWindowEnabled(grand_parent), "wrong grand parent state (dialog style %#lx)\n", style_in); DestroyWindow(parent); DestroyWindow(grand_parent); @@ -4773,8 +5600,6 @@ static void test_dialog_parent(void) /* Regular child. If passed as an owner, its parent will be true owner window. */ child2 = CreateWindowExA(0, "static", NULL, WS_CHILD, 0, 0, 0, 0, child, NULL, NULL, NULL); - trace("parent %p child %p child2 %p desktop %p\n", parent, child, child2, desktop); - /* When dialog is created with WS_CHILD style, its parent depends on function used to create it. */ dlg_data.dt.style = WS_CHILD; @@ -4796,7 +5621,7 @@ static void test_dialog_parent(void) param.root = parent; param.ga_root_owner = child; ret = DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, child2, parent_dlg_proc, (LPARAM)¶m); - ok(ret == 2, "DialogBoxIndirectParam returned %ld\n", ret); + ok(ret == 2, "DialogBoxIndirectParam returned %Id\n", ret); /* Dialogs without WS_CHILD behave as expected, they use passed owner just like CreateWindow does. */ dlg_data.dt.style = WS_OVERLAPPEDWINDOW; @@ -4817,7 +5642,7 @@ static void test_dialog_parent(void) param.owner = child; param.root = param.ga_root_owner = NULL; ret = DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, child2, parent_dlg_proc, (LPARAM)¶m); - ok(ret == 2, "DialogBoxIndirectParam returned %ld\n", ret); + ok(ret == 2, "DialogBoxIndirectParam returned %Id\n", ret); other = CreateWindowExA(0, "static", NULL, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL, NULL, NULL); SetWindowLongPtrA(child, GWLP_WNDPROC, (ULONG_PTR)reparent_dialog_owner_proc); @@ -4841,7 +5666,7 @@ static void test_dialog_parent(void) param.root = NULL; param.ga_root_owner = child; ret = DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, child2, parent_dlg_proc, (LPARAM)¶m); - ok(ret == 2, "DialogBoxIndirectParam returned %ld\n", ret); + ok(ret == 2, "DialogBoxIndirectParam returned %Id\n", ret); /* If we change parent in WM_INITDIALOG for WS_CHILD dialog WM_ENTERIDLE is still sent to the original * parent. EndDialog will enable the new parent. */ @@ -4849,7 +5674,7 @@ static void test_dialog_parent(void) EnableWindow(other, FALSE); dlg_data.dt.style = WS_CHILD; ret = DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, child2, reparent_dlg_proc, (LPARAM)other); - ok(ret == 2, "DialogBoxIndirectParam returned %ld\n", ret); + ok(ret == 2, "DialogBoxIndirectParam returned %Id\n", ret); ok(!IsWindowEnabled(other), "other is not disabled\n"); ok(!IsWindowEnabled(child), "child is not disabled\n"); ok(IsWindowEnabled(child2), "child2 is not enabled\n"); @@ -4861,7 +5686,7 @@ static void test_dialog_parent(void) EnableWindow(other, FALSE); dlg_data.dt.style = WS_OVERLAPPED; ret = DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, child2, reparent_owned_dlg_proc, (LPARAM)other); - ok(ret == 1, "DialogBoxIndirectParam returned %ld\n", ret); + ok(ret == 1, "DialogBoxIndirectParam returned %Id\n", ret); ok(!IsWindowEnabled(other), "other is not disabled\n"); ok(!IsWindowEnabled(child), "child is not disabled\n"); ok(IsWindowEnabled(child2), "child2 is not enabled\n"); @@ -4871,17 +5696,18 @@ static void test_dialog_parent(void) /* Quit dialog message loop by sending WM_QUIT message. Dialog owner is not enabled. */ SetWindowLongPtrA(child, GWLP_WNDPROC, (ULONG_PTR)post_quit_dialog_owner_proc); ret = DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, other, empty_dlg_proc, 0); - ok(ret == 1, "DialogBoxIndirectParam returned %ld\n", ret); + ok(ret == 1, "DialogBoxIndirectParam returned %Id\n", ret); ok(!IsWindowEnabled(other), "other is enabled\n"); EnableWindow(other, TRUE); /* Quit dialog message loop by destroying the window. Dialog owner is not enabled. */ SetWindowLongPtrA(child, GWLP_WNDPROC, (ULONG_PTR)destroy_dialog_owner_proc); ret = DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, other, empty_dlg_proc, 0); - ok(ret == 1, "DialogBoxIndirectParam returned %ld\n", ret); + ok(ret == 1, "DialogBoxIndirectParam returned %Id\n", ret); ok(!IsWindowEnabled(other), "other is enabled\n"); EnableWindow(other, TRUE); + DestroyWindow(other); DestroyWindow(parent); } @@ -4912,7 +5738,7 @@ static void test_scrollwindow( HWND hwnd) flush_events(FALSE); /* expected: black should have scrolled to the upper half */ colr = GetPixel( hdc, (rc2.left+rc2.right)/ 2, rc2.bottom / 4 ); - ok ( colr == 0, "pixel should be black, color is %08x\n", colr); + ok ( colr == 0, "pixel should be black, color is %08lx\n", colr); /* Repeat that test of ScrollWindow(Ex) now with clip rectangle */ /* paint the lower half of the window black */ rc2 = rc; @@ -4932,7 +5758,7 @@ static void test_scrollwindow( HWND hwnd) flush_events(FALSE); /* expected: black should have scrolled to the upper half */ colr = GetPixel( hdc, (rc2.left+rc2.right)/ 2, rc2.bottom / 4 ); - ok ( colr == 0, "pixel should be black, color is %08x\n", colr); + ok ( colr == 0, "pixel should be black, color is %08lx\n", colr); /* clean up */ ReleaseDC( hwnd, hdc); @@ -4967,7 +5793,6 @@ static void test_scrollvalidate( HWND parent) /* for a visual touch */ TextOutA( hdc, 0,10, "0123456789", 10); ScrollDC( hdc, -10, -5, &rc, &cliprc, hrgn, &rcu); - if (winetest_debug > 0) dump_region(hrgn); /* create a region with what is expected */ SetRectRgn( exprgn, 39,0,49,74); SetRectRgn( tmprgn, 88,79,98,93); @@ -4975,11 +5800,14 @@ static void test_scrollvalidate( HWND parent) SetRectRgn( tmprgn, 0,93,98,98); CombineRgn( exprgn, exprgn, tmprgn, RGN_OR); ok( EqualRgn( exprgn, hrgn), "wrong update region\n"); - trace("update rect is %s\n", wine_dbgstr_rect(&rcu)); + if (!EqualRgn( exprgn, hrgn)) + { + trace("update rect is %s\n", wine_dbgstr_rect(&rcu)); + dump_region(hrgn); + } /* now with clipping region */ SelectClipRgn( hdc, clipping); ScrollDC( hdc, -10, -5, &rc, &cliprc, hrgn, &rcu); - if (winetest_debug > 0) dump_region(hrgn); /* create a region with what is expected */ SetRectRgn( exprgn, 39,10,49,74); SetRectRgn( tmprgn, 80,79,90,85); @@ -4987,7 +5815,11 @@ static void test_scrollvalidate( HWND parent) SetRectRgn( tmprgn, 10,85,90,90); CombineRgn( exprgn, exprgn, tmprgn, RGN_OR); ok( EqualRgn( exprgn, hrgn), "wrong update region\n"); - trace("update rect is %s\n", wine_dbgstr_rect(&rcu)); + if (!EqualRgn( exprgn, hrgn)) + { + trace("update rect is %s\n", wine_dbgstr_rect(&rcu)); + dump_region(hrgn); + } ReleaseDC( hwnd1, hdc); /* test scrolling a rect by more than its size */ @@ -4997,11 +5829,11 @@ static void test_scrollvalidate( HWND parent) InvalidateRect( hwnd1, &rc, 1); ScrollWindowEx( hwnd1, -20, 0, &rc, NULL, hrgn, &rcu, SW_SCROLLCHILDREN | SW_INVALIDATE); - if (winetest_debug > 0) dump_region(hrgn); SetRectRgn( exprgn, 20, 40, 30, 50); SetRectRgn( tmprgn, 40, 40, 50, 50); CombineRgn( exprgn, exprgn, tmprgn, RGN_OR); ok( EqualRgn( exprgn, hrgn), "wrong update region\n"); + if (!EqualRgn( exprgn, hrgn)) dump_region(hrgn); ok( rcu.left == 20 && rcu.top == 40 && rcu.right == 50 && rcu.bottom == 50, "unexpected update rect: %s\n", wine_dbgstr_rect(&rcu)); @@ -5013,11 +5845,11 @@ static void test_scrollvalidate( HWND parent) cliprc=rc; ScrollWindowEx( hwnd1, -10, 0, &rc, &cliprc, hrgn, &rcu, SW_SCROLLCHILDREN | SW_INVALIDATE); - if (winetest_debug > 0) dump_region(hrgn); SetRectRgn( exprgn, 88,0,98,98); SetRectRgn( tmprgn, 30, 40, 50, 50); CombineRgn( exprgn, exprgn, tmprgn, RGN_OR); ok( EqualRgn( exprgn, hrgn), "wrong update region\n"); + if (!EqualRgn( exprgn, hrgn)) dump_region(hrgn); /* clear an update region */ UpdateWindow( hwnd1 ); @@ -5025,9 +5857,9 @@ static void test_scrollvalidate( HWND parent) SetRect( &rc, 0,40, 100,60); SetRect( &cliprc, 0,0, 100,100); ScrollWindowEx( hwnd1, 0, -25, &rc, &cliprc, hrgn, &rcu, SW_INVALIDATE); - if (winetest_debug > 0) dump_region( hrgn ); SetRectRgn( exprgn, 0, 40, 98, 60 ); ok( EqualRgn( exprgn, hrgn), "wrong update region in excessive scroll\n"); + if (!EqualRgn( exprgn, hrgn)) dump_region(hrgn); /* now test ScrollWindowEx with a combination of * WS_CLIPCHILDREN style and SW_SCROLLCHILDREN flag */ @@ -5045,36 +5877,35 @@ static void test_scrollvalidate( HWND parent) ValidateRect( hwnd2, NULL); ScrollWindowEx( hwnd1, -10, -10, &rc, &cliprc, hrgn, &rcu, SW_SCROLLCHILDREN | SW_INVALIDATE); - if (winetest_debug > 0) dump_region(hrgn); SetRectRgn( exprgn, 88,0,98,88); SetRectRgn( tmprgn, 0,88,98,98); CombineRgn( exprgn, exprgn, tmprgn, RGN_OR); ok( EqualRgn( exprgn, hrgn), "wrong update region\n"); + if (!EqualRgn( exprgn, hrgn)) dump_region(hrgn); /* SW_SCROLLCHILDREN */ SetWindowLongA( hwnd1, GWL_STYLE, GetWindowLongA( hwnd1, GWL_STYLE) & ~WS_CLIPCHILDREN ); ValidateRect( hwnd1, NULL); ValidateRect( hwnd2, NULL); ScrollWindowEx( hwnd1, -10, -10, &rc, &cliprc, hrgn, &rcu, SW_SCROLLCHILDREN | SW_INVALIDATE); - if (winetest_debug > 0) dump_region(hrgn); /* expected region is the same as in previous test */ ok( EqualRgn( exprgn, hrgn), "wrong update region\n"); + if (!EqualRgn( exprgn, hrgn)) dump_region(hrgn); /* no SW_SCROLLCHILDREN */ SetWindowLongA( hwnd1, GWL_STYLE, GetWindowLongA( hwnd1, GWL_STYLE) & ~WS_CLIPCHILDREN ); ValidateRect( hwnd1, NULL); ValidateRect( hwnd2, NULL); ScrollWindowEx( hwnd1, -10, -10, &rc, &cliprc, hrgn, &rcu, SW_INVALIDATE); - if (winetest_debug > 0) dump_region(hrgn); /* expected region is the same as in previous test */ ok( EqualRgn( exprgn, hrgn), "wrong update region\n"); + if (!EqualRgn( exprgn, hrgn)) dump_region(hrgn); /* WS_CLIPCHILDREN and no SW_SCROLLCHILDREN */ SetWindowLongA( hwnd1, GWL_STYLE, GetWindowLongA( hwnd1, GWL_STYLE) | WS_CLIPCHILDREN ); ValidateRect( hwnd1, NULL); ValidateRect( hwnd2, NULL); ScrollWindowEx( hwnd1, -10, -10, &rc, &cliprc, hrgn, &rcu, SW_INVALIDATE); - if (winetest_debug > 0) dump_region(hrgn); SetRectRgn( exprgn, 88,0,98,20); SetRectRgn( tmprgn, 20,20,98,30); CombineRgn( exprgn, exprgn, tmprgn, RGN_OR); @@ -5083,6 +5914,7 @@ static void test_scrollvalidate( HWND parent) SetRectRgn( tmprgn, 0,88,30,98); CombineRgn( exprgn, exprgn, tmprgn, RGN_OR); ok( EqualRgn( exprgn, hrgn), "wrong update region\n"); + if (!EqualRgn( exprgn, hrgn)) dump_region(hrgn); /* clean up */ DeleteObject( hrgn); @@ -5104,12 +5936,7 @@ static void test_scroll(void) 100, 100, 200, 200, 0, 0, 0, NULL); /* horizontal */ ret = GetScrollRange( hwnd, SB_HORZ, &min, &max); - if (!ret) /* win9x */ - { - win_skip( "GetScrollRange doesn't work\n" ); - DestroyWindow( hwnd); - return; - } + ok( ret, "GetScrollRange failed\n" ); ok( min == 0, "minimum scroll pos is %d (should be zero)\n", min); ok( max == 0, "maximum scroll pos is %d (should be zero)\n", min); si.cbSize = sizeof( si); @@ -5162,25 +5989,28 @@ static void test_scrolldc( HWND parent) cliprc.top = (rc.top + rc.bottom) /2; /* test whether scrolled pixels are properly clipped */ colr = GetPixel( hdc, (rc.left+rc.right)/2, ( rc.top + rc.bottom) /2 - 1); - ok ( colr == 0, "pixel should be black, color is %08x\n", colr); + ok ( colr == 0, "pixel should be black, color is %08lx\n", colr); /* this scroll should not cause any visible changes */ ScrollDC( hdc, 5, -20, &rc, &cliprc, hrgn, &rcu); colr = GetPixel( hdc, (rc.left+rc.right)/2, ( rc.top + rc.bottom) /2 - 1); - ok ( colr == 0, "pixel should be black, color is %08x\n", colr); + ok ( colr == 0, "pixel should be black, color is %08lx\n", colr); /* test with NULL clip rect */ ScrollDC( hdc, 20, -20, &rc, NULL, hrgn, &rcu); /*FillRgn(hdc, hrgn, GetStockObject(WHITE_BRUSH));*/ - trace("update rect: %s\n", wine_dbgstr_rect(&rcu)); - if (winetest_debug > 0) dump_region(hrgn); SetRect(&rc2, 0, 0, 100, 100); ok(EqualRect(&rcu, &rc2), "rects do not match %s / %s\n", wine_dbgstr_rect(&rcu), wine_dbgstr_rect(&rc2)); + if (!EqualRect(&rcu, &rc2)) + { + trace("update rect: %s\n", wine_dbgstr_rect(&rcu)); + dump_region(hrgn); + } SetRectRgn( exprgn, 0, 0, 20, 80); SetRectRgn( tmprgn, 0, 80, 100, 100); CombineRgn(exprgn, exprgn, tmprgn, RGN_OR); - if (winetest_debug > 0) dump_region(exprgn); ok(EqualRgn(exprgn, hrgn), "wrong update region\n"); + if (!EqualRgn(exprgn, hrgn)) dump_region(exprgn); /* test clip rect > scroll rect */ FillRect( hdc, &rc, GetStockObject(WHITE_BRUSH)); rc2=rc; @@ -5191,10 +6021,13 @@ static void test_scrolldc( HWND parent) SetRectRgn( tmprgn, 25, 35, 35, 75); CombineRgn(exprgn, exprgn, tmprgn, RGN_OR); ok(EqualRgn(exprgn, hrgn), "wrong update region\n"); - trace("update rect: %s\n", wine_dbgstr_rect(&rcu)); - if (winetest_debug > 0) dump_region(hrgn); - + if (!EqualRgn(exprgn, hrgn)) + { + trace("update rect: %s\n", wine_dbgstr_rect(&rcu)); + dump_region(hrgn); + } /* clean up */ + ReleaseDC(hwnd1, hdc); DeleteObject(hrgn); DeleteObject(exprgn); DeleteObject(tmprgn); @@ -5211,17 +6044,9 @@ static void test_params(void) ok(!IsWindow(HWND_TOPMOST), "IsWindow(HWND_TOPMOST)\n"); /* Just a param check */ - if (pGetMonitorInfoA) - { - SetLastError(0xdeadbeef); - rc = GetWindowTextA(hwndMain2, NULL, 1024); - ok( rc==0, "GetWindowText: rc=%d err=%d\n",rc,GetLastError()); - } - else - { - /* Skips actually on Win95 and NT4 */ - win_skip("Test would crash on Win95\n"); - } + SetLastError(0xdeadbeef); + rc = GetWindowTextA(hwndMain2, NULL, 1024); + ok(!rc, "GetWindowText: rc=%d err=%ld\n",rc,GetLastError()); SetLastError(0xdeadbeef); hwnd=CreateWindowA("LISTBOX", "TestList", @@ -5232,9 +6057,8 @@ static void test_params(void) ok(!hwnd || broken(hwnd != NULL), /* w2k3 sp2 */ "CreateWindow with invalid menu handle should fail\n"); if (!hwnd) - ok(GetLastError() == ERROR_INVALID_MENU_HANDLE || /* NT */ - GetLastError() == 0xdeadbeef, /* Win9x */ - "wrong last error value %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, + "wrong last error value %ld\n", GetLastError()); } static void test_AWRwindow(LPCSTR class, LONG style, LONG exStyle, BOOL menu) @@ -5247,11 +6071,17 @@ static void test_AWRwindow(LPCSTR class, LONG style, LONG exStyle, BOOL menu) 0, menu ? hmenu : 0, 0, 0); - if (!hwnd) { - trace("Failed to create window class=%s, style=0x%08x, exStyle=0x%08x\n", class, style, exStyle); - return; - } + ok(hwnd != NULL, "Failed to create window class=%s, style=0x%08lx, exStyle=0x%08lx\n", class, style, exStyle); + ShowWindow(hwnd, SW_SHOW); + flush_events(TRUE); + + /* retry setting the maximized state to workaround a FVWM bug */ + if ((style & WS_MAXIMIZE) && !(GetWindowLongW(hwnd, GWL_STYLE) & WS_MAXIMIZE)) + { + ShowWindow(hwnd, SW_MAXIMIZE); + flush_events(TRUE); + } test_nonclient_area(hwnd); @@ -5305,9 +6135,9 @@ static void test_AWR_window_size(BOOL menu) /* A exhaustive check of all the styles takes too long * so just do a (hopefully representative) sample */ - for (i = 0; i < COUNTOF(styles); ++i) + for (i = 0; i < ARRAY_SIZE(styles); ++i) test_AWRwindow(szAWRClass, styles[i], 0, menu); - for (i = 0; i < COUNTOF(exStyles); ++i) { + for (i = 0; i < ARRAY_SIZE(exStyles); ++i) { test_AWRwindow(szAWRClass, WS_POPUP, exStyles[i], menu); test_AWRwindow(szAWRClass, WS_THICKFRAME, exStyles[i], menu); } @@ -5315,30 +6145,38 @@ static void test_AWR_window_size(BOOL menu) static void test_AWR_flags(void) { - static const DWORD styles[] = { WS_POPUP, WS_BORDER, WS_DLGFRAME, WS_THICKFRAME }; + static const DWORD styles[] = { WS_POPUP, WS_BORDER, WS_DLGFRAME, WS_THICKFRAME, WS_MINIMIZE }; static const DWORD exStyles[] = { WS_EX_CLIENTEDGE, WS_EX_TOOLWINDOW, WS_EX_WINDOWEDGE, WS_EX_APPWINDOW, WS_EX_DLGMODALFRAME, WS_EX_STATICEDGE }; DWORD i, j, k, style, exstyle; RECT rect, rect2; - for (i = 0; i < (1 << COUNTOF(styles)); i++) + for (i = 0; i < (1 << ARRAY_SIZE(styles)); i++) { - for (k = style = 0; k < COUNTOF(styles); k++) if (i & (1 << k)) style |= styles[k]; + for (k = style = 0; k < ARRAY_SIZE(styles); k++) if (i & (1 << k)) style |= styles[k]; - for (j = 0; j < (1 << COUNTOF(exStyles)); j++) + for (j = 0; j < (1 << ARRAY_SIZE(exStyles)); j++) { - for (k = exstyle = 0; k < COUNTOF(exStyles); k++) if (j & (1 << k)) exstyle |= exStyles[k]; + for (k = exstyle = 0; k < ARRAY_SIZE(exStyles); k++) if (j & (1 << k)) exstyle |= exStyles[k]; SetRect( &rect, 100, 100, 200, 200 ); rect2 = rect; AdjustWindowRectEx( &rect, style, FALSE, exstyle ); wine_AdjustWindowRectEx( &rect2, style, FALSE, exstyle ); - ok( EqualRect( &rect, &rect2 ), "rects do not match: win %s wine %s\n", - wine_dbgstr_rect( &rect ), wine_dbgstr_rect( &rect2 )); + ok( EqualRect( &rect, &rect2 ), "%08lx %08lx rects do not match: win %s wine %s\n", + style, exstyle, wine_dbgstr_rect( &rect ), wine_dbgstr_rect( &rect2 )); + if (pAdjustWindowRectExForDpi) + { + SetRect( &rect, 100, 100, 200, 200 ); + rect2 = rect; + pAdjustWindowRectExForDpi( &rect, style, FALSE, exstyle, 192 ); + wine_AdjustWindowRectExForDpi( &rect2, style, FALSE, exstyle, 192 ); + ok( EqualRect( &rect, &rect2 ), "%08lx %08lx rects do not match: win %s wine %s\n", + style, exstyle, wine_dbgstr_rect( &rect ), wine_dbgstr_rect( &rect2 )); + } } } } -#undef COUNTOF #define SHOWSYSMETRIC(SM) trace(#SM "=%d\n", GetSystemMetrics(SM)) @@ -5378,7 +6216,6 @@ static LRESULT WINAPI redraw_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LP switch (msg) { case WM_PAINT: - trace("doing WM_PAINT %d\n", WMPAINT_count); WMPAINT_count++; if (WMPAINT_count > 10 && redrawComplete == 0) { PAINTSTRUCT ps; @@ -5396,6 +6233,7 @@ static void test_redrawnow(void) { WNDCLASSA cls; HWND hwndMain; + BOOL ret; cls.style = CS_DBLCLKS; cls.lpfnWndProc = redraw_window_procA; @@ -5407,11 +6245,8 @@ static void test_redrawnow(void) cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = "RedrawWindowClass"; - - if(!RegisterClassA(&cls)) { - trace("Register failed %d\n", GetLastError()); - return; - } + ret = RegisterClassA(&cls); + ok(ret, "Failed to register a test class.\n"); hwndMain = CreateWindowA("RedrawWindowClass", "Main Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 100, 100, NULL, NULL, 0, NULL); @@ -5420,7 +6255,7 @@ static void test_redrawnow(void) ShowWindow(hwndMain, SW_SHOW); ok( WMPAINT_count == 0, "Multiple unexpected WM_PAINT calls %d\n", WMPAINT_count); RedrawWindow(hwndMain, NULL,NULL,RDW_UPDATENOW | RDW_ALLCHILDREN); - ok( WMPAINT_count == 1 || broken(WMPAINT_count == 0), /* sometimes on win9x */ + ok( WMPAINT_count == 1, "Multiple unexpected WM_PAINT calls %d\n", WMPAINT_count); redrawComplete = TRUE; ok( WMPAINT_count < 10, "RedrawWindow (RDW_UPDATENOW) never completed (%d)\n", WMPAINT_count); @@ -5454,14 +6289,16 @@ static LRESULT WINAPI parentdc_window_procA(HWND hwnd, UINT msg, WPARAM wparam, GetClientRect(hwnd, &rc); t->client = rc; GetWindowRect(hwnd, &rc); - trace("WM_PAINT: hwnd %p, client rect %s, window rect %s\n", hwnd, - wine_dbgstr_rect(&t->client), wine_dbgstr_rect(&rc)); + if (winetest_debug > 1) + trace("WM_PAINT: hwnd %p, client rect %s, window rect %s\n", hwnd, + wine_dbgstr_rect(&t->client), wine_dbgstr_rect(&rc)); BeginPaint(hwnd, &ps); t->paint = ps.rcPaint; GetClipBox(ps.hdc, &rc); t->clip = rc; - trace("clip rect %s, paint rect %s\n", wine_dbgstr_rect(&rc), - wine_dbgstr_rect(&ps.rcPaint)); + if (winetest_debug > 1) + trace("clip rect %s, paint rect %s\n", wine_dbgstr_rect(&rc), + wine_dbgstr_rect(&ps.rcPaint)); EndPaint(hwnd, &ps); return 0; } @@ -5484,7 +6321,7 @@ static void zero_parentdc_test(struct parentdc_test *t) #define parentdc_field_ok(t, w, r, f, got) \ ok (t.w.r.f==got.w.r.f, "window " #w ", rect " #r ", field " #f \ - ": expected %d, got %d\n", \ + ": expected %ld, got %ld\n", \ t.w.r.f, got.w.r.f) #define parentdc_todo_field_ok(t, w, r, f, got) \ @@ -5511,6 +6348,7 @@ static void test_csparentdc(void) { WNDCLASSA clsMain, cls; HWND hwndMain, hwnd1, hwnd2; + BOOL ret; RECT rc; struct parentdc_test test_answer; @@ -5522,6 +6360,14 @@ static void test_csparentdc(void) {{0, 0, 40, 40}, {-20, -20, 130, 130}, {0, 0, 40, 40}}, {{0, 0, 0, 0}, {1, 1, 1, 1}, {0, 0, 0, 0}}, {{0, 0, 40, 40}, {-40, -40, 110, 110}, {0, 0, 40, 40}}, {{0, 0, 0, 0}, {1, 1, 1, 1}, {0, 0, 0, 0}}, }; +#ifdef __REACTOS__ + const struct parentdc_test test1_win8 = + { + {{0, 0, 166, 150}, {0, 0, 166, 150}, {0, 0, 166, 150}}, nothing_todo, + {{0, 0, 40, 40}, {-20, -20, 146, 130}, {0, 0, 40, 40}}, {{0, 0, 0, 0}, {1, 1, 1, 1}, {0, 0, 0, 0}}, + {{0, 0, 40, 40}, {-40, -40, 126, 110}, {0, 0, 40, 40}}, {{0, 0, 0, 0}, {1, 1, 1, 1}, {0, 0, 0, 0}}, + }; +#endif const struct parentdc_test test2 = { @@ -5529,6 +6375,14 @@ static void test_csparentdc(void) {{0, 0, 40, 40}, {-20, -20, 30, 30}, {0, 0, 30, 30}}, {{0, 0, 0, 0}, {1, 1, 0, 0}, {0, 0, 0, 0}}, {{0, 0, 40, 40}, {-40, -40, 10, 10}, {0, 0, 10, 10}}, {{0, 0, 0, 0}, {1, 1, 0, 0}, {0, 0, 0, 0}}, }; +#ifdef __REACTOS__ + const struct parentdc_test test2_win8 = + { + {{0, 0, 166, 150}, {0, 0, 50, 50}, {0, 0, 50, 50}}, nothing_todo, + {{0, 0, 40, 40}, {-20, -20, 30, 30}, {0, 0, 30, 30}}, {{0, 0, 0, 0}, {1, 1, 0, 0}, {0, 0, 0, 0}}, + {{0, 0, 40, 40}, {-40, -40, 10, 10}, {0, 0, 10, 10}}, {{0, 0, 0, 0}, {1, 1, 0, 0}, {0, 0, 0, 0}}, + }; +#endif const struct parentdc_test test3 = { @@ -5536,6 +6390,14 @@ static void test_csparentdc(void) {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, nothing_todo, {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, nothing_todo, }; +#ifdef __REACTOS__ + const struct parentdc_test test3_win8 = + { + {{0, 0, 166, 150}, {0, 0, 10, 10}, {0, 0, 10, 10}}, nothing_todo, + {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, nothing_todo, + {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, nothing_todo, + }; +#endif const struct parentdc_test test4 = { @@ -5543,6 +6405,14 @@ static void test_csparentdc(void) {{0, 0, 40, 40}, {20, 20, 30, 30}, {20, 20, 30, 30}}, nothing_todo, {{0, 0, 40, 40}, {0, 0, 10, 10}, {0, 0, 10, 10}}, nothing_todo, }; +#ifdef __REACTOS__ + const struct parentdc_test test4_win8 = + { + {{0, 0, 166, 150}, {40, 40, 50, 50}, {40, 40, 50, 50}}, nothing_todo, + {{0, 0, 40, 40}, {20, 20, 30, 30}, {20, 20, 30, 30}}, nothing_todo, + {{0, 0, 40, 40}, {0, 0, 10, 10}, {0, 0, 10, 10}}, nothing_todo, + }; +#endif const struct parentdc_test test5 = { @@ -5550,6 +6420,14 @@ static void test_csparentdc(void) {{0, 0, 40, 40}, {-20, -20, 130, 130}, {0, 0, 40, 40}}, {{0, 0, 0, 0}, {1, 1, 1, 1}, {0, 0, 0, 0}}, {{0, 0, 40, 40}, {-20, -20, 20, 20}, {0, 0, 20, 20}}, {{0, 0, 0, 0}, {1, 1, 0, 0}, {0, 0, 0, 0}}, }; +#ifdef __REACTOS__ + const struct parentdc_test test5_win8 = + { + {{0, 0, 166, 150}, {20, 20, 60, 60}, {20, 20, 60, 60}}, nothing_todo, + {{0, 0, 40, 40}, {-20, -20, 146, 130}, {0, 0, 40, 40}}, {{0, 0, 0, 0}, {1, 1, 1, 1}, {0, 0, 0, 0}}, + {{0, 0, 40, 40}, {-20, -20, 20, 20}, {0, 0, 20, 20}}, {{0, 0, 0, 0}, {1, 1, 0, 0}, {0, 0, 0, 0}}, + }; +#endif const struct parentdc_test test6 = { @@ -5564,6 +6442,14 @@ static void test_csparentdc(void) {{0, 0, 40, 40}, {-20, -20, 130, 130}, {0, 0, 40, 40}}, {{0, 0, 0, 0}, {1, 1, 1, 1}, {0, 0, 0, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, nothing_todo, }; +#ifdef __REACTOS__ + const struct parentdc_test test7_win8 = + { + {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, nothing_todo, + {{0, 0, 40, 40}, {-20, -20, 146, 130}, {0, 0, 40, 40}}, {{0, 0, 0, 0}, {1, 1, 1, 1}, {0, 0, 0, 0}}, + {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, nothing_todo, + }; +#endif #undef nothing_todo clsMain.style = CS_DBLCLKS; @@ -5576,11 +6462,8 @@ static void test_csparentdc(void) clsMain.hbrBackground = GetStockObject(WHITE_BRUSH); clsMain.lpszMenuName = NULL; clsMain.lpszClassName = "ParentDcMainWindowClass"; - - if(!RegisterClassA(&clsMain)) { - trace("Register failed %d\n", GetLastError()); - return; - } + ret = RegisterClassA(&clsMain); + ok(ret, "Failed to register a test class.\n"); cls.style = CS_DBLCLKS | CS_PARENTDC; cls.lpfnWndProc = parentdc_window_procA; @@ -5592,11 +6475,8 @@ static void test_csparentdc(void) cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = "ParentDcWindowClass"; - - if(!RegisterClassA(&cls)) { - trace("Register failed %d\n", GetLastError()); - return; - } + ret = RegisterClassA(&cls); + ok(ret, "Failed to register a test class.\n"); SetRect(&rc, 0, 0, 150, 150); AdjustWindowRectEx(&rc, WS_OVERLAPPEDWINDOW, FALSE, 0); @@ -5618,31 +6498,81 @@ static void test_csparentdc(void) zero_parentdc_test(&test_answer); InvalidateRect(hwndMain, NULL, TRUE); flush_events( TRUE ); +#ifdef __REACTOS__ + /* The parentdc_ok macro breaks if/else staements without braces */ + if (GetNTVersion() >= _WIN32_WINNT_WIN8) { + parentdc_ok(test1_win8, test_answer); + } + else { + parentdc_ok(test1, test_answer); + } +#else parentdc_ok(test1, test_answer); +#endif zero_parentdc_test(&test_answer); SetRect(&rc, 0, 0, 50, 50); InvalidateRect(hwndMain, &rc, TRUE); flush_events( TRUE ); +#ifdef __REACTOS__ + /* The parentdc_ok macro breaks if/else staements without braces */ + if (GetNTVersion() >= _WIN32_WINNT_WIN8) { + parentdc_ok(test2_win8, test_answer); + } + else { + parentdc_ok(test2, test_answer); + } +#else parentdc_ok(test2, test_answer); +#endif zero_parentdc_test(&test_answer); SetRect(&rc, 0, 0, 10, 10); InvalidateRect(hwndMain, &rc, TRUE); flush_events( TRUE ); +#ifdef __REACTOS__ + /* The parentdc_ok macro breaks if/else staements without braces */ + if (GetNTVersion() >= _WIN32_WINNT_WIN8) { + parentdc_ok(test3_win8, test_answer); + } + else { + parentdc_ok(test3, test_answer); + } +#else parentdc_ok(test3, test_answer); +#endif zero_parentdc_test(&test_answer); SetRect(&rc, 40, 40, 50, 50); InvalidateRect(hwndMain, &rc, TRUE); flush_events( TRUE ); +#ifdef __REACTOS__ + /* The parentdc_ok macro breaks if/else staements without braces */ + if (GetNTVersion() >= _WIN32_WINNT_WIN8) { + parentdc_ok(test4_win8, test_answer); + } + else { + parentdc_ok(test4, test_answer); + } +#else parentdc_ok(test4, test_answer); +#endif zero_parentdc_test(&test_answer); SetRect(&rc, 20, 20, 60, 60); InvalidateRect(hwndMain, &rc, TRUE); flush_events( TRUE ); +#ifdef __REACTOS__ + /* The parentdc_ok macro breaks if/else staements without braces */ + if (GetNTVersion() >= _WIN32_WINNT_WIN8) { + parentdc_ok(test5_win8, test_answer); + } + else { + parentdc_ok(test5, test_answer); + } +#else parentdc_ok(test5, test_answer); +#endif zero_parentdc_test(&test_answer); SetRect(&rc, 0, 0, 10, 10); @@ -5654,7 +6584,17 @@ static void test_csparentdc(void) SetRect(&rc, -5, -5, 65, 65); InvalidateRect(hwnd1, &rc, TRUE); flush_events( TRUE ); +#ifdef __REACTOS__ + /* The parentdc_ok macro breaks if/else staements without braces */ + if (GetNTVersion() >= _WIN32_WINNT_WIN8) { + parentdc_ok(test7_win8, test_answer); + } + else { + parentdc_ok(test7, test_answer); + } +#else parentdc_ok(test7, test_answer); +#endif DestroyWindow(hwndMain); DestroyWindow(hwnd1); @@ -5686,7 +6626,7 @@ static void test_IsWindowUnicode(void) classW.hInstance = GetModuleHandleA(0); classW.lpfnWndProc = def_window_procW; classW.lpszClassName = unicode_class_nameW; - if (!RegisterClassW(&classW)) return; /* this catches Win9x as well */ + RegisterClassW(&classW); memset(&classA, 0, sizeof(classA)); classA.hInstance = GetModuleHandleA(0); @@ -5838,12 +6778,10 @@ static LRESULT CALLBACK winsizes_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM CREATESTRUCTA *cs = (CREATESTRUCTA *)lp; RECT rect; GetWindowRect( hwnd, &rect ); - trace( "hwnd %p msg %x size %dx%d rect %s\n", hwnd, msg, cs->cx, cs->cy, - wine_dbgstr_rect( &rect )); ok( cs->cx == expected_cx || broken(cs->cx == (short)expected_cx), - "wrong x size %d/%d\n", cs->cx, expected_cx ); + "%p msg %x wrong x size %d/%d\n", hwnd, msg, cs->cx, expected_cx ); ok( cs->cy == expected_cy || broken(cs->cy == (short)expected_cy), - "wrong y size %d/%d\n", cs->cy, expected_cy ); + "%p msg %x wrong y size %d/%d\n", hwnd, msg, cs->cy, expected_cy ); ok( (rect.right - rect.left == expected_rect.right - expected_rect.left && rect.bottom - rect.top == expected_rect.bottom - expected_rect.top) || (rect.right - rect.left == min( 65535, expected_rect.right - expected_rect.left ) && @@ -5852,16 +6790,20 @@ static LRESULT CALLBACK winsizes_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM rect.bottom - rect.top == broken_rect.bottom - broken_rect.top) || broken( rect.right - rect.left == (short)broken_rect.right - (short)broken_rect.left && rect.bottom - rect.top == (short)broken_rect.bottom - (short)broken_rect.top), - "wrong rect %s / %s\n", wine_dbgstr_rect( &rect ), wine_dbgstr_rect( &expected_rect )); + "%p msg %x wrong rect %s / %s\n", hwnd, msg, wine_dbgstr_rect( &rect ), + wine_dbgstr_rect( &expected_rect )); return DefWindowProcA(hwnd, msg, wp, lp); } case WM_NCCALCSIZE: { + LRESULT ret; RECT rect, *r = (RECT *)lp; GetWindowRect( hwnd, &rect ); ok( EqualRect( &rect, r ), "passed rect %s doesn't match window rect %s\n", wine_dbgstr_rect( r ), wine_dbgstr_rect( &rect )); - return DefWindowProcA(hwnd, msg, wp, lp); + ret = DefWindowProcA(hwnd, msg, wp, lp); + ok(!ret, "got %08Ix\n", ret); + return ret; } default: return DefWindowProcA(hwnd, msg, wp, lp); @@ -5876,22 +6818,18 @@ static void test_CreateWindow(void) RECT rc, rc_minmax; MINMAXINFO minmax; BOOL res; + HDC hdc; #define expect_menu(window, menu) \ SetLastError(0xdeadbeef); \ res = (GetMenu(window) == (HMENU)menu); \ - ok(res, "GetMenu error %d\n", GetLastError()) + ok(res, "GetMenu error %ld\n", GetLastError()) #define expect_style(window, style)\ - ok((ULONG)GetWindowLongA(window, GWL_STYLE) == (style), "expected style %x != %x\n", (LONG)(style), GetWindowLongA(window, GWL_STYLE)) + ok((ULONG)GetWindowLongA(window, GWL_STYLE) == (style), "expected style %lx != %lx\n", (LONG)(style), GetWindowLongA(window, GWL_STYLE)) #define expect_ex_style(window, ex_style)\ - ok((ULONG)GetWindowLongA(window, GWL_EXSTYLE) == (ex_style), "expected ex_style %x != %x\n", (LONG)(ex_style), GetWindowLongA(window, GWL_EXSTYLE)) - -#define expect_gle_broken_9x(gle)\ - ok(GetLastError() == gle ||\ - broken(GetLastError() == 0xdeadbeef),\ - "IsMenu set error %d\n", GetLastError()) + ok((ULONG)GetWindowLongA(window, GWL_EXSTYLE) == (ex_style), "expected ex_style %lx != %lx\n", (LONG)(ex_style), GetWindowLongA(window, GWL_EXSTYLE)) hmenu = CreateMenu(); assert(hmenu != 0); @@ -5900,13 +6838,13 @@ static void test_CreateWindow(void) SetLastError(0xdeadbeef); res = IsMenu(hmenu); - ok(res, "IsMenu error %d\n", GetLastError()); + ok(res, "IsMenu error %ld\n", GetLastError()); /* WS_CHILD */ SetLastError(0xdeadbeef); hwnd = CreateWindowExA(WS_EX_APPWINDOW, "static", NULL, WS_CHILD, 0, 0, 100, 100, parent, (HMENU)1, 0, NULL); - ok(hwnd != 0, "CreateWindowEx error %d\n", GetLastError()); + ok(hwnd != 0, "CreateWindowEx error %ld\n", GetLastError()); expect_menu(hwnd, 1); expect_style(hwnd, WS_CHILD); expect_ex_style(hwnd, WS_EX_APPWINDOW); @@ -5915,7 +6853,7 @@ static void test_CreateWindow(void) SetLastError(0xdeadbeef); hwnd = CreateWindowExA(WS_EX_APPWINDOW, "static", NULL, WS_CHILD | WS_CAPTION, 0, 0, 100, 100, parent, (HMENU)1, 0, NULL); - ok(hwnd != 0, "CreateWindowEx error %d\n", GetLastError()); + ok(hwnd != 0, "CreateWindowEx error %ld\n", GetLastError()); expect_menu(hwnd, 1); expect_style(hwnd, WS_CHILD | WS_CAPTION); expect_ex_style(hwnd, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE); @@ -5924,7 +6862,7 @@ static void test_CreateWindow(void) SetLastError(0xdeadbeef); hwnd = CreateWindowExA(0, "static", NULL, WS_CHILD, 0, 0, 100, 100, parent, (HMENU)1, 0, NULL); - ok(hwnd != 0, "CreateWindowEx error %d\n", GetLastError()); + ok(hwnd != 0, "CreateWindowEx error %ld\n", GetLastError()); expect_menu(hwnd, 1); expect_style(hwnd, WS_CHILD); expect_ex_style(hwnd, 0); @@ -5933,7 +6871,7 @@ static void test_CreateWindow(void) SetLastError(0xdeadbeef); hwnd = CreateWindowExA(0, "static", NULL, WS_CHILD | WS_CAPTION, 0, 0, 100, 100, parent, (HMENU)1, 0, NULL); - ok(hwnd != 0, "CreateWindowEx error %d\n", GetLastError()); + ok(hwnd != 0, "CreateWindowEx error %ld\n", GetLastError()); expect_menu(hwnd, 1); expect_style(hwnd, WS_CHILD | WS_CAPTION); expect_ex_style(hwnd, WS_EX_WINDOWEDGE); @@ -5943,63 +6881,63 @@ static void test_CreateWindow(void) SetLastError(0xdeadbeef); hwnd = CreateWindowExA(WS_EX_APPWINDOW, "static", NULL, WS_POPUP, 0, 0, 100, 100, parent, hmenu, 0, NULL); - ok(hwnd != 0, "CreateWindowEx error %d\n", GetLastError()); + ok(hwnd != 0, "CreateWindowEx error %ld\n", GetLastError()); expect_menu(hwnd, hmenu); expect_style(hwnd, WS_POPUP | WS_CLIPSIBLINGS); expect_ex_style(hwnd, WS_EX_APPWINDOW); DestroyWindow(hwnd); SetLastError(0xdeadbeef); ok(!IsMenu(hmenu), "IsMenu should fail\n"); - expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE); + ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %ld\n", GetLastError()); hmenu = CreateMenu(); assert(hmenu != 0); SetLastError(0xdeadbeef); hwnd = CreateWindowExA(WS_EX_APPWINDOW, "static", NULL, WS_POPUP | WS_CAPTION, 0, 0, 100, 100, parent, hmenu, 0, NULL); - ok(hwnd != 0, "CreateWindowEx error %d\n", GetLastError()); + ok(hwnd != 0, "CreateWindowEx error %ld\n", GetLastError()); expect_menu(hwnd, hmenu); expect_style(hwnd, WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS); expect_ex_style(hwnd, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE); DestroyWindow(hwnd); SetLastError(0xdeadbeef); ok(!IsMenu(hmenu), "IsMenu should fail\n"); - expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE); + ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %ld\n", GetLastError()); hmenu = CreateMenu(); assert(hmenu != 0); SetLastError(0xdeadbeef); hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 100, 100, parent, hmenu, 0, NULL); - ok(hwnd != 0, "CreateWindowEx error %d\n", GetLastError()); + ok(hwnd != 0, "CreateWindowEx error %ld\n", GetLastError()); expect_menu(hwnd, hmenu); expect_style(hwnd, WS_POPUP | WS_CLIPSIBLINGS); expect_ex_style(hwnd, 0); DestroyWindow(hwnd); SetLastError(0xdeadbeef); ok(!IsMenu(hmenu), "IsMenu should fail\n"); - expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE); + ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %ld\n", GetLastError()); hmenu = CreateMenu(); assert(hmenu != 0); SetLastError(0xdeadbeef); hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_CAPTION, 0, 0, 100, 100, parent, hmenu, 0, NULL); - ok(hwnd != 0, "CreateWindowEx error %d\n", GetLastError()); + ok(hwnd != 0, "CreateWindowEx error %ld\n", GetLastError()); expect_menu(hwnd, hmenu); expect_style(hwnd, WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS); expect_ex_style(hwnd, WS_EX_WINDOWEDGE); DestroyWindow(hwnd); SetLastError(0xdeadbeef); ok(!IsMenu(hmenu), "IsMenu should fail\n"); - expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE); + ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %ld\n", GetLastError()); /* WS_CHILD | WS_POPUP */ SetLastError(0xdeadbeef); hwnd = CreateWindowExA(WS_EX_APPWINDOW, "static", NULL, WS_CHILD | WS_POPUP, 0, 0, 100, 100, parent, (HMENU)1, 0, NULL); - ok(!hwnd || broken(hwnd != 0 /* Win9x */), "CreateWindowEx should fail\n"); - expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE); + ok(!hwnd, "CreateWindowEx should fail\n"); + ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %ld\n", GetLastError()); if (hwnd) DestroyWindow(hwnd); @@ -6008,20 +6946,20 @@ static void test_CreateWindow(void) SetLastError(0xdeadbeef); hwnd = CreateWindowExA(WS_EX_APPWINDOW, "static", NULL, WS_CHILD | WS_POPUP, 0, 0, 100, 100, parent, hmenu, 0, NULL); - ok(hwnd != 0, "CreateWindowEx error %d\n", GetLastError()); + ok(hwnd != 0, "CreateWindowEx error %ld\n", GetLastError()); expect_menu(hwnd, hmenu); expect_style(hwnd, WS_CHILD | WS_POPUP | WS_CLIPSIBLINGS); expect_ex_style(hwnd, WS_EX_APPWINDOW); DestroyWindow(hwnd); SetLastError(0xdeadbeef); ok(!IsMenu(hmenu), "IsMenu should fail\n"); - expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE); + ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %ld\n", GetLastError()); SetLastError(0xdeadbeef); hwnd = CreateWindowExA(WS_EX_APPWINDOW, "static", NULL, WS_CHILD | WS_POPUP | WS_CAPTION, 0, 0, 100, 100, parent, (HMENU)1, 0, NULL); - ok(!hwnd || broken(hwnd != 0 /* Win9x */), "CreateWindowEx should fail\n"); - expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE); + ok(!hwnd, "CreateWindowEx should fail\n"); + ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %ld\n", GetLastError()); if (hwnd) DestroyWindow(hwnd); @@ -6030,20 +6968,20 @@ static void test_CreateWindow(void) SetLastError(0xdeadbeef); hwnd = CreateWindowExA(WS_EX_APPWINDOW, "static", NULL, WS_CHILD | WS_POPUP | WS_CAPTION, 0, 0, 100, 100, parent, hmenu, 0, NULL); - ok(hwnd != 0, "CreateWindowEx error %d\n", GetLastError()); + ok(hwnd != 0, "CreateWindowEx error %ld\n", GetLastError()); expect_menu(hwnd, hmenu); expect_style(hwnd, WS_CHILD | WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS); expect_ex_style(hwnd, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE); DestroyWindow(hwnd); SetLastError(0xdeadbeef); ok(!IsMenu(hmenu), "IsMenu should fail\n"); - expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE); + ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %ld\n", GetLastError()); SetLastError(0xdeadbeef); hwnd = CreateWindowExA(0, "static", NULL, WS_CHILD | WS_POPUP, 0, 0, 100, 100, parent, (HMENU)1, 0, NULL); - ok(!hwnd || broken(hwnd != 0 /* Win9x */), "CreateWindowEx should fail\n"); - expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE); + ok(!hwnd, "CreateWindowEx should fail\n"); + ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %ld\n", GetLastError()); if (hwnd) DestroyWindow(hwnd); @@ -6052,20 +6990,20 @@ static void test_CreateWindow(void) SetLastError(0xdeadbeef); hwnd = CreateWindowExA(0, "static", NULL, WS_CHILD | WS_POPUP, 0, 0, 100, 100, parent, hmenu, 0, NULL); - ok(hwnd != 0, "CreateWindowEx error %d\n", GetLastError()); + ok(hwnd != 0, "CreateWindowEx error %ld\n", GetLastError()); expect_menu(hwnd, hmenu); expect_style(hwnd, WS_CHILD | WS_POPUP | WS_CLIPSIBLINGS); expect_ex_style(hwnd, 0); DestroyWindow(hwnd); SetLastError(0xdeadbeef); ok(!IsMenu(hmenu), "IsMenu should fail\n"); - expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE); + ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %ld\n", GetLastError()); SetLastError(0xdeadbeef); hwnd = CreateWindowExA(0, "static", NULL, WS_CHILD | WS_POPUP | WS_CAPTION, 0, 0, 100, 100, parent, (HMENU)1, 0, NULL); - ok(!hwnd || broken(hwnd != 0 /* Win9x */), "CreateWindowEx should fail\n"); - expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE); + ok(!hwnd, "CreateWindowEx should fail\n"); + ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %ld\n", GetLastError()); if (hwnd) DestroyWindow(hwnd); @@ -6074,14 +7012,14 @@ static void test_CreateWindow(void) SetLastError(0xdeadbeef); hwnd = CreateWindowExA(0, "static", NULL, WS_CHILD | WS_POPUP | WS_CAPTION, 0, 0, 100, 100, parent, hmenu, 0, NULL); - ok(hwnd != 0, "CreateWindowEx error %d\n", GetLastError()); + ok(hwnd != 0, "CreateWindowEx error %ld\n", GetLastError()); expect_menu(hwnd, hmenu); expect_style(hwnd, WS_CHILD | WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS); expect_ex_style(hwnd, WS_EX_WINDOWEDGE); DestroyWindow(hwnd); SetLastError(0xdeadbeef); ok(!IsMenu(hmenu), "IsMenu should fail\n"); - expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE); + ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %ld\n", GetLastError()); /* test child window sizing */ cls.style = 0; @@ -6099,7 +7037,7 @@ static void test_CreateWindow(void) SetLastError(0xdeadbeef); parent = CreateWindowExA(0, "MinMax_WndClass", NULL, WS_CAPTION | WS_SYSMENU | WS_THICKFRAME, 0, 0, 100, 100, 0, 0, 0, NULL); - ok(parent != 0, "CreateWindowEx error %d\n", GetLastError()); + ok(parent != 0, "CreateWindowEx error %ld\n", GetLastError()); expect_menu(parent, 0); expect_style(parent, WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_CLIPSIBLINGS); expect_ex_style(parent, WS_EX_WINDOWEDGE); @@ -6117,13 +7055,12 @@ static void test_CreateWindow(void) ok(!IsRectEmpty(&rc), "parent client rect is empty\n"); InflateRect(&rc, 200, 200); - trace("creating child with rect %s\n", wine_dbgstr_rect(&rc)); SetLastError(0xdeadbeef); hwnd = CreateWindowExA(0, "MinMax_WndClass", NULL, WS_CHILD | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, parent, (HMENU)1, 0, NULL); - ok(hwnd != 0, "CreateWindowEx error %d\n", GetLastError()); + ok(hwnd != 0, "CreateWindowEx error %ld\n", GetLastError()); expect_menu(hwnd, 1); expect_style(hwnd, WS_CHILD | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME); expect_ex_style(hwnd, WS_EX_WINDOWEDGE); @@ -6146,49 +7083,49 @@ static void test_CreateWindow(void) SetRect( &expected_rect, 0, 0, 200000, 200000 ); broken_rect = expected_rect; hwnd = CreateWindowExA(0, "Sizes_WndClass", NULL, WS_CHILD, 300000, 300000, 200000, 200000, parent, 0, 0, NULL); - ok( hwnd != 0, "creation failed err %u\n", GetLastError()); + ok( hwnd != 0, "creation failed err %lu\n", GetLastError()); GetClientRect( hwnd, &rc ); ok( rc.right == 200000 || rc.right == 65535 || broken(rc.right == (short)200000), - "invalid rect right %u\n", rc.right ); + "invalid rect right %lu\n", rc.right ); ok( rc.bottom == 200000 || rc.bottom == 65535 || broken(rc.bottom == (short)200000), - "invalid rect bottom %u\n", rc.bottom ); + "invalid rect bottom %lu\n", rc.bottom ); DestroyWindow(hwnd); expected_cx = expected_cy = -10; SetRectEmpty(&expected_rect); SetRect( &broken_rect, 0, 0, -10, -10 ); hwnd = CreateWindowExA(0, "Sizes_WndClass", NULL, WS_CHILD, -20, -20, -10, -10, parent, 0, 0, NULL); - ok( hwnd != 0, "creation failed err %u\n", GetLastError()); + ok( hwnd != 0, "creation failed err %lu\n", GetLastError()); GetClientRect( hwnd, &rc ); - ok( rc.right == 0, "invalid rect right %u\n", rc.right ); - ok( rc.bottom == 0, "invalid rect bottom %u\n", rc.bottom ); + ok( rc.right == 0, "invalid rect right %lu\n", rc.right ); + ok( rc.bottom == 0, "invalid rect bottom %lu\n", rc.bottom ); DestroyWindow(hwnd); expected_cx = expected_cy = -200000; SetRectEmpty(&expected_rect); SetRect( &broken_rect, 0, 0, -200000, -200000 ); hwnd = CreateWindowExA(0, "Sizes_WndClass", NULL, WS_CHILD, -300000, -300000, -200000, -200000, parent, 0, 0, NULL); - ok( hwnd != 0, "creation failed err %u\n", GetLastError()); + ok( hwnd != 0, "creation failed err %lu\n", GetLastError()); GetClientRect( hwnd, &rc ); - ok( rc.right == 0, "invalid rect right %u\n", rc.right ); - ok( rc.bottom == 0, "invalid rect bottom %u\n", rc.bottom ); + ok( rc.right == 0, "invalid rect right %lu\n", rc.right ); + ok( rc.bottom == 0, "invalid rect bottom %lu\n", rc.bottom ); DestroyWindow(hwnd); /* we need a parent at 0,0 so that child coordinates match */ DestroyWindow(parent); parent = CreateWindowExA(0, "MinMax_WndClass", NULL, WS_POPUP, 0, 0, 100, 100, 0, 0, 0, NULL); - ok(parent != 0, "CreateWindowEx error %d\n", GetLastError()); + ok(parent != 0, "CreateWindowEx error %ld\n", GetLastError()); expected_cx = 100; expected_cy = 0x7fffffff; SetRect( &expected_rect, 10, 10, 110, 0x7fffffff ); SetRect( &broken_rect, 10, 10, 110, 0x7fffffffU + 10 ); hwnd = CreateWindowExA(0, "Sizes_WndClass", NULL, WS_CHILD, 10, 10, 100, 0x7fffffff, parent, 0, 0, NULL); - ok( hwnd != 0, "creation failed err %u\n", GetLastError()); + ok( hwnd != 0, "creation failed err %lu\n", GetLastError()); GetClientRect( hwnd, &rc ); - ok( rc.right == 100, "invalid rect right %u\n", rc.right ); + ok( rc.right == 100, "invalid rect right %lu\n", rc.right ); ok( rc.bottom == 0x7fffffff - 10 || rc.bottom ==65535 || broken(rc.bottom == 0), - "invalid rect bottom %u\n", rc.bottom ); + "invalid rect bottom %lu\n", rc.bottom ); DestroyWindow(hwnd); expected_cx = 0x7fffffff; @@ -6196,98 +7133,101 @@ static void test_CreateWindow(void) SetRect( &expected_rect, 20, 10, 0x7fffffff, 0x7fffffff ); SetRect( &broken_rect, 20, 10, 0x7fffffffU + 20, 0x7fffffffU + 10 ); hwnd = CreateWindowExA(0, "Sizes_WndClass", NULL, WS_CHILD, 20, 10, 0x7fffffff, 0x7fffffff, parent, 0, 0, NULL); - ok( hwnd != 0, "creation failed err %u\n", GetLastError()); + ok( hwnd != 0, "creation failed err %lu\n", GetLastError()); GetClientRect( hwnd, &rc ); ok( rc.right == 0x7fffffff - 20 || rc.right == 65535 || broken(rc.right == 0), - "invalid rect right %u\n", rc.right ); + "invalid rect right %lu\n", rc.right ); ok( rc.bottom == 0x7fffffff - 10 || rc.right == 65535 || broken(rc.bottom == 0), - "invalid rect bottom %u\n", rc.bottom ); + "invalid rect bottom %lu\n", rc.bottom ); DestroyWindow(hwnd); /* top level window */ expected_cx = expected_cy = 200000; SetRect( &expected_rect, 0, 0, GetSystemMetrics(SM_CXMAXTRACK), GetSystemMetrics(SM_CYMAXTRACK) ); hwnd = CreateWindowExA(0, "Sizes_WndClass", NULL, WS_OVERLAPPEDWINDOW, 300000, 300000, 200000, 200000, 0, 0, 0, NULL); - ok( hwnd != 0, "creation failed err %u\n", GetLastError()); + ok( hwnd != 0, "creation failed err %lu\n", GetLastError()); GetClientRect( hwnd, &rc ); - ok( rc.right <= expected_cx, "invalid rect right %u\n", rc.right ); - ok( rc.bottom <= expected_cy, "invalid rect bottom %u\n", rc.bottom ); + ok( rc.right <= expected_cx, "invalid rect right %lu\n", rc.right ); + ok( rc.bottom <= expected_cy, "invalid rect bottom %lu\n", rc.bottom ); DestroyWindow(hwnd); - if (pGetLayout && pSetLayout) + /* invalid class */ + SetLastError(0xdeadbeef); + hwnd = CreateWindowExA(0, "INVALID_CLASS", NULL, WS_CHILD, 10, 10, 100, 100, parent, 0, 0, NULL); + ok(hwnd == 0, "CreateWindowEx succeeded\n"); + ok(GetLastError() == ERROR_CLASS_DOES_NOT_EXIST || GetLastError() == ERROR_CANNOT_FIND_WND_CLASS, + "invalid error %lu\n", GetLastError()); + DestroyWindow(hwnd); + + hdc = GetDC( parent ); + SetLayout( hdc, LAYOUT_RTL ); + if (GetLayout( hdc )) { - HDC hdc = GetDC( parent ); - pSetLayout( hdc, LAYOUT_RTL ); - if (pGetLayout( hdc )) + ReleaseDC( parent, hdc ); + DestroyWindow( parent ); + SetLastError( 0xdeadbeef ); + parent = CreateWindowExA(WS_EX_APPWINDOW | WS_EX_LAYOUTRTL, "static", NULL, WS_POPUP, + 0, 0, 100, 100, 0, 0, 0, NULL); + ok( parent != 0, "creation failed err %lu\n", GetLastError()); + expect_ex_style( parent, WS_EX_APPWINDOW | WS_EX_LAYOUTRTL ); + hwnd = CreateWindowExA(0, "static", NULL, WS_CHILD, 0, 0, 20, 20, parent, 0, 0, NULL); + ok( hwnd != 0, "creation failed err %lu\n", GetLastError()); + expect_ex_style( hwnd, WS_EX_LAYOUTRTL ); + DestroyWindow( hwnd ); + hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 20, 20, parent, 0, 0, NULL); + ok( hwnd != 0, "creation failed err %lu\n", GetLastError()); + expect_ex_style( hwnd, 0 ); + DestroyWindow( hwnd ); + SetWindowLongW( parent, GWL_EXSTYLE, WS_EX_APPWINDOW | WS_EX_LAYOUTRTL | WS_EX_NOINHERITLAYOUT ); + hwnd = CreateWindowExA(0, "static", NULL, WS_CHILD, 0, 0, 20, 20, parent, 0, 0, NULL); + ok( hwnd != 0, "creation failed err %lu\n", GetLastError()); + expect_ex_style( hwnd, 0 ); + DestroyWindow( hwnd ); + + if (pGetProcessDefaultLayout && pSetProcessDefaultLayout) { - ReleaseDC( parent, hdc ); - DestroyWindow( parent ); + DWORD layout; + SetLastError( 0xdeadbeef ); - parent = CreateWindowExA(WS_EX_APPWINDOW | WS_EX_LAYOUTRTL, "static", NULL, WS_POPUP, - 0, 0, 100, 100, 0, 0, 0, NULL); - ok( parent != 0, "creation failed err %u\n", GetLastError()); - expect_ex_style( parent, WS_EX_APPWINDOW | WS_EX_LAYOUTRTL ); - hwnd = CreateWindowExA(0, "static", NULL, WS_CHILD, 0, 0, 20, 20, parent, 0, 0, NULL); - ok( hwnd != 0, "creation failed err %u\n", GetLastError()); - expect_ex_style( hwnd, WS_EX_LAYOUTRTL ); + ok( !pGetProcessDefaultLayout( NULL ), "GetProcessDefaultLayout succeeded\n" ); + ok( GetLastError() == ERROR_NOACCESS, "wrong error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + res = pGetProcessDefaultLayout( &layout ); + ok( res, "GetProcessDefaultLayout failed err %lu\n", GetLastError ()); + ok( layout == 0, "GetProcessDefaultLayout wrong layout %lx\n", layout ); + SetLastError( 0xdeadbeef ); + res = pSetProcessDefaultLayout( 7 ); + ok( res, "SetProcessDefaultLayout failed err %lu\n", GetLastError ()); + res = pGetProcessDefaultLayout( &layout ); + ok( res, "GetProcessDefaultLayout failed err %lu\n", GetLastError ()); + ok( layout == 7, "GetProcessDefaultLayout wrong layout %lx\n", layout ); + SetLastError( 0xdeadbeef ); + res = pSetProcessDefaultLayout( LAYOUT_RTL ); + ok( res, "SetProcessDefaultLayout failed err %lu\n", GetLastError ()); + res = pGetProcessDefaultLayout( &layout ); + ok( res, "GetProcessDefaultLayout failed err %lu\n", GetLastError ()); + ok( layout == LAYOUT_RTL, "GetProcessDefaultLayout wrong layout %lx\n", layout ); + hwnd = CreateWindowExA(WS_EX_APPWINDOW, "static", NULL, WS_POPUP, + 0, 0, 100, 100, 0, 0, 0, NULL); + ok( hwnd != 0, "creation failed err %lu\n", GetLastError()); + expect_ex_style( hwnd, WS_EX_APPWINDOW | WS_EX_LAYOUTRTL ); DestroyWindow( hwnd ); - hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 20, 20, parent, 0, 0, NULL); - ok( hwnd != 0, "creation failed err %u\n", GetLastError()); - expect_ex_style( hwnd, 0 ); + hwnd = CreateWindowExA(WS_EX_APPWINDOW, "static", NULL, WS_POPUP, + 0, 0, 100, 100, parent, 0, 0, NULL); + ok( hwnd != 0, "creation failed err %lu\n", GetLastError()); + expect_ex_style( hwnd, WS_EX_APPWINDOW ); DestroyWindow( hwnd ); - SetWindowLongW( parent, GWL_EXSTYLE, WS_EX_APPWINDOW | WS_EX_LAYOUTRTL | WS_EX_NOINHERITLAYOUT ); - hwnd = CreateWindowExA(0, "static", NULL, WS_CHILD, 0, 0, 20, 20, parent, 0, 0, NULL); - ok( hwnd != 0, "creation failed err %u\n", GetLastError()); - expect_ex_style( hwnd, 0 ); - DestroyWindow( hwnd ); - - if (pGetProcessDefaultLayout && pSetProcessDefaultLayout) - { - DWORD layout; - - SetLastError( 0xdeadbeef ); - ok( !pGetProcessDefaultLayout( NULL ), "GetProcessDefaultLayout succeeded\n" ); - ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() ); - SetLastError( 0xdeadbeef ); - res = pGetProcessDefaultLayout( &layout ); - ok( res, "GetProcessDefaultLayout failed err %u\n", GetLastError ()); - ok( layout == 0, "GetProcessDefaultLayout wrong layout %x\n", layout ); - SetLastError( 0xdeadbeef ); - res = pSetProcessDefaultLayout( 7 ); - ok( res, "SetProcessDefaultLayout failed err %u\n", GetLastError ()); - res = pGetProcessDefaultLayout( &layout ); - ok( res, "GetProcessDefaultLayout failed err %u\n", GetLastError ()); - ok( layout == 7, "GetProcessDefaultLayout wrong layout %x\n", layout ); - SetLastError( 0xdeadbeef ); - res = pSetProcessDefaultLayout( LAYOUT_RTL ); - ok( res, "SetProcessDefaultLayout failed err %u\n", GetLastError ()); - res = pGetProcessDefaultLayout( &layout ); - ok( res, "GetProcessDefaultLayout failed err %u\n", GetLastError ()); - ok( layout == LAYOUT_RTL, "GetProcessDefaultLayout wrong layout %x\n", layout ); - hwnd = CreateWindowExA(WS_EX_APPWINDOW, "static", NULL, WS_POPUP, - 0, 0, 100, 100, 0, 0, 0, NULL); - ok( hwnd != 0, "creation failed err %u\n", GetLastError()); - expect_ex_style( hwnd, WS_EX_APPWINDOW | WS_EX_LAYOUTRTL ); - DestroyWindow( hwnd ); - hwnd = CreateWindowExA(WS_EX_APPWINDOW, "static", NULL, WS_POPUP, - 0, 0, 100, 100, parent, 0, 0, NULL); - ok( hwnd != 0, "creation failed err %u\n", GetLastError()); - expect_ex_style( hwnd, WS_EX_APPWINDOW ); - DestroyWindow( hwnd ); - pSetProcessDefaultLayout( 0 ); - } - else win_skip( "SetProcessDefaultLayout not supported\n" ); + pSetProcessDefaultLayout( 0 ); } - else win_skip( "SetLayout not supported\n" ); + else win_skip( "SetProcessDefaultLayout not supported\n" ); } - else win_skip( "SetLayout not available\n" ); + else win_skip( "SetLayout not supported\n" ); DestroyWindow(parent); UnregisterClassA("MinMax_WndClass", GetModuleHandleA(NULL)); UnregisterClassA("Sizes_WndClass", GetModuleHandleA(NULL)); -#undef expect_gle_broken_9x #undef expect_menu #undef expect_style #undef expect_ex_style @@ -6303,6 +7243,209 @@ static int check_error(DWORD actual, DWORD expected) return (!sets_last_error && (actual == 0xdeadbeef)) || (actual == expected); } +static void test_set_window_long_size(void) +{ +#ifdef _WIN64 + WNDPROC wnd_proc, wnd_proc_2; + LONG_PTR retval; + HWND hwnd; + LONG ret; + + /* It's not allowed to set or get 64-bit pointer values using 32-bit functions. */ + hwnd = CreateWindowExA(0, "MainWindowClass", "Child window", WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_CHILD | + WS_MAXIMIZEBOX | WS_VISIBLE, 100, 100, 200, 200, hwndMain, 0, GetModuleHandleA(NULL), NULL); + ok(hwnd != NULL, "Failed to create test window.\n"); + + /* GWLP_WNDPROC */ + SetLastError(0xdeadbeef); + wnd_proc = (WNDPROC)(LONG_PTR)GetWindowLongA(hwnd, GWLP_WNDPROC); + ok(!wnd_proc && GetLastError() == ERROR_INVALID_INDEX, "Unexpected window proc.\n"); + + wnd_proc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC); + ok(!!wnd_proc, "Unexpected window proc.\n"); + + SetLastError(0xdeadbeef); + wnd_proc_2 = (WNDPROC)(LONG_PTR)SetWindowLongA(hwnd, GWLP_WNDPROC, 0xdeadbeef); + ok(!wnd_proc_2 && GetLastError() == ERROR_INVALID_INDEX, "Unexpected window proc.\n"); + + wnd_proc_2 = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC); + ok(wnd_proc_2 == wnd_proc, "Unexpected window proc.\n"); + + SetLastError(0xdeadbeef); + ret = GetWindowWord(hwnd, GWLP_WNDPROC); + ok(!ret && GetLastError() == ERROR_INVALID_INDEX, "Unexpected return value.\n"); + + /* GWLP_USERDATA */ + SetWindowLongPtrA(hwnd, GWLP_USERDATA, ((LONG_PTR)1 << 32) | 123); + ret = GetWindowLongA(hwnd, GWLP_USERDATA); + ok(ret == 123, "Unexpected user data %#lx.\n", ret); + retval = GetWindowLongPtrA(hwnd, GWLP_USERDATA); + ok(retval > 123, "Unexpected user data.\n"); + ret = GetWindowWord(hwnd, GWLP_USERDATA); + ok(ret == 123, "Unexpected user data %#lx.\n", ret); + ret = SetWindowWord(hwnd, GWLP_USERDATA, 124); + ok(ret == 123, "Unexpected user data %#lx.\n", ret); + ret = GetWindowLongA(hwnd, GWLP_USERDATA); + ok(ret == 124, "Unexpected user data %#lx.\n", ret); + retval = GetWindowLongPtrA(hwnd, GWLP_USERDATA); + ok(retval == 124, "Unexpected user data.\n"); + + SetWindowLongA(hwnd, GWLP_USERDATA, (1 << 16) | 123); + ret = GetWindowLongA(hwnd, GWLP_USERDATA); + ok(ret == ((1 << 16) | 123), "Unexpected user data %#lx.\n", ret); + ret = GetWindowWord(hwnd, GWLP_USERDATA); + ok(ret == 123, "Unexpected user data %#lx.\n", ret); + + ret = SetWindowWord(hwnd, GWLP_USERDATA, 124); + ok(ret == 123, "Unexpected user data %#lx.\n", ret); + ret = GetWindowLongA(hwnd, GWLP_USERDATA); + ok(ret == ((1 << 16) | 124), "Unexpected user data %#lx.\n", ret); + ret = GetWindowWord(hwnd, GWLP_USERDATA); + ok(ret == 124, "Unexpected user data %#lx.\n", ret); + + /* GWLP_ID */ + ret = SetWindowLongA(hwnd, GWLP_ID, 1); + ok(!ret, "Unexpected id %#lx.\n", ret); + + ret = GetWindowLongA(hwnd, GWLP_ID); + ok(ret == 1, "Unexpected id %#lx.\n", ret); + + ret = GetWindowLongW(hwnd, GWLP_ID); + ok(ret == 1, "Unexpected id %#lx.\n", ret); + + SetWindowLongPtrA(hwnd, GWLP_ID, ((LONG_PTR)1 << 32) | 123); + ret = GetWindowLongA(hwnd, GWLP_ID); + ok(ret == 123, "Unexpected id %#lx.\n", ret); + ret = GetWindowLongW(hwnd, GWLP_ID); + ok(ret == 123, "Unexpected id %#lx.\n", ret); + retval = GetWindowLongPtrA(hwnd, GWLP_ID); + ok(retval > 123, "Unexpected id.\n"); + SetLastError(0xdeadbeef); + ret = GetWindowWord(hwnd, GWLP_ID); + ok(!ret && GetLastError() == ERROR_INVALID_INDEX, "Unexpected id %#lx.\n", ret); + + /* GWLP_HINSTANCE */ + retval = GetWindowLongPtrA(hwnd, GWLP_HINSTANCE); + ok(retval == (LONG_PTR)GetModuleHandleA(NULL), "Unexpected instance %#Ix.\n", retval); + + SetLastError(0xdeadbeef); + ret = GetWindowLongA(hwnd, GWLP_HINSTANCE); + ok(!ret && GetLastError() == ERROR_INVALID_INDEX, "Unexpected instance %#lx.\n", ret); + + SetLastError(0xdeadbeef); + ret = GetWindowLongW(hwnd, GWLP_HINSTANCE); + ok(!ret && GetLastError() == ERROR_INVALID_INDEX, "Unexpected instance %#lx.\n", ret); + + SetLastError(0xdeadbeef); + ret = GetWindowWord(hwnd, GWLP_HINSTANCE); + ok(!ret && GetLastError() == ERROR_INVALID_INDEX, "Unexpected instance %#lx.\n", ret); + + SetLastError(0xdeadbeef); + ret = SetWindowLongA(hwnd, GWLP_HINSTANCE, 1); + ok(!ret && GetLastError() == ERROR_INVALID_INDEX, "Unexpected instance %#lx.\n", ret); + + SetLastError(0xdeadbeef); + ret = SetWindowLongW(hwnd, GWLP_HINSTANCE, 1); + ok(!ret && GetLastError() == ERROR_INVALID_INDEX, "Unexpected instance %#lx.\n", ret); + + /* GWLP_HWNDPARENT */ + SetLastError(0xdeadbeef); + ret = GetWindowLongA(hwnd, GWLP_HWNDPARENT); + ok(!ret && GetLastError() == ERROR_INVALID_INDEX, "Unexpected parent window %#lx.\n", ret); + + SetLastError(0xdeadbeef); + ret = SetWindowLongA(hwnd, GWLP_HWNDPARENT, 0); + ok(!ret && GetLastError() == ERROR_INVALID_INDEX, "Unexpected parent window %#lx.\n", ret); + + SetLastError(0xdeadbeef); + ret = SetWindowLongW(hwnd, GWLP_HWNDPARENT, 0); + ok(!ret && GetLastError() == ERROR_INVALID_INDEX, "Unexpected parent window %#lx.\n", ret); + + SetLastError(0xdeadbeef); + ret = GetWindowWord(hwnd, GWLP_HWNDPARENT); + ok(!ret && GetLastError() == ERROR_INVALID_INDEX, "Unexpected parent window %#lx.\n", ret); + + DestroyWindow(hwnd); +#endif +} + +static void test_set_window_word_size(void) +{ + WNDPROC wnd_proc, wnd_proc_2; + LONG_PTR retval; + HWND hwnd; + LONG ret; + + /* It's not allowed to set or get 64-bit pointer values using 32-bit functions. */ + hwnd = CreateWindowExA(0, "MainWindowClass", "Child window", WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_CHILD | + WS_MAXIMIZEBOX | WS_VISIBLE, 100, 100, 200, 200, hwndMain, 0, GetModuleHandleA(NULL), NULL); + ok(hwnd != NULL, "Failed to create test window.\n"); + + /* GWLP_WNDPROC */ + wnd_proc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC); + ok(!!wnd_proc, "Unexpected window proc.\n"); + + SetLastError(0xdeadbeef); + ret = GetWindowWord(hwnd, GWLP_WNDPROC); + ok(!ret && GetLastError() == ERROR_INVALID_INDEX, "Unexpected window proc.\n"); + + SetLastError(0xdeadbeef); + ret = SetWindowWord(hwnd, GWLP_WNDPROC, 0xbeef); + ok(!ret && GetLastError() == ERROR_INVALID_INDEX, "Unexpected window proc.\n"); + + wnd_proc_2 = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC); + ok(wnd_proc_2 == wnd_proc, "Unexpected window proc.\n"); + + /* GWLP_USERDATA */ + ret = SetWindowLongA(hwnd, GWLP_USERDATA, (1 << 16) | 123); + ok(!ret, "Unexpected user data %#lx.\n", ret); + ret = GetWindowLongA(hwnd, GWLP_USERDATA); + ok(ret > 123, "Unexpected user data %#lx.\n", ret); + ret = GetWindowWord(hwnd, GWLP_USERDATA); + ok(ret == 123, "Unexpected user data %#lx.\n", ret); + ret = SetWindowWord(hwnd, GWLP_USERDATA, 124); + ok(ret == 123, "Unexpected user data %#lx.\n", ret); + ret = GetWindowWord(hwnd, GWLP_USERDATA); + ok(ret == 124, "Unexpected user data %#lx.\n", ret); + ret = GetWindowLongA(hwnd, GWLP_USERDATA); + ok(ret == ((1 << 16) | 124), "Unexpected user data %#lx.\n", ret); + + /* GWLP_ID */ + ret = SetWindowLongA(hwnd, GWLP_ID, 1); + ok(!ret, "Unexpected id %#lx.\n", ret); + ret = GetWindowLongA(hwnd, GWLP_ID); + ok(ret == 1, "Unexpected id %#lx.\n", ret); + + SetLastError(0xdeadbeef); + ret = GetWindowWord(hwnd, GWLP_ID); + ok(!ret && GetLastError() == ERROR_INVALID_INDEX, "Unexpected id %#lx.\n", ret); + SetLastError(0xdeadbeef); + ret = SetWindowWord(hwnd, GWLP_ID, 2); + ok(!ret && GetLastError() == ERROR_INVALID_INDEX, "Unexpected id %#lx.\n", ret); + + /* GWLP_HINSTANCE */ + retval = GetWindowLongPtrA(hwnd, GWLP_HINSTANCE); + ok(retval == (LONG_PTR)GetModuleHandleA(NULL), "Unexpected instance %#Ix.\n", retval); + + SetLastError(0xdeadbeef); + ret = GetWindowWord(hwnd, GWLP_HINSTANCE); + ok(!ret && GetLastError() == ERROR_INVALID_INDEX, "Unexpected instance %#lx.\n", ret); + + SetLastError(0xdeadbeef); + ret = SetWindowWord(hwnd, GWLP_HINSTANCE, 0xdead); + ok(!ret && GetLastError() == ERROR_INVALID_INDEX, "Unexpected instance %#lx.\n", ret); + + /* GWLP_HWNDPARENT */ + retval = GetWindowLongPtrA(hwnd, GWLP_HWNDPARENT); + ok(!!retval, "Unexpected parent window %#lx.\n", ret); + + SetLastError(0xdeadbeef); + ret = GetWindowWord(hwnd, GWLP_HWNDPARENT); + ok(!ret && GetLastError() == ERROR_INVALID_INDEX, "Unexpected parent window %#lx.\n", ret); + + DestroyWindow(hwnd); +} + static void test_SetWindowLong(void) { LONG_PTR retval; @@ -6310,24 +7453,24 @@ static void test_SetWindowLong(void) SetLastError(0xdeadbeef); retval = SetWindowLongPtrA(NULL, GWLP_WNDPROC, 0); - ok(!retval, "SetWindowLongPtr on invalid window handle should have returned 0 instead of 0x%lx\n", retval); + ok(!retval, "SetWindowLongPtr on invalid window handle should have returned 0 instead of 0x%Ix\n", retval); ok(check_error(GetLastError(), ERROR_INVALID_WINDOW_HANDLE), - "SetWindowLongPtr should have set error to ERROR_INVALID_WINDOW_HANDLE instead of %d\n", GetLastError()); + "SetWindowLongPtr should have set error to ERROR_INVALID_WINDOW_HANDLE instead of %ld\n", GetLastError()); SetLastError(0xdeadbeef); retval = SetWindowLongPtrA(hwndMain, 0xdeadbeef, 0); - ok(!retval, "SetWindowLongPtr on invalid index should have returned 0 instead of 0x%lx\n", retval); + ok(!retval, "SetWindowLongPtr on invalid index should have returned 0 instead of 0x%Ix\n", retval); ok(check_error(GetLastError(), ERROR_INVALID_INDEX), - "SetWindowLongPtr should have set error to ERROR_INVALID_INDEX instead of %d\n", GetLastError()); + "SetWindowLongPtr should have set error to ERROR_INVALID_INDEX instead of %ld\n", GetLastError()); SetLastError(0xdeadbeef); retval = SetWindowLongPtrA(hwndMain, GWLP_WNDPROC, 0); - ok((WNDPROC)retval == main_window_procA || broken(!retval), /* win9x */ - "SetWindowLongPtr on invalid window proc should have returned address of main_window_procA instead of 0x%lx\n", retval); - ok(GetLastError() == 0xdeadbeef, "SetWindowLongPtr shouldn't have set the last error, instead of setting it to %d\n", GetLastError()); + ok((WNDPROC)retval == main_window_procA, + "SetWindowLongPtr on invalid window proc should have returned address of main_window_procA instead of 0x%Ix\n", retval); + ok(GetLastError() == 0xdeadbeef, "SetWindowLongPtr shouldn't have set the last error, instead of setting it to %ld\n", GetLastError()); retval = GetWindowLongPtrA(hwndMain, GWLP_WNDPROC); ok((WNDPROC)retval == main_window_procA, - "SetWindowLongPtr on invalid window proc shouldn't have changed the value returned by GetWindowLongPtr, instead of changing it to 0x%lx\n", retval); + "SetWindowLongPtr on invalid window proc shouldn't have changed the value returned by GetWindowLongPtr, instead of changing it to 0x%Ix\n", retval); ok(!IsWindowUnicode(hwndMain), "hwndMain shouldn't be Unicode\n"); old_window_procW = (WNDPROC)GetWindowLongPtrW(hwndMain, GWLP_WNDPROC); @@ -6335,15 +7478,27 @@ static void test_SetWindowLong(void) retval = SetWindowLongPtrW(hwndMain, GWLP_WNDPROC, 0); if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) { - ok(GetLastError() == 0xdeadbeef, "SetWindowLongPtr shouldn't have set the last error, instead of setting it to %d\n", GetLastError()); - ok(retval != 0, "SetWindowLongPtr error %d\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "SetWindowLongPtr shouldn't have set the last error, instead of setting it to %ld\n", GetLastError()); + ok(retval != 0, "SetWindowLongPtr error %ld\n", GetLastError()); ok((WNDPROC)retval == old_window_procW, - "SetWindowLongPtr on invalid window proc shouldn't have changed the value returned by GetWindowLongPtr, instead of changing it to 0x%lx\n", retval); + "SetWindowLongPtr on invalid window proc shouldn't have changed the value returned by GetWindowLongPtr, instead of changing it to 0x%Ix\n", retval); ok(IsWindowUnicode(hwndMain), "hwndMain should now be Unicode\n"); + /* Make sure nothing changes if we set the same proc */ + retval = SetWindowLongPtrW(hwndMain, GWLP_WNDPROC, (LONG_PTR)old_window_procW); + todo_wine + ok((WNDPROC)retval == main_window_procA, "unexpected proc 0x%Ix\n", retval); + retval = GetWindowLongPtrW(hwndMain, GWLP_WNDPROC); + ok((WNDPROC)retval == old_window_procW, "unexpected proc 0x%Ix\n", retval); + retval = GetWindowLongPtrA(hwndMain, GWLP_WNDPROC); + ok((WNDPROC)retval == main_window_procA, "unexpected proc 0x%Ix\n", retval); + /* set it back to ANSI */ SetWindowLongPtrA(hwndMain, GWLP_WNDPROC, 0); } + + test_set_window_long_size(); + test_set_window_word_size(); } static LRESULT WINAPI check_style_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) @@ -6353,16 +7508,16 @@ static LRESULT WINAPI check_style_wnd_proc(HWND hwnd, UINT message, WPARAM wPara if (message == WM_STYLECHANGING && wParam == GWL_STYLE) { - ok(got->styleOld == expected[0].styleOld, "expected old style %#x, got %#x\n", + ok(got->styleOld == expected[0].styleOld, "expected old style %#lx, got %#lx\n", expected[0].styleOld, got->styleOld); - ok(got->styleNew == expected[0].styleNew, "expected new style %#x, got %#x\n", + ok(got->styleNew == expected[0].styleNew, "expected new style %#lx, got %#lx\n", expected[0].styleNew, got->styleNew); } else if (message == WM_STYLECHANGED && wParam == GWL_STYLE) { - ok(got->styleOld == expected[1].styleOld, "expected old style %#x, got %#x\n", + ok(got->styleOld == expected[1].styleOld, "expected old style %#lx, got %#lx\n", expected[1].styleOld, got->styleOld); - ok(got->styleNew == expected[1].styleNew, "expected new style %#x, got %#x\n", + ok(got->styleNew == expected[1].styleNew, "expected new style %#lx, got %#lx\n", expected[1].styleNew, got->styleNew); } @@ -6408,7 +7563,7 @@ static void test_set_window_style(void) cls.lpszClassName = "TestSetWindowStylesClass"; ok(RegisterClassA(&cls), "RegisterClass failed\n"); - for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) + for (i = 0; i < ARRAY_SIZE(tests); i++) { expected_style = tests[i].style; if (tests[i].creation_style & WS_MINIMIZE) @@ -6425,10 +7580,10 @@ static void test_set_window_style(void) SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)&expected_stylestruct); old_style = SetWindowLongA(hwnd, GWL_STYLE, tests[i].style); - ok(old_style == tests[i].creation_style, "expected old style %#x, got %#x\n", + ok(old_style == tests[i].creation_style, "expected old style %#lx, got %#lx\n", tests[i].creation_style, old_style); new_style = GetWindowLongA(hwnd, GWL_STYLE); - ok(new_style == expected_style, "expected new style %#x, got %#x\n", + ok(new_style == expected_style, "expected new style %#lx, got %#lx\n", expected_style, new_style); SetWindowLongPtrA(hwnd, GWLP_USERDATA, 0); @@ -6442,10 +7597,32 @@ static void test_ShowWindow(void) { HWND hwnd; DWORD style; - RECT rcMain, rc, rcMinimized; + RECT rcMain, rc, rcMinimized, rcClient, rcEmpty, rcMaximized, rcResized, rcNonClient, rcBroken; LPARAM ret; + MONITORINFO mon_info; + unsigned int i; - SetRect(&rcMain, 120, 120, 210, 210); + DWORD test_style[] = + { + WS_OVERLAPPED | WS_VISIBLE | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME, + WS_OVERLAPPED | WS_VISIBLE | WS_SYSMENU | WS_MINIMIZEBOX | WS_THICKFRAME, + WS_OVERLAPPED | WS_VISIBLE | WS_SYSMENU | WS_MAXIMIZEBOX | WS_THICKFRAME, + WS_OVERLAPPED | WS_VISIBLE | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, + WS_OVERLAPPED | WS_VISIBLE | WS_SYSMENU | WS_MINIMIZEBOX, + WS_OVERLAPPED | WS_VISIBLE | WS_SYSMENU | WS_MAXIMIZEBOX, + WS_OVERLAPPED | WS_VISIBLE | WS_SYSMENU | WS_THICKFRAME, + WS_OVERLAPPED | WS_VISIBLE | WS_SYSMENU, + WS_OVERLAPPED | WS_VISIBLE | WS_THICKFRAME, + WS_OVERLAPPED | WS_VISIBLE + }; + + SetRect(&rcClient, 0, 0, 90, 90); + rcMain = rcClient; + OffsetRect(&rcMain, 120, 120); + AdjustWindowRect(&rcMain, WS_CAPTION, 0); + SetRect(&rcMinimized, -32000, -32000, -32000 + GetSystemMetrics(SM_CXMINIMIZED), + -32000 + GetSystemMetrics(SM_CYMINIMIZED)); + SetRectEmpty(&rcEmpty); hwnd = CreateWindowExA(0, "MainWindowClass", NULL, WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | @@ -6455,6 +7632,12 @@ static void test_ShowWindow(void) 0, 0, 0, NULL); assert(hwnd); + mon_info.cbSize = sizeof(mon_info); + GetMonitorInfoW(MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY), &mon_info); + rcMaximized = mon_info.rcWork; + AdjustWindowRectEx(&rcMaximized, GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BORDER, + 0, GetWindowLongA(hwnd, GWL_EXSTYLE)); + style = GetWindowLongA(hwnd, GWL_STYLE); ok(!(style & WS_DISABLED), "window should not be disabled\n"); ok(!(style & WS_VISIBLE), "window should not be visible\n"); @@ -6463,9 +7646,12 @@ static void test_ShowWindow(void) GetWindowRect(hwnd, &rc); ok(EqualRect(&rcMain, &rc), "expected %s, got %s\n", wine_dbgstr_rect(&rcMain), wine_dbgstr_rect(&rc)); + GetClientRect(hwnd, &rc); + ok(EqualRect(&rcClient, &rc), "expected %s, got %s\n", + wine_dbgstr_rect(&rcClient), wine_dbgstr_rect(&rc)); ret = ShowWindow(hwnd, SW_SHOW); - ok(!ret, "not expected ret: %lu\n", ret); + ok(!ret, "not expected ret: %Iu\n", ret); style = GetWindowLongA(hwnd, GWL_STYLE); ok(!(style & WS_DISABLED), "window should not be disabled\n"); ok(style & WS_VISIBLE, "window should be visible\n"); @@ -6474,27 +7660,87 @@ static void test_ShowWindow(void) GetWindowRect(hwnd, &rc); ok(EqualRect(&rcMain, &rc), "expected %s, got %s\n", wine_dbgstr_rect(&rcMain), wine_dbgstr_rect(&rc)); + GetClientRect(hwnd, &rc); + ok(EqualRect(&rcClient, &rc), "expected %s, got %s\n", + wine_dbgstr_rect(&rcClient), wine_dbgstr_rect(&rc)); ret = ShowWindow(hwnd, SW_MINIMIZE); - ok(ret, "not expected ret: %lu\n", ret); + ok(ret, "not expected ret: %Iu\n", ret); style = GetWindowLongA(hwnd, GWL_STYLE); ok(!(style & WS_DISABLED), "window should not be disabled\n"); ok(style & WS_VISIBLE, "window should be visible\n"); ok(style & WS_MINIMIZE, "window should be minimized\n"); ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); - GetWindowRect(hwnd, &rcMinimized); - ok(!EqualRect(&rcMain, &rcMinimized), "rects shouldn't match\n"); + GetWindowRect(hwnd, &rc); + ok(EqualRect(&rcMinimized, &rc), "expected %s, got %s\n", + wine_dbgstr_rect(&rcMinimized), wine_dbgstr_rect(&rc)); + GetClientRect(hwnd, &rc); + ok(EqualRect(&rcEmpty, &rc), "expected %s, got %s\n", + wine_dbgstr_rect(&rcEmpty), wine_dbgstr_rect(&rc)); /* shouldn't be able to resize minimized windows */ ret = SetWindowPos(hwnd, 0, 0, 0, (rcMinimized.right - rcMinimized.left) * 2, (rcMinimized.bottom - rcMinimized.top) * 2, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER); - ok(ret, "not expected ret: %lu\n", ret); + ok(ret, "not expected ret: %Iu\n", ret); GetWindowRect(hwnd, &rc); - ok(EqualRect(&rc, &rcMinimized), "rects should match\n"); + ok(EqualRect(&rcMinimized, &rc), "expected %s, got %s\n", + wine_dbgstr_rect(&rcMinimized), wine_dbgstr_rect(&rc)); + GetClientRect(hwnd, &rc); + ok(EqualRect(&rcEmpty, &rc), "expected %s, got %s\n", + wine_dbgstr_rect(&rcEmpty), wine_dbgstr_rect(&rc)); + /* SetWindowPos shouldn't affect the client rect */ + ret = SetWindowPos(hwnd, 0, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); + ok(ret, "not expected ret: %Iu\n", ret); + GetWindowRect(hwnd, &rc); + ok(EqualRect(&rcMinimized, &rc), "expected %s, got %s\n", + wine_dbgstr_rect(&rcMinimized), wine_dbgstr_rect(&rc)); + GetClientRect(hwnd, &rc); + ok(EqualRect(&rcEmpty, &rc), "expected %s, got %s\n", + wine_dbgstr_rect(&rcEmpty), wine_dbgstr_rect(&rc)); + /* test NC area */ + GetWindowRect(hwnd, &rc); + SetRect(&rcNonClient, rc.left, rc.top, rc.left, rc.top); + ret = DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc); + ok(!ret, "got %08Ix\n", ret); + ok(EqualRect(&rc, &rcNonClient), "expected %s, got %s\n", + wine_dbgstr_rect(&rcNonClient), wine_dbgstr_rect(&rc)); - ShowWindow(hwnd, SW_RESTORE); - ok(ret, "not expected ret: %lu\n", ret); + ret = ShowWindow(hwnd, SW_RESTORE); + ok(ret, "not expected ret: %Iu\n", ret); + style = GetWindowLongA(hwnd, GWL_STYLE); + ok(!(style & WS_DISABLED), "window should not be disabled\n"); + ok(style & WS_VISIBLE, "window should be visible\n"); + ok(!(style & WS_MINIMIZE), "window should not be minimized\n"); + ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); + GetWindowRect(hwnd, &rc); + ok(EqualRect(&rcMain, &rc), "expected %s, got %s\n", wine_dbgstr_rect(&rcMain), + wine_dbgstr_rect(&rc)); + GetClientRect(hwnd, &rc); + ok(EqualRect(&rcClient, &rc), "expected %s, got %s\n", + wine_dbgstr_rect(&rcClient), wine_dbgstr_rect(&rc)); + + ret = ShowWindow(hwnd, SW_MAXIMIZE); + ok(ret, "not expected ret: %Iu\n", ret); + style = GetWindowLongA(hwnd, GWL_STYLE); + ok(!(style & WS_DISABLED), "window should not be disabled\n"); + ok(style & WS_VISIBLE, "window should be visible\n"); + ok(!(style & WS_MINIMIZE), "window should be minimized\n"); + ok(style & WS_MAXIMIZE, "window should not be maximized\n"); + GetWindowRect(hwnd, &rc); + ok(EqualRect(&rcMaximized, &rc), "expected %s, got %s\n", + wine_dbgstr_rect(&rcMaximized), wine_dbgstr_rect(&rc)); + /* maximized windows can be resized */ + ret = SetWindowPos(hwnd, 0, 300, 300, 200, 200, SWP_NOACTIVATE | SWP_NOZORDER); + ok(ret, "not expected ret: %Iu\n", ret); + SetRect(&rcResized, 300, 300, 500, 500); + GetWindowRect(hwnd, &rc); + ok(EqualRect(&rcResized, &rc), "expected %s, got %s\n", + wine_dbgstr_rect(&rcResized), wine_dbgstr_rect(&rc)); + + ret = ShowWindow(hwnd, SW_RESTORE); + ok(ret, "not expected ret: %Iu\n", ret); style = GetWindowLongA(hwnd, GWL_STYLE); ok(!(style & WS_DISABLED), "window should not be disabled\n"); ok(style & WS_VISIBLE, "window should be visible\n"); @@ -6505,12 +7751,12 @@ static void test_ShowWindow(void) wine_dbgstr_rect(&rc)); ret = EnableWindow(hwnd, FALSE); - ok(!ret, "not expected ret: %lu\n", ret); + ok(!ret, "not expected ret: %Iu\n", ret); style = GetWindowLongA(hwnd, GWL_STYLE); ok(style & WS_DISABLED, "window should be disabled\n"); ret = DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0); - ok(!ret, "not expected ret: %lu\n", ret); + ok(!ret, "not expected ret: %Iu\n", ret); style = GetWindowLongA(hwnd, GWL_STYLE); ok(style & WS_DISABLED, "window should be disabled\n"); ok(style & WS_VISIBLE, "window should be visible\n"); @@ -6519,9 +7765,12 @@ static void test_ShowWindow(void) GetWindowRect(hwnd, &rc); ok(EqualRect(&rcMain, &rc), "expected %s, got %s\n", wine_dbgstr_rect(&rcMain), wine_dbgstr_rect(&rc)); + GetClientRect(hwnd, &rc); + ok(EqualRect(&rcClient, &rc), "expected %s, got %s\n", + wine_dbgstr_rect(&rcClient), wine_dbgstr_rect(&rc)); ret = DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0); - ok(!ret, "not expected ret: %lu\n", ret); + ok(!ret, "not expected ret: %Iu\n", ret); style = GetWindowLongA(hwnd, GWL_STYLE); ok(style & WS_DISABLED, "window should be disabled\n"); ok(style & WS_VISIBLE, "window should be visible\n"); @@ -6530,29 +7779,40 @@ static void test_ShowWindow(void) GetWindowRect(hwnd, &rc); ok(EqualRect(&rcMain, &rc), "expected %s, got %s\n", wine_dbgstr_rect(&rcMain), wine_dbgstr_rect(&rc)); + GetClientRect(hwnd, &rc); + ok(EqualRect(&rcClient, &rc), "expected %s, got %s\n", + wine_dbgstr_rect(&rcClient), wine_dbgstr_rect(&rc)); ret = ShowWindow(hwnd, SW_MINIMIZE); - ok(ret, "not expected ret: %lu\n", ret); + ok(ret, "not expected ret: %Iu\n", ret); style = GetWindowLongA(hwnd, GWL_STYLE); ok(style & WS_DISABLED, "window should be disabled\n"); ok(style & WS_VISIBLE, "window should be visible\n"); ok(style & WS_MINIMIZE, "window should be minimized\n"); ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); GetWindowRect(hwnd, &rc); - ok(!EqualRect(&rcMain, &rc), "rects shouldn't match\n"); + ok(EqualRect(&rcMinimized, &rc), "expected %s, got %s\n", + wine_dbgstr_rect(&rcMinimized), wine_dbgstr_rect(&rc)); + GetClientRect(hwnd, &rc); + ok(EqualRect(&rcEmpty, &rc), "expected %s, got %s\n", + wine_dbgstr_rect(&rcEmpty), wine_dbgstr_rect(&rc)); ret = DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0); - ok(!ret, "not expected ret: %lu\n", ret); + ok(!ret, "not expected ret: %Iu\n", ret); style = GetWindowLongA(hwnd, GWL_STYLE); ok(style & WS_DISABLED, "window should be disabled\n"); ok(style & WS_VISIBLE, "window should be visible\n"); ok(style & WS_MINIMIZE, "window should be minimized\n"); ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); GetWindowRect(hwnd, &rc); - ok(!EqualRect(&rcMain, &rc), "rects shouldn't match\n"); + ok(EqualRect(&rcMinimized, &rc), "expected %s, got %s\n", + wine_dbgstr_rect(&rcMinimized), wine_dbgstr_rect(&rc)); + GetClientRect(hwnd, &rc); + ok(EqualRect(&rcEmpty, &rc), "expected %s, got %s\n", + wine_dbgstr_rect(&rcEmpty), wine_dbgstr_rect(&rc)); ret = ShowWindow(hwnd, SW_RESTORE); - ok(ret, "not expected ret: %lu\n", ret); + ok(ret, "not expected ret: %Iu\n", ret); style = GetWindowLongA(hwnd, GWL_STYLE); ok(style & WS_DISABLED, "window should be disabled\n"); ok(style & WS_VISIBLE, "window should be visible\n"); @@ -6561,17 +7821,584 @@ static void test_ShowWindow(void) GetWindowRect(hwnd, &rc); ok(EqualRect(&rcMain, &rc), "expected %s, got %s\n", wine_dbgstr_rect(&rcMain), wine_dbgstr_rect(&rc)); + GetClientRect(hwnd, &rc); + ok(EqualRect(&rcClient, &rc), "expected %s, got %s\n", + wine_dbgstr_rect(&rcClient), wine_dbgstr_rect(&rc)); ret = DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0); - ok(!ret, "not expected ret: %lu\n", ret); + ok(!ret, "not expected ret: %Iu\n", ret); ok(IsWindow(hwnd), "window should exist\n"); ret = EnableWindow(hwnd, TRUE); - ok(ret, "not expected ret: %lu\n", ret); + ok(ret, "not expected ret: %Iu\n", ret); ret = DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0); - ok(!ret, "not expected ret: %lu\n", ret); + ok(!ret, "not expected ret: %Iu\n", ret); ok(!IsWindow(hwnd), "window should not exist\n"); + + hwnd = CreateWindowExA(0, "MainWindowClass", NULL, + WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | + WS_MAXIMIZEBOX | WS_POPUP | WS_MINIMIZE, + rcMain.left, rcMain.top, + rcMain.right - rcMain.left, rcMain.bottom - rcMain.top, + 0, 0, 0, NULL); + ok(hwnd != NULL, "failed to create window with error %lu\n", GetLastError()); + style = GetWindowLongA(hwnd, GWL_STYLE); + ok(style & WS_MINIMIZE, "window should be minimized\n"); + GetWindowRect(hwnd, &rc); + todo_wine + ok(EqualRect(&rcMinimized, &rc), "expected %s, got %s\n", + wine_dbgstr_rect(&rcMinimized), wine_dbgstr_rect(&rc)); + GetClientRect(hwnd, &rc); + ok(EqualRect(&rcEmpty, &rc), "expected %s, got %s\n", + wine_dbgstr_rect(&rcEmpty), wine_dbgstr_rect(&rc)); + DestroyWindow(hwnd); + + hwnd = CreateWindowExA(0, "MainWindowClass", NULL, + WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | + WS_MAXIMIZEBOX | WS_POPUP | WS_MINIMIZE | WS_VISIBLE, + rcMain.left, rcMain.top, + rcMain.right - rcMain.left, rcMain.bottom - rcMain.top, + 0, 0, 0, NULL); + ok(hwnd != NULL, "failed to create window with error %lu\n", GetLastError()); + style = GetWindowLongA(hwnd, GWL_STYLE); + ok(style & WS_MINIMIZE, "window should be minimized\n"); + GetWindowRect(hwnd, &rc); + ok(EqualRect(&rcMinimized, &rc), "expected %s, got %s\n", + wine_dbgstr_rect(&rcMinimized), wine_dbgstr_rect(&rc)); + GetClientRect(hwnd, &rc); + ok(EqualRect(&rcEmpty, &rc), "expected %s, got %s\n", + wine_dbgstr_rect(&rcEmpty), wine_dbgstr_rect(&rc)); + DestroyWindow(hwnd); + + flush_events(TRUE); + + /* test maximize and restore windows without setting WS_CAPTION */ + + for (i = 0; i < ARRAY_SIZE(test_style); ++i) + { + SetRect(&rcMain, 0, 0, 90, 90); + OffsetRect(&rcMain, 120, 120); + hwnd = CreateWindowExA(0, "MainWindowClass", NULL, test_style[i], + rcMain.left, rcMain.top, + rcMain.right - rcMain.left, rcMain.bottom - rcMain.top, + 0, 0, 0, NULL); + ok(hwnd != NULL, "Test %u: failed to create window with error %lu\n", i, GetLastError()); + + GetWindowRect(hwnd, &rcMain); + ok(rcMain.left > mon_info.rcMonitor.left && + rcMain.right < mon_info.rcMonitor.right && + rcMain.top > mon_info.rcMonitor.top && + rcMain.bottom < mon_info.rcMonitor.bottom, + "Test %u: window should not be fullscreen\n", i); + + rcMaximized = (test_style[i] & WS_MAXIMIZEBOX) ? mon_info.rcWork : mon_info.rcMonitor; + AdjustWindowRectEx(&rcMaximized, GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BORDER, + 0, GetWindowLongA(hwnd, GWL_EXSTYLE)); + + ret = ShowWindow(hwnd, SW_MAXIMIZE); + ok(ret, "unexpected ret: %Iu\n", ret); + style = GetWindowLongA(hwnd, GWL_STYLE); + ok(style & WS_MAXIMIZE, "Test %u: window should be maximized\n", i); + GetWindowRect(hwnd, &rc); + + rcBroken = rcMaximized; + if (test_style[i] & WS_THICKFRAME) + { + InflateRect(&rcBroken, -2, -2); + OffsetRect(&rcBroken, -2, -2); + } + + ok(EqualRect(&rcMaximized, &rc) || broken(EqualRect(&rcBroken, &rc)), + "Test %u: expected %s, got %s\n", i, wine_dbgstr_rect(&rcMaximized), + wine_dbgstr_rect(&rc)); + + ret = ShowWindow(hwnd, SW_RESTORE); + ok(ret, "unexpected ret: %Iu\n", ret); + style = GetWindowLongA(hwnd, GWL_STYLE); + ok(!(style & WS_MAXIMIZE), "Test %u: window should not be maximized\n", i); + GetWindowRect(hwnd, &rc); + ok(EqualRect(&rcMain, &rc), "Test %u: expected %s, got %s\n", + i, wine_dbgstr_rect(&rcMain), wine_dbgstr_rect(&rc)); + + DestroyWindow(hwnd); + + flush_events(TRUE); + } +} + +static void test_ShowWindow_owned(HWND hwndMain) +{ + MONITORINFO mon_info = {sizeof(mon_info)}; + RECT rect, orig, expect, nc; + LPARAM ret; + HWND hwnd, hwnd2; + LONG style; + + GetMonitorInfoW(MonitorFromWindow(hwndMain, MONITOR_DEFAULTTOPRIMARY), &mon_info); + SetRect(&orig, 20, 20, 210, 110); + hwnd = CreateWindowA("MainWindowClass", "owned", WS_CAPTION | WS_SYSMENU | + WS_MINIMIZEBOX | WS_MAXIMIZEBOX, + orig.left, orig.top, orig.right - orig.left, + orig.bottom - orig.top, hwndMain, 0, 0, NULL); + ok(!!hwnd, "failed to create window, error %lu\n", GetLastError()); + hwnd2 = CreateWindowA("MainWindowClass", "owned2", WS_CAPTION | WS_SYSMENU | + WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE, + orig.left, orig.top, orig.right - orig.left, + orig.bottom - orig.top, hwndMain, 0, 0, NULL); + ok(!!hwnd2, "failed to create window, error %lu\n", GetLastError()); + + style = GetWindowLongA(hwnd, GWL_STYLE); + ok(!(style & WS_DISABLED), "window should not be disabled\n"); + ok(!(style & WS_VISIBLE), "window should not be visible\n"); + ok(!(style & WS_MINIMIZE), "window should not be minimized\n"); + ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); + GetWindowRect(hwnd, &rect); + ok(EqualRect(&orig, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&orig), wine_dbgstr_rect(&rect)); + + ret = ShowWindow(hwnd, SW_SHOW); + ok(!ret, "wrong ret %Iu\n", ret); + style = GetWindowLongA(hwnd, GWL_STYLE); + ok(!(style & WS_DISABLED), "window should not be disabled\n"); + ok(style & WS_VISIBLE, "window should be visible\n"); + ok(!(style & WS_MINIMIZE), "window should not be minimized\n"); + ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); + GetWindowRect(hwnd, &rect); + ok(EqualRect(&orig, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&orig), wine_dbgstr_rect(&rect)); + + ret = ShowWindow(hwnd, SW_MINIMIZE); + ok(ret, "wrong ret %Iu\n", ret); + style = GetWindowLongA(hwnd, GWL_STYLE); + ok(!(style & WS_DISABLED), "window should not be disabled\n"); + ok(style & WS_VISIBLE, "window should be visible\n"); + ok(style & WS_MINIMIZE, "window should be minimized\n"); + ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); + GetWindowRect(hwnd, &rect); + SetRect(&expect, 0, mon_info.rcWork.bottom - GetSystemMetrics(SM_CYMINIMIZED), + GetSystemMetrics(SM_CXMINIMIZED), mon_info.rcWork.bottom); + todo_wine + ok(EqualRect(&expect, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + /* shouldn't be able to resize minimized windows */ + ret = SetWindowPos(hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER); + ok(ret, "wrong ret %Iu\n", ret); + GetWindowRect(hwnd, &rect); + todo_wine + ok(EqualRect(&expect, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + /* test NC area */ + GetWindowRect(hwnd, &rect); + SetRect(&nc, rect.left, rect.top, rect.left, rect.top); + ret = DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rect); + ok(!ret, "got %08Ix\n", ret); + ok(EqualRect(&rect, &nc), "expected %s, got %s\n", + wine_dbgstr_rect(&nc), wine_dbgstr_rect(&rect)); + + /* multiple minimized owned windows stack next to each other (and eventually + * on top of each other) */ + OffsetRect(&expect, GetSystemMetrics(SM_CXMINIMIZED), 0); + ret = ShowWindow(hwnd2, SW_MINIMIZE); + ok(ret, "wrong ret %Iu\n", ret); + style = GetWindowLongA(hwnd2, GWL_STYLE); + ok(!(style & WS_DISABLED), "window should not be disabled\n"); + ok(style & WS_VISIBLE, "window should be visible\n"); + ok(style & WS_MINIMIZE, "window should be minimized\n"); + ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); + GetWindowRect(hwnd2, &rect); + todo_wine + ok(EqualRect(&expect, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + + ret = ShowWindow(hwnd, SW_RESTORE); + ok(ret, "wrong ret %Iu\n", ret); + style = GetWindowLongA(hwnd, GWL_STYLE); + ok(!(style & WS_DISABLED), "window should not be disabled\n"); + ok(style & WS_VISIBLE, "window should be visible\n"); + ok(!(style & WS_MINIMIZE), "window should not be minimized\n"); + ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); + GetWindowRect(hwnd, &rect); + ok(EqualRect(&orig, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&orig), wine_dbgstr_rect(&rect)); + + ret = ShowWindow(hwnd, SW_MAXIMIZE); + ok(ret, "wrong ret %Iu\n", ret); + style = GetWindowLongA(hwnd, GWL_STYLE); + ok(!(style & WS_DISABLED), "window should not be disabled\n"); + ok(style & WS_VISIBLE, "window should be visible\n"); + ok(!(style & WS_MINIMIZE), "window should be minimized\n"); + ok(style & WS_MAXIMIZE, "window should not be maximized\n"); + GetWindowRect(hwnd, &rect); + expect = mon_info.rcWork; + AdjustWindowRectEx(&expect, GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BORDER, + 0, GetWindowLongA(hwnd, GWL_EXSTYLE)); + ok(EqualRect(&expect, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + /* maximized windows can be resized */ + ret = SetWindowPos(hwnd, 0, 300, 300, 200, 200, SWP_NOACTIVATE | SWP_NOZORDER); + ok(ret, "wrong ret %Iu\n", ret); + GetWindowRect(hwnd, &rect); + SetRect(&expect, 300, 300, 500, 500); + ok(EqualRect(&expect, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + + ret = ShowWindow(hwnd, SW_RESTORE); + ok(ret, "wrong ret %Iu\n", ret); + style = GetWindowLongA(hwnd, GWL_STYLE); + ok(!(style & WS_DISABLED), "window should not be disabled\n"); + ok(style & WS_VISIBLE, "window should be visible\n"); + ok(!(style & WS_MINIMIZE), "window should not be minimized\n"); + ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); + GetWindowRect(hwnd, &rect); + ok(EqualRect(&orig, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&orig), wine_dbgstr_rect(&rect)); + + DestroyWindow(hwnd2); + DestroyWindow(hwnd); +} + +static void test_ShowWindow_child(HWND hwndMain) +{ + RECT rect, orig, expect, nc; + LPARAM ret; + HWND hwnd, hwnd2; + LONG style; + POINT pt = {0}; + + SetRect(&orig, 20, 20, 210, 110); + hwnd = CreateWindowA("MainWindowClass", "child", WS_CAPTION | WS_SYSMENU | + WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CHILD, + orig.left, orig.top, orig.right - orig.left, + orig.bottom - orig.top, hwndMain, 0, 0, NULL); + ok(!!hwnd, "failed to create window, error %lu\n", GetLastError()); + hwnd2 = CreateWindowA("MainWindowClass", "child2", WS_CAPTION | WS_SYSMENU | + WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CHILD | WS_VISIBLE, + orig.left, orig.top, orig.right - orig.left, + orig.bottom - orig.top, hwndMain, 0, 0, NULL); + ok(!!hwnd2, "failed to create window, error %lu\n", GetLastError()); + + ClientToScreen(hwndMain, &pt); + OffsetRect(&orig, pt.x, pt.y); + + style = GetWindowLongA(hwnd, GWL_STYLE); + ok(!(style & WS_DISABLED), "window should not be disabled\n"); + ok(!(style & WS_VISIBLE), "window should not be visible\n"); + ok(!(style & WS_MINIMIZE), "window should not be minimized\n"); + ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); + GetWindowRect(hwnd, &rect); + ok(EqualRect(&orig, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&orig), wine_dbgstr_rect(&rect)); + + ret = ShowWindow(hwnd, SW_SHOW); + ok(!ret, "wrong ret %Iu\n", ret); + style = GetWindowLongA(hwnd, GWL_STYLE); + ok(!(style & WS_DISABLED), "window should not be disabled\n"); + ok(style & WS_VISIBLE, "window should be visible\n"); + ok(!(style & WS_MINIMIZE), "window should not be minimized\n"); + ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); + GetWindowRect(hwnd, &rect); + ok(EqualRect(&orig, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&orig), wine_dbgstr_rect(&rect)); + + ret = ShowWindow(hwnd, SW_MINIMIZE); + ok(ret, "wrong ret %Iu\n", ret); + style = GetWindowLongA(hwnd, GWL_STYLE); + ok(!(style & WS_DISABLED), "window should not be disabled\n"); + ok(style & WS_VISIBLE, "window should be visible\n"); + ok(style & WS_MINIMIZE, "window should be minimized\n"); + ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); + GetWindowRect(hwnd, &rect); + GetClientRect(hwndMain, &expect); + SetRect(&expect, 0, expect.bottom - GetSystemMetrics(SM_CYMINIMIZED), + GetSystemMetrics(SM_CXMINIMIZED), expect.bottom); + OffsetRect(&expect, pt.x, pt.y); + ok(EqualRect(&expect, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + /* shouldn't be able to resize minimized windows */ + ret = SetWindowPos(hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER); + ok(ret, "wrong ret %Iu\n", ret); + GetWindowRect(hwnd, &rect); + ok(EqualRect(&expect, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + /* test NC area */ + GetWindowRect(hwnd, &rect); + SetRect(&nc, rect.left, rect.top, rect.left, rect.top); + ret = DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rect); + ok(!ret, "got %08Ix\n", ret); + ok(EqualRect(&rect, &nc), "expected %s, got %s\n", + wine_dbgstr_rect(&nc), wine_dbgstr_rect(&rect)); + + /* multiple minimized children also stack; here the parent is too small to + * fit more than one per row */ + OffsetRect(&expect, 0, -GetSystemMetrics(SM_CYMINIMIZED)); + ret = ShowWindow(hwnd2, SW_MINIMIZE); + ok(ret, "wrong ret %Iu\n", ret); + style = GetWindowLongA(hwnd2, GWL_STYLE); + ok(!(style & WS_DISABLED), "window should not be disabled\n"); + ok(style & WS_VISIBLE, "window should be visible\n"); + ok(style & WS_MINIMIZE, "window should be minimized\n"); + ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); + GetWindowRect(hwnd2, &rect); + ok(EqualRect(&expect, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + + ret = ShowWindow(hwnd, SW_RESTORE); + ok(ret, "wrong ret %Iu\n", ret); + style = GetWindowLongA(hwnd, GWL_STYLE); + ok(!(style & WS_DISABLED), "window should not be disabled\n"); + ok(style & WS_VISIBLE, "window should be visible\n"); + ok(!(style & WS_MINIMIZE), "window should not be minimized\n"); + ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); + GetWindowRect(hwnd, &rect); + ok(EqualRect(&orig, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&orig), wine_dbgstr_rect(&rect)); + + ret = ShowWindow(hwnd, SW_MAXIMIZE); + ok(ret, "wrong ret %Iu\n", ret); + style = GetWindowLongA(hwnd, GWL_STYLE); + ok(!(style & WS_DISABLED), "window should not be disabled\n"); + ok(style & WS_VISIBLE, "window should be visible\n"); + ok(!(style & WS_MINIMIZE), "window should be minimized\n"); + ok(style & WS_MAXIMIZE, "window should not be maximized\n"); + GetWindowRect(hwnd, &rect); + GetClientRect(hwndMain, &expect); + AdjustWindowRectEx(&expect, GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BORDER, + 0, GetWindowLongA(hwnd, GWL_EXSTYLE)); + OffsetRect(&expect, pt.x, pt.y); + ok(EqualRect(&expect, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + /* maximized windows can be resized */ + ret = SetWindowPos(hwnd, 0, 300, 300, 200, 200, SWP_NOACTIVATE | SWP_NOZORDER); + ok(ret, "wrong ret %Iu\n", ret); + GetWindowRect(hwnd, &rect); + SetRect(&expect, 300, 300, 500, 500); + OffsetRect(&expect, pt.x, pt.y); + ok(EqualRect(&expect, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + + ret = ShowWindow(hwnd, SW_RESTORE); + ok(ret, "wrong ret %Iu\n", ret); + style = GetWindowLongA(hwnd, GWL_STYLE); + ok(!(style & WS_DISABLED), "window should not be disabled\n"); + ok(style & WS_VISIBLE, "window should be visible\n"); + ok(!(style & WS_MINIMIZE), "window should not be minimized\n"); + ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); + GetWindowRect(hwnd, &rect); + ok(EqualRect(&orig, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&orig), wine_dbgstr_rect(&rect)); + + DestroyWindow(hwnd2); + DestroyWindow(hwnd); +} + +static void test_ShowWindow_mdichild(HWND hwndMain) +{ + RECT rect, orig, expect, nc; + LPARAM ret; + HWND mdiclient, hwnd, hwnd2; + LONG style; + POINT pt = {0}; + CLIENTCREATESTRUCT mdi_client_cs = {0,1}; + + SetRect(&orig, 20, 20, 210, 110); + GetClientRect(hwndMain, &rect); + mdiclient = CreateWindowA("mdiclient", "MDI client", WS_CHILD, + rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, + hwndMain, 0, 0, &mdi_client_cs); + ok(!!mdiclient, "failed to create window, error %lu\n", GetLastError()); + hwnd = CreateWindowExA(WS_EX_MDICHILD, "MainWindowClass", "MDI child", + WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, + orig.left, orig.top, orig.right - orig.left, + orig.bottom - orig.top, mdiclient, 0, 0, NULL); + ok(!!hwnd, "failed to create window, error %lu\n", GetLastError()); + hwnd2 = CreateWindowExA(WS_EX_MDICHILD, "MainWindowClass", "MDI child 2", + WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, + orig.left, orig.top, orig.right - orig.left, + orig.bottom - orig.top, mdiclient, 0, 0, NULL); + ok(!!hwnd2, "failed to create window, error %lu\n", GetLastError()); + + ClientToScreen(hwndMain, &pt); + OffsetRect(&orig, pt.x, pt.y); + + style = GetWindowLongA(hwnd, GWL_STYLE); + ok(!(style & WS_DISABLED), "window should not be disabled\n"); + ok(style & WS_VISIBLE, "window should not be visible\n"); + ok(!(style & WS_MINIMIZE), "window should not be minimized\n"); + ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); + GetWindowRect(hwnd, &rect); + ok(EqualRect(&orig, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&orig), wine_dbgstr_rect(&rect)); + + ret = ShowWindow(hwnd, SW_MINIMIZE); + ok(ret, "wrong ret %Iu\n", ret); + style = GetWindowLongA(hwnd, GWL_STYLE); + ok(!(style & WS_DISABLED), "window should not be disabled\n"); + ok(style & WS_VISIBLE, "window should be visible\n"); + ok(style & WS_MINIMIZE, "window should be minimized\n"); + ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); + GetWindowRect(hwnd, &rect); + GetClientRect(hwndMain, &expect); + SetRect(&expect, 0, expect.bottom - GetSystemMetrics(SM_CYMINIMIZED), + GetSystemMetrics(SM_CXMINIMIZED), expect.bottom); + OffsetRect(&expect, pt.x, pt.y); + ok(EqualRect(&expect, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + /* shouldn't be able to resize minimized windows */ + ret = SetWindowPos(hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER); + ok(ret, "wrong ret %Iu\n", ret); + GetWindowRect(hwnd, &rect); + ok(EqualRect(&expect, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + /* test NC area */ + GetWindowRect(hwnd, &rect); + SetRect(&nc, rect.left, rect.top, rect.left, rect.top); + ret = DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rect); + ok(!ret, "got %08Ix\n", ret); + ok(EqualRect(&rect, &nc), "expected %s, got %s\n", + wine_dbgstr_rect(&nc), wine_dbgstr_rect(&rect)); + + /* multiple minimized children also stack; here the parent is too small to + * fit more than one per row */ + OffsetRect(&expect, 0, -GetSystemMetrics(SM_CYMINIMIZED)); + ret = ShowWindow(hwnd2, SW_MINIMIZE); + ok(ret, "wrong ret %Iu\n", ret); + style = GetWindowLongA(hwnd2, GWL_STYLE); + ok(!(style & WS_DISABLED), "window should not be disabled\n"); + ok(style & WS_VISIBLE, "window should be visible\n"); + ok(style & WS_MINIMIZE, "window should be minimized\n"); + ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); + GetWindowRect(hwnd2, &rect); + ok(EqualRect(&expect, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + + ret = ShowWindow(hwnd, SW_RESTORE); + ok(ret, "wrong ret %Iu\n", ret); + style = GetWindowLongA(hwnd, GWL_STYLE); + ok(!(style & WS_DISABLED), "window should not be disabled\n"); + ok(style & WS_VISIBLE, "window should be visible\n"); + ok(!(style & WS_MINIMIZE), "window should not be minimized\n"); + ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); + GetWindowRect(hwnd, &rect); + ok(EqualRect(&orig, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&orig), wine_dbgstr_rect(&rect)); + + ret = ShowWindow(hwnd, SW_MAXIMIZE); + ok(ret, "wrong ret %Iu\n", ret); + style = GetWindowLongA(hwnd, GWL_STYLE); + ok(!(style & WS_DISABLED), "window should not be disabled\n"); + ok(style & WS_VISIBLE, "window should be visible\n"); + ok(!(style & WS_MINIMIZE), "window should be minimized\n"); + ok(style & WS_MAXIMIZE, "window should not be maximized\n"); + GetWindowRect(hwnd, &rect); + GetClientRect(hwndMain, &expect); + AdjustWindowRectEx(&expect, GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BORDER, + 0, GetWindowLongA(hwnd, GWL_EXSTYLE)); + OffsetRect(&expect, pt.x, pt.y); + ok(EqualRect(&expect, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + /* maximized windows can be resized */ + ret = SetWindowPos(hwnd, 0, 300, 300, 200, 200, SWP_NOACTIVATE | SWP_NOZORDER); + ok(ret, "wrong ret %Iu\n", ret); + GetWindowRect(hwnd, &rect); + SetRect(&expect, 300, 300, 500, 500); + OffsetRect(&expect, pt.x, pt.y); + ok(EqualRect(&expect, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + + ret = ShowWindow(hwnd, SW_RESTORE); + ok(ret, "wrong ret %Iu\n", ret); + style = GetWindowLongA(hwnd, GWL_STYLE); + ok(!(style & WS_DISABLED), "window should not be disabled\n"); + ok(style & WS_VISIBLE, "window should be visible\n"); + ok(!(style & WS_MINIMIZE), "window should not be minimized\n"); + ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); + GetWindowRect(hwnd, &rect); + ok(EqualRect(&orig, &rect), "expected %s, got %s\n", + wine_dbgstr_rect(&orig), wine_dbgstr_rect(&rect)); + + DestroyWindow(hwnd2); + DestroyWindow(hwnd); + DestroyWindow(mdiclient); +} + +static DWORD CALLBACK enablewindow_thread(LPVOID arg) +{ + HWND hwnd = arg; + EnableWindow(hwnd, FALSE); + return 0; +} + +static LRESULT CALLBACK enable_window_procA(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (msg == WM_CANCELMODE) + return 0; + return DefWindowProcA(hwnd, msg, wParam, lParam); +} + +static void test_EnableWindow(void) +{ + WNDCLASSA cls; + HWND hwnd; + HANDLE hthread; + DWORD tid; + MSG msg; + + hwnd = CreateWindowExA(0, "MainWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), + 0, 0, 0, NULL); + assert(hwnd); + flush_events( TRUE ); + ok(IsWindowEnabled(hwnd), "window should be enabled\n"); + SetFocus(hwnd); + SetCapture(hwnd); + + EnableWindow(hwnd, FALSE); + check_wnd_state(hwnd, hwnd, 0, 0); + ok(!IsWindowEnabled(hwnd), "window should not be enabled\n"); + + SetFocus(hwnd); + SetCapture(hwnd); + check_wnd_state(hwnd, hwnd, 0, hwnd); + + EnableWindow(hwnd, TRUE); + SetFocus(hwnd); + check_wnd_state(hwnd, hwnd, hwnd, hwnd); + ok(IsWindowEnabled(hwnd), "window should be enabled\n"); + + /* test disabling from thread */ + hthread = CreateThread(NULL, 0, enablewindow_thread, hwnd, 0, &tid); + + while (MsgWaitForMultipleObjects(1, &hthread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0) + { + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE)) + DispatchMessageA(&msg); + } + + ok(!IsWindowEnabled(hwnd), "window should not be enabled\n"); + check_active_state(hwnd, hwnd, hwnd); + ok(0 == GetCapture(), "GetCapture() = %p\n", GetCapture()); + + CloseHandle(hthread); + DestroyWindow(hwnd); + + /* test preventing release of capture */ + memset(&cls, 0, sizeof(cls)); + cls.lpfnWndProc = enable_window_procA; + cls.hInstance = GetModuleHandleA(0); + cls.lpszClassName = "EnableWindowClass"; + ok(RegisterClassA(&cls), "RegisterClass failed\n"); + + hwnd = CreateWindowExA(0, "EnableWindowClass", NULL, WS_OVERLAPPEDWINDOW, + 0, 0, 100, 100, 0, 0, 0, NULL); + assert(hwnd); + SetFocus(hwnd); + SetCapture(hwnd); + + EnableWindow(hwnd, FALSE); + check_wnd_state(hwnd, hwnd, 0, hwnd); + + DestroyWindow(hwnd); } static DWORD CALLBACK gettext_msg_thread( LPVOID arg ) @@ -6586,7 +8413,7 @@ static DWORD CALLBACK gettext_msg_thread( LPVOID arg ) buf_len = GetWindowTextA( hwnd, buf, sizeof(buf) ); ok( buf_len != 0, "expected a nonempty window text\n" ); ok( !strcmp(buf, "another_caption"), "got wrong window text '%s'\n", buf ); - ok( num_gettext_msgs == 1, "got %u WM_GETTEXT messages\n", num_gettext_msgs ); + ok( num_gettext_msgs == 1, "got %lu WM_GETTEXT messages\n", num_gettext_msgs ); return 0; } @@ -6600,13 +8427,14 @@ static DWORD CALLBACK settext_msg_thread( LPVOID arg ) num_settext_msgs = 0; success = SetWindowTextA( hwnd, "thread_caption" ); ok( success, "SetWindowTextA failed\n" ); - ok( num_settext_msgs == 1, "got %u WM_SETTEXT messages\n", num_settext_msgs ); + ok( num_settext_msgs == 1, "got %lu WM_SETTEXT messages\n", num_settext_msgs ); return 0; } static void test_gettext(void) { + static const WCHAR textW[] = {'t','e','x','t'}; DWORD tid, num_msgs; WCHAR bufW[32]; HANDLE thread; @@ -6618,7 +8446,7 @@ static void test_gettext(void) MSG msg; hwnd = CreateWindowExA( 0, "MainWindowClass", "caption", WS_POPUP, 0, 0, 0, 0, 0, 0, 0, NULL ); - ok( hwnd != 0, "CreateWindowExA error %d\n", GetLastError() ); + ok( hwnd != 0, "CreateWindowExA error %ld\n", GetLastError() ); /* test GetWindowTextA */ num_gettext_msgs = 0; @@ -6626,7 +8454,7 @@ static void test_gettext(void) buf_len = GetWindowTextA( hwnd, buf, sizeof(buf) ); ok( buf_len != 0, "expected a nonempty window text\n" ); ok( !strcmp(buf, "caption"), "got wrong window text '%s'\n", buf ); - ok( num_gettext_msgs == 1, "got %u WM_GETTEXT messages\n", num_gettext_msgs ); + ok( num_gettext_msgs == 1, "got %lu WM_GETTEXT messages\n", num_gettext_msgs ); /* other process window */ strcpy( buf, "a" ); @@ -6652,7 +8480,7 @@ static void test_gettext(void) buf_len = GetWindowTextA( hwnd, buf, sizeof(buf) ); ok( buf_len == 0, "got %d\n", buf_len ); ok( *buf == 0, "got %x\n", *buf ); - ok( num_gettext_msgs == 1, "got %u WM_GETTEXT messages\n", num_gettext_msgs ); + ok( num_gettext_msgs == 1, "got %lu WM_GETTEXT messages\n", num_gettext_msgs ); num_gettext_msgs = 0; strcpy( buf, "blah" ); @@ -6660,23 +8488,28 @@ static void test_gettext(void) buf_len = GetWindowTextA( hwnd, buf, 0 ); ok( buf_len == 0, "got %d\n", buf_len ); ok( !strcmp(buf, "blah"), "got %s\n", buf ); - ok( num_gettext_msgs == 0, "got %u WM_GETTEXT messages\n", num_gettext_msgs ); + ok( num_gettext_msgs == 0, "got %lu WM_GETTEXT messages\n", num_gettext_msgs ); + + bufW[0] = 0xcc; + buf_len = InternalGetWindowText( hwnd, bufW, ARRAYSIZE(bufW) ); + ok( buf_len == ARRAYSIZE("caption") - 1, "expected a nonempty window text\n" ); + ok( !lstrcmpW( bufW, L"caption" ), "got %s\n", debugstr_w(bufW) ); g_wm_gettext_override.enabled = FALSE; /* same for W window */ hwnd2 = CreateWindowExW( 0, mainclassW, NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, NULL ); - ok( hwnd2 != 0, "CreateWindowExA error %d\n", GetLastError() ); + ok( hwnd2 != 0, "CreateWindowExA error %ld\n", GetLastError() ); g_wm_gettext_override.enabled = TRUE; num_gettext_msgs = 0; memset( bufW, 0xcc, sizeof(bufW) ); g_wm_gettext_override.buffW = bufW; - buf_len = GetWindowTextW( hwnd2, bufW, sizeof(bufW)/sizeof(WCHAR) ); + buf_len = GetWindowTextW( hwnd2, bufW, ARRAY_SIZE(bufW)); ok( buf_len == 0, "got %d\n", buf_len ); ok( *bufW == 0, "got %x\n", *bufW ); - ok( num_gettext_msgs == 1, "got %u WM_GETTEXT messages\n", num_gettext_msgs ); + ok( num_gettext_msgs == 1, "got %lu WM_GETTEXT messages\n", num_gettext_msgs ); num_gettext_msgs = 0; memset( bufW, 0xcc, sizeof(bufW) ); @@ -6684,7 +8517,7 @@ static void test_gettext(void) buf_len = GetWindowTextW( hwnd2, bufW, 0 ); ok( buf_len == 0, "got %d\n", buf_len ); ok( *bufW == 0xcccc, "got %x\n", *bufW ); - ok( num_gettext_msgs == 0, "got %u WM_GETTEXT messages\n", num_gettext_msgs ); + ok( num_gettext_msgs == 0, "got %lu WM_GETTEXT messages\n", num_gettext_msgs ); g_wm_gettext_override.enabled = FALSE; @@ -6696,33 +8529,33 @@ static void test_gettext(void) r = SendMessageA( hwnd, WM_GETTEXT, sizeof(buf), (LONG_PTR)buf ); ok( r != 0, "expected a nonempty window text\n" ); ok( !strcmp(buf, "caption"), "got wrong window text '%s'\n", buf ); - ok( num_gettext_msgs == 1, "got %u WM_GETTEXT messages\n", num_gettext_msgs ); + ok( num_gettext_msgs == 1, "got %lu WM_GETTEXT messages\n", num_gettext_msgs ); /* test SetWindowTextA */ num_settext_msgs = 0; success = SetWindowTextA( hwnd, "new_caption" ); ok( success, "SetWindowTextA failed\n" ); - ok( num_settext_msgs == 1, "got %u WM_SETTEXT messages\n", num_settext_msgs ); + ok( num_settext_msgs == 1, "got %lu WM_SETTEXT messages\n", num_settext_msgs ); num_gettext_msgs = 0; memset( buf, 0, sizeof(buf) ); buf_len = GetWindowTextA( hwnd, buf, sizeof(buf) ); ok( buf_len != 0, "expected a nonempty window text\n" ); ok( !strcmp(buf, "new_caption"), "got wrong window text '%s'\n", buf ); - ok( num_gettext_msgs == 1, "got %u WM_GETTEXT messages\n", num_gettext_msgs ); + ok( num_gettext_msgs == 1, "got %lu WM_GETTEXT messages\n", num_gettext_msgs ); /* test WM_SETTEXT */ num_settext_msgs = 0; r = SendMessageA( hwnd, WM_SETTEXT, 0, (ULONG_PTR)"another_caption" ); ok( r != 0, "WM_SETTEXT failed\n" ); - ok( num_settext_msgs == 1, "got %u WM_SETTEXT messages\n", num_settext_msgs ); + ok( num_settext_msgs == 1, "got %lu WM_SETTEXT messages\n", num_settext_msgs ); num_gettext_msgs = 0; memset( buf, 0, sizeof(buf) ); buf_len = GetWindowTextA( hwnd, buf, sizeof(buf) ); ok( buf_len != 0, "expected a nonempty window text\n" ); ok( !strcmp(buf, "another_caption"), "got wrong window text '%s'\n", buf ); - ok( num_gettext_msgs == 1, "got %u WM_GETTEXT messages\n", num_gettext_msgs ); + ok( num_gettext_msgs == 1, "got %lu WM_GETTEXT messages\n", num_gettext_msgs ); while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE )) DispatchMessageA( &msg ); @@ -6730,7 +8563,7 @@ static void test_gettext(void) /* test interthread GetWindowTextA */ num_msgs = 0; thread = CreateThread( NULL, 0, gettext_msg_thread, hwnd, 0, &tid ); - ok(thread != NULL, "CreateThread failed, error %d\n", GetLastError()); + ok(thread != NULL, "CreateThread failed, error %ld\n", GetLastError()); while (MsgWaitForMultipleObjects( 1, &thread, FALSE, INFINITE, QS_SENDMESSAGE ) != WAIT_OBJECT_0) { while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE )) @@ -6738,12 +8571,12 @@ static void test_gettext(void) num_msgs++; } CloseHandle( thread ); - ok( num_msgs >= 1, "got %u wakeups from MsgWaitForMultipleObjects\n", num_msgs ); + ok( num_msgs >= 1, "got %lu wakeups from MsgWaitForMultipleObjects\n", num_msgs ); /* test interthread SetWindowText */ num_msgs = 0; thread = CreateThread( NULL, 0, settext_msg_thread, hwnd, 0, &tid ); - ok(thread != NULL, "CreateThread failed, error %d\n", GetLastError()); + ok(thread != NULL, "CreateThread failed, error %ld\n", GetLastError()); while (MsgWaitForMultipleObjects( 1, &thread, FALSE, INFINITE, QS_SENDMESSAGE ) != WAIT_OBJECT_0) { while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE )) @@ -6751,31 +8584,96 @@ static void test_gettext(void) num_msgs++; } CloseHandle( thread ); - ok( num_msgs >= 1, "got %u wakeups from MsgWaitForMultipleObjects\n", num_msgs ); + ok( num_msgs >= 1, "got %lu wakeups from MsgWaitForMultipleObjects\n", num_msgs ); num_gettext_msgs = 0; memset( buf, 0, sizeof(buf) ); buf_len = GetWindowTextA( hwnd, buf, sizeof(buf) ); ok( buf_len != 0, "expected a nonempty window text\n" ); ok( !strcmp(buf, "thread_caption"), "got wrong window text '%s'\n", buf ); - ok( num_gettext_msgs == 1, "got %u WM_GETTEXT messages\n", num_gettext_msgs ); + ok( num_gettext_msgs == 1, "got %lu WM_GETTEXT messages\n", num_gettext_msgs ); + + /* WM_GETTEXT does not terminate returned string */ + memset( buf, 0x1c, sizeof(buf) ); + g_wm_gettext_override.dont_terminate = TRUE; + buf_len = GetWindowTextA( hwnd, buf, sizeof(buf) ); + ok( buf_len == 4, "Unexpected text length, %d\n", buf_len ); + ok( !memcmp(buf, "text", 4), "Unexpected window text, '%s'\n", buf ); + ok( buf[4] == 0x1c, "Unexpected buffer contents\n" ); + g_wm_gettext_override.dont_terminate = FALSE; + + memset( bufW, 0x1c, sizeof(bufW) ); + g_wm_gettext_override.dont_terminate = TRUE; + buf_len = GetWindowTextW( hwnd, bufW, ARRAY_SIZE(bufW)); + ok( buf_len == 4, "Unexpected text length, %d\n", buf_len ); + ok( !memcmp(bufW, textW, 4 * sizeof(WCHAR)), "Unexpected window text, %s\n", wine_dbgstr_w(bufW) ); + ok( bufW[4] == 0, "Unexpected buffer contents, %#x\n", bufW[4] ); + g_wm_gettext_override.dont_terminate = FALSE; + + hwnd2 = CreateWindowExW( 0, mainclassW, NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, NULL ); + ok( hwnd2 != 0, "CreateWindowExA error %ld\n", GetLastError() ); + + memset( buf, 0x1c, sizeof(buf) ); + g_wm_gettext_override.dont_terminate = TRUE; + buf_len = GetWindowTextA( hwnd2, buf, sizeof(buf) ); + ok( buf_len == 4, "Unexpected text length, %d\n", buf_len ); + ok( !memcmp(buf, "text", 4), "Unexpected window text, '%s'\n", buf ); + ok( buf[4] == 0, "Unexpected buffer contents, %#x\n", buf[4] ); + g_wm_gettext_override.dont_terminate = FALSE; + + memset( bufW, 0x1c, sizeof(bufW) ); + g_wm_gettext_override.dont_terminate = TRUE; + buf_len = GetWindowTextW( hwnd2, bufW, ARRAY_SIZE(bufW)); + ok( buf_len == 4, "Unexpected text length, %d\n", buf_len ); + ok( !memcmp(bufW, textW, 4 * sizeof(WCHAR)), "Unexpected window text, %s\n", wine_dbgstr_w(bufW) ); + ok( bufW[4] == 0x1c1c, "Unexpected buffer contents, %#x\n", bufW[4] ); + g_wm_gettext_override.dont_terminate = FALSE; + + DestroyWindow(hwnd2); /* seems to crash on every modern Windows version */ if (0) { r = SendMessageA( hwnd, WM_GETTEXT, 0x10, 0x1000); - ok( r == 0, "settext should return zero\n"); + ok( r == 0, "WM_GETTEXT should return zero (%Id)\n", r ); r = SendMessageA( hwnd, WM_GETTEXT, 0x10000, 0); - ok( r == 0, "settext should return zero (%ld)\n", r); + ok( r == 0, "WM_GETTEXT should return zero (%Id)\n", r ); r = SendMessageA( hwnd, WM_GETTEXT, 0xff000000, 0x1000); - ok( r == 0, "settext should return zero (%ld)\n", r); + ok( r == 0, "WM_GETTEXT should return zero (%Id)\n", r ); r = SendMessageA( hwnd, WM_GETTEXT, 0x1000, 0xff000000); - ok( r == 0, "settext should return zero (%ld)\n", r); + ok( r == 0, "WM_GETTEXT should return zero (%Id)\n", r ); } + /* GetWindowText doesn't crash */ +#ifdef __REACTOS__ + if (is_reactos()) { + ok(FALSE, "FIXME: These tests crash on ReactOS!\n"); + } else { +#endif + r = GetWindowTextA( hwnd, (LPSTR)0x10, 0x1000 ); + ok( r == 0, "GetWindowText should return zero (%Id)\n", r ); + r = GetWindowTextA( hwnd, (LPSTR)0x10000, 0 ); + ok( r == 0, "GetWindowText should return zero (%Id)\n", r ); + r = GetWindowTextA( hwnd, (LPSTR)0xff000000, 0x1000 ); + ok( r == 0, "GetWindowText should return zero (%Id)\n", r ); + r = GetWindowTextA( hwnd, (LPSTR)0x1000, 0xff000000 ); + ok( r == 0, "GetWindowText should return zero (%Id)\n", r ); + + r = GetWindowTextW( hwnd, (LPWSTR)0x10, 0x1000 ); + ok( r == 0, "GetWindowText should return zero (%Id)\n", r ); + r = GetWindowTextW( hwnd, (LPWSTR)0x10000, 0 ); + ok( r == 0, "GetWindowText should return zero (%Id)\n", r ); + r = GetWindowTextW( hwnd, (LPWSTR)0xff000000, 0x1000 ); + ok( r == 0, "GetWindowText should return zero (%Id)\n", r ); + r = GetWindowTextW( hwnd, (LPWSTR)0x1000, 0xff000000); + ok( r == 0, "GetWindowText should return zero (%Id)\n", r ); +#ifdef __REACTOS__ + } +#endif + DestroyWindow(hwnd); } @@ -6841,11 +8739,8 @@ static void test_GetUpdateRect(void) cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = classNameA; - - if(!RegisterClassA(&cls)) { - trace("Register failed %d\n", GetLastError()); - return; - } + ret = RegisterClassA(&cls); + ok(ret, "Failed to register a test class.\n"); hgrandparent = CreateWindowA(classNameA, "grandparent", WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, NULL, NULL, 0, NULL); @@ -6974,6 +8869,7 @@ static void run_NCRedrawLoop(UINT flags) UINT loopcount = 0; + flush_events( TRUE ); hwnd = CreateWindowA("TestNCRedrawClass", "MainWindow", WS_OVERLAPPEDWINDOW, 0, 0, 200, 100, NULL, NULL, 0, &flags); @@ -7031,84 +8927,61 @@ static void test_GetWindowModuleFileName(void) assert(hwnd); hinst = (HINSTANCE)GetWindowLongPtrA(hwnd, GWLP_HINSTANCE); - ok(hinst == 0 || broken(hinst == GetModuleHandleA(NULL)), /* win9x */ "expected 0, got %p\n", hinst); + ok(hinst == 0, "expected 0, got %p\n", hinst); buf1[0] = 0; SetLastError(0xdeadbeef); ret1 = GetModuleFileNameA(hinst, buf1, sizeof(buf1)); - ok(ret1, "GetModuleFileName error %u\n", GetLastError()); + ok(ret1, "GetModuleFileName error %lu\n", GetLastError()); buf2[0] = 0; SetLastError(0xdeadbeef); ret2 = pGetWindowModuleFileNameA(hwnd, buf2, sizeof(buf2)); - ok(ret2 || broken(!ret2), /* nt4 sp 3 */ - "GetWindowModuleFileNameA error %u\n", GetLastError()); + ok(ret2, "GetWindowModuleFileNameA error %lu\n", GetLastError()); if (ret2) { - ok(ret1 == ret2 || broken(ret2 == ret1 + 1), /* win98 */ "%u != %u\n", ret1, ret2); + ok(ret1 == ret2, "%u != %u\n", ret1, ret2); ok(!strcmp(buf1, buf2), "%s != %s\n", buf1, buf2); } hinst = GetModuleHandleA(NULL); SetLastError(0xdeadbeef); ret2 = GetModuleFileNameA(hinst, buf2, ret1 - 2); - ok(ret2 == ret1 - 2 || broken(ret2 == ret1 - 3), /* win98 */ - "expected %u, got %u\n", ret1 - 2, ret2); + ok(ret2 == ret1 - 2, "expected %u, got %u\n", ret1 - 2, ret2); ok(GetLastError() == 0xdeadbeef /* XP */ || GetLastError() == ERROR_INSUFFICIENT_BUFFER, /* win2k3, vista */ - "expected 0xdeadbeef or ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError()); + "expected 0xdeadbeef or ERROR_INSUFFICIENT_BUFFER, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret2 = GetModuleFileNameA(hinst, buf2, 0); ok(!ret2, "GetModuleFileName should return 0\n"); ok(GetLastError() == 0xdeadbeef /* XP */ || GetLastError() == ERROR_INSUFFICIENT_BUFFER, /* win2k3, vista */ - "expected 0xdeadbeef or ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError()); + "expected 0xdeadbeef or ERROR_INSUFFICIENT_BUFFER, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret2 = pGetWindowModuleFileNameA(hwnd, buf2, ret1 - 2); - ok(ret2 == ret1 - 2 || broken(ret2 == ret1 - 3) /* win98 */ || broken(!ret2), /* nt4 sp3 */ - "expected %u, got %u\n", ret1 - 2, ret2); + ok(ret2 == ret1 - 2, "expected %u, got %u\n", ret1 - 2, ret2); ok(GetLastError() == 0xdeadbeef /* XP */ || GetLastError() == ERROR_INSUFFICIENT_BUFFER, /* win2k3, vista */ - "expected 0xdeadbeef or ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError()); + "expected 0xdeadbeef or ERROR_INSUFFICIENT_BUFFER, got %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret2 = pGetWindowModuleFileNameA(hwnd, buf2, 0); ok(!ret2, "expected 0, got %u\n", ret2); ok(GetLastError() == 0xdeadbeef /* XP */ || GetLastError() == ERROR_INSUFFICIENT_BUFFER, /* win2k3, vista */ - "expected 0xdeadbeef or ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError()); + "expected 0xdeadbeef or ERROR_INSUFFICIENT_BUFFER, got %lu\n", GetLastError()); DestroyWindow(hwnd); - buf2[0] = 0; hwnd = (HWND)0xdeadbeef; SetLastError(0xdeadbeef); ret1 = pGetWindowModuleFileNameA(hwnd, buf1, sizeof(buf1)); ok(!ret1, "expected 0, got %u\n", ret1); - ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef), /* win9x */ - "expected ERROR_INVALID_WINDOW_HANDLE, got %u\n", GetLastError()); - - hwnd = FindWindowA("Shell_TrayWnd", NULL); - ok(IsWindow(hwnd) || broken(!hwnd), "got invalid tray window %p\n", hwnd); - SetLastError(0xdeadbeef); - ret1 = pGetWindowModuleFileNameA(hwnd, buf1, sizeof(buf1)); - ok(!ret1 || broken(ret1), /* win98 */ "expected 0, got %u\n", ret1); - - if (!ret1) /* inter-process GetWindowModuleFileName works on win9x, so don't test the desktop there */ - { - ret1 = GetModuleFileNameA(0, buf1, sizeof(buf1)); - hwnd = GetDesktopWindow(); - ok(IsWindow(hwnd), "got invalid desktop window %p\n", hwnd); - SetLastError(0xdeadbeef); - ret2 = pGetWindowModuleFileNameA(hwnd, buf2, sizeof(buf2)); - ok(!ret2 || - ret1 == ret2 || /* vista */ - broken(ret2), /* some win98 return user.exe as file name */ - "expected 0 or %u, got %u %s\n", ret1, ret2, buf2); - } + ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, + "expected ERROR_INVALID_WINDOW_HANDLE, got %lu\n", GetLastError()); } static void test_hwnd_message(void) @@ -7118,38 +8991,45 @@ static void test_hwnd_message(void) HWND parent = 0, hwnd, found; RECT rect; + static const struct + { + int offset; + ULONG_PTR expect; + DWORD error; + } + tests[] = + { + { GWLP_USERDATA, 0, 0 }, + { GWL_STYLE, WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0 }, + { GWL_EXSTYLE, 0, 0 }, + { GWLP_ID, 0, 0 }, + /* GWLP_HWNDPARENT - returns random values */ + /* GWLP_HINSTANCE - not useful and not consistent between Windows versions */ + { GWLP_WNDPROC, 0, ERROR_ACCESS_DENIED }, + { DWLP_MSGRESULT, 0, ERROR_INVALID_INDEX } + }; + HWND root, desktop = GetDesktopWindow(); + DWORD_PTR result; + char buffer[100]; + int i; - /* HWND_MESSAGE is not supported below w2k, but win9x return != 0 - on CreateWindowExA and crash later in the test. - Use UNICODE here to fail on win9x */ hwnd = CreateWindowExW(0, mainwindowclassW, message_windowW, WS_CAPTION | WS_VISIBLE, 100, 100, 200, 200, HWND_MESSAGE, 0, 0, NULL); - if (!hwnd) - { - win_skip("CreateWindowExW with parent HWND_MESSAGE failed\n"); - return; - } - + ok( hwnd != 0, "CreateWindowExW with parent HWND_MESSAGE failed\n" ); ok( !GetParent(hwnd), "GetParent should return 0 for message only windows\n" ); - if (pGetAncestor) - { - char buffer[100]; - HWND root, desktop = GetDesktopWindow(); - parent = pGetAncestor(hwnd, GA_PARENT); - ok(parent != 0, "GetAncestor(GA_PARENT) should not return 0 for message windows\n"); - ok(parent != desktop, "GetAncestor(GA_PARENT) should not return desktop for message windows\n"); - root = pGetAncestor(hwnd, GA_ROOT); - ok(root == hwnd, "GetAncestor(GA_ROOT) should return hwnd for message windows\n"); - ok( !pGetAncestor(parent, GA_PARENT) || broken(pGetAncestor(parent, GA_PARENT) != 0), /* win2k */ - "parent shouldn't have parent %p\n", pGetAncestor(parent, GA_PARENT) ); - trace("parent %p root %p desktop %p\n", parent, root, desktop); - if (!GetClassNameA( parent, buffer, sizeof(buffer) )) buffer[0] = 0; - ok( !lstrcmpiA( buffer, "Message" ), "wrong parent class '%s'\n", buffer ); - GetWindowRect( parent, &rect ); - ok( rect.left == 0 && rect.right == 100 && rect.top == 0 && rect.bottom == 100, - "wrong parent rect %s\n", wine_dbgstr_rect( &rect )); - } + parent = GetAncestor(hwnd, GA_PARENT); + ok(parent != 0, "GetAncestor(GA_PARENT) should not return 0 for message windows\n"); + ok(parent != desktop, "GetAncestor(GA_PARENT) should not return desktop for message windows\n"); + root = GetAncestor(hwnd, GA_ROOT); + ok(root == hwnd, "GetAncestor(GA_ROOT) should return hwnd for message windows\n"); + ok( !GetAncestor(parent, GA_PARENT), + "parent shouldn't have parent %p\n", GetAncestor(parent, GA_PARENT) ); + if (!GetClassNameA( parent, buffer, sizeof(buffer) )) buffer[0] = 0; + ok( !lstrcmpiA( buffer, "Message" ), "wrong parent class '%s'\n", buffer ); + GetWindowRect( parent, &rect ); + ok( rect.left == 0 && rect.right == 100 && rect.top == 0 && rect.bottom == 100, + "wrong parent rect %s\n", wine_dbgstr_rect( &rect )); GetWindowRect( hwnd, &rect ); ok( rect.left == 100 && rect.right == 300 && rect.top == 100 && rect.bottom == 300, "wrong window rect %s\n", wine_dbgstr_rect( &rect )); @@ -7161,7 +9041,7 @@ static void test_hwnd_message(void) SetLastError(0xdeadbeef); found = FindWindowExA( GetDesktopWindow(), 0, 0, "message window" ); ok( found == 0, "found message window %p/%p\n", found, hwnd ); - ok( GetLastError() == 0xdeadbeef, "expected deadbeef, got %d\n", GetLastError() ); + ok( GetLastError() == 0xdeadbeef, "expected deadbeef, got %ld\n", GetLastError() ); if (parent) { found = FindWindowExA( parent, 0, 0, "message window" ); @@ -7177,12 +9057,151 @@ static void test_hwnd_message(void) ok( !IsWindowVisible( hwnd ), "HWND_MESSAGE window is visible\n" ); if (parent) ok( !IsWindowVisible( parent ), "HWND_MESSAGE parent is visible\n" ); + /* GetWindowLong */ + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + SetLastError( 0xdeadbeef ); + result = GetWindowLongPtrW( parent, tests[i].offset ); + ok( result == tests[i].expect, "offset %d, got %08Ix expect %08Ix\n", + tests[i].offset, result, tests[i].expect ); + if (tests[i].error) + ok( GetLastError() == tests[i].error, "offset %d: error %ld expect %ld\n", + tests[i].offset, GetLastError(), tests[i].error ); + else + ok( GetLastError() == 0xdeadbeef, "offset %d: error %ld expect unchanged\n", + tests[i].offset, GetLastError() ); + } + DestroyWindow(hwnd); } +static HWND message_window_topmost_hwnd_msg = NULL; +static BOOL message_window_topmost_received_killfocus; + +static LRESULT WINAPI message_window_topmost_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + ok(hwnd != message_window_topmost_hwnd_msg, "Received message %u for message-only window %p\n", msg, hwnd); + if (msg == WM_KILLFOCUS) message_window_topmost_received_killfocus = TRUE; + return DefWindowProcW(hwnd, msg, wparam, lparam); +} + + +static void test_message_window_topmost(void) +{ + /* All SWP_* flags except SWP_NOZORDER, which has a different effect. */ + const UINT swp_flags = SWP_ASYNCWINDOWPOS | SWP_DEFERERASE | SWP_DRAWFRAME | SWP_FRAMECHANGED + | SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOOWNERZORDER + | SWP_NOREDRAW | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_SHOWWINDOW; + /* Same as above, except the flags that cause + * ERROR_INVALID_PARAMETER to be returned by DeferWindowPos(). */ + const UINT dwp_flags = SWP_DRAWFRAME | SWP_FRAMECHANGED + | SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOOWNERZORDER + | SWP_NOREDRAW | SWP_NOSIZE | SWP_SHOWWINDOW; + HWND hwnd, hwnd_msg; + HDWP hdwp; + RECT rect; + BOOL ret; + MSG msg; + + hwnd = CreateWindowW(L"static", L"main window", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 210, 211, 212, 213, NULL, NULL, GetModuleHandleW(NULL), NULL); + ok(!!hwnd, "Cannot create main window\n"); + flush_events(TRUE); + SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)message_window_topmost_proc); + + hwnd_msg = CreateWindowW(L"static", L"message window", 0, + 220, 221, 222, 223, HWND_MESSAGE, NULL, GetModuleHandleW(NULL), NULL); + ok(!!hwnd_msg, "Cannot create message window\n"); + flush_events(TRUE); + SetWindowLongPtrW(hwnd_msg, GWLP_WNDPROC, (LONG_PTR)message_window_topmost_proc); + + ret = GetWindowRect(hwnd_msg, &rect); + ok(ret, "Unexpected failure when calling GetWindowRect()\n"); + ok(rect.left == 220 && rect.top == 221 && rect.right == 220 + 222 && rect.bottom == 221 + 223, + "Unexpected rectangle %s\n", wine_dbgstr_rect(&rect)); + + while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + + message_window_topmost_hwnd_msg = hwnd_msg; + + SetLastError(0xdeadbeef); + + ret = SetWindowPos(hwnd_msg, HWND_TOPMOST, 230, 231, 232, 233, 0); + ok(ret, "Unexpected failure when calling SetWindowPos()\n"); + + ret = SetWindowPos(hwnd_msg, HWND_TOPMOST, 234, 235, 236, 237, swp_flags); + ok(ret, "Unexpected failure when calling SetWindowPos()\n"); + + ret = SetWindowPos(hwnd_msg, HWND_NOTOPMOST, 240, 241, 242, 243, 0); + ok(ret, "Unexpected failure when calling SetWindowPos()\n"); + + ret = SetWindowPos(hwnd_msg, HWND_NOTOPMOST, 244, 245, 246, 247, swp_flags); + ok(ret, "Unexpected failure when calling SetWindowPos()\n"); + + hdwp = BeginDeferWindowPos(4); + ok(!!hdwp, "Unexpected failure when calling BeginDeferWindowPos()\n"); + + hdwp = DeferWindowPos(hdwp, hwnd_msg, HWND_TOPMOST, 250, 251, 252, 253, 0); + ok(!!hdwp, "Unexpected failure when calling DeferWindowPos()\n"); + + hdwp = DeferWindowPos(hdwp, hwnd_msg, HWND_TOPMOST, 254, 255, 256, 257, dwp_flags); + ok(!!hdwp, "Unexpected failure when calling DeferWindowPos()\n"); + + hdwp = DeferWindowPos(hdwp, hwnd_msg, HWND_NOTOPMOST, 260, 261, 262, 263, 0); + ok(!!hdwp, "Unexpected failure when calling DeferWindowPos()\n"); + + hdwp = DeferWindowPos(hdwp, hwnd_msg, HWND_NOTOPMOST, 264, 265, 266, 267, dwp_flags); + ok(!!hdwp, "Unexpected failure when calling DeferWindowPos()\n"); + + ret = EndDeferWindowPos(hdwp); + ok(ret, "Unexpected failure when calling EndDeferWindowPos()\n"); + + ok(GetLastError() == 0xdeadbeef, "Last error unexpectedly set to %#lx\n", GetLastError()); + + while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + + message_window_topmost_hwnd_msg = NULL; + + ret = GetWindowRect(hwnd_msg, &rect); + ok(ret, "Unexpected failure when calling GetWindowRect()\n"); + ok(rect.left == 220 && rect.top == 221 && rect.right == 220 + 222 && rect.bottom == 221 + 223, + "Unexpected rectangle %s\n", wine_dbgstr_rect(&rect)); + + ok(!message_window_topmost_received_killfocus, "Received WM_KILLFOCUS\n"); + message_window_topmost_received_killfocus = FALSE; + + ret = SetWindowPos(hwnd_msg, HWND_TOPMOST, 230, 231, 232, 233, SWP_NOZORDER); + ok(ret, "Unexpected failure when calling SetWindowPos()\n"); + + while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + + ok(message_window_topmost_received_killfocus, "Did not receive WM_KILLFOCUS\n"); + + ret = GetWindowRect(hwnd_msg, &rect); + ok(ret, "Unexpected failure when calling GetWindowRect()\n"); + ok(rect.left == 230 && rect.top == 231 && rect.right == 230 + 232 && rect.bottom == 231 + 233, + "Unexpected rectangle %s\n", wine_dbgstr_rect(&rect)); + + ok(DestroyWindow(hwnd_msg), "Cannot destroy main window\n"); + ok(DestroyWindow(hwnd), "Cannot destroy message window\n"); +} + + static void test_layered_window(void) { - HWND hwnd; + HWND hwnd, child; COLORREF key = 0; BYTE alpha = 0; DWORD flags = 0; @@ -7191,6 +9210,7 @@ static void test_layered_window(void) HDC hdc; HBITMAP hbm; BOOL ret; + MSG msg; if (!pGetLayeredWindowAttributes || !pSetLayeredWindowAttributes || !pUpdateLayeredWindow) { @@ -7208,7 +9228,7 @@ static void test_layered_window(void) SetLastError( 0xdeadbeef ); ret = pUpdateLayeredWindow( hwnd, 0, NULL, &sz, hdc, &pt, 0, NULL, ULW_OPAQUE ); ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError() ); ret = pGetLayeredWindowAttributes( hwnd, &key, &alpha, &flags ); ok( !ret, "GetLayeredWindowAttributes should fail on non-layered window\n" ); ret = pSetLayeredWindowAttributes( hwnd, 0, 0, LWA_ALPHA ); @@ -7224,13 +9244,13 @@ static void test_layered_window(void) ok( ret, "SetLayeredWindowAttributes should succeed on layered window\n" ); ret = pGetLayeredWindowAttributes( hwnd, &key, &alpha, &flags ); ok( ret, "GetLayeredWindowAttributes should succeed on layered window\n" ); - ok( key == 0x123456 || key == 0, "wrong color key %x\n", key ); + ok( key == 0x123456 || key == 0, "wrong color key %lx\n", key ); ok( alpha == 44, "wrong alpha %u\n", alpha ); - ok( flags == LWA_ALPHA, "wrong flags %x\n", flags ); + ok( flags == LWA_ALPHA, "wrong flags %lx\n", flags ); SetLastError( 0xdeadbeef ); ret = pUpdateLayeredWindow( hwnd, 0, NULL, &sz, hdc, &pt, 0, NULL, ULW_OPAQUE ); ok( !ret, "UpdateLayeredWindow should fail on layered but initialized window\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError() ); /* clearing WS_EX_LAYERED resets attributes */ SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED ); @@ -7246,7 +9266,7 @@ static void test_layered_window(void) ok( ret, "UpdateLayeredWindow should succeed on layered window\n" ); ret = pUpdateLayeredWindow( hwnd, 0, NULL, &sz, hdc, &pt, 0, NULL, ULW_OPAQUE | ULW_EX_NORESIZE ); ok( !ret, "UpdateLayeredWindow should fail with ex flag\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); if (pUpdateLayeredWindowIndirect) { UPDATELAYEREDWINDOWINFO info; @@ -7268,7 +9288,7 @@ static void test_layered_window(void) ok( !ret, "UpdateLayeredWindowIndirect should fail\n" ); /* particular error code differs from version to version, could be ERROR_INCORRECT_SIZE, ERROR_MR_MID_NOT_FOUND or ERROR_GEN_FAILURE (Win8/Win10) */ - ok( GetLastError() != 0, "wrong error %u\n", GetLastError() ); + ok( GetLastError() != 0, "wrong error %lu\n", GetLastError() ); info.dwFlags = ULW_OPAQUE; ret = pUpdateLayeredWindowIndirect( hwnd, &info ); ok( ret, "UpdateLayeredWindowIndirect should succeed on layered window\n" ); @@ -7276,38 +9296,38 @@ static void test_layered_window(void) info.dwFlags = ULW_OPAQUE | 0xf00; ret = pUpdateLayeredWindowIndirect( hwnd, &info ); ok( !ret, "UpdateLayeredWindowIndirect should fail\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); info.cbSize--; info.dwFlags = ULW_OPAQUE; ret = pUpdateLayeredWindowIndirect( hwnd, &info ); ok( !ret, "UpdateLayeredWindowIndirect should fail\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); ret = pUpdateLayeredWindowIndirect( hwnd, NULL ); ok( !ret, "UpdateLayeredWindowIndirect should fail\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); } ret = pSetLayeredWindowAttributes( hwnd, 0x654321, 22, LWA_COLORKEY | LWA_ALPHA ); ok( ret, "SetLayeredWindowAttributes should succeed on layered window\n" ); ret = pGetLayeredWindowAttributes( hwnd, &key, &alpha, &flags ); ok( ret, "GetLayeredWindowAttributes should succeed on layered window\n" ); - ok( key == 0x654321, "wrong color key %x\n", key ); + ok( key == 0x654321, "wrong color key %lx\n", key ); ok( alpha == 22, "wrong alpha %u\n", alpha ); - ok( flags == (LWA_COLORKEY | LWA_ALPHA), "wrong flags %x\n", flags ); + ok( flags == (LWA_COLORKEY | LWA_ALPHA), "wrong flags %lx\n", flags ); SetLastError( 0xdeadbeef ); ret = pUpdateLayeredWindow( hwnd, 0, NULL, &sz, hdc, &pt, 0, NULL, ULW_OPAQUE ); ok( !ret, "UpdateLayeredWindow should fail on layered but initialized window\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError() ); ret = pSetLayeredWindowAttributes( hwnd, 0x888888, 33, LWA_COLORKEY ); ok( ret, "SetLayeredWindowAttributes should succeed on layered window\n" ); alpha = 0; ret = pGetLayeredWindowAttributes( hwnd, &key, &alpha, &flags ); ok( ret, "GetLayeredWindowAttributes should succeed on layered window\n" ); - ok( key == 0x888888, "wrong color key %x\n", key ); + ok( key == 0x888888, "wrong color key %lx\n", key ); /* alpha not changed on vista if LWA_ALPHA is not set */ ok( alpha == 22 || alpha == 33, "wrong alpha %u\n", alpha ); - ok( flags == LWA_COLORKEY, "wrong flags %x\n", flags ); + ok( flags == LWA_COLORKEY, "wrong flags %lx\n", flags ); /* color key may or may not be changed without LWA_COLORKEY */ ret = pSetLayeredWindowAttributes( hwnd, 0x999999, 44, 0 ); @@ -7315,9 +9335,9 @@ static void test_layered_window(void) alpha = 0; ret = pGetLayeredWindowAttributes( hwnd, &key, &alpha, &flags ); ok( ret, "GetLayeredWindowAttributes should succeed on layered window\n" ); - ok( key == 0x888888 || key == 0x999999, "wrong color key %x\n", key ); + ok( key == 0x888888 || key == 0x999999, "wrong color key %lx\n", key ); ok( alpha == 22 || alpha == 44, "wrong alpha %u\n", alpha ); - ok( flags == 0, "wrong flags %x\n", flags ); + ok( flags == 0, "wrong flags %lx\n", flags ); /* default alpha and color key is 0 */ SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED ); @@ -7326,9 +9346,51 @@ static void test_layered_window(void) ok( ret, "SetLayeredWindowAttributes should succeed on layered window\n" ); ret = pGetLayeredWindowAttributes( hwnd, &key, &alpha, &flags ); ok( ret, "GetLayeredWindowAttributes should succeed on layered window\n" ); - ok( key == 0 || key == 0x222222, "wrong color key %x\n", key ); + ok( key == 0 || key == 0x222222, "wrong color key %lx\n", key ); ok( alpha == 0 || alpha == 55, "wrong alpha %u\n", alpha ); - ok( flags == 0, "wrong flags %x\n", flags ); + ok( flags == 0, "wrong flags %lx\n", flags ); + + /* test layered window with WS_CLIPCHILDREN flag */ + SetWindowLongA( hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) | WS_CLIPCHILDREN ); + SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED ); + SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED ); + child = CreateWindowExA( 0, "button", "button", WS_VISIBLE | WS_CHILD, + 0, 0, 50, 50, hwnd, 0, 0, NULL ); + ok( child != NULL, "CreateWindowEx error %lu\n", GetLastError() ); + ShowWindow( hwnd, SW_SHOW ); + + ret = pSetLayeredWindowAttributes( hwnd, 0, 255, LWA_ALPHA ); + ok( ret, "SetLayeredWindowAttributes should succeed on layered window\n" ); + while (GetMessageA(&msg, 0, 0, 0)) + { + DispatchMessageA(&msg); + + if (msg.message == WM_PAINT && msg.hwnd == child) + break; + } + + SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED ); + SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED ); + ret = pUpdateLayeredWindow( hwnd, 0, NULL, &sz, hdc, &pt, 0, NULL, ULW_OPAQUE ); + ok( ret, "UpdateLayeredWindow should succeed on layered window\n" ); + + ret = pSetLayeredWindowAttributes( hwnd, 0, 255, LWA_ALPHA ); + ok( ret, "SetLayeredWindowAttributes should succeed on layered window\n" ); +#ifdef __REACTOS__ + if (is_reactos()) { + ok(FALSE, "FIXME: This hangs on ReactOS!\n"); + } else { +#endif + while (GetMessageA(&msg, 0, 0, 0)) + { + DispatchMessageA(&msg); + + if (msg.message == WM_PAINT && msg.hwnd == child) + break; + } +#ifdef __REACTOS__ + } +#endif DestroyWindow( hwnd ); DeleteDC( hdc ); @@ -7353,12 +9415,18 @@ static LRESULT CALLBACK fullscreen_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPAR case WM_GETMINMAXINFO: { MINMAXINFO *minmax = (MINMAXINFO *)lp; - ok(minmax->ptMaxPosition.x <= mi.rcMonitor.left, "%d <= %d\n", minmax->ptMaxPosition.x, mi.rcMonitor.left); - ok(minmax->ptMaxPosition.y <= mi.rcMonitor.top, "%d <= %d\n", minmax->ptMaxPosition.y, mi.rcMonitor.top); - ok(minmax->ptMaxSize.x >= mi.rcMonitor.right, "%d >= %d\n", minmax->ptMaxSize.x, mi.rcMonitor.right); - ok(minmax->ptMaxSize.y >= mi.rcMonitor.bottom, "%d >= %d\n", minmax->ptMaxSize.y, mi.rcMonitor.bottom); + ok(minmax->ptMaxPosition.x <= mi.rcMonitor.left, "%ld <= %ld\n", minmax->ptMaxPosition.x, mi.rcMonitor.left); + ok(minmax->ptMaxPosition.y <= mi.rcMonitor.top, "%ld <= %ld\n", minmax->ptMaxPosition.y, mi.rcMonitor.top); + ok(minmax->ptMaxSize.x >= mi.rcMonitor.right, "%ld >= %ld\n", minmax->ptMaxSize.x, mi.rcMonitor.right); + ok(minmax->ptMaxSize.y >= mi.rcMonitor.bottom, "%ld >= %ld\n", minmax->ptMaxSize.y, mi.rcMonitor.bottom); break; } + case WM_NCCALCSIZE: + { + LRESULT ret = DefWindowProcA(hwnd, WM_NCCALCSIZE, wp, lp); + ok(!ret, "got %08Ix (%08Ix %08Ix)\n", ret, wp, lp); + return ret; + } } return DefWindowProcA(hwnd, msg, wp, lp); } @@ -7371,29 +9439,24 @@ static void test_fullscreen(void) static const DWORD t_ex_style[] = { 0, WS_EX_APPWINDOW, WS_EX_TOOLWINDOW }; + RECT rc, virtual_rect, expected_rect; WNDCLASSA cls; + int timeout; HWND hwnd; int i, j; POINT pt; - RECT rc; HMONITOR hmon; LRESULT ret; - if (!pGetMonitorInfoA || !pMonitorFromPoint) - { - win_skip("GetMonitorInfoA or MonitorFromPoint are not available on this platform\n"); - return; - } - pt.x = pt.y = 0; SetLastError(0xdeadbeef); - hmon = pMonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY); - ok(hmon != 0, "MonitorFromPoint error %u\n", GetLastError()); + hmon = MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY); + ok(hmon != 0, "MonitorFromPoint error %lu\n", GetLastError()); mi.cbSize = sizeof(mi); SetLastError(0xdeadbeef); - ret = pGetMonitorInfoA(hmon, &mi); - ok(ret, "GetMonitorInfo error %u\n", GetLastError()); + ret = GetMonitorInfoA(hmon, &mi); + ok(ret, "GetMonitorInfo error %lu\n", GetLastError()); trace("monitor %s, work %s\n", wine_dbgstr_rect(&mi.rcMonitor), wine_dbgstr_rect(&mi.rcWork)); cls.style = 0; @@ -7408,14 +9471,14 @@ static void test_fullscreen(void) cls.lpszClassName = "fullscreen_class"; RegisterClassA(&cls); - for (i = 0; i < sizeof(t_style)/sizeof(t_style[0]); i++) + for (i = 0; i < ARRAY_SIZE(t_style); i++) { DWORD style, ex_style; /* avoid a WM interaction */ assert(!(t_style[i] & WS_VISIBLE)); - for (j = 0; j < sizeof(t_ex_style)/sizeof(t_ex_style[0]); j++) + for (j = 0; j < ARRAY_SIZE(t_ex_style); j++) { int fixup; @@ -7425,63 +9488,58 @@ static void test_fullscreen(void) hwnd = CreateWindowExA(ex_style, "fullscreen_class", NULL, style, mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom, GetDesktopWindow(), 0, GetModuleHandleA(NULL), NULL); - ok(hwnd != 0, "%d: CreateWindowExA(%#x/%#x) failed\n", i, ex_style, style); + ok(hwnd != 0, "%d: CreateWindowExA(%#lx/%#lx) failed\n", i, ex_style, style); GetWindowRect(hwnd, &rc); - trace("%#x/%#x: window rect %s\n", ex_style, style, wine_dbgstr_rect(&rc)); ok(rc.left <= mi.rcMonitor.left && rc.top <= mi.rcMonitor.top && rc.right >= mi.rcMonitor.right && rc.bottom >= mi.rcMonitor.bottom, - "%#x/%#x: window rect %s\n", ex_style, style, wine_dbgstr_rect(&rc)); + "%#lx/%#lx: window rect %s\n", ex_style, style, wine_dbgstr_rect(&rc)); DestroyWindow(hwnd); style = t_style[i] | WS_MAXIMIZE; hwnd = CreateWindowExA(ex_style, "fullscreen_class", NULL, style, mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom, GetDesktopWindow(), 0, GetModuleHandleA(NULL), NULL); - ok(hwnd != 0, "%d: CreateWindowExA(%#x/%#x) failed\n", i, ex_style, style); + ok(hwnd != 0, "%d: CreateWindowExA(%#lx/%#lx) failed\n", i, ex_style, style); GetWindowRect(hwnd, &rc); - trace("%#x/%#x: window rect %s\n", ex_style, style, wine_dbgstr_rect(&rc)); ok(rc.left <= mi.rcMonitor.left && rc.top <= mi.rcMonitor.top && rc.right >= mi.rcMonitor.right && rc.bottom >= mi.rcMonitor.bottom, - "%#x/%#x: window rect %s\n", ex_style, style, wine_dbgstr_rect(&rc)); + "%#lx/%#lx: window rect %s\n", ex_style, style, wine_dbgstr_rect(&rc)); DestroyWindow(hwnd); style = t_style[i] | WS_MAXIMIZE | WS_CAPTION; hwnd = CreateWindowExA(ex_style, "fullscreen_class", NULL, style, mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom, GetDesktopWindow(), 0, GetModuleHandleA(NULL), NULL); - ok(hwnd != 0, "%d: CreateWindowExA(%#x/%#x) failed\n", i, ex_style, style); + ok(hwnd != 0, "%d: CreateWindowExA(%#lx/%#lx) failed\n", i, ex_style, style); GetWindowRect(hwnd, &rc); - trace("%#x/%#x: window rect %s\n", ex_style, style, wine_dbgstr_rect(&rc)); ok(rc.left <= mi.rcMonitor.left && rc.top <= mi.rcMonitor.top && rc.right >= mi.rcMonitor.right && rc.bottom >= mi.rcMonitor.bottom, - "%#x/%#x: window rect %s\n", ex_style, style, wine_dbgstr_rect(&rc)); + "%#lx/%#lx: window rect %s\n", ex_style, style, wine_dbgstr_rect(&rc)); DestroyWindow(hwnd); style = t_style[i] | WS_CAPTION | WS_MAXIMIZEBOX; hwnd = CreateWindowExA(ex_style, "fullscreen_class", NULL, style, mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom, GetDesktopWindow(), 0, GetModuleHandleA(NULL), NULL); - ok(hwnd != 0, "%d: CreateWindowExA(%#x/%#x) failed\n", i, ex_style, style); + ok(hwnd != 0, "%d: CreateWindowExA(%#lx/%#lx) failed\n", i, ex_style, style); GetWindowRect(hwnd, &rc); - trace("%#x/%#x: window rect %s\n", ex_style, style, wine_dbgstr_rect(&rc)); ok(rc.left <= mi.rcMonitor.left && rc.top <= mi.rcMonitor.top && rc.right >= mi.rcMonitor.right && rc.bottom >= mi.rcMonitor.bottom, - "%#x/%#x: window rect %s\n", ex_style, style, wine_dbgstr_rect(&rc)); + "%#lx/%#lx: window rect %s\n", ex_style, style, wine_dbgstr_rect(&rc)); DestroyWindow(hwnd); style = t_style[i] | WS_MAXIMIZE | WS_CAPTION | WS_MAXIMIZEBOX; hwnd = CreateWindowExA(ex_style, "fullscreen_class", NULL, style, mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom, GetDesktopWindow(), 0, GetModuleHandleA(NULL), NULL); - ok(hwnd != 0, "%d: CreateWindowExA(%#x/%#x) failed\n", i, ex_style, style); + ok(hwnd != 0, "%d: CreateWindowExA(%#lx/%#lx) failed\n", i, ex_style, style); GetWindowRect(hwnd, &rc); - trace("%#x/%#x: window rect %s\n", ex_style, style, wine_dbgstr_rect(&rc)); /* Windows makes a maximized window slightly larger (to hide the borders?) */ fixup = min(abs(rc.left), abs(rc.top)); InflateRect(&rc, -fixup, -fixup); ok(rc.left >= mi.rcMonitor.left && rc.top >= mi.rcMonitor.top && rc.right <= mi.rcMonitor.right && rc.bottom <= mi.rcMonitor.bottom, - "%#x/%#x: window rect %s must be in %s\n", ex_style, style, wine_dbgstr_rect(&rc), + "%#lx/%#lx: window rect %s must be in %s\n", ex_style, style, wine_dbgstr_rect(&rc), wine_dbgstr_rect(&mi.rcMonitor)); DestroyWindow(hwnd); @@ -7489,25 +9547,93 @@ static void test_fullscreen(void) hwnd = CreateWindowExA(ex_style, "fullscreen_class", NULL, style, mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom, GetDesktopWindow(), 0, GetModuleHandleA(NULL), NULL); - ok(hwnd != 0, "%d: CreateWindowExA(%#x/%#x) failed\n", i, ex_style, style); + ok(hwnd != 0, "%d: CreateWindowExA(%#lx/%#lx) failed\n", i, ex_style, style); GetWindowRect(hwnd, &rc); - trace("%#x/%#x: window rect %s\n", ex_style, style, wine_dbgstr_rect(&rc)); /* Windows makes a maximized window slightly larger (to hide the borders?) */ fixup = min(abs(rc.left), abs(rc.top)); InflateRect(&rc, -fixup, -fixup); if (style & (WS_CHILD | WS_POPUP)) ok(rc.left <= mi.rcMonitor.left && rc.top <= mi.rcMonitor.top && rc.right >= mi.rcMonitor.right && rc.bottom >= mi.rcMonitor.bottom, - "%#x/%#x: window rect %s\n", ex_style, style, wine_dbgstr_rect(&rc)); + "%#lx/%#lx: window rect %s\n", ex_style, style, wine_dbgstr_rect(&rc)); else ok(rc.left >= mi.rcMonitor.left && rc.top >= mi.rcMonitor.top && rc.right <= mi.rcMonitor.right && rc.bottom <= mi.rcMonitor.bottom, - "%#x/%#x: window rect %s\n", ex_style, style, wine_dbgstr_rect(&rc)); + "%#lx/%#lx: window rect %s\n", ex_style, style, wine_dbgstr_rect(&rc)); DestroyWindow(hwnd); } } + /* Test restoring a full screen window with WS_THICKFRAME style to normal */ + /* Add WS_THICKFRAME style later so that the window can cover the entire monitor */ + hwnd = CreateWindowA("fullscreen_class", NULL, WS_POPUP | WS_VISIBLE, 0, 0, mi.rcMonitor.right, + mi.rcMonitor.bottom, NULL, NULL, GetModuleHandleA(NULL), NULL); + ok(!!hwnd, "CreateWindow failed, error %#lx.\n", GetLastError()); + flush_events(TRUE); + + /* Add WS_THICKFRAME and exit full screen */ + SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) | WS_THICKFRAME); + SetWindowPos(hwnd, 0, 0, 0, 100, 100, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS); + flush_events(TRUE); + + /* TestBots need about 1000ms to exit full screen */ + timeout = 1000; + while (timeout > 0) + { + timeout -= 200; + flush_events(TRUE); + GetWindowRect(hwnd, &rc); + if (rc.right - rc.left == 100 && rc.bottom - rc.top == 100) + break; + } + ok(rc.right - rc.left == 100, "Expect width %d, got %ld.\n", 100, rc.right - rc.left); + ok(rc.bottom - rc.top == 100, "Expect height %d, got %ld.\n", 100, rc.bottom - rc.top); + DestroyWindow(hwnd); + UnregisterClassA("fullscreen_class", GetModuleHandleA(NULL)); + + /* Test fullscreen windows spanning multiple monitors */ + if (GetSystemMetrics(SM_CMONITORS) > 1) + { + /* Test windows covering all monitors */ + virtual_rect.left = GetSystemMetrics(SM_XVIRTUALSCREEN); + virtual_rect.top = GetSystemMetrics(SM_YVIRTUALSCREEN); + virtual_rect.right = virtual_rect.left + GetSystemMetrics(SM_CXVIRTUALSCREEN); + virtual_rect.bottom = virtual_rect.top + GetSystemMetrics(SM_CYVIRTUALSCREEN); + + hwnd = CreateWindowA("static", NULL, WS_POPUP | WS_VISIBLE, virtual_rect.left, + virtual_rect.top, virtual_rect.right - virtual_rect.left, + virtual_rect.bottom - virtual_rect.top, NULL, NULL, NULL, NULL); + ok(!!hwnd, "CreateWindow failed, error %#lx.\n", GetLastError()); + flush_events(TRUE); + + GetWindowRect(hwnd, &rc); + /* FVWM used by TestBots doesn't support _NET_WM_FULLSCREEN_MONITORS */ + todo_wine_if(!EqualRect(&rc, &virtual_rect)) + ok(EqualRect(&rc, &virtual_rect), "Expected %s, got %s.\n", + wine_dbgstr_rect(&virtual_rect), wine_dbgstr_rect(&rc)); + DestroyWindow(hwnd); + + /* Test windows covering one monitor and 1 pixel larger on available sides */ + expected_rect = mi.rcMonitor; + InflateRect(&expected_rect, 1, 1); + IntersectRect(&expected_rect, &expected_rect, &virtual_rect); + hwnd = CreateWindowA("static", NULL, WS_POPUP | WS_VISIBLE, expected_rect.left, + expected_rect.top, expected_rect.right - expected_rect.left, + expected_rect.bottom - expected_rect.top, NULL, NULL, NULL, NULL); + ok(!!hwnd, "CreateWindow failed, error %#lx.\n", GetLastError()); + flush_events(TRUE); + + GetWindowRect(hwnd, &rc); + todo_wine + ok(EqualRect(&rc, &expected_rect), "Expected %s, got %s.\n", + wine_dbgstr_rect(&expected_rect), wine_dbgstr_rect(&rc)); + DestroyWindow(hwnd); + } + else + { + skip("This test requires at least two monitors.\n"); + } } static BOOL test_thick_child_got_minmax; @@ -7541,9 +9667,11 @@ static LRESULT WINAPI test_thick_child_size_winproc(HWND hwnd, UINT msg, WPARAM case WM_GETMINMAXINFO: { minmax = (MINMAXINFO *)lparam; - trace("hwnd %p, WM_GETMINMAXINFO, %08lx, %08lx\n", hwnd, wparam, lparam); - dump_minmax_info( minmax ); - + if (winetest_debug > 1) + { + trace("hwnd %p, WM_GETMINMAXINFO, %08Ix, %08Ix\n", hwnd, wparam, lparam); + dump_minmax_info( minmax ); + } test_thick_child_got_minmax = TRUE; @@ -7601,6 +9729,13 @@ static LRESULT WINAPI test_thick_child_size_winproc(HWND hwnd, UINT msg, WPARAM break; } + + case WM_NCCALCSIZE: + { + LRESULT ret = DefWindowProcA(hwnd, WM_NCCALCSIZE, wparam, lparam); + ok(!ret, "got %08Ix (%08Ix %08Ix)\n", ret, wparam, lparam); + return ret; + } } return DefWindowProcA(hwnd, msg, wparam, lparam); @@ -7689,7 +9824,7 @@ static void test_thick_child_size(HWND parentWindow) cls.lpszClassName = className; SetLastError(0xdeadbeef); success = RegisterClassA(&cls); - ok(success,"RegisterClassA failed, error: %u\n", GetLastError()); + ok(success,"RegisterClassA failed, error: %lu\n", GetLastError()); for(i = 0; i < NUMBER_OF_THICK_CHILD_TESTS; i++) { @@ -7700,13 +9835,13 @@ static void test_thick_child_size(HWND parentWindow) SetLastError(0xdeadbeef); childWindow = CreateWindowExA( exStyles[i], className, "", styles[i], 0, 0, 0, 0, parentWindow, 0, GetModuleHandleA(0), NULL ); - ok(childWindow != NULL, "Failed to create child window, error: %u\n", GetLastError()); + ok(childWindow != NULL, "Failed to create child window, error: %lu\n", GetLastError()); ok(test_thick_child_got_minmax, "Got no WM_GETMINMAXINFO\n"); SetLastError(0xdeadbeef); success = GetWindowRect(childWindow, &childRect); - ok(success,"GetWindowRect call failed, error: %u\n", GetLastError()); + ok(success,"GetWindowRect call failed, error: %lu\n", GetLastError()); childWidth = childRect.right - childRect.left; childHeight = childRect.bottom - childRect.top; @@ -7729,12 +9864,12 @@ static void test_thick_child_size(HWND parentWindow) } ok((childWidth == expectedWidth) && (childHeight == expectedHeight), - "size of window (%s) is wrong: expected size %dx%d != actual size %dx%d\n", + "size of window (%s) is wrong: expected size %ldx%ld != actual size %ldx%ld\n", test_thick_child_name, expectedWidth, expectedHeight, childWidth, childHeight); SetLastError(0xdeadbeef); success = DestroyWindow(childWindow); - ok(success,"DestroyWindow call failed, error: %u\n", GetLastError()); + ok(success,"DestroyWindow call failed, error: %lu\n", GetLastError()); } ok(UnregisterClassA(className, GetModuleHandleA(NULL)),"UnregisterClass call failed\n"); } @@ -7747,7 +9882,7 @@ static void test_handles( HWND full_hwnd ) SetLastError( 0xdeadbeef ); ret = GetWindowRect( hwnd, &rect ); - ok( ret, "GetWindowRect failed for %p err %u\n", hwnd, GetLastError() ); + ok( ret, "GetWindowRect failed for %p err %lu\n", hwnd, GetLastError() ); #ifdef _WIN64 if ((ULONG_PTR)full_hwnd >> 32) @@ -7756,24 +9891,24 @@ static void test_handles( HWND full_hwnd ) hwnd = (HWND)((ULONG_PTR)full_hwnd | ((ULONG_PTR)~0u << 32)); SetLastError( 0xdeadbeef ); ret = GetWindowRect( hwnd, &rect ); - ok( ret, "GetWindowRect failed for %p err %u\n", hwnd, GetLastError() ); + ok( ret, "GetWindowRect failed for %p err %lu\n", hwnd, GetLastError() ); hwnd = (HWND)(((ULONG_PTR)full_hwnd & ~0u) | ((ULONG_PTR)0x1234 << 32)); SetLastError( 0xdeadbeef ); ret = GetWindowRect( hwnd, &rect ); - ok( ret, "GetWindowRect failed for %p err %u\n", hwnd, GetLastError() ); + ok( ret, "GetWindowRect failed for %p err %lu\n", hwnd, GetLastError() ); hwnd = (HWND)(((ULONG_PTR)full_hwnd & 0xffff) | ((ULONG_PTR)0x9876 << 16)); SetLastError( 0xdeadbeef ); ret = GetWindowRect( hwnd, &rect ); ok( !ret, "GetWindowRect succeeded for %p\n", hwnd ); - ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %lu\n", GetLastError() ); hwnd = (HWND)(((ULONG_PTR)full_hwnd & 0xffff) | ((ULONG_PTR)0x12345678 << 16)); SetLastError( 0xdeadbeef ); ret = GetWindowRect( hwnd, &rect ); ok( !ret, "GetWindowRect succeeded for %p\n", hwnd ); - ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %lu\n", GetLastError() ); #endif } @@ -7795,7 +9930,7 @@ static void test_winregion(void) SetLastError(0xdeadbeef); ret = pGetWindowRgnBox(hwnd, NULL); ok( ret == ERROR, "Expected ERROR, got %d\n", ret); - ok( GetLastError() == 0xdeadbeef, "Expected , got %d\n", GetLastError()); + ok( GetLastError() == 0xdeadbeef, "Expected , got %ld\n", GetLastError()); hrgn = CreateRectRgn(2, 3, 10, 15); ok( hrgn != NULL, "Region creation failed\n"); @@ -7806,7 +9941,7 @@ static void test_winregion(void) SetLastError(0xdeadbeef); ret = pGetWindowRgnBox(hwnd, NULL); ok( ret == ERROR, "Expected ERROR, got %d\n", ret); - ok( GetLastError() == 0xdeadbeef, "Expected , got %d\n", GetLastError()); + ok( GetLastError() == 0xdeadbeef, "Expected , got %ld\n", GetLastError()); SetRectEmpty(&r); ret = pGetWindowRgnBox(hwnd, &r); @@ -7865,7 +10000,7 @@ static void test_rtl_layout(void) ok( r.left == 30 && r.right == 10, "wrong rect %s\n", wine_dbgstr_rect( &r )); pt.x = pt.y = 12; MapWindowPoints( child, parent, &pt, 1 ); - ok( pt.x == 22 && pt.y == 22, "wrong point %d,%d\n", pt.x, pt.y ); + ok( pt.x == 22 && pt.y == 22, "wrong point %ld,%ld\n", pt.x, pt.y ); SetWindowPos( parent, 0, 0, 0, 250, 250, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE ); GetWindowRect( parent, &r ); ok( r.left == 100 && r.right == 350, "wrong rect %s\n", wine_dbgstr_rect( &r )); @@ -7902,19 +10037,21 @@ static void test_FlashWindow(void) hwnd = CreateWindowExA( 0, "MainWindowClass", "FlashWindow", WS_POPUP, 0, 0, 0, 0, 0, 0, 0, NULL ); - ok( hwnd != 0, "CreateWindowExA error %d\n", GetLastError() ); + ok( hwnd != 0, "CreateWindowExA error %ld\n", GetLastError() ); SetLastError( 0xdeadbeef ); ret = pFlashWindow( NULL, TRUE ); - ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "FlashWindow returned with %d\n", GetLastError() ); + ok( !ret && (GetLastError() == ERROR_INVALID_PARAMETER || + GetLastError() == ERROR_INVALID_WINDOW_HANDLE), + "FlashWindow returned with %ld\n", GetLastError() ); DestroyWindow( hwnd ); SetLastError( 0xdeadbeef ); ret = pFlashWindow( hwnd, TRUE ); - ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, - "FlashWindow returned with %d\n", GetLastError() ); + ok( !ret && (GetLastError() == ERROR_INVALID_PARAMETER || + GetLastError() == ERROR_INVALID_WINDOW_HANDLE), + "FlashWindow returned with %ld\n", GetLastError() ); } static void test_FlashWindowEx(void) @@ -7931,7 +10068,7 @@ static void test_FlashWindowEx(void) hwnd = CreateWindowExA( 0, "MainWindowClass", "FlashWindow", WS_POPUP, 0, 0, 0, 0, 0, 0, 0, NULL ); - ok( hwnd != 0, "CreateWindowExA error %d\n", GetLastError() ); + ok( hwnd != 0, "CreateWindowExA error %ld\n", GetLastError() ); finfo.cbSize = sizeof(FLASHWINFO); finfo.dwFlags = FLASHW_TIMER; @@ -7940,14 +10077,15 @@ static void test_FlashWindowEx(void) finfo.hwnd = NULL; SetLastError(0xdeadbeef); ret = pFlashWindowEx(&finfo); - ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, - "FlashWindowEx returned with %d\n", GetLastError()); + ok(!ret && (GetLastError() == ERROR_INVALID_PARAMETER || + GetLastError() == ERROR_INVALID_WINDOW_HANDLE), + "FlashWindowEx returned with %ld\n", GetLastError()); finfo.hwnd = hwnd; SetLastError(0xdeadbeef); ret = pFlashWindowEx(NULL); ok(!ret && GetLastError() == ERROR_NOACCESS, - "FlashWindowEx returned with %d\n", GetLastError()); + "FlashWindowEx returned with %ld\n", GetLastError()); SetLastError(0xdeadbeef); ret = pFlashWindowEx(&finfo); @@ -7970,33 +10108,34 @@ static void test_FlashWindowEx(void) SetLastError(0xdeadbeef); ret = pFlashWindowEx(&finfo); - ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, - "FlashWindowEx returned with %d\n", GetLastError()); + ok(!ret && (GetLastError() == ERROR_INVALID_PARAMETER || + GetLastError() == ERROR_INVALID_WINDOW_HANDLE), + "FlashWindowEx returned with %ld\n", GetLastError()); ok(finfo.cbSize == sizeof(FLASHWINFO), "FlashWindowEx modified cdSize to %x\n", finfo.cbSize); ok(finfo.hwnd == hwnd, "FlashWindowEx modified hwnd to %p\n", finfo.hwnd); - ok(finfo.dwFlags == FLASHW_TIMER, "FlashWindowEx modified dwFlags to %x\n", finfo.dwFlags); + ok(finfo.dwFlags == FLASHW_TIMER, "FlashWindowEx modified dwFlags to %lx\n", finfo.dwFlags); ok(finfo.uCount == 3, "FlashWindowEx modified uCount to %x\n", finfo.uCount); - ok(finfo.dwTimeout == 200, "FlashWindowEx modified dwTimeout to %x\n", finfo.dwTimeout); + ok(finfo.dwTimeout == 200, "FlashWindowEx modified dwTimeout to %lx\n", finfo.dwTimeout); hwnd = CreateWindowExA( 0, "MainWindowClass", "FlashWindow", WS_VISIBLE | WS_POPUPWINDOW, 0, 0, 0, 0, 0, 0, 0, NULL ); - ok( hwnd != 0, "CreateWindowExA error %d\n", GetLastError() ); + ok( hwnd != 0, "CreateWindowExA error %ld\n", GetLastError() ); finfo.hwnd = hwnd; SetLastError(0xdeadbeef); ret = pFlashWindowEx(NULL); ok(!ret && GetLastError() == ERROR_NOACCESS, - "FlashWindowEx returned with %d\n", GetLastError()); + "FlashWindowEx returned with %ld\n", GetLastError()); SetLastError(0xdeadbeef); prev = pFlashWindowEx(&finfo); ok(finfo.cbSize == sizeof(FLASHWINFO), "FlashWindowEx modified cdSize to %x\n", finfo.cbSize); ok(finfo.hwnd == hwnd, "FlashWindowEx modified hwnd to %p\n", finfo.hwnd); - ok(finfo.dwFlags == FLASHW_TIMER, "FlashWindowEx modified dwFlags to %x\n", finfo.dwFlags); + ok(finfo.dwFlags == FLASHW_TIMER, "FlashWindowEx modified dwFlags to %lx\n", finfo.dwFlags); ok(finfo.uCount == 3, "FlashWindowEx modified uCount to %x\n", finfo.uCount); - ok(finfo.dwTimeout == 200, "FlashWindowEx modified dwTimeout to %x\n", finfo.dwTimeout); + ok(finfo.dwTimeout == 200, "FlashWindowEx modified dwTimeout to %lx\n", finfo.dwTimeout); finfo.dwFlags = FLASHW_STOP; SetLastError(0xdeadbeef); @@ -8011,37 +10150,47 @@ static void test_FindWindowEx(void) HWND hwnd, found; hwnd = CreateWindowExA( 0, "MainWindowClass", "caption", WS_POPUP, 0,0,0,0, 0, 0, 0, NULL ); - ok( hwnd != 0, "CreateWindowExA error %d\n", GetLastError() ); + ok( hwnd != 0, "CreateWindowExA error %ld\n", GetLastError() ); + + num_gettext_msgs = 0; + found = FindWindowExA( 0, 0, "ClassThatDoesntExist", "" ); + ok( found == NULL, "expected a NULL hwnd\n" ); + ok( num_gettext_msgs == 0, "got %lu WM_GETTEXT messages\n", num_gettext_msgs ); + + num_gettext_msgs = 0; + found = FindWindowExA( 0, 0, "ClassThatDoesntExist", NULL ); + ok( found == NULL, "expected a NULL hwnd\n" ); + ok( num_gettext_msgs == 0, "got %lu WM_GETTEXT messages\n", num_gettext_msgs ); num_gettext_msgs = 0; found = FindWindowExA( 0, 0, "MainWindowClass", "" ); ok( found == NULL, "expected a NULL hwnd\n" ); - ok( num_gettext_msgs == 0, "got %u WM_GETTEXT messages\n", num_gettext_msgs ); + ok( num_gettext_msgs == 0, "got %lu WM_GETTEXT messages\n", num_gettext_msgs ); num_gettext_msgs = 0; found = FindWindowExA( 0, 0, "MainWindowClass", NULL ); ok( found == hwnd, "found is %p, expected a valid hwnd\n", found ); - ok( num_gettext_msgs == 0, "got %u WM_GETTEXT messages\n", num_gettext_msgs ); + ok( num_gettext_msgs == 0, "got %lu WM_GETTEXT messages\n", num_gettext_msgs ); num_gettext_msgs = 0; found = FindWindowExA( 0, 0, "MainWindowClass", "caption" ); ok( found == hwnd, "found is %p, expected a valid hwnd\n", found ); - ok( num_gettext_msgs == 0, "got %u WM_GETTEXT messages\n", num_gettext_msgs ); + ok( num_gettext_msgs == 0, "got %lu WM_GETTEXT messages\n", num_gettext_msgs ); DestroyWindow( hwnd ); hwnd = CreateWindowExA( 0, "MainWindowClass", NULL, WS_POPUP, 0,0,0,0, 0, 0, 0, NULL ); - ok( hwnd != 0, "CreateWindowExA error %d\n", GetLastError() ); + ok( hwnd != 0, "CreateWindowExA error %ld\n", GetLastError() ); num_gettext_msgs = 0; found = FindWindowExA( 0, 0, "MainWindowClass", "" ); ok( found == hwnd, "found is %p, expected a valid hwnd\n", found ); - ok( num_gettext_msgs == 0, "got %u WM_GETTEXT messages\n", num_gettext_msgs ); + ok( num_gettext_msgs == 0, "got %lu WM_GETTEXT messages\n", num_gettext_msgs ); num_gettext_msgs = 0; found = FindWindowExA( 0, 0, "MainWindowClass", NULL ); ok( found == hwnd, "found is %p, expected a valid hwnd\n", found ); - ok( num_gettext_msgs == 0, "got %u WM_GETTEXT messages\n", num_gettext_msgs ); + ok( num_gettext_msgs == 0, "got %lu WM_GETTEXT messages\n", num_gettext_msgs ); DestroyWindow( hwnd ); @@ -8052,6 +10201,62 @@ static void test_FindWindowEx(void) ok( found != NULL, "found is NULL, expected a valid hwnd\n" ); } +static void test_FindWindow(void) +{ + HWND hwnd, found; + + hwnd = CreateWindowExA( 0, "MainWindowClass", "caption", WS_POPUP, 0,0,0,0, 0, 0, 0, NULL ); + ok( hwnd != 0, "CreateWindowExA error %ld\n", GetLastError() ); + + num_gettext_msgs = 0; + found = FindWindowA( "ClassThatDoesntExist", "" ); + ok( found == NULL, "expected a NULL hwnd\n" ); + ok( num_gettext_msgs == 0, "got %lu WM_GETTEXT messages\n", num_gettext_msgs ); + + num_gettext_msgs = 0; + found = FindWindowA( "ClassThatDoesntExist", NULL ); + ok( found == NULL, "expected a NULL hwnd\n" ); + ok( num_gettext_msgs == 0, "got %lu WM_GETTEXT messages\n", num_gettext_msgs ); + + num_gettext_msgs = 0; + found = FindWindowA( "MainWindowClass", "" ); + ok( found == NULL, "expected a NULL hwnd\n" ); + ok( num_gettext_msgs == 0, "got %lu WM_GETTEXT messages\n", num_gettext_msgs ); + + num_gettext_msgs = 0; + found = FindWindowA( "MainWindowClass", NULL ); + ok( found == hwnd, "found is %p, expected a valid hwnd\n", found ); + ok( num_gettext_msgs == 0, "got %lu WM_GETTEXT messages\n", num_gettext_msgs ); + + num_gettext_msgs = 0; + found = FindWindowA( "MainWindowClass", "caption" ); + ok( found == hwnd, "found is %p, expected a valid hwnd\n", found ); + ok( num_gettext_msgs == 0, "got %lu WM_GETTEXT messages\n", num_gettext_msgs ); + + DestroyWindow( hwnd ); + + hwnd = CreateWindowExA( 0, "MainWindowClass", NULL, WS_POPUP, 0,0,0,0, 0, 0, 0, NULL ); + ok( hwnd != 0, "CreateWindowExA error %ld\n", GetLastError() ); + + num_gettext_msgs = 0; + found = FindWindowA( "MainWindowClass", "" ); + ok( found == hwnd, "found is %p, expected a valid hwnd\n", found ); + ok( num_gettext_msgs == 0, "got %lu WM_GETTEXT messages\n", num_gettext_msgs ); + + num_gettext_msgs = 0; + found = FindWindowA( "MainWindowClass", NULL ); + ok( found == hwnd, "found is %p, expected a valid hwnd\n", found ); + ok( num_gettext_msgs == 0, "got %lu WM_GETTEXT messages\n", num_gettext_msgs ); + + DestroyWindow( hwnd ); + + /* test behaviour with a window title that is an empty character */ + found = FindWindowA( "Shell_TrayWnd", "" ); + ok( found != NULL, "found is NULL, expected a valid hwnd\n" ); + found = FindWindowA( "Shell_TrayWnd", NULL ); + ok( found != NULL, "found is NULL, expected a valid hwnd\n" ); +} + static void test_GetLastActivePopup(void) { HWND hwndOwner, hwndPopup1, hwndPopup2; @@ -8093,7 +10298,7 @@ static void create_window_tree(HWND parent, HWND *window, int size) memset(window, 0, size * sizeof(window[0])); pos = 0; - for (i = 0; i < sizeof(style)/sizeof(style[0]); i++) + for (i = 0; i < ARRAY_SIZE(style); i++) { assert(pos < size); window[pos] = CreateWindowExA(0, "my_window", NULL, style[i] | WS_CHILD, @@ -8211,8 +10416,6 @@ static void test_child_window_from_point(void) { static const int real_child_pos[] = { 14,15,16,17,18,19,20,21,24,25,26,27,42,43, 44,45,46,47,48,49,52,53,54,55,51,50,23,22,-1 }; - static const int real_child_pos_nt4[] = { 14,15,16,17,20,21,24,25,26,27,42,43,44,45, - 48,49,52,53,54,55,51,50,47,46,23,22,19,18,-1 }; WNDCLASSA cls; HWND hwnd, parent, window[100]; POINT pt; @@ -8242,7 +10445,7 @@ static void test_child_window_from_point(void) ok(parent != 0, "CreateWindowEx failed\n"); trace("parent %p\n", parent); - create_window_tree(parent, window, sizeof(window)/sizeof(window[0])); + create_window_tree(parent, window, ARRAY_SIZE(window)); found_invisible = 0; found_disabled = 0; @@ -8251,17 +10454,17 @@ static void test_child_window_from_point(void) found_extransparent = 0; /* FIXME: also test WindowFromPoint, ChildWindowFromPoint, ChildWindowFromPointEx */ - for (i = 0; i < sizeof(real_child_pos)/sizeof(real_child_pos[0]); i++) + for (i = 0; i < ARRAY_SIZE(real_child_pos); i++) { struct window_attributes attrs; pt.x = pt.y = 50; hwnd = RealChildWindowFromPoint(parent, pt); ok(hwnd != 0, "RealChildWindowFromPoint failed\n"); - ret = window_to_index(hwnd, window, sizeof(window)/sizeof(window[0])); + ret = window_to_index(hwnd, window, ARRAY_SIZE(window)); /* FIXME: remove once Wine is fixed */ todo_wine_if (ret != real_child_pos[i]) - ok(ret == real_child_pos[i] || broken(ret == real_child_pos_nt4[i]), "expected %d, got %d\n", real_child_pos[i], ret); + ok(ret == real_child_pos[i], "expected %d, got %d\n", real_child_pos[i], ret); get_window_attributes(hwnd, &attrs); if (!attrs.is_visible) found_invisible++; @@ -8290,10 +10493,10 @@ static void test_child_window_from_point(void) ok(!found_invisible, "found %d invisible windows\n", found_invisible); ok(found_disabled, "found %d disabled windows\n", found_disabled); -todo_wine + todo_wine ok(found_groupbox == 4, "found %d groupbox windows\n", found_groupbox); ok(found_httransparent, "found %d httransparent windows\n", found_httransparent); -todo_wine + todo_wine ok(found_extransparent, "found %d extransparent windows\n", found_extransparent); ret = UnregisterClassA("my_button", cls.hInstance); @@ -8308,19 +10511,22 @@ static void simulate_click(int x, int y) { INPUT input[2]; UINT events_no; + POINT pt; + GetCursorPos(&pt); SetCursorPos(x, y); memset(input, 0, sizeof(input)); input[0].type = INPUT_MOUSE; - U(input[0]).mi.dx = x; - U(input[0]).mi.dy = y; - U(input[0]).mi.dwFlags = MOUSEEVENTF_LEFTDOWN; + input[0].mi.dx = x; + input[0].mi.dy = y; + input[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN; input[1].type = INPUT_MOUSE; - U(input[1]).mi.dx = x; - U(input[1]).mi.dy = y; - U(input[1]).mi.dwFlags = MOUSEEVENTF_LEFTUP; + input[1].mi.dx = x; + input[1].mi.dy = y; + input[1].mi.dwFlags = MOUSEEVENTF_LEFTUP; events_no = SendInput(2, input, sizeof(input[0])); ok(events_no == 2, "SendInput returned %d\n", events_no); + SetCursorPos(pt.x, pt.y); } static WNDPROC def_static_proc; @@ -8352,14 +10558,16 @@ static void window_from_point_proc(HWND parent) child_static = CreateWindowExA(0, "static", "static", WS_CHILD | WS_VISIBLE, 0, 0, 100, 100, parent, 0, NULL, NULL); ok(child_static != 0, "CreateWindowEx failed\n"); - pt.x = pt.y = 150; + pt.x = pt.y = 50; + ClientToScreen( child_static, &pt ); win = WindowFromPoint(pt); ok(win == parent, "WindowFromPoint returned %p, expected %p\n", win, parent); child_button = CreateWindowExA(0, "button", "button", WS_CHILD | WS_VISIBLE, 100, 0, 100, 100, parent, 0, NULL, NULL); ok(child_button != 0, "CreateWindowEx failed\n"); - pt.x = 250; + pt.x = pt.y = 50; + ClientToScreen( child_button, &pt ); win = WindowFromPoint(pt); ok(win == child_button, "WindowFromPoint returned %p, expected %p\n", win, child_button); @@ -8386,13 +10594,13 @@ static void window_from_point_proc(HWND parent) ok(got_click, "button under static window didn't get WM_LBUTTONUP\n"); ret = WaitForSingleObject(end_event, 5000); - ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %lx\n", ret); CloseHandle(start_event); CloseHandle(end_event); } -static void test_window_from_point(const char *argv0) +static void test_window_from_point(HWND main_window, const char *argv0) { HWND hwnd, child, win; POINT pt; @@ -8402,12 +10610,15 @@ static void test_window_from_point(const char *argv0) HANDLE start_event, end_event; hwnd = CreateWindowExA(0, "MainWindowClass", NULL, WS_POPUP | WS_VISIBLE, - 100, 100, 200, 100, 0, 0, NULL, NULL); + 100, 100, 200, 100, main_window, 0, NULL, NULL); ok(hwnd != 0, "CreateWindowEx failed\n"); - pt.x = pt.y = 150; + pt.x = pt.y = 50; + ClientToScreen( hwnd, &pt ); win = WindowFromPoint(pt); - pt.x = 250; + pt.x = 150; + pt.y = 50; + ClientToScreen( hwnd, &pt ); if(win == hwnd) win = WindowFromPoint(pt); if(win != hwnd) { @@ -8419,7 +10630,8 @@ static void test_window_from_point(const char *argv0) child = CreateWindowExA(0, "static", "static", WS_CHILD | WS_VISIBLE, 0, 0, 100, 100, hwnd, 0, NULL, NULL); ok(child != 0, "CreateWindowEx failed\n"); - pt.x = pt.y = 150; + pt.x = pt.y = 50; + ClientToScreen( hwnd, &pt ); win = WindowFromPoint(pt); ok(win == hwnd, "WindowFromPoint returned %p, expected %p\n", win, hwnd); DestroyWindow(child); @@ -8441,22 +10653,24 @@ static void test_window_from_point(const char *argv0) startup.cb = sizeof(startup); ok(CreateProcessA(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info), "CreateProcess failed.\n"); - ok(wait_for_event(start_event, 1000), "didn't get start_event\n"); + ok(wait_for_events(1, &start_event, 1000) == 0, "didn't get start_event\n"); child = GetWindow(hwnd, GW_CHILD); win = WindowFromPoint(pt); ok(win == child, "WindowFromPoint returned %p, expected %p\n", win, child); - simulate_click(150, 150); + simulate_click(pt.x, pt.y); flush_events(TRUE); child = GetWindow(child, GW_HWNDNEXT); - pt.x = 250; + pt.x = 150; + pt.y = 50; + ClientToScreen( hwnd, &pt ); win = WindowFromPoint(pt); ok(win == child, "WindowFromPoint returned %p, expected %p\n", win, child); SetEvent(end_event); - winetest_wait_child_process(info.hProcess); + wait_child_process(info.hProcess); CloseHandle(start_event); CloseHandle(end_event); CloseHandle(info.hProcess); @@ -8489,15 +10703,15 @@ static void test_map_points(void) /* Verify window rect and client rect (they should have the same width and height) */ GetWindowRect(wnd, &window_rect); - ok(window_rect.left == pos.x, "left is %d instead of %d\n", window_rect.left, pos.x); - ok(window_rect.top == pos.y, "top is %d instead of %d\n", window_rect.top, pos.y); - ok(window_rect.right == pos.x + width, "right is %d instead of %d\n", window_rect.right, pos.x + width); - ok(window_rect.bottom == pos.y + height, "bottom is %d instead of %d\n", window_rect.bottom, pos.y + height); + ok(window_rect.left == pos.x, "left is %ld instead of %ld\n", window_rect.left, pos.x); + ok(window_rect.top == pos.y, "top is %ld instead of %ld\n", window_rect.top, pos.y); + ok(window_rect.right == pos.x + width, "right is %ld instead of %ld\n", window_rect.right, pos.x + width); + ok(window_rect.bottom == pos.y + height, "bottom is %ld instead of %ld\n", window_rect.bottom, pos.y + height); GetClientRect(wnd, &client_rect); - ok(client_rect.left == 0, "left is %d instead of 0\n", client_rect.left); - ok(client_rect.top == 0, "top is %d instead of 0\n", client_rect.top); - ok(client_rect.right == width, "right is %d instead of %d\n", client_rect.right, width); - ok(client_rect.bottom == height, "bottom is %d instead of %d\n", client_rect.bottom, height); + ok(client_rect.left == 0, "left is %ld instead of 0\n", client_rect.left); + ok(client_rect.top == 0, "top is %ld instead of 0\n", client_rect.top); + ok(client_rect.right == width, "right is %ld instead of %d\n", client_rect.right, width); + ok(client_rect.bottom == height, "bottom is %ld instead of %d\n", client_rect.bottom, height); /* Test MapWindowPoints */ @@ -8507,20 +10721,20 @@ static void test_map_points(void) n = MapWindowPoints(NULL, NULL, NULL, 0); err = GetLastError(); ok(n == 0, "Got %d, expected %d\n", n, 0); - ok(err == 0xdeadbeef, "Got %x, expected %x\n", err, 0xdeadbeef); + ok(err == 0xdeadbeef, "Got %lx, expected %x\n", err, 0xdeadbeef); SetLastError(0xdeadbeef); n = MapWindowPoints(wnd, wnd, NULL, 0); err = GetLastError(); ok(n == 0, "Got %d, expected %d\n", n, 0); - ok(err == 0xdeadbeef, "Got %x, expected %x\n", err, 0xdeadbeef); + ok(err == 0xdeadbeef, "Got %lx, expected %x\n", err, 0xdeadbeef); n = MapWindowPoints(wnd, NULL, NULL, 0); - ok(n == MAKELONG(window_rect.left, window_rect.top), "Got %x, expected %x\n", + ok(n == MAKELONG(window_rect.left, window_rect.top), "Got %x, expected %lx\n", n, MAKELONG(window_rect.left, window_rect.top)); n = MapWindowPoints(NULL, wnd, NULL, 0); - ok(n == MAKELONG(-window_rect.left, -window_rect.top), "Got %x, expected %x\n", + ok(n == MAKELONG(-window_rect.left, -window_rect.top), "Got %x, expected %lx\n", n, MAKELONG(-window_rect.left, -window_rect.top)); SetLastError(0xdeadbeef); @@ -8528,69 +10742,69 @@ static void test_map_points(void) n = MapWindowPoints(dwnd, NULL, &p, 1); err = GetLastError(); ok(n == 0, "Got %d, expected %d\n", n, 0); - ok(p.x == 100 && p.y == 100, "Failed got(%d, %d), expected (%d, %d)\n", p.x, p.y, 100, 100); - ok(err == ERROR_INVALID_WINDOW_HANDLE, "Got %x, expected %x\n", err, ERROR_INVALID_WINDOW_HANDLE); + ok(p.x == 100 && p.y == 100, "Failed got(%ld, %ld), expected (%d, %d)\n", p.x, p.y, 100, 100); + ok(err == ERROR_INVALID_WINDOW_HANDLE, "Got %lx, expected %x\n", err, ERROR_INVALID_WINDOW_HANDLE); SetLastError(0xdeadbeef); p.x = p.y = 100; n = MapWindowPoints(dwnd, wnd, &p, 1); err = GetLastError(); ok(n == 0, "Got %d, expected %d\n", n, 0); - ok(p.x == 100 && p.y == 100, "Failed got(%d, %d), expected (%d, %d)\n", p.x, p.y, 100, 100); - ok(err == ERROR_INVALID_WINDOW_HANDLE, "Got %x, expected %x\n", err, ERROR_INVALID_WINDOW_HANDLE); + ok(p.x == 100 && p.y == 100, "Failed got(%ld, %ld), expected (%d, %d)\n", p.x, p.y, 100, 100); + ok(err == ERROR_INVALID_WINDOW_HANDLE, "Got %lx, expected %x\n", err, ERROR_INVALID_WINDOW_HANDLE); SetLastError(0xdeadbeef); p.x = p.y = 100; n = MapWindowPoints(NULL, dwnd, &p, 1); err = GetLastError(); ok(n == 0, "Got %d, expected %d\n", n, 0); - ok(p.x == 100 && p.y == 100, "Failed got(%d, %d), expected (%d, %d)\n", p.x, p.y, 100, 100); - ok(err == ERROR_INVALID_WINDOW_HANDLE, "Got %x, expected %x\n", err, ERROR_INVALID_WINDOW_HANDLE); + ok(p.x == 100 && p.y == 100, "Failed got(%ld, %ld), expected (%d, %d)\n", p.x, p.y, 100, 100); + ok(err == ERROR_INVALID_WINDOW_HANDLE, "Got %lx, expected %x\n", err, ERROR_INVALID_WINDOW_HANDLE); SetLastError(0xdeadbeef); p.x = p.y = 100; n = MapWindowPoints(wnd, dwnd, &p, 1); err = GetLastError(); ok(n == 0, "Got %d, expected %d\n", n, 0); - ok(p.x == 100 && p.y == 100, "Failed got(%d, %d), expected (%d, %d)\n", p.x, p.y, 100, 100); - ok(err == ERROR_INVALID_WINDOW_HANDLE, "Got %x, expected %x\n", err, ERROR_INVALID_WINDOW_HANDLE); + ok(p.x == 100 && p.y == 100, "Failed got(%ld, %ld), expected (%d, %d)\n", p.x, p.y, 100, 100); + ok(err == ERROR_INVALID_WINDOW_HANDLE, "Got %lx, expected %x\n", err, ERROR_INVALID_WINDOW_HANDLE); SetLastError(0xdeadbeef); p.x = p.y = 100; n = MapWindowPoints(dwnd, dwnd, &p, 1); err = GetLastError(); ok(n == 0, "Got %d, expected %d\n", n, 0); - ok(p.x == 100 && p.y == 100, "Failed got(%d, %d), expected (%d, %d)\n", p.x, p.y, 100, 100); - ok(err == ERROR_INVALID_WINDOW_HANDLE, "Got %x, expected %x\n", err, ERROR_INVALID_WINDOW_HANDLE); + ok(p.x == 100 && p.y == 100, "Failed got(%ld, %ld), expected (%d, %d)\n", p.x, p.y, 100, 100); + ok(err == ERROR_INVALID_WINDOW_HANDLE, "Got %lx, expected %x\n", err, ERROR_INVALID_WINDOW_HANDLE); SetLastError(0xdeadbeef); p.x = p.y = 100; n = MapWindowPoints(NULL, NULL, &p, 1); err = GetLastError(); ok(n == 0, "Got %d, expected %d\n", n, 0); - ok(p.x == 100 && p.y == 100, "Failed got(%d, %d), expected (%d, %d)\n", p.x, p.y, 100, 100); - ok(err == 0xdeadbeef, "Got %x, expected %x\n", err, 0xdeadbeef); + ok(p.x == 100 && p.y == 100, "Failed got(%ld, %ld), expected (%d, %d)\n", p.x, p.y, 100, 100); + ok(err == 0xdeadbeef, "Got %lx, expected %x\n", err, 0xdeadbeef); SetLastError(0xdeadbeef); p.x = p.y = 100; n = MapWindowPoints(wnd, wnd, &p, 1); err = GetLastError(); ok(n == 0, "Got %d, expected %d\n", n, 0); - ok(p.x == 100 && p.y == 100, "Failed got(%d, %d), expected (%d, %d)\n", p.x, p.y, 100, 100); - ok(err == 0xdeadbeef, "Got %x, expected %x\n", err, 0xdeadbeef); + ok(p.x == 100 && p.y == 100, "Failed got(%ld, %ld), expected (%d, %d)\n", p.x, p.y, 100, 100); + ok(err == 0xdeadbeef, "Got %lx, expected %x\n", err, 0xdeadbeef); p.x = p.y = 100; n = MapWindowPoints(wnd, NULL, &p, 1); - ok(n == MAKELONG(window_rect.left, window_rect.top), "Got %x, expected %x\n", + ok(n == MAKELONG(window_rect.left, window_rect.top), "Got %x, expected %lx\n", n, MAKELONG(window_rect.left, window_rect.top)); - ok((p.x == (window_rect.left + 100)) && (p.y == (window_rect.top + 100)), "Failed got (%d, %d), expected (%d, %d)\n", + ok((p.x == (window_rect.left + 100)) && (p.y == (window_rect.top + 100)), "Failed got (%ld, %ld), expected (%ld, %ld)\n", p.x, p.y, window_rect.left + 100, window_rect.top + 100); p.x = p.y = 100; n = MapWindowPoints(NULL, wnd, &p, 1); - ok(n == MAKELONG(-window_rect.left, -window_rect.top), "Got %x, expected %x\n", + ok(n == MAKELONG(-window_rect.left, -window_rect.top), "Got %x, expected %lx\n", n, MAKELONG(-window_rect.left, -window_rect.top)); - ok((p.x == (-window_rect.left + 100)) && (p.y == (-window_rect.top + 100)), "Failed got (%d, %d), expected (%d, %d)\n", + ok((p.x == (-window_rect.left + 100)) && (p.y == (-window_rect.top + 100)), "Failed got (%ld, %ld), expected (%ld, %ld)\n", p.x, p.y, -window_rect.left + 100, -window_rect.top + 100); SetLastError(0xdeadbeef); @@ -8598,16 +10812,16 @@ static void test_map_points(void) n = MapWindowPoints(wnd0, NULL, &p, 1); err = GetLastError(); ok(n == 0, "Got %x, expected 0\n", n); - ok((p.x == 0) && (p.y == 0), "Failed got (%d, %d), expected (0, 0)\n", p.x, p.y); - ok(err == 0xdeadbeef, "Got %x, expected %x\n", err, 0xdeadbeef); + ok((p.x == 0) && (p.y == 0), "Failed got (%ld, %ld), expected (0, 0)\n", p.x, p.y); + ok(err == 0xdeadbeef, "Got %lx, expected %x\n", err, 0xdeadbeef); SetLastError(0xdeadbeef); p.x = p.y = 0; n = MapWindowPoints(NULL, wnd0, &p, 1); err = GetLastError(); ok(n == 0, "Got %x, expected 0\n", n); - ok((p.x == 0) && (p.y == 0), "Failed got (%d, %d), expected (0, 0)\n", p.x, p.y); - ok(err == 0xdeadbeef, "Got %x, expected %x\n", err, 0xdeadbeef); + ok((p.x == 0) && (p.y == 0), "Failed got (%ld, %ld), expected (0, 0)\n", p.x, p.y); + ok(err == 0xdeadbeef, "Got %lx, expected %x\n", err, 0xdeadbeef); /* Test ClientToScreen */ @@ -8617,34 +10831,34 @@ static void test_map_points(void) ret = ClientToScreen(NULL, NULL); err = GetLastError(); ok(!ret, "Should fail\n"); - ok(err == ERROR_INVALID_WINDOW_HANDLE, "Got %x, expected %x\n", err, ERROR_INVALID_WINDOW_HANDLE); + ok(err == ERROR_INVALID_WINDOW_HANDLE, "Got %lx, expected %x\n", err, ERROR_INVALID_WINDOW_HANDLE); SetLastError(0xdeadbeef); p.x = p.y = 100; ret = ClientToScreen(NULL, &p); err = GetLastError(); ok(!ret, "Should fail\n"); - ok(p.x == 100 && p.y == 100, "Failed got(%d, %d), expected (%d, %d)\n", p.x, p.y, 100, 100); - ok(err == ERROR_INVALID_WINDOW_HANDLE, "Got %x, expected %x\n", err, ERROR_INVALID_WINDOW_HANDLE); + ok(p.x == 100 && p.y == 100, "Failed got(%ld, %ld), expected (%d, %d)\n", p.x, p.y, 100, 100); + ok(err == ERROR_INVALID_WINDOW_HANDLE, "Got %lx, expected %x\n", err, ERROR_INVALID_WINDOW_HANDLE); SetLastError(0xdeadbeef); p.x = p.y = 100; ret = ClientToScreen(dwnd, &p); err = GetLastError(); ok(!ret, "Should fail\n"); - ok(p.x == 100 && p.y == 100, "Failed got(%d, %d), expected (%d, %d)\n", p.x, p.y, 100, 100); - ok(err == ERROR_INVALID_WINDOW_HANDLE, "Got %x, expected %x\n", err, ERROR_INVALID_WINDOW_HANDLE); + ok(p.x == 100 && p.y == 100, "Failed got(%ld, %ld), expected (%d, %d)\n", p.x, p.y, 100, 100); + ok(err == ERROR_INVALID_WINDOW_HANDLE, "Got %lx, expected %x\n", err, ERROR_INVALID_WINDOW_HANDLE); p.x = p.y = 100; ret = ClientToScreen(wnd, &p); - ok(ret, "Failed with error %u\n", GetLastError()); - ok((p.x == (window_rect.left + 100)) && (p.y == (window_rect.top + 100)), "Failed got (%d, %d), expected (%d, %d)\n", + ok(ret, "Failed with error %lu\n", GetLastError()); + ok((p.x == (window_rect.left + 100)) && (p.y == (window_rect.top + 100)), "Failed got (%ld, %ld), expected (%ld, %ld)\n", p.x, p.y, window_rect.left + 100, window_rect.top + 100); p.x = p.y = 0; ret = ClientToScreen(wnd0, &p); - ok(ret, "Failed with error %u\n", GetLastError()); - ok((p.x == 0) && (p.y == 0), "Failed got (%d, %d), expected (0, 0)\n", p.x, p.y); + ok(ret, "Failed with error %lu\n", GetLastError()); + ok((p.x == 0) && (p.y == 0), "Failed got (%ld, %ld), expected (0, 0)\n", p.x, p.y); /* Test ScreenToClient */ @@ -8654,34 +10868,34 @@ static void test_map_points(void) ret = ScreenToClient(NULL, NULL); err = GetLastError(); ok(!ret, "Should fail\n"); - ok(err == ERROR_INVALID_WINDOW_HANDLE, "Got %x, expected %x\n", err, ERROR_INVALID_WINDOW_HANDLE); + ok(err == ERROR_INVALID_WINDOW_HANDLE, "Got %lx, expected %x\n", err, ERROR_INVALID_WINDOW_HANDLE); SetLastError(0xdeadbeef); p.x = p.y = 100; ret = ScreenToClient(NULL, &p); err = GetLastError(); ok(!ret, "Should fail\n"); - ok(p.x == 100 && p.y == 100, "Failed got(%d, %d), expected (%d, %d)\n", p.x, p.y, 100, 100); - ok(err == ERROR_INVALID_WINDOW_HANDLE, "Got %x, expected %x\n", err, ERROR_INVALID_WINDOW_HANDLE); + ok(p.x == 100 && p.y == 100, "Failed got(%ld, %ld), expected (%d, %d)\n", p.x, p.y, 100, 100); + ok(err == ERROR_INVALID_WINDOW_HANDLE, "Got %lx, expected %x\n", err, ERROR_INVALID_WINDOW_HANDLE); SetLastError(0xdeadbeef); p.x = p.y = 100; ret = ScreenToClient(dwnd, &p); err = GetLastError(); ok(!ret, "Should fail\n"); - ok(p.x == 100 && p.y == 100, "Failed got(%d, %d), expected (%d, %d)\n", p.x, p.y, 100, 100); - ok(err == ERROR_INVALID_WINDOW_HANDLE, "Got %x, expected %x\n", err, ERROR_INVALID_WINDOW_HANDLE); + ok(p.x == 100 && p.y == 100, "Failed got(%ld, %ld), expected (%d, %d)\n", p.x, p.y, 100, 100); + ok(err == ERROR_INVALID_WINDOW_HANDLE, "Got %lx, expected %x\n", err, ERROR_INVALID_WINDOW_HANDLE); p.x = p.y = 100; ret = ScreenToClient(wnd, &p); - ok(ret, "Failed with error %u\n", GetLastError()); - ok((p.x == (-window_rect.left + 100)) && (p.y == (-window_rect.top + 100)), "Failed got(%d, %d), expected (%d, %d)\n", + ok(ret, "Failed with error %lu\n", GetLastError()); + ok((p.x == (-window_rect.left + 100)) && (p.y == (-window_rect.top + 100)), "Failed got(%ld, %ld), expected (%ld, %ld)\n", p.x, p.y, -window_rect.left + 100, -window_rect.top + 100); p.x = p.y = 0; ret = ScreenToClient(wnd0, &p); - ok(ret, "Failed with error %u\n", GetLastError()); - ok((p.x == 0) && (p.y == 0), "Failed got (%d, %d), expected (0, 0)\n", p.x, p.y); + ok(ret, "Failed with error %lu\n", GetLastError()); + ok((p.x == 0) && (p.y == 0), "Failed got (%ld, %ld), expected (0, 0)\n", p.x, p.y); DestroyWindow(wnd); DestroyWindow(wnd0); @@ -8734,7 +10948,7 @@ static void test_update_region(void) rc.right + wnd_orig.x, rc.bottom + wnd_orig.y); CombineRgn(rgn1, rgn1, rgn2, RGN_OR); GetUpdateRgn(parent, rgn2, FALSE); -todo_wine + todo_wine ok(EqualRgn(rgn1, rgn2), "wrong update region\n"); /* hwnd has the same invalid region as before moving */ @@ -8746,7 +10960,7 @@ todo_wine SetRectRgn(rgn1, rc.left - child_orig.x , rc.top - child_orig.y, rc.right - child_orig.x, rc.bottom - child_orig.y); GetUpdateRgn(child, rgn2, FALSE); -todo_wine + todo_wine ok(EqualRgn(rgn1, rgn2), "wrong update region\n"); DeleteObject(rgn1); @@ -8821,7 +11035,7 @@ static LRESULT WINAPI smresult_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARA /* Send another message while we have a reply queued for the current one. */ res = SendMessageA(data->thread_hwnd, WM_APP+2, 0, lparam); - ok(res == 0x449b0190, "unexpected result %lx\n", res); + ok(res == 0x449b0190, "unexpected result %Ix\n", res); return 0; } @@ -8919,12 +11133,12 @@ static void test_smresult(void) 100, 100, 200, 200, 0, 0, 0, NULL); hThread = CreateThread(NULL, 0, smresult_thread_proc, &data, 0, &tid); - ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError()); + ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError()); ok(WaitForSingleObject(data.thread_started, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); res = SendMessageA(data.thread_hwnd, WM_APP, 0, (LPARAM)&data); - ok(res == 0x240408ea, "unexpected result %lx\n", res); + ok(res == 0x240408ea, "unexpected result %Ix\n", res); SendMessageA(data.thread_hwnd, WM_CLOSE, 0, 0); @@ -8936,6 +11150,7 @@ static void test_smresult(void) CloseHandle(data.thread_got_wm_app); CloseHandle(data.main_in_wm_app_1); CloseHandle(data.thread_replied); + CloseHandle(hThread); } static void test_GetMessagePos(void) @@ -8951,42 +11166,42 @@ static void test_GetMessagePos(void) SetCursorPos(120, 140); flush_events(TRUE); pos = GetMessagePos(); - ok(pos == MAKELONG(120, 140), "pos = %08x\n", pos); + ok(pos == MAKELONG(120, 140), "pos = %08lx\n", pos); SetCursorPos(340, 320); pos = GetMessagePos(); - ok(pos == MAKELONG(120, 140), "pos = %08x\n", pos); + ok(pos == MAKELONG(120, 140), "pos = %08lx\n", pos); SendMessageW(button, WM_APP, 0, 0); pos = GetMessagePos(); - ok(pos == MAKELONG(120, 140), "pos = %08x\n", pos); + ok(pos == MAKELONG(120, 140), "pos = %08lx\n", pos); PostMessageA(button, WM_APP, 0, 0); GetMessageA(&msg, button, 0, 0); ok(msg.message == WM_APP, "msg.message = %x\n", msg.message); pos = GetMessagePos(); - ok(pos == MAKELONG(340, 320), "pos = %08x\n", pos); + ok(pos == MAKELONG(340, 320), "pos = %08lx\n", pos); PostMessageA(button, WM_APP, 0, 0); SetCursorPos(350, 330); GetMessageA(&msg, button, 0, 0); ok(msg.message == WM_APP, "msg.message = %x\n", msg.message); pos = GetMessagePos(); - ok(pos == MAKELONG(340, 320), "pos = %08x\n", pos); + ok(pos == MAKELONG(340, 320), "pos = %08lx\n", pos); PostMessageA(button, WM_APP, 0, 0); SetCursorPos(320, 340); PostMessageA(button, WM_APP+1, 0, 0); pos = GetMessagePos(); - ok(pos == MAKELONG(340, 320), "pos = %08x\n", pos); + ok(pos == MAKELONG(340, 320), "pos = %08lx\n", pos); GetMessageA(&msg, button, 0, 0); ok(msg.message == WM_APP, "msg.message = %x\n", msg.message); pos = GetMessagePos(); - ok(pos == MAKELONG(350, 330), "pos = %08x\n", pos); + ok(pos == MAKELONG(350, 330), "pos = %08lx\n", pos); GetMessageA(&msg, button, 0, 0); ok(msg.message == WM_APP+1, "msg.message = %x\n", msg.message); pos = GetMessagePos(); - ok(pos == MAKELONG(320, 340), "pos = %08x\n", pos); + ok(pos == MAKELONG(320, 340), "pos = %08lx\n", pos); SetTimer(button, 1, 250, NULL); SetCursorPos(330, 350); @@ -8998,7 +11213,7 @@ static void test_GetMessagePos(void) } ok(msg.message == WM_TIMER, "msg.message = %x\n", msg.message); pos = GetMessagePos(); - ok(pos == MAKELONG(330, 350), "pos = %08x\n", pos); + ok(pos == MAKELONG(330, 350), "pos = %08lx\n", pos); KillTimer(button, 1); DestroyWindow(button); @@ -9237,7 +11452,7 @@ static LRESULT WINAPI winproc_convA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l { const char *text = (const char*)lparam; - ok(!wparam, "wparam = %08lx\n", wparam); + ok(!wparam, "wparam = %08Ix\n", wparam); ok(!strcmp(text, "text"), "WM_SETTEXT lparam = %s\n", text); return 1; } @@ -9251,7 +11466,7 @@ static LRESULT WINAPI winproc_convW(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l { const WCHAR *text = (const WCHAR*)lparam; - ok(!wparam, "wparam = %08lx\n", wparam); + ok(!wparam, "wparam = %08Ix\n", wparam); ok(!lstrcmpW(text, textW), "WM_SETTEXT lparam = %s\n", wine_dbgstr_w(text)); return 1; } @@ -9274,10 +11489,10 @@ static void test_winproc_handles(const char *argv0) wnd_classA.lpszClassName = "winproc_test"; wnd_classA.lpfnWndProc = winproc; ret = RegisterClassA(&wnd_classA); - ok(ret, "RegisterClass failed with error %d\n", GetLastError()); + ok(ret, "RegisterClass failed with error %ld\n", GetLastError()); ret = GetClassInfoW(hinst, winproc_testW, &wnd_classW); - ok(ret, "GetClassInfoW failed with error %d\n", GetLastError()); + ok(ret, "GetClassInfoW failed with error %ld\n", GetLastError()); ok(wnd_classA.lpfnWndProc != wnd_classW.lpfnWndProc, "winproc pointers should not be identical\n"); @@ -9289,7 +11504,7 @@ static void test_winproc_handles(const char *argv0) ok(count == 1, "winproc should be called once (%d)\n", count); ret = UnregisterClassW(winproc_testW, hinst); - ok(ret, "UnregisterClass failed with error %d\n", GetLastError()); + ok(ret, "UnregisterClass failed with error %ld\n", GetLastError()); /* crashes on 64-bit windows because lpfnWndProc handle is already freed */ if (sizeof(void*) == 4) @@ -9306,7 +11521,7 @@ static void test_winproc_handles(const char *argv0) startup.cb = sizeof(startup); ok(CreateProcessA(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info), "CreateProcess failed.\n"); - winetest_wait_child_process(info.hProcess); + wait_child_process(info.hProcess); CloseHandle(info.hProcess); CloseHandle(info.hThread); } @@ -9336,12 +11551,12 @@ static void test_winproc_limit(void) ok(i != 0xffff, "unable to run out of winproc slots\n"); ret = SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)winproc_convA); - ok(ret, "SetWindowLongPtr failed with error %d\n", GetLastError()); + ok(ret, "SetWindowLongPtr failed with error %ld\n", GetLastError()); ok(SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"text"), "WM_SETTEXT failed\n"); ok(SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)textW), "WM_SETTEXT with conversion failed\n"); ret = SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)winproc_convW); - ok(ret, "SetWindowLongPtr failed with error %d\n", GetLastError()); + ok(ret, "SetWindowLongPtr failed with error %ld\n", GetLastError()); ok(SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"text"), "WM_SETTEXT failed\n"); ok(SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)textW), "WM_SETTEXT with conversion failed\n"); @@ -9371,6 +11586,7 @@ static void test_winproc_limit(void) static void test_deferwindowpos(void) { HDWP hdwp, hdwp2; + HWND hwnd; BOOL ret; hdwp = BeginDeferWindowPos(0); @@ -9380,26 +11596,1933 @@ static void test_deferwindowpos(void) ok(!ret, "got %d\n", ret); hdwp2 = DeferWindowPos(NULL, NULL, NULL, 0, 0, 10, 10, 0); -todo_wine + todo_wine ok(hdwp2 == NULL && ((GetLastError() == ERROR_INVALID_DWP_HANDLE) || - broken(GetLastError() == ERROR_INVALID_WINDOW_HANDLE) /* before win8 */), "got %p, error %d\n", hdwp2, GetLastError()); + broken(GetLastError() == ERROR_INVALID_WINDOW_HANDLE) /* before win8 */), "got %p, error %ld\n", hdwp2, GetLastError()); hdwp2 = DeferWindowPos((HDWP)0xdead, GetDesktopWindow(), NULL, 0, 0, 10, 10, 0); -todo_wine + todo_wine ok(hdwp2 == NULL && ((GetLastError() == ERROR_INVALID_DWP_HANDLE) || - broken(GetLastError() == ERROR_INVALID_WINDOW_HANDLE) /* before win8 */), "got %p, error %d\n", hdwp2, GetLastError()); + broken(GetLastError() == ERROR_INVALID_WINDOW_HANDLE) /* before win8 */), "got %p, error %ld\n", hdwp2, GetLastError()); hdwp2 = DeferWindowPos(hdwp, NULL, NULL, 0, 0, 10, 10, 0); - ok(hdwp2 == NULL && GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "got %p, error %d\n", hdwp2, GetLastError()); + ok(hdwp2 == NULL && GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "got %p, error %ld\n", hdwp2, GetLastError()); hdwp2 = DeferWindowPos(hdwp, GetDesktopWindow(), NULL, 0, 0, 10, 10, 0); - ok(hdwp2 == NULL && GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "got %p, error %d\n", hdwp2, GetLastError()); + ok(hdwp2 == NULL && GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "got %p, error %ld\n", hdwp2, GetLastError()); hdwp2 = DeferWindowPos(hdwp, (HWND)0xdead, NULL, 0, 0, 10, 10, 0); - ok(hdwp2 == NULL && GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "got %p, error %d\n", hdwp2, GetLastError()); + ok(hdwp2 == NULL && GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "got %p, error %ld\n", hdwp2, GetLastError()); ret = EndDeferWindowPos(hdwp); ok(ret, "got %d\n", ret); + hdwp = BeginDeferWindowPos(0); + ok(hdwp != NULL, "got %p\n", hdwp); + + hwnd = create_tool_window(WS_POPUP, 0); + hdwp2 = DeferWindowPos(hdwp, hwnd, NULL, 0, 0, 10, 10, 0); + ok(hdwp2 != NULL, "got %p, error %ld\n", hdwp2, GetLastError()); + DestroyWindow(hwnd); + + ret = EndDeferWindowPos(hdwp); + ok(ret, "got %d\n", ret); +} + +static void test_LockWindowUpdate(HWND parent) +{ + typedef struct + { + HWND hwnd_lock, hwnd_draw; + BOOL allow_drawing; + BOOL expect_valid; + } TEST; + + int i; + HWND child = CreateWindowA("static", 0, WS_CHILD | WS_VISIBLE, 0, 0, 20, 20, parent, 0, 0, 0); + + TEST tests[] = { + {child, child, 0, 0}, + {child, child, 1, 1}, + {child, parent, 0, 1}, + {child, parent, 1, 1}, + {parent, child, 0, 0}, + {parent, child, 1, 1}, + {parent, parent, 0, 0}, + {parent, parent, 1, 1} + }; + + if (!child) + { + skip("CreateWindow failed, skipping LockWindowUpdate tests\n"); + return; + } + + ShowWindow(parent, SW_SHOW); + UpdateWindow(parent); + flush_events(TRUE); + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + HDC hdc; + POINT p = {10, 10}; + BOOL ret; + const DWORD dc_flags = DCX_USESTYLE | (tests[i].allow_drawing ? DCX_LOCKWINDOWUPDATE : 0); + const COLORREF c1 = 0x111100, c2 = 0x222200; + + hdc = GetDCEx(tests[i].hwnd_draw, 0, dc_flags); + +#define TEST_PIXEL(c_valid, c_invalid) \ + do { \ + COLORREF c = GetPixel(hdc, p.x, p.y); \ + COLORREF e = tests[i].expect_valid ? (c_valid) : (c_invalid); \ + todo_wine_if(!tests[i].expect_valid) \ + ok(c == e, "%u: GetPixel: got %08lx, expected %08lx\n", i, c, e); \ + } while (0) + + SetPixel(hdc, p.x, p.y, c1); + ret = LockWindowUpdate(tests[i].hwnd_lock); + ok(ret, "%u: LockWindowUpdate failed\n", i); + TEST_PIXEL(c1, CLR_INVALID); + SetPixel(hdc, p.x, p.y, c2); + TEST_PIXEL(c2, CLR_INVALID); + LockWindowUpdate(0); + TEST_PIXEL(c2, c1); + ReleaseDC(tests[i].hwnd_draw, hdc); +#undef TEST_PIXEL + } + DestroyWindow(child); +} + +static void test_hide_window(void) +{ + HWND hwnd, hwnd2, hwnd3; + + hwnd = CreateWindowExA(0, "MainWindowClass", "Main window", WS_POPUP | WS_VISIBLE, + 100, 100, 200, 200, 0, 0, GetModuleHandleA(NULL), NULL); + hwnd2 = CreateWindowExA(0, "MainWindowClass", "Main window 2", WS_POPUP | WS_VISIBLE, + 100, 100, 200, 200, 0, 0, GetModuleHandleA(NULL), NULL); + if (winetest_debug > 1) trace("hwnd = %p, hwnd2 = %p\n", hwnd, hwnd2); + check_active_state(hwnd2, hwnd2, hwnd2); + ok(GetWindow(hwnd2, GW_HWNDNEXT) == hwnd, "expected %p, got %p\n", hwnd, GetWindow(hwnd2, GW_HWNDNEXT)); + + /* test hiding two normal windows */ + ShowWindow(hwnd2, SW_HIDE); + check_active_state(hwnd, hwnd, hwnd); + todo_wine + ok(GetWindow(hwnd, GW_HWNDNEXT) == hwnd2, "expected %p, got %p\n", hwnd2, GetWindow(hwnd, GW_HWNDNEXT)); + + ShowWindow(hwnd, SW_HIDE); + check_active_state(hwndMain, 0, hwndMain); + ok(GetWindow(hwnd, GW_HWNDNEXT) == hwnd2, "expected %p, got %p\n", hwnd2, GetWindow(hwnd, GW_HWNDNEXT)); + + ShowWindow(hwnd, SW_SHOW); + check_active_state(hwnd, hwnd, hwnd); + + ShowWindow(hwnd2, SW_SHOW); + check_active_state(hwnd2, hwnd2, hwnd2); + ok(GetWindow(hwnd2, GW_HWNDNEXT) == hwnd, "expected %p, got %p\n", hwnd, GetWindow(hwnd2, GW_HWNDNEXT)); + + /* hide a non-active window */ + ShowWindow(hwnd, SW_HIDE); + check_active_state(hwnd2, hwnd2, hwnd2); + todo_wine + ok(GetWindow(hwnd2, GW_HWNDNEXT) == hwnd, "expected %p, got %p\n", hwnd, GetWindow(hwnd2, GW_HWNDNEXT)); + + /* hide a window in the middle */ + ShowWindow(hwnd, SW_SHOW); + ShowWindow(hwnd2, SW_SHOW); + hwnd3 = CreateWindowExA(0, "MainWindowClass", "Main window 3", WS_POPUP | WS_VISIBLE, + 100, 100, 200, 200, 0, 0, GetModuleHandleA(NULL), NULL); + SetActiveWindow(hwnd2); + ShowWindow(hwnd2, SW_HIDE); + check_active_state(hwnd3, hwnd3, hwnd3); + todo_wine { + ok(GetWindow(hwnd3, GW_HWNDNEXT) == hwnd2, "expected %p, got %p\n", hwnd2, GetWindow(hwnd3, GW_HWNDNEXT)); + ok(GetWindow(hwnd2, GW_HWNDNEXT) == hwnd, "expected %p, got %p\n", hwnd, GetWindow(hwnd2, GW_HWNDNEXT)); + } + + DestroyWindow(hwnd3); + + /* hide a normal window when there is a topmost window */ + hwnd3 = CreateWindowExA(WS_EX_TOPMOST, "MainWindowClass", "Topmost window 3", WS_POPUP|WS_VISIBLE, + 100, 100, 200, 200, 0, 0, GetModuleHandleA(NULL), NULL); + ShowWindow(hwnd, SW_SHOW); + ShowWindow(hwnd2, SW_SHOW); + check_active_state(hwnd2, hwnd2, hwnd2); + ShowWindow(hwnd2, SW_HIDE); + todo_wine + check_active_state(hwnd3, hwnd3, hwnd3); + ok(GetWindow(hwnd2, GW_HWNDNEXT) == hwnd, "expected %p, got %p\n", hwnd, GetWindow(hwnd2, GW_HWNDNEXT)); + + /* hide a topmost window */ + ShowWindow(hwnd2, SW_SHOW); + ShowWindow(hwnd3, SW_SHOW); + ShowWindow(hwnd3, SW_HIDE); + check_active_state(hwnd2, hwnd2, hwnd2); + ok(GetWindow(hwnd2, GW_HWNDNEXT) == hwnd, "expected %p, got %p\n", hwnd, GetWindow(hwnd2, GW_HWNDNEXT)); + + DestroyWindow(hwnd3); + + /* hiding an owned window activates its owner */ + ShowWindow(hwnd, SW_SHOW); + ShowWindow(hwnd2, SW_SHOW); + hwnd3 = CreateWindowExA(0, "MainWindowClass", "Owned window 3", WS_POPUP|WS_VISIBLE, + 100, 100, 200, 200, hwnd, 0, GetModuleHandleA(NULL), NULL); + ShowWindow(hwnd3, SW_HIDE); + check_active_state(hwnd, hwnd, hwnd); + todo_wine { + ok(GetWindow(hwnd3, GW_HWNDNEXT) == hwnd, "expected %p, got %p\n", hwnd, GetWindow(hwnd3, GW_HWNDNEXT)); + ok(GetWindow(hwnd, GW_HWNDNEXT) == hwnd2, "expected %p, got %p\n", hwnd2, GetWindow(hwnd, GW_HWNDNEXT)); + } + + /* hide an owner window */ + ShowWindow(hwnd, SW_SHOW); + ShowWindow(hwnd2, SW_SHOW); + ShowWindow(hwnd3, SW_SHOW); + ShowWindow(hwnd, SW_HIDE); + check_active_state(hwnd3, hwnd3, hwnd3); + ok(GetWindow(hwnd3, GW_HWNDNEXT) == hwnd, "expected %p, got %p\n", hwnd, GetWindow(hwnd3, GW_HWNDNEXT)); + ok(GetWindow(hwnd, GW_HWNDNEXT) == hwnd2, "expected %p, got %p\n", hwnd2, GetWindow(hwnd, GW_HWNDNEXT)); + + DestroyWindow(hwnd3); + DestroyWindow(hwnd2); + DestroyWindow(hwnd); +} + +static void test_minimize_window(HWND hwndMain) +{ + HWND hwnd, hwnd2, hwnd3; + + hwnd = CreateWindowExA(0, "MainWindowClass", "Main window", WS_POPUP | WS_VISIBLE, + 100, 100, 200, 200, 0, 0, GetModuleHandleA(NULL), NULL); + hwnd2 = CreateWindowExA(0, "MainWindowClass", "Main window 2", WS_POPUP | WS_VISIBLE, + 100, 100, 200, 200, 0, 0, GetModuleHandleA(NULL), NULL); + if (winetest_debug > 1) trace("hwnd = %p, hwnd2 = %p\n", hwnd, hwnd2); + check_active_state(hwnd2, hwnd2, hwnd2); + + /* test hiding two normal windows */ + ShowWindow(hwnd2, SW_MINIMIZE); + todo_wine + check_active_state(hwnd, hwnd, hwnd); + + ShowWindow(hwnd, SW_MINIMIZE); + todo_wine + if (GetActiveWindow() == 0) + check_active_state(0, 0, 0); + + ShowWindow(hwnd, SW_RESTORE); + check_active_state(hwnd, hwnd, hwnd); + + ShowWindow(hwnd2, SW_RESTORE); + check_active_state(hwnd2, hwnd2, hwnd2); + + /* try SW_SHOWMINIMIZED */ + ShowWindow(hwnd2, SW_SHOWMINIMIZED); + check_active_state(hwnd2, hwnd2, 0); + + ShowWindow(hwnd2, SW_RESTORE); + check_active_state(hwnd2, hwnd2, hwnd2); + + /* hide a non-active window */ + ShowWindow(hwnd, SW_MINIMIZE); + check_active_state(hwnd2, hwnd2, hwnd2); + + /* hide a window in the middle */ + ShowWindow(hwnd, SW_RESTORE); + ShowWindow(hwnd2, SW_RESTORE); + hwnd3 = CreateWindowExA(0, "MainWindowClass", "Main window 3", WS_POPUP | WS_VISIBLE, + 100, 100, 200, 200, 0, 0, GetModuleHandleA(NULL), NULL); + SetActiveWindow(hwnd2); + ShowWindow(hwnd2, SW_MINIMIZE); + todo_wine + check_active_state(hwnd3, hwnd3, hwnd3); + + DestroyWindow(hwnd3); + + /* hide a normal window when there is a topmost window */ + hwnd3 = CreateWindowExA(WS_EX_TOPMOST, "MainWindowClass", "Topmost window 3", WS_POPUP|WS_VISIBLE, + 100, 100, 200, 200, 0, 0, GetModuleHandleA(NULL), NULL); + ShowWindow(hwnd, SW_RESTORE); + ShowWindow(hwnd2, SW_RESTORE); + check_active_state(hwnd2, hwnd2, hwnd2); + ShowWindow(hwnd2, SW_MINIMIZE); + todo_wine + check_active_state(hwnd3, hwnd3, hwnd3); + + /* hide a topmost window */ + ShowWindow(hwnd2, SW_RESTORE); + ShowWindow(hwnd3, SW_RESTORE); + ShowWindow(hwnd3, SW_MINIMIZE); + check_active_state(hwnd2, hwnd2, hwnd2); + + DestroyWindow(hwnd3); + + /* hide an owned window */ + ShowWindow(hwnd, SW_RESTORE); + ShowWindow(hwnd2, SW_RESTORE); + hwnd3 = CreateWindowExA(0, "MainWindowClass", "Owned window 3", WS_POPUP|WS_VISIBLE, + 100, 100, 200, 200, hwnd, 0, GetModuleHandleA(NULL), NULL); + ShowWindow(hwnd3, SW_MINIMIZE); + todo_wine + check_active_state(hwnd2, hwnd2, hwnd2); + + /* with SW_SHOWMINIMIZED */ + ShowWindow(hwnd3, SW_RESTORE); + ShowWindow(hwnd3, SW_SHOWMINIMIZED); + check_active_state(hwnd3, hwnd3, 0); + + /* hide an owner window */ + ShowWindow(hwnd, SW_RESTORE); + ShowWindow(hwnd2, SW_RESTORE); + ShowWindow(hwnd3, SW_RESTORE); + ShowWindow(hwnd, SW_MINIMIZE); + todo_wine + check_active_state(hwnd2, hwnd2, hwnd2); + + DestroyWindow(hwnd3); + + /* test a child window - focus should be yielded back to the parent */ + ShowWindow(hwnd, SW_RESTORE); + hwnd3 = CreateWindowExA(0, "MainWindowClass", "Child window 3", WS_CHILD|WS_VISIBLE, + 100, 100, 200, 200, hwnd, 0, GetModuleHandleA(NULL), NULL); + SetFocus(hwnd3); + check_active_state(hwnd, hwnd, hwnd3); + ShowWindow(hwnd3, SW_MINIMIZE); + check_active_state(hwnd, hwnd, hwnd); + + /* with SW_SHOWMINIMIZED */ + ShowWindow(hwnd3, SW_RESTORE); + SetFocus(hwnd3); + check_active_state(hwnd, hwnd, hwnd3); + ShowWindow(hwnd3, SW_SHOWMINIMIZED); + check_active_state(hwnd, hwnd, hwnd); + + DestroyWindow(hwnd3); + DestroyWindow(hwnd2); + DestroyWindow(hwnd); +} + +static void test_desktop( void ) +{ + HWND desktop = GetDesktopWindow(); + /* GetWindowLong Desktop window tests */ + static const struct + { + int offset; + ULONG_PTR expect; + DWORD error; + } + tests[] = + { + { GWLP_USERDATA, 0, 0 }, + { GWL_STYLE, WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0 }, + { GWL_EXSTYLE, 0, 0 }, + { GWLP_ID, 0, 0 }, + { GWLP_HWNDPARENT, 0, 0 }, + /* GWLP_HINSTANCE - not useful and not consistent between Windows versions */ + { GWLP_WNDPROC, 0, ERROR_ACCESS_DENIED }, + { DWLP_MSGRESULT, 0, ERROR_INVALID_INDEX } + }; + DWORD_PTR result; + int i; + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + SetLastError( 0xdeadbeef ); + result = GetWindowLongPtrW( desktop, tests[i].offset ); + ok( result == tests[i].expect, "offset %d, got %08Ix expect %08Ix\n", + tests[i].offset, result, tests[i].expect ); + if (tests[i].error) + ok( GetLastError() == tests[i].error, "offset %d: error %ld expect %ld\n", + tests[i].offset, GetLastError(), tests[i].error ); + else + ok( GetLastError() == 0xdeadbeef, "offset %d: error %ld expect unchanged\n", + tests[i].offset, GetLastError() ); + } +} + +static BOOL is_topmost(HWND hwnd) +{ + return (GetWindowLongA(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0; +} + +static void swp_after(HWND hwnd, HWND after) +{ + BOOL ret; + + ret = SetWindowPos(hwnd, after, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); + ok(ret, "SetWindowPos failed\n"); + flush_events( TRUE ); +} + +static void reset_window_state(HWND *state, int n) +{ + int i; + + for (i = 0; i < n; i++) + { + if (state[i]) + { + swp_after(state[i], HWND_NOTOPMOST); + todo_wine_if(i == 5) /* FIXME: remove once Wine is fixed */ + ok(!is_topmost(state[i]), "%d: hwnd %p is still topmost\n", i, state[i]); + swp_after(state[i], HWND_TOP); + } + } +} + +static void test_topmost(void) +{ + HWND owner, hwnd, hwnd2, hwnd_child, hwnd_child2, hwnd_grandchild, state[6] = { 0 }; + BOOL is_wine = !strcmp(winetest_platform, "wine"); + + owner = create_tool_window(WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | + WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE, 0); + ok(owner != 0, "Failed to create owner window (%ld)\n", GetLastError()); + + /* Give current thread foreground state otherwise the tests may fail. */ + if (!SetForegroundWindow(owner)) + { + DestroyWindow(owner); + skip("SetForegroundWindow not working\n"); + return; + } + + hwnd = create_tool_window(WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | + WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE, owner); + ok(hwnd != 0, "Failed to create popup window (%ld)\n", GetLastError()); + hwnd2 = create_tool_window(WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | + WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE, owner); + ok(hwnd2 != 0, "Failed to create popup window (%ld)\n", GetLastError()); + + flush_events( TRUE ); + + if (winetest_debug > 1) trace("owner %p, hwnd %p, hwnd2 %p\n", owner, hwnd, hwnd2); + state[0] = owner; + state[1] = hwnd; + state[2] = hwnd2; + + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(!is_topmost(hwnd), "hwnd should NOT be topmost\n"); + ok(!is_topmost(hwnd2), "hwnd2 should NOT be topmost\n"); + check_z_order(hwnd, 0, hwnd2, owner, FALSE); + + swp_after(hwnd, HWND_TOPMOST); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(is_topmost(hwnd), "hwnd should be topmost\n"); + ok(!is_topmost(hwnd2), "hwnd2 should NOT be topmost\n"); + check_z_order(hwnd, hwnd2, 0, owner, TRUE); + swp_after(hwnd, HWND_TOP); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(is_topmost(hwnd), "hwnd should be topmost\n"); + ok(!is_topmost(hwnd2), "hwnd2 should NOT be topmost\n"); + check_z_order(hwnd, hwnd2, 0, owner, TRUE); + swp_after(hwnd, HWND_NOTOPMOST); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(!is_topmost(hwnd), "hwnd should NOT be topmost\n"); + ok(!is_topmost(hwnd2), "hwnd2 should NOT be topmost\n"); + check_z_order(hwnd, hwnd2, 0, owner, FALSE); + reset_window_state(state, ARRAY_SIZE(state)); + + swp_after(hwnd, HWND_TOPMOST); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(is_topmost(hwnd), "hwnd should be topmost\n"); + ok(!is_topmost(hwnd2), "hwnd2 should NOT be topmost\n"); + check_z_order(hwnd, hwnd2, 0, owner, TRUE); + swp_after(hwnd2, hwnd); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(is_topmost(hwnd), "hwnd should be topmost\n"); + ok(!is_topmost(hwnd2), "hwnd2 should NOT be topmost\n"); + check_z_order(hwnd, hwnd2, 0, owner, TRUE); + swp_after(hwnd, hwnd2); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(is_topmost(hwnd), "hwnd should be topmost\n"); + ok(!is_topmost(hwnd2), "hwnd2 should NOT be topmost\n"); + check_z_order(hwnd, hwnd2, 0, owner, TRUE); + swp_after(hwnd2, HWND_TOP); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(is_topmost(hwnd), "hwnd should be topmost\n"); + ok(!is_topmost(hwnd2), "hwnd2 should NOT be topmost\n"); + check_z_order(hwnd, hwnd2, 0, owner, TRUE); + swp_after(owner, HWND_TOPMOST); + todo_wine + ok(is_topmost(owner), "owner should be topmost\n"); + ok(is_topmost(hwnd), "hwnd should be topmost\n"); + todo_wine + ok(is_topmost(hwnd2), "hwnd2 should be topmost\n"); + swp_after(hwnd, HWND_NOTOPMOST); + ok(!is_topmost(owner) || broken(is_topmost(owner)) /*win7 64-bit*/, "owner should NOT be topmost\n"); + ok(!is_topmost(hwnd), "hwnd should NOT be topmost\n"); + ok(!is_topmost(hwnd2) || broken(is_topmost(hwnd2)) /*win7 64-bit*/, "hwnd2 should NOT be topmost\n"); + if (0) /*win7 64-bit is broken*/ + check_z_order(hwnd, hwnd2, 0, owner, FALSE); + swp_after(hwnd2, HWND_NOTOPMOST); + ok(!is_topmost(owner) || broken(is_topmost(owner)) /*win7 64-bit*/, "owner should NOT be topmost\n"); + ok(!is_topmost(hwnd), "hwnd should NOT be topmost\n"); + ok(!is_topmost(hwnd2), "hwnd2 should NOT be topmost\n"); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd, 0, hwnd2, owner, FALSE); + reset_window_state(state, ARRAY_SIZE(state)); + + swp_after(hwnd, HWND_TOPMOST); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(is_topmost(hwnd), "hwnd should be topmost\n"); + ok(!is_topmost(hwnd2), "hwnd2 should NOT be topmost\n"); + check_z_order(hwnd, hwnd2, 0, owner, TRUE); + swp_after(hwnd, HWND_BOTTOM); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + todo_wine + ok(!is_topmost(hwnd), "hwnd should NOT be topmost\n"); + ok(!is_topmost(hwnd2), "hwnd2 should NOT be topmost\n"); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd, 0, hwnd2, owner, FALSE); + reset_window_state(state, ARRAY_SIZE(state)); + + swp_after(hwnd, HWND_TOPMOST); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(is_topmost(hwnd), "hwnd should be topmost\n"); + ok(!is_topmost(hwnd2), "hwnd2 should NOT be topmost\n"); + check_z_order(hwnd, hwnd2, 0, owner, TRUE); + swp_after(hwnd, hwnd2); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + todo_wine + ok(!is_topmost(hwnd), "hwnd should NOT be topmost\n"); + ok(!is_topmost(hwnd2), "hwnd2 should NOT be topmost\n"); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd, 0, hwnd2, owner, FALSE); + /* FIXME: compensate todo_wine above */ + swp_after(hwnd, HWND_NOTOPMOST); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(!is_topmost(hwnd), "hwnd should NOT be topmost\n"); + ok(!is_topmost(hwnd2), "hwnd2 should NOT be topmost\n"); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd, 0, hwnd2, owner, FALSE); + reset_window_state(state, ARRAY_SIZE(state)); + + hwnd_child2 = create_tool_window(WS_VISIBLE|WS_POPUP, hwnd); + ok(hwnd_child2 != 0, "Failed to create popup window (%ld)\n", GetLastError()); + hwnd_child = create_tool_window(WS_VISIBLE|WS_POPUP, hwnd); + ok(hwnd_child != 0, "Failed to create popup window (%ld)\n", GetLastError()); + hwnd_grandchild = create_tool_window(WS_VISIBLE|WS_POPUP, hwnd_child); + ok(hwnd_grandchild != 0, "Failed to create popup window (%ld)\n", GetLastError()); + + flush_events( TRUE ); + + if (winetest_debug > 1) + trace("hwnd_child %p, hwnd_child2 %p, hwnd_grandchild %p\n", hwnd_child, hwnd_child2, hwnd_grandchild); + state[3] = hwnd_child2; + state[4] = hwnd_child; + state[5] = hwnd_grandchild; + + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(!is_topmost(hwnd), "hwnd should NOT be topmost\n"); + ok(!is_topmost(hwnd2), "hwnd2 should NOT be topmost\n"); + ok(!is_topmost(hwnd_child), "child should NOT be topmost\n"); + ok(!is_topmost(hwnd_child2), "child2 should NOT be topmost\n"); + ok(!is_topmost(hwnd_grandchild), "grandchild should NOT be topmost\n"); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd, hwnd2, 0, owner, FALSE); + check_z_order(hwnd_child, hwnd_child2, 0, hwnd, FALSE); + + swp_after(hwnd, HWND_TOPMOST); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + todo_wine + ok(is_topmost(hwnd), "hwnd should be topmost\n"); + todo_wine + ok(is_topmost(hwnd_child), "child should be topmost\n"); + todo_wine + ok(is_topmost(hwnd_child2), "child2 should be topmost\n"); + ok(is_topmost(hwnd_grandchild), "grandchild should be topmost\n"); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd, hwnd2, 0, owner, TRUE); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd_child, hwnd_child2, 0, hwnd, TRUE); + swp_after(hwnd, HWND_NOTOPMOST); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(!is_topmost(hwnd), "hwnd should NOT be topmost\n"); + ok(!is_topmost(hwnd_child), "child should NOT be topmost\n"); + ok(!is_topmost(hwnd_child2), "child2 should NOT be topmost\n"); + todo_wine + ok(!is_topmost(hwnd_grandchild), "grandchild should NOT be topmost\n"); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd, hwnd2, 0, owner, FALSE); + check_z_order(hwnd_child, hwnd_child2, 0, hwnd, FALSE); + reset_window_state(state, ARRAY_SIZE(state)); + + swp_after(hwnd, HWND_TOPMOST); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + todo_wine + ok(is_topmost(hwnd), "hwnd should be topmost\n"); + todo_wine + ok(is_topmost(hwnd_child), "child should be topmost\n"); + todo_wine + ok(is_topmost(hwnd_child2), "child2 should be topmost\n"); + ok(is_topmost(hwnd_grandchild), "grandchild should be topmost\n"); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd, hwnd2, 0, owner, TRUE); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd_child, hwnd_child2, 0, hwnd, TRUE); + swp_after(hwnd_child, HWND_NOTOPMOST); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(!is_topmost(hwnd), "hwnd should NOT be topmost\n"); + ok(!is_topmost(hwnd_child), "child should NOT be topmost\n"); + ok(!is_topmost(hwnd_child2), "child2 should NOT be topmost\n"); + todo_wine + ok(!is_topmost(hwnd_grandchild), "grandchild should NOT be topmost\n"); + check_z_order(hwnd, hwnd2, 0, owner, FALSE); + check_z_order(hwnd_child, hwnd_child2, 0, hwnd, FALSE); + reset_window_state(state, ARRAY_SIZE(state)); + + swp_after(hwnd, HWND_TOPMOST); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + todo_wine + ok(is_topmost(hwnd), "hwnd should be topmost\n"); + todo_wine + ok(is_topmost(hwnd_child), "child should be topmost\n"); + todo_wine + ok(is_topmost(hwnd_child2), "child2 should be topmost\n"); + ok(is_topmost(hwnd_grandchild), "grandchild should be topmost\n"); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd, hwnd2, 0, owner, TRUE); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd_child, hwnd_child2, 0, hwnd, TRUE); + swp_after(hwnd_grandchild, HWND_NOTOPMOST); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(!is_topmost(hwnd), "hwnd should NOT be topmost\n"); + ok(!is_topmost(hwnd_child), "child should NOT be topmost\n"); + ok(!is_topmost(hwnd_child2), "child2 should NOT be topmost\n"); + todo_wine + ok(!is_topmost(hwnd_grandchild), "grandchild should NOT be topmost\n"); + check_z_order(hwnd, hwnd2, 0, owner, FALSE); + check_z_order(hwnd_child, hwnd_child2, 0, hwnd, FALSE); + reset_window_state(state, ARRAY_SIZE(state)); + + swp_after(hwnd_child, HWND_TOPMOST); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(!is_topmost(hwnd), "hwnd should NOT be topmost\n"); + todo_wine + ok(is_topmost(hwnd_child), "child should be topmost\n"); + ok(!is_topmost(hwnd_child2), "child2 should NOT be topmost\n"); + ok(is_topmost(hwnd_grandchild), "grandchild should be topmost\n"); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd, hwnd2, 0, owner, FALSE); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd_child, hwnd_child2, 0, hwnd, TRUE); + swp_after(hwnd_child, HWND_TOP); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(!is_topmost(hwnd), "hwnd should NOT be topmost\n"); + todo_wine + ok(is_topmost(hwnd_child), "child should be topmost\n"); + ok(!is_topmost(hwnd_child2), "child2 should NOT be topmost\n"); + ok(is_topmost(hwnd_grandchild), "grandchild should be topmost\n"); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd, hwnd2, 0, owner, FALSE); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd_child, hwnd_child2, 0, hwnd, TRUE); + swp_after(hwnd, HWND_NOTOPMOST); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(!is_topmost(hwnd), "hwnd should NOT be topmost\n"); + ok(!is_topmost(hwnd_child), "child should NOT be topmost\n"); + ok(!is_topmost(hwnd_child2), "child2 should NOT be topmost\n"); + todo_wine + ok(!is_topmost(hwnd_grandchild) || broken(is_topmost(hwnd_grandchild))/*win2008 64-bit*/, "grandchild should NOT be topmost\n"); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd, hwnd2, 0, owner, FALSE); + check_z_order(hwnd_child, hwnd_child2, 0, hwnd, FALSE); + reset_window_state(state, ARRAY_SIZE(state)); + + swp_after(hwnd_child, HWND_TOPMOST); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(!is_topmost(hwnd), "hwnd should NOT be topmost\n"); + todo_wine + ok(is_topmost(hwnd_child), "child should be topmost\n"); + ok(!is_topmost(hwnd_child2), "child2 should NOT be topmost\n"); + ok(is_topmost(hwnd_grandchild), "grandchild should be topmost\n"); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd, hwnd2, 0, owner, FALSE); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd_child, hwnd_child2, 0, hwnd, TRUE); + swp_after(hwnd, HWND_NOTOPMOST); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(!is_topmost(hwnd), "hwnd should NOT be topmost\n"); + ok(!is_topmost(hwnd_child), "child should NOT be topmost\n"); + ok(!is_topmost(hwnd_child2), "child2 should NOT be topmost\n"); + todo_wine + ok(!is_topmost(hwnd_grandchild), "grandchild should NOT be topmost\n"); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd, hwnd2, 0, owner, FALSE); + check_z_order(hwnd_child, hwnd_child2, 0, hwnd, FALSE); + reset_window_state(state, ARRAY_SIZE(state)); + + swp_after(hwnd_grandchild, HWND_TOPMOST); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(!is_topmost(hwnd), "hwnd should NOT be topmost\n"); + ok(!is_topmost(hwnd_child), "child should NOT be topmost\n"); + ok(!is_topmost(hwnd_child2), "child2 should NOT be topmost\n"); + ok(is_topmost(hwnd_grandchild), "grandchild should be topmost\n"); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd, hwnd2, 0, owner, FALSE); + check_z_order(hwnd_child, hwnd_child2, 0, hwnd, FALSE); + swp_after(hwnd_child2, HWND_NOTOPMOST); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(!is_topmost(hwnd), "hwnd should NOT be topmost\n"); + ok(!is_topmost(hwnd_child), "child should NOT be topmost\n"); + ok(!is_topmost(hwnd_child2), "child2 should NOT be topmost\n"); + ok(is_topmost(hwnd_grandchild) || broken(!is_topmost(hwnd_grandchild)) /* win8+ */, "grandchild should be topmost\n"); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd, hwnd2, 0, owner, FALSE); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd_child, 0, hwnd_child2, hwnd, FALSE); + reset_window_state(state, ARRAY_SIZE(state)); + + swp_after(hwnd_child, HWND_TOPMOST); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(!is_topmost(hwnd), "hwnd should NOT be topmost\n"); + todo_wine + ok(is_topmost(hwnd_child), "child should be topmost\n"); + ok(!is_topmost(hwnd_child2), "child2 should NOT be topmost\n"); + ok(is_topmost(hwnd_grandchild), "grandchild should be topmost\n"); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd, hwnd2, 0, owner, FALSE); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd_child, hwnd_child2, 0, hwnd, TRUE); + swp_after(hwnd_child, HWND_BOTTOM); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(!is_topmost(hwnd), "hwnd should NOT be topmost\n"); + ok(!is_topmost(hwnd_child), "child should NOT be topmost\n"); + ok(!is_topmost(hwnd_child2), "child2 should NOT be topmost\n"); + todo_wine + ok(!is_topmost(hwnd_grandchild), "grandchild should NOT be topmost\n"); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd, 0, hwnd2, owner, FALSE); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd_child, 0, hwnd_child2, hwnd, FALSE); + reset_window_state(state, ARRAY_SIZE(state)); + + swp_after(hwnd_child, HWND_TOPMOST); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(!is_topmost(hwnd), "hwnd should NOT be topmost\n"); + todo_wine + ok(is_topmost(hwnd_child), "child should be topmost\n"); + ok(!is_topmost(hwnd_child2), "child2 should NOT be topmost\n"); + ok(is_topmost(hwnd_grandchild), "grandchild should be topmost\n"); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd, hwnd2, 0, owner, FALSE); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd_child, hwnd_child2, 0, hwnd, TRUE); + swp_after(hwnd_child, hwnd_child2); + ok(!is_topmost(owner), "owner should NOT be topmost\n"); + ok(!is_topmost(hwnd), "hwnd should NOT be topmost\n"); + ok(!is_topmost(hwnd_child), "child should NOT be topmost\n"); + ok(!is_topmost(hwnd_child2), "child2 should NOT be topmost\n"); + todo_wine + ok(!is_topmost(hwnd_grandchild), "grandchild should NOT be topmost\n"); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd, hwnd2, 0, owner, FALSE); + if (!is_wine) /* FIXME: remove once Wine is fixed */ + check_z_order(hwnd_child, 0, hwnd_child2, hwnd, FALSE); + reset_window_state(state, ARRAY_SIZE(state)); + + DestroyWindow(hwnd_grandchild); + DestroyWindow(hwnd_child); + DestroyWindow(hwnd_child2); + DestroyWindow(hwnd); + DestroyWindow(hwnd2); + DestroyWindow(owner); +} + +static void test_display_affinity( HWND win ) +{ + DWORD affinity; + BOOL ret, dwm; + LONG styleex; + + if (!pGetWindowDisplayAffinity || !pSetWindowDisplayAffinity) + { + win_skip("GetWindowDisplayAffinity or SetWindowDisplayAffinity missing\n"); + return; + } + + ret = pGetWindowDisplayAffinity(NULL, NULL); + ok(!ret, "GetWindowDisplayAffinity succeeded\n"); + ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "Expected ERROR_INVALID_WINDOW_HANDLE, got %lu\n", GetLastError()); + + ret = pGetWindowDisplayAffinity(NULL, &affinity); + ok(!ret, "GetWindowDisplayAffinity succeeded\n"); + ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "Expected ERROR_INVALID_WINDOW_HANDLE, got %lu\n", GetLastError()); + + ret = pGetWindowDisplayAffinity(win, NULL); + ok(!ret, "GetWindowDisplayAffinity succeeded\n"); + ok(GetLastError() == ERROR_NOACCESS, "Expected ERROR_NOACCESS, got %lu\n", GetLastError()); + + styleex = GetWindowLongW(win, GWL_EXSTYLE); + SetWindowLongW(win, GWL_EXSTYLE, styleex & ~WS_EX_LAYERED); + + affinity = 0xdeadbeef; + ret = pGetWindowDisplayAffinity(win, &affinity); + ok(ret, "GetWindowDisplayAffinity failed with %lu\n", GetLastError()); + ok(affinity == WDA_NONE, "Expected WDA_NONE, got 0x%lx\n", affinity); + + /* Windows 7 fails with ERROR_NOT_ENOUGH_MEMORY when dwm compositing is disabled */ + ret = pSetWindowDisplayAffinity(win, WDA_MONITOR); + ok(ret || GetLastError() == ERROR_NOT_ENOUGH_MEMORY, + "SetWindowDisplayAffinity failed with %lu\n", GetLastError()); + dwm = ret; + + affinity = 0xdeadbeef; + ret = pGetWindowDisplayAffinity(win, &affinity); + ok(ret, "GetWindowDisplayAffinity failed with %lu\n", GetLastError()); + if (dwm) ok(affinity == WDA_MONITOR, "Expected WDA_MONITOR, got 0x%lx\n", affinity); + else ok(affinity == WDA_NONE, "Expected WDA_NONE, got 0x%lx\n", affinity); + + ret = pSetWindowDisplayAffinity(win, WDA_NONE); + ok(ret || GetLastError() == ERROR_NOT_ENOUGH_MEMORY, + "SetWindowDisplayAffinity failed with %lu\n", GetLastError()); + + affinity = 0xdeadbeef; + ret = pGetWindowDisplayAffinity(win, &affinity); + ok(ret, "GetWindowDisplayAffinity failed with %lu\n", GetLastError()); + ok(affinity == WDA_NONE, "Expected WDA_NONE, got 0x%lx\n", affinity); + + SetWindowLongW(win, GWL_EXSTYLE, styleex | WS_EX_LAYERED); + + affinity = 0xdeadbeef; + ret = pGetWindowDisplayAffinity(win, &affinity); + ok(ret, "GetWindowDisplayAffinity failed with %lu\n", GetLastError()); + ok(affinity == WDA_NONE, "Expected WDA_NONE, got 0x%lx\n", affinity); + + ret = pSetWindowDisplayAffinity(win, WDA_MONITOR); + ok(ret || GetLastError() == ERROR_NOT_ENOUGH_MEMORY, + "SetWindowDisplayAffinity failed with %lu\n", GetLastError()); + + affinity = 0xdeadbeef; + ret = pGetWindowDisplayAffinity(win, &affinity); + ok(ret, "GetWindowDisplayAffinity failed with %lu\n", GetLastError()); + if (dwm) ok(affinity == WDA_MONITOR, "Expected WDA_MONITOR, got 0x%lx\n", affinity); + else ok(affinity == WDA_NONE, "Expected WDA_NONE, got 0x%lx\n", affinity); + + ret = pSetWindowDisplayAffinity(win, WDA_NONE); + ok(ret || GetLastError() == ERROR_NOT_ENOUGH_MEMORY, + "SetWindowDisplayAffinity failed with %lu\n", GetLastError()); + + affinity = 0xdeadbeef; + ret = pGetWindowDisplayAffinity(win, &affinity); + ok(ret, "GetWindowDisplayAffinity failed with %lu\n", GetLastError()); + ok(affinity == WDA_NONE, "Expected WDA_NONE, got 0x%lx\n", affinity); + + SetWindowLongW(win, GWL_EXSTYLE, styleex); +} + +static struct destroy_data +{ + HWND main_wnd; + HWND thread1_wnd; + HWND thread2_wnd; + HANDLE evt; + DWORD main_tid; + DWORD destroy_count; + DWORD ncdestroy_count; +} destroy_data; + +static LRESULT WINAPI destroy_thread1_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch (msg) + { + case WM_DESTROY: + ok( destroy_data.destroy_count > 0, "parent didn't get WM_DESTROY\n" ); + PostQuitMessage(0); + break; + case WM_NCDESTROY: + ok( destroy_data.ncdestroy_count > 0, "parent didn't get WM_NCDESTROY\n" ); + break; + } + return DefWindowProcA(hwnd, msg, wparam, lparam); +} + +static LRESULT WINAPI destroy_thread2_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch (msg) + { + case WM_DESTROY: + ok( destroy_data.destroy_count > 0, "parent didn't get WM_DESTROY\n" ); + break; + case WM_NCDESTROY: + ok( destroy_data.ncdestroy_count > 0, "parent didn't get WM_NCDESTROY\n" ); + ok( WaitForSingleObject(destroy_data.evt, 10000) != WAIT_TIMEOUT, "timeout\n" ); + PostQuitMessage(0); + break; + } + return DefWindowProcA(hwnd, msg, wparam, lparam); +} + +static LRESULT WINAPI destroy_main_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch (msg) + { + case WM_DESTROY: + destroy_data.destroy_count++; + break; + case WM_NCDESTROY: + destroy_data.ncdestroy_count++; + break; + } + return DefWindowProcA(hwnd, msg, wparam, lparam); +} + +static DWORD CALLBACK destroy_thread1(void *user) +{ + MSG msg; + + destroy_data.thread1_wnd = CreateWindowExA(0, "destroy_test_thread1", + "destroy test thread", WS_CHILD, 100, 100, 100, 100, + destroy_data.main_wnd, 0, GetModuleHandleA(NULL), NULL); + ok(destroy_data.thread1_wnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError()); + PostThreadMessageW(destroy_data.main_tid, WM_USER, 0, 0); + + while (GetMessageA(&msg, 0, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessageA(&msg); + } + PostThreadMessageW(destroy_data.main_tid, WM_USER + 2, 0, 0); + ok( WaitForSingleObject(destroy_data.evt, 10000) != WAIT_TIMEOUT, "timeout\n" ); + ok( IsWindow( destroy_data.thread1_wnd ), "window destroyed\n" ); + return 0; +} + +static DWORD CALLBACK destroy_thread2(void *user) +{ + MSG msg; + + destroy_data.thread2_wnd = CreateWindowExA(0, "destroy_test_thread2", + "destroy test thread", WS_CHILD, 100, 100, 100, 100, + destroy_data.main_wnd, 0, GetModuleHandleA(NULL), NULL); + ok(destroy_data.thread2_wnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError()); + + PostThreadMessageW(destroy_data.main_tid, WM_USER + 1, 0, 0); + Sleep( 100 ); + + while (GetMessageA(&msg, 0, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessageA(&msg); + } + ok( !IsWindow( destroy_data.thread2_wnd ), "window not destroyed\n" ); + return 0; +} + +static void test_destroy_quit(void) +{ + MSG msg; + WNDCLASSA wnd_classA; + ATOM ret; + HANDLE thread1, thread2; + + destroy_data.main_tid = GetCurrentThreadId(); + destroy_data.evt = CreateEventW(NULL, TRUE, FALSE, NULL); + destroy_data.destroy_count = 0; + destroy_data.ncdestroy_count = 0; + + memset(&wnd_classA, 0, sizeof(wnd_classA)); + wnd_classA.lpszClassName = "destroy_test_main"; + wnd_classA.lpfnWndProc = destroy_main_wndproc; + ret = RegisterClassA(&wnd_classA); + ok(ret, "RegisterClass failed with error %ld\n", GetLastError()); + + wnd_classA.lpszClassName = "destroy_test_thread1"; + wnd_classA.lpfnWndProc = destroy_thread1_wndproc; + ret = RegisterClassA(&wnd_classA); + ok(ret, "RegisterClass failed with error %ld\n", GetLastError()); + + wnd_classA.lpszClassName = "destroy_test_thread2"; + wnd_classA.lpfnWndProc = destroy_thread2_wndproc; + ret = RegisterClassA(&wnd_classA); + ok(ret, "RegisterClass failed with error %ld\n", GetLastError()); + + destroy_data.main_wnd = CreateWindowExA(0, "destroy_test_main", + "destroy test main", WS_OVERLAPPED | WS_CAPTION, 100, 100, 100, 100, + 0, 0, GetModuleHandleA(NULL), NULL); + ok(destroy_data.main_wnd != NULL, "CreateWindowEx failed with error %ld\n", GetLastError()); + if (!destroy_data.main_wnd) + { + CloseHandle(destroy_data.evt); + return; + } + + thread1 = CreateThread(NULL, 0, destroy_thread1, 0, 0, NULL); + + while (GetMessageA(&msg, 0, 0, 0)) + { + BOOL done = 0; + switch (msg.message) + { + case WM_USER: + thread2 = CreateThread(NULL, 0, destroy_thread2, 0, 0, NULL); + CloseHandle( thread2 ); + break; + case WM_USER + 1: + DestroyWindow(destroy_data.main_wnd); + break; + case WM_USER + 2: + SetEvent(destroy_data.evt); + done = 1; + break; + default: + DispatchMessageA(&msg); + break; + } + if (done) break; + } + + ok( WaitForSingleObject( thread1, 10000 ) != WAIT_TIMEOUT, "timeout\n" ); + ok( !IsWindow( destroy_data.thread1_wnd ), "window not destroyed\n" ); + CloseHandle( thread1 ); +} + +static void test_IsWindowEnabled(void) +{ + BOOL ret; + HWND hwnd; + + ret = IsWindowEnabled(NULL); + ok(!ret, "Expect IsWindowEnabled() return FALSE\n"); + + hwnd = GetDesktopWindow(); + ret = IsWindowEnabled(hwnd); + ok(ret, "Expect IsWindowEnabled() return TRUE\n"); + + hwnd = create_tool_window(WS_CHILD | WS_VISIBLE, hwndMain); + ret = IsWindowEnabled(hwnd); + ok(ret, "Expect IsWindowEnabled() return TRUE\n"); + EnableWindow(hwnd, FALSE); + ret = IsWindowEnabled(hwnd); + ok(!ret, "Expect IsWindowEnabled() return FALSE\n"); + DestroyWindow(hwnd); +} + +static void test_window_placement(void) +{ + RECT orig = {100, 200, 300, 400}, orig2 = {200, 300, 400, 500}, rect, work_rect; + WINDOWPLACEMENT wp = {sizeof(wp)}; + MONITORINFO mon_info; + HWND hwnd; + BOOL ret; + + hwnd = CreateWindowA("MainWindowClass", "wp", WS_OVERLAPPEDWINDOW, + orig.left, orig.top, orig.right - orig.left, orig.bottom - orig.top, 0, 0, 0, 0); + ok(!!hwnd, "failed to create window, error %lu\n", GetLastError()); + + mon_info.cbSize = sizeof(mon_info); + GetMonitorInfoW(MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY), &mon_info); + work_rect = mon_info.rcWork; + + ret = GetWindowPlacement(hwnd, &wp); + ok(ret, "failed to get window placement, error %lu\n", GetLastError()); + ok(wp.showCmd == SW_SHOWNORMAL, "got show cmd %u\n", wp.showCmd); + ok(wp.ptMinPosition.x == -1 && wp.ptMinPosition.y == -1, + "got minimized pos (%ld,%ld)\n", wp.ptMinPosition.x, wp.ptMinPosition.y); + ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1, + "got maximized pos (%ld,%ld)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y); + ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n", + wine_dbgstr_rect(&wp.rcNormalPosition)); + + ShowWindow(hwnd, SW_MINIMIZE); + + ret = GetWindowPlacement(hwnd, &wp); + ok(ret, "failed to get window placement, error %lu\n", GetLastError()); + ok(!wp.flags, "got flags %#x\n", wp.flags); + ok(wp.showCmd == SW_SHOWMINIMIZED, "got show cmd %u\n", wp.showCmd); + ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000, + "got minimized pos (%ld,%ld)\n", wp.ptMinPosition.x, wp.ptMinPosition.y); + ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1, + "got maximized pos (%ld,%ld)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y); + ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n", + wine_dbgstr_rect(&wp.rcNormalPosition)); + + ShowWindow(hwnd, SW_RESTORE); + + ret = GetWindowPlacement(hwnd, &wp); + ok(ret, "failed to get window placement, error %lu\n", GetLastError()); + ok(wp.showCmd == SW_SHOWNORMAL, "got show cmd %u\n", wp.showCmd); + ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000, + "got minimized pos (%ld,%ld)\n", wp.ptMinPosition.x, wp.ptMinPosition.y); + ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1, + "got maximized pos (%ld,%ld)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y); + ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n", + wine_dbgstr_rect(&wp.rcNormalPosition)); + + ShowWindow(hwnd, SW_MAXIMIZE); + + ret = GetWindowPlacement(hwnd, &wp); + ok(ret, "failed to get window placement, error %lu\n", GetLastError()); + ok(wp.showCmd == SW_SHOWMAXIMIZED, "got show cmd %u\n", wp.showCmd); + ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000, + "got minimized pos (%ld,%ld)\n", wp.ptMinPosition.x, wp.ptMinPosition.y); + ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1, + "got maximized pos (%ld,%ld)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y); + ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n", + wine_dbgstr_rect(&wp.rcNormalPosition)); + + SetWindowPos(hwnd, 0, 100, 100, 100, 100, SWP_NOZORDER | SWP_NOACTIVATE); + + ret = GetWindowPlacement(hwnd, &wp); + ok(ret, "failed to get window placement, error %lu\n", GetLastError()); + ok(wp.showCmd == SW_SHOWMAXIMIZED, "got show cmd %u\n", wp.showCmd); + ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000, + "got minimized pos (%ld,%ld)\n", wp.ptMinPosition.x, wp.ptMinPosition.y); + ok(wp.ptMaxPosition.x == 100 && wp.ptMaxPosition.y == 100, + "got maximized pos (%ld,%ld)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y); + ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n", + wine_dbgstr_rect(&wp.rcNormalPosition)); + + SetWindowPos(hwnd, 0, work_rect.left, work_rect.top, work_rect.right - work_rect.left, + work_rect.bottom - work_rect.top, SWP_NOZORDER | SWP_NOACTIVATE); + ret = GetWindowPlacement(hwnd, &wp); + ok(ret, "failed to get window placement, error %lu\n", GetLastError()); + ok(wp.showCmd == SW_SHOWMAXIMIZED, "got show cmd %u\n", wp.showCmd); + ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000, + "got minimized pos (%ld,%ld)\n", wp.ptMinPosition.x, wp.ptMinPosition.y); + ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1, + "got maximized pos (%ld,%ld)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y); + ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n", + wine_dbgstr_rect(&wp.rcNormalPosition)); + + SetWindowPos(hwnd, 0, work_rect.left, work_rect.top, work_rect.right - work_rect.left - 1, + work_rect.bottom - work_rect.top, SWP_NOZORDER | SWP_NOACTIVATE); + ret = GetWindowPlacement(hwnd, &wp); + ok(ret, "failed to get window placement, error %lu\n", GetLastError()); + ok(wp.showCmd == SW_SHOWMAXIMIZED, "got show cmd %u\n", wp.showCmd); + ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000, + "got minimized pos (%ld,%ld)\n", wp.ptMinPosition.x, wp.ptMinPosition.y); + ok(wp.ptMaxPosition.x == work_rect.left && wp.ptMaxPosition.y == work_rect.top, + "got maximized pos (%ld,%ld)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y); + ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n", + wine_dbgstr_rect(&wp.rcNormalPosition)); + + SetWindowPos(hwnd, 0, work_rect.left, work_rect.top, work_rect.right - work_rect.left, + work_rect.bottom - work_rect.top - 1, SWP_NOZORDER | SWP_NOACTIVATE); + ret = GetWindowPlacement(hwnd, &wp); + ok(ret, "failed to get window placement, error %lu\n", GetLastError()); + ok(wp.showCmd == SW_SHOWMAXIMIZED, "got show cmd %u\n", wp.showCmd); + ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000, + "got minimized pos (%ld,%ld)\n", wp.ptMinPosition.x, wp.ptMinPosition.y); + ok(wp.ptMaxPosition.x == work_rect.left && wp.ptMaxPosition.y == work_rect.top, + "got maximized pos (%ld,%ld)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y); + ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n", + wine_dbgstr_rect(&wp.rcNormalPosition)); + + ShowWindow(hwnd, SW_MINIMIZE); + + ret = GetWindowPlacement(hwnd, &wp); + ok(ret, "failed to get window placement, error %lu\n", GetLastError()); + ok(wp.flags == WPF_RESTORETOMAXIMIZED, "got flags %#x\n", wp.flags); + ok(wp.showCmd == SW_SHOWMINIMIZED, "got show cmd %u\n", wp.showCmd); + ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000, + "got minimized pos (%ld,%ld)\n", wp.ptMinPosition.x, wp.ptMinPosition.y); + ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1, + "got maximized pos (%ld,%ld)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y); + ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n", + wine_dbgstr_rect(&wp.rcNormalPosition)); + + ShowWindow(hwnd, SW_RESTORE); + + ret = GetWindowPlacement(hwnd, &wp); + ok(ret, "failed to get window placement, error %lu\n", GetLastError()); + ok(wp.showCmd == SW_SHOWMAXIMIZED, "got show cmd %u\n", wp.showCmd); + ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000, + "got minimized pos (%ld,%ld)\n", wp.ptMinPosition.x, wp.ptMinPosition.y); + ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1, + "got maximized pos (%ld,%ld)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y); + ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n", + wine_dbgstr_rect(&wp.rcNormalPosition)); + + ShowWindow(hwnd, SW_RESTORE); + + ret = GetWindowPlacement(hwnd, &wp); + ok(ret, "failed to get window placement, error %lu\n", GetLastError()); + ok(wp.showCmd == SW_SHOWNORMAL, "got show cmd %u\n", wp.showCmd); + ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000, + "got minimized pos (%ld,%ld)\n", wp.ptMinPosition.x, wp.ptMinPosition.y); + ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1, + "got maximized pos (%ld,%ld)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y); + ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n", + wine_dbgstr_rect(&wp.rcNormalPosition)); + + wp.flags = WPF_SETMINPOSITION; + wp.ptMinPosition.x = wp.ptMinPosition.y = 100; + wp.ptMaxPosition.x = wp.ptMaxPosition.y = 100; + wp.rcNormalPosition = orig2; + ret = SetWindowPlacement(hwnd, &wp); + ok(ret, "failed to set window placement, error %lu\n", GetLastError()); + + ret = GetWindowPlacement(hwnd, &wp); + ok(ret, "failed to get window placement, error %lu\n", GetLastError()); + ok(wp.showCmd == SW_SHOWNORMAL, "got show cmd %u\n", wp.showCmd); + ok(wp.ptMinPosition.x == 100 && wp.ptMinPosition.y == 100, + "got minimized pos (%ld,%ld)\n", wp.ptMinPosition.x, wp.ptMinPosition.y); + ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1, + "got maximized pos (%ld,%ld)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y); + ok(EqualRect(&wp.rcNormalPosition, &orig2), "got normal pos %s\n", + wine_dbgstr_rect(&wp.rcNormalPosition)); + GetWindowRect(hwnd, &rect); + ok(EqualRect(&rect, &orig2), "got window rect %s\n", wine_dbgstr_rect(&rect)); + + ShowWindow(hwnd, SW_MINIMIZE); + + ret = GetWindowPlacement(hwnd, &wp); + ok(ret, "failed to get window placement, error %lu\n", GetLastError()); + ok(!wp.flags, "got flags %#x\n", wp.flags); + ok(wp.showCmd == SW_SHOWMINIMIZED, "got show cmd %u\n", wp.showCmd); + ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000, + "got minimized pos (%ld,%ld)\n", wp.ptMinPosition.x, wp.ptMinPosition.y); + ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1, + "got maximized pos (%ld,%ld)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y); + ok(EqualRect(&wp.rcNormalPosition, &orig2), "got normal pos %s\n", + wine_dbgstr_rect(&wp.rcNormalPosition)); + + ShowWindow(hwnd, SW_RESTORE); + + wp.flags = WPF_SETMINPOSITION; + wp.showCmd = SW_MINIMIZE; + wp.ptMinPosition.x = wp.ptMinPosition.y = 100; + wp.ptMaxPosition.x = wp.ptMaxPosition.y = 100; + wp.rcNormalPosition = orig; + ret = SetWindowPlacement(hwnd, &wp); + ok(ret, "failed to set window placement, error %lu\n", GetLastError()); + + ret = GetWindowPlacement(hwnd, &wp); + ok(ret, "failed to get window placement, error %lu\n", GetLastError()); + ok(!wp.flags, "got flags %#x\n", wp.flags); + ok(wp.showCmd == SW_SHOWMINIMIZED, "got show cmd %u\n", wp.showCmd); + ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000, + "got minimized pos (%ld,%ld)\n", wp.ptMinPosition.x, wp.ptMinPosition.y); + ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1, + "got maximized pos (%ld,%ld)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y); + ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n", + wine_dbgstr_rect(&wp.rcNormalPosition)); + + ShowWindow(hwnd, SW_RESTORE); + + wp.flags = WPF_SETMINPOSITION; + wp.showCmd = SW_MAXIMIZE; + wp.ptMinPosition.x = wp.ptMinPosition.y = 100; + wp.ptMaxPosition.x = wp.ptMaxPosition.y = 100; + wp.rcNormalPosition = orig; + ret = SetWindowPlacement(hwnd, &wp); + ok(ret, "failed to set window placement, error %lu\n", GetLastError()); + + ret = GetWindowPlacement(hwnd, &wp); + ok(ret, "failed to get window placement, error %lu\n", GetLastError()); + ok(wp.showCmd == SW_SHOWMAXIMIZED, "got show cmd %u\n", wp.showCmd); + ok(wp.ptMinPosition.x == 100 && wp.ptMinPosition.y == 100, + "got minimized pos (%ld,%ld)\n", wp.ptMinPosition.x, wp.ptMinPosition.y); + ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1, + "got maximized pos (%ld,%ld)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y); + ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n", + wine_dbgstr_rect(&wp.rcNormalPosition)); + + wp.flags = WPF_SETMINPOSITION; + wp.showCmd = SW_NORMAL; + wp.ptMinPosition.x = wp.ptMinPosition.y = 100; + wp.ptMaxPosition.x = wp.ptMaxPosition.y = 100; + wp.rcNormalPosition = orig; + ret = SetWindowPlacement(hwnd, &wp); + ok(ret, "failed to set window placement, error %lu\n", GetLastError()); + + ShowWindow(hwnd, SW_MINIMIZE); + + ret = GetWindowPlacement(hwnd, &wp); + ok(ret, "failed to get window placement, error %lu\n", GetLastError()); + ok(wp.showCmd == SW_SHOWMINIMIZED, "got show cmd %u\n", wp.showCmd); + ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000, + "got minimized pos (%ld,%ld)\n", wp.ptMinPosition.x, wp.ptMinPosition.y); + ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1, + "got maximized pos (%ld,%ld)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y); + ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n", + wine_dbgstr_rect(&wp.rcNormalPosition)); + + ret = SetWindowPos(hwnd, NULL, 100, 100, 151, 151, SWP_NOACTIVATE | SWP_NOZORDER); + ok(ret, "failed to set window pos, error %lu\n", GetLastError()); + + ret = GetWindowPlacement(hwnd, &wp); + ok(ret, "failed to get window placement, error %lu\n", GetLastError()); + ok(wp.showCmd == SW_SHOWMINIMIZED, "got show cmd %u\n", wp.showCmd); + ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000, + "got minimized pos (%ld,%ld)\n", wp.ptMinPosition.x, wp.ptMinPosition.y); + ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1, + "got maximized pos (%ld,%ld)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y); + ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n", + wine_dbgstr_rect(&wp.rcNormalPosition)); + GetWindowRect(hwnd, &rect); + ok(rect.left == -32000 && rect.top == -32000, "got window rect %s\n", wine_dbgstr_rect(&rect)); + + ShowWindow(hwnd, SW_SHOWNORMAL); + + ret = GetWindowPlacement(hwnd, &wp); + ok(ret, "failed to get window placement, error %lu\n", GetLastError()); + ok(wp.showCmd == SW_NORMAL, "got show cmd %u\n", wp.showCmd); + ok(wp.ptMinPosition.x == -32000 && wp.ptMinPosition.y == -32000, + "got minimized pos (%ld,%ld)\n", wp.ptMinPosition.x, wp.ptMinPosition.y); + ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1, + "got maximized pos (%ld,%ld)\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y); + ok(EqualRect(&wp.rcNormalPosition, &orig), "got normal pos %s\n", + wine_dbgstr_rect(&wp.rcNormalPosition)); + GetWindowRect(hwnd, &rect); + ok(EqualRect(&rect, &orig), "got window rect %s\n", wine_dbgstr_rect(&rect)); + + ret = SetWindowPlacement(hwnd, &wp); + ok(ret, "failed to set window placement, error %lu\n", GetLastError()); + + wp.length = 0; + SetLastError(0xdeadbeef); + ret = SetWindowPlacement(hwnd, &wp); + ok(!ret, "SetWindowPlacement should have failed\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError()); + + DestroyWindow(hwnd); +} + +static void test_arrange_iconic_windows(void) +{ + MINIMIZEDMETRICS mm = {sizeof(mm)}, oldmm = {sizeof(oldmm)}; + RECT orig = {100, 200, 300, 400}, rect, expect, parent_rect; + POINT pt = {0}; + HWND parent, hwnds[10]; + UINT ret; + int i, row, col; + + parent = CreateWindowA("MainWindowClass", "parent", WS_OVERLAPPEDWINDOW, + 100, 200, 500, 300, NULL, 0, 0, NULL); + ok(!!parent, "failed to create window, error %lu\n", GetLastError()); + + GetClientRect(parent, &parent_rect); + ClientToScreen(parent, &pt); + SystemParametersInfoA(SPI_GETMINIMIZEDMETRICS, sizeof(oldmm), &oldmm, 0); + + mm.iWidth = 100; + mm.iHorzGap = 40; + mm.iVertGap = 3; + mm.iArrange = ARW_TOPLEFT | ARW_RIGHT; + ret = SystemParametersInfoA(SPI_SETMINIMIZEDMETRICS, sizeof(mm), &mm, 0); + ok(ret, "failed to set minimized metrics, error %lu\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = ArrangeIconicWindows(parent); + ok(!ret, "wrong ret %u\n", ret); + ok(GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError()); + + for (i = 0; i < ARRAY_SIZE(hwnds); ++i) + { + hwnds[i] = CreateWindowA("MainWindowClass", "child", WS_CHILD | + WS_OVERLAPPEDWINDOW, orig.left, orig.top, orig.right - orig.left, + orig.bottom - orig.top, parent, 0, 0, NULL); + ok(!!hwnds[i], "failed to create window %u, error %lu\n", i, GetLastError()); + } + + SetLastError(0xdeadbeef); + ret = ArrangeIconicWindows(parent); + ok(!ret, "wrong ret %u\n", ret); + ok(GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError()); + + for (i = 0; i < ARRAY_SIZE(hwnds); ++i) + { + GetWindowRect(hwnds[i], &rect); + expect = orig; + OffsetRect(&expect, pt.x, pt.y); + ok(EqualRect(&rect, &expect), "hwnd %u: expected rect %s, got %s\n", i, + wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + } + + ShowWindow(hwnds[0], SW_MINIMIZE); + + for (i = 0; i < ARRAY_SIZE(hwnds); ++i) + { + ret = SetWindowPos(hwnds[i], 0, orig.left, orig.top, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + ok(ret, "hwnd %u: failed to move window, error %lu\n", i, GetLastError()); + } + + ret = ArrangeIconicWindows(parent); + ok(ret == 1, "wrong ret %u\n", ret); + + GetWindowRect(hwnds[0], &rect); + SetRect(&expect, 0, 0, GetSystemMetrics(SM_CXMINIMIZED), GetSystemMetrics(SM_CYMINIMIZED)); + OffsetRect(&expect, mm.iHorzGap, mm.iVertGap); + OffsetRect(&expect, pt.x, pt.y); + ok(EqualRect(&rect, &expect), "expected rect %s, got %s\n", + wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + + for (i = 1; i < ARRAY_SIZE(hwnds); ++i) + { + GetWindowRect(hwnds[i], &rect); + expect = orig; + OffsetRect(&expect, pt.x, pt.y); + ok(EqualRect(&rect, &expect), "hwnd %u: expected rect %s, got %s\n", i, + wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + } + + for (i = 0; i < ARRAY_SIZE(hwnds); ++i) + { + ShowWindow(hwnds[i], SW_MINIMIZE); + ret = SetWindowPos(hwnds[i], 0, orig.left, orig.top, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + ok(ret, "hwnd %u: failed to move window, error %lu\n", i, GetLastError()); + } + + ret = ArrangeIconicWindows(parent); + ok(ret == 10, "wrong ret %u\n", ret); + + col = mm.iHorzGap; + row = mm.iVertGap; + for (i = 0; i < ARRAY_SIZE(hwnds); ++i) + { + if (col + GetSystemMetrics(SM_CXMINIMIZED) > parent_rect.right - parent_rect.left) + { + col = mm.iHorzGap; + row += GetSystemMetrics(SM_CYMINIMIZED) + mm.iVertGap; + } + + GetWindowRect(hwnds[i], &rect); + SetRect(&expect, col, row, col + GetSystemMetrics(SM_CXMINIMIZED), + row + GetSystemMetrics(SM_CYMINIMIZED)); + OffsetRect(&expect, pt.x, pt.y); + ok(EqualRect(&rect, &expect), "hwnd %u: expected rect %s, got %s\n", i, + wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + + col += GetSystemMetrics(SM_CXMINIMIZED) + mm.iHorzGap; + } + + mm.iArrange = ARW_BOTTOMRIGHT | ARW_UP; + mm.iVertGap = 10; + ret = SystemParametersInfoA(SPI_SETMINIMIZEDMETRICS, sizeof(mm), &mm, 0); + ok(ret, "failed to set minimized metrics, error %lu\n", GetLastError()); + + for (i = 0; i < ARRAY_SIZE(hwnds); ++i) + { + ret = SetWindowPos(hwnds[i], 0, orig.left, orig.top, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + ok(ret, "hwnd %u: failed to move window, error %lu\n", i, GetLastError()); + } + + ret = ArrangeIconicWindows(parent); + ok(ret == 10, "wrong ret %u\n", ret); + + col = parent_rect.right - mm.iHorzGap; + row = parent_rect.bottom - mm.iVertGap; + for (i = 0; i < ARRAY_SIZE(hwnds); ++i) + { + if (row - GetSystemMetrics(SM_CYMINIMIZED) < parent_rect.top) + { + row = parent_rect.bottom - mm.iVertGap; + col -= GetSystemMetrics(SM_CXMINIMIZED) + mm.iHorzGap; + } + + GetWindowRect(hwnds[i], &rect); + SetRect(&expect, col - GetSystemMetrics(SM_CXMINIMIZED), + row - GetSystemMetrics(SM_CYMINIMIZED), col, row); + OffsetRect(&expect, pt.x, pt.y); + ok(EqualRect(&rect, &expect), "hwnd %u: expected rect %s, got %s\n", i, + wine_dbgstr_rect(&expect), wine_dbgstr_rect(&rect)); + + row -= GetSystemMetrics(SM_CYMINIMIZED) + mm.iVertGap; + } + + for (i = 0; i < ARRAY_SIZE(hwnds); ++i) + DestroyWindow(hwnds[i]); + DestroyWindow(parent); + + ret = SystemParametersInfoA(SPI_SETMINIMIZEDMETRICS, sizeof(oldmm), &oldmm, 0); + ok(ret, "failed to restore minimized metrics, error %lu\n", GetLastError()); +} + +static void other_process_proc(HWND hwnd) +{ + HANDLE window_ready_event, test_done_event; + WINDOWPLACEMENT wp = {0}; + DWORD ret; + + window_ready_event = OpenEventA(EVENT_ALL_ACCESS, FALSE, "test_opw_window"); + ok(!!window_ready_event, "OpenEvent failed.\n"); + test_done_event = OpenEventA(EVENT_ALL_ACCESS, FALSE, "test_opw_test"); + ok(!!test_done_event, "OpenEvent failed.\n"); + + /* SW_SHOW */ + ret = WaitForSingleObject(window_ready_event, 5000); + ok(ret == WAIT_OBJECT_0, "Unexpected ret %lx.\n", ret); + ret = GetWindowPlacement(hwnd, &wp); + ok(ret, "Unexpected ret %#lx.\n", ret); + ok(wp.showCmd == SW_SHOWNORMAL, "Unexpected showCmd %#x.\n", wp.showCmd); + ok(!wp.flags, "Unexpected flags %#x.\n", wp.flags); + SetEvent(test_done_event); + + /* SW_SHOWMAXIMIZED */ + ret = WaitForSingleObject(window_ready_event, 5000); + ok(ret == WAIT_OBJECT_0, "Unexpected ret %lx.\n", ret); + ret = GetWindowPlacement(hwnd, &wp); + ok(ret, "Unexpected ret %#lx.\n", ret); + ok(wp.showCmd == SW_SHOWMAXIMIZED, "Unexpected showCmd %#x.\n", wp.showCmd); + todo_wine ok(wp.flags == WPF_RESTORETOMAXIMIZED, "Unexpected flags %#x.\n", wp.flags); + SetEvent(test_done_event); + + /* SW_SHOWMINIMIZED */ + ret = WaitForSingleObject(window_ready_event, 5000); + ok(ret == WAIT_OBJECT_0, "Unexpected ret %lx.\n", ret); + ret = GetWindowPlacement(hwnd, &wp); + ok(ret, "Unexpected ret %#lx.\n", ret); + ok(wp.showCmd == SW_SHOWMINIMIZED, "Unexpected showCmd %#x.\n", wp.showCmd); + todo_wine ok(wp.flags == WPF_RESTORETOMAXIMIZED, "Unexpected flags %#x.\n", wp.flags); + SetEvent(test_done_event); + + /* SW_RESTORE */ + ret = WaitForSingleObject(window_ready_event, 5000); + ok(ret == WAIT_OBJECT_0, "Unexpected ret %lx.\n", ret); + ret = GetWindowPlacement(hwnd, &wp); + ok(ret, "Unexpected ret %#lx.\n", ret); + ok(wp.showCmd == SW_SHOWMAXIMIZED, "Unexpected showCmd %#x.\n", wp.showCmd); + todo_wine ok(wp.flags == WPF_RESTORETOMAXIMIZED, "Unexpected flags %#x.\n", wp.flags); + SetEvent(test_done_event); + + CloseHandle(window_ready_event); + CloseHandle(test_done_event); +} + +static void test_SC_SIZE(void) +{ + HWND hwnd; + RECT rect; + MSG msg; + + hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE, + 100, 100, 100, 100, 0, 0, NULL, NULL); + ok(!!hwnd, "CreateWindowEx failed.\n"); + + GetWindowRect(hwnd, &rect); + ok(rect.left == 100, "rect.left = %ld\n", rect.left); + ok(rect.top == 100, "rect.top = %ld\n", rect.top); + ok(rect.right == 200, "rect.right = %ld\n", rect.right); + ok(rect.bottom == 200, "rect.bottom = %ld\n", rect.bottom); + + SetCursorPos(100, 100); + PostMessageA(hwnd, WM_SYSCOMMAND, SC_SIZE | 9, MAKELONG(100, 100)); + SetCursorPos(110, 100); + PostMessageA(hwnd, WM_MOUSEMOVE, 0, MAKELONG(110, 100)); + PostMessageA(hwnd, WM_KEYDOWN, VK_RETURN, 0); + + while (GetMessageA(&msg, 0, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessageA(&msg); + + if (msg.message == WM_SYSCOMMAND) break; + } + + GetWindowRect(hwnd, &rect); + ok(rect.left == 110, "rect.left = %ld\n", rect.left); + ok(rect.top == 100, "rect.top = %ld\n", rect.top); + ok(rect.right == 210, "rect.right = %ld\n", rect.right); + ok(rect.bottom == 200, "rect.bottom = %ld\n", rect.bottom); + + DestroyWindow(hwnd); +} + +static void test_other_process_window(const char *argv0) +{ + HANDLE window_ready_event, test_done_event; + PROCESS_INFORMATION info; + STARTUPINFOA startup; + char cmd[MAX_PATH]; + HWND hwnd; + BOOL ret; + + hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, + 100, 100, 100, 100, 0, 0, NULL, NULL); + ok(!!hwnd, "CreateWindowEx failed.\n"); + + window_ready_event = CreateEventA(NULL, FALSE, FALSE, "test_opw_window"); + ok(!!window_ready_event, "CreateEvent failed.\n"); + test_done_event = CreateEventA(NULL, FALSE, FALSE, "test_opw_test"); + ok(!!test_done_event, "CreateEvent failed.\n"); + + sprintf(cmd, "%s win test_other_process_window %p", argv0, hwnd); + memset(&startup, 0, sizeof(startup)); + startup.cb = sizeof(startup); + + ok(CreateProcessA(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, + &startup, &info), "CreateProcess failed.\n"); + + ret = ShowWindow(hwnd, SW_SHOW); + ok(!ret, "Unexpected ret %#x.\n", ret); + SetEvent(window_ready_event); + ret = WaitForSingleObject(test_done_event, 5000); + ok(ret == WAIT_OBJECT_0, "Unexpected ret %x.\n", ret); + + ret = ShowWindow(hwnd, SW_SHOWMAXIMIZED); + ok(ret, "Unexpected ret %#x.\n", ret); + SetEvent(window_ready_event); + ret = WaitForSingleObject(test_done_event, 5000); + ok(ret == WAIT_OBJECT_0, "Unexpected ret %x.\n", ret); + + ret = ShowWindow(hwnd, SW_SHOWMINIMIZED); + ok(ret, "Unexpected ret %#x.\n", ret); + SetEvent(window_ready_event); + ret = WaitForSingleObject(test_done_event, 5000); + ok(ret == WAIT_OBJECT_0, "Unexpected ret %x.\n", ret); + + ret = ShowWindow(hwnd, SW_RESTORE); + ok(ret, "Unexpected ret %#x.\n", ret); + SetEvent(window_ready_event); + ret = WaitForSingleObject(test_done_event, 5000); + ok(ret == WAIT_OBJECT_0, "Unexpected ret %x.\n", ret); + + wait_child_process(info.hProcess); + CloseHandle(window_ready_event); + CloseHandle(test_done_event); + CloseHandle(info.hProcess); + CloseHandle(info.hThread); + DestroyWindow(hwnd); +} + +static void test_cancel_mode(void) +{ + HWND hwnd1, hwnd2, child; + LRESULT ret; + + hwnd1 = CreateWindowA("MainWindowClass", "window 1", WS_OVERLAPPEDWINDOW, + 100, 200, 500, 300, NULL, NULL, NULL, NULL); + hwnd2 = CreateWindowA("MainWindowClass", "window 2", WS_OVERLAPPEDWINDOW, + 100, 200, 500, 300, NULL, NULL, NULL, NULL); + flush_events(TRUE); + SetCapture(hwnd1); + ok(GetCapture() == hwnd1, "got capture %p\n", GetCapture()); + + ret = SendMessageA(hwnd2, WM_CANCELMODE, 0, 0); + ok(!ret, "got %Id\n", ret); + ok(GetCapture() == hwnd1, "got capture %p\n", GetCapture()); + + ret = SendMessageA(hwnd1, WM_CANCELMODE, 0, 0); + ok(!ret, "got %Id\n", ret); + ok(!GetCapture(), "got capture %p\n", GetCapture()); + + child = CreateWindowA("MainWindowClass", "child", WS_CHILD, + 0, 0, 100, 100, hwnd1, NULL, NULL, NULL); + + SetCapture(child); + ok(GetCapture() == child, "got capture %p\n", GetCapture()); + + ret = SendMessageA(hwnd2, WM_CANCELMODE, 0, 0); + ok(!ret, "got %Id\n", ret); + ok(GetCapture() == child, "got capture %p\n", GetCapture()); + + ret = SendMessageA(hwnd1, WM_CANCELMODE, 0, 0); + ok(!ret, "got %Id\n", ret); + ok(GetCapture() == child, "got capture %p\n", GetCapture()); + + ret = SendMessageA(child, WM_CANCELMODE, 0, 0); + ok(!ret, "got %Id\n", ret); + ok(!GetCapture(), "got capture %p\n", GetCapture()); + + DestroyWindow(child); + DestroyWindow(hwnd1); + DestroyWindow(hwnd2); +} + +static void test_DragDetect(void) +{ + int cx_drag = GetSystemMetrics( SM_CXDRAG ), cy_drag = GetSystemMetrics( SM_CYDRAG ); + HWND hwnd; + POINT pt; + BOOL ret; + + ok(!GetCapture(), "got capture window %p\n", GetCapture()); + ok(!(GetKeyState( VK_LBUTTON ) & 0x8000), "got VK_LBUTTON\n"); + + GetCursorPos(&pt); + ret = DragDetect(hwndMain, pt); + ok(!ret, "got %d\n", ret); + + ok(!GetCapture(), "got capture window %p\n", GetCapture()); + ok(!(GetKeyState( VK_LBUTTON ) & 0x8000), "got VK_LBUTTON\n"); + + /* Test mouse moving out of the drag rectangle in client coordinates */ + hwnd = CreateWindowA( "static", "test", WS_POPUP | WS_VISIBLE, 100, 100, 50, 50, 0, 0, 0, 0 ); + hold_key( VK_LBUTTON ); + + PostMessageA( hwnd, WM_MOUSEMOVE, MK_LBUTTON, MAKELPARAM(cx_drag, cy_drag) ); + + pt.x = 0; + pt.y = 0; + ret = DragDetect( hwnd, pt ); + ok(ret, "Got unexpected %d.\n", ret); + flush_events( TRUE ); + + /* Test mouse not moving out of the drag rectangle in client coordinates */ + PostMessageA( hwnd, WM_MOUSEMOVE, MK_LBUTTON, MAKELPARAM(cx_drag - 1, cy_drag - 1) ); + PostMessageA( hwnd, WM_LBUTTONUP, 0, 0 ); + + pt.x = 0; + pt.y = 0; + ret = DragDetect( hwnd, pt ); + ok(!ret || broken(ret) /* Win 7 */, "Got unexpected %d\n", ret); + flush_events( TRUE ); + + /* Test mouse moving out of the drag rectangle in screen coordinates */ + PostMessageA( hwnd, WM_MOUSEMOVE, MK_LBUTTON, MAKELPARAM(cx_drag, cy_drag) ); + + pt.x = 0; + pt.y = 0; + ClientToScreen( hwnd, &pt ); + ret = DragDetect( hwnd, pt ); + ok(ret || broken(!ret) /* Win 7 */, "Got unexpected %d\n", ret); + flush_events( TRUE ); + + /* Test mouse not moving out of the drag rectangle in screen coordinates */ + PostMessageA( hwnd, WM_MOUSEMOVE, MK_LBUTTON, MAKELPARAM(0, 0) ); + + pt.x = 0; + pt.y = 0; + ClientToScreen( hwnd, &pt ); + ret = DragDetect( hwnd, pt ); + /* NOTE that if DragDetect() do use screen coordinates for the second parameter for the initial + * mouse position, then FALSE should be returned in this case. But TRUE is returned here. So + * this means that DragDetect() don't use screen coordinates even though MSDN says that it does */ + ok(ret, "Got unexpected %d\n", ret); + + DestroyWindow( hwnd ); + release_key( VK_LBUTTON ); +} + +static LRESULT WINAPI ncdestroy_test_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) +{ + unsigned int ret; + HWND parent, child; + RECT rect, exp; + + switch (msg) + { + case WM_NCDESTROY: + SetLastError( 0xdeadbeef ); + ret = SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 100, 100, SWP_NOSIZE|SWP_NOMOVE ); + todo_wine + ok( !ret, "SetWindowPos succeeded\n" ); + todo_wine + ok( GetLastError() == ERROR_INVALID_PARAMETER, "SetWindowPos returned error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + parent = SetParent( hwnd, hwndMain ); + ok( parent == 0, "SetParent returned %p\n", parent ); +#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 = GetWindowRect( hwnd, &rect ); + ok( ret, "GetWindowRect failed: %lu\n", GetLastError() ); + SetRect( &exp, 10, 20, 110, 220 ); + ok( EqualRect( &rect, &exp ), "unexpected rect %s, expected %s\n", wine_dbgstr_rect( &rect ), + wine_dbgstr_rect( &exp )); + + ret = MoveWindow( hwnd, 11, 12, 20, 30, FALSE ); + ok( ret, "MoveWindow failed: %lu\n", GetLastError() ); + ret = GetWindowRect( hwnd, &rect ); + ok( ret, "GetWindowRect failed: %lu\n", GetLastError() ); + SetRect( &exp, 11, 12, 31, 42 ); + ok( EqualRect( &rect, &exp ), "unexpected rect %s, expected %s\n", wine_dbgstr_rect( &rect ), + wine_dbgstr_rect( &exp )); + + child = CreateWindowExA( 0, "ToolWindowClass", "Tool window 1", WS_CHILD, + 0, 0, 100, 100, hwnd, 0, 0, NULL ); +#ifdef __REACTOS__ + ok( GetLastError() == ERROR_INVALID_PARAMETER /* MSVC test builds return child, GCC test builds don't on Windows */ + || broken(child && GetLastError() == ERROR_SUCCESS) /* WS03 */, + "CreateWindowExA returned %p %lu\n", child, GetLastError() ); +#else + ok( !child && GetLastError() == ERROR_INVALID_PARAMETER, + "CreateWindowExA returned %p %lu\n", child, GetLastError() ); +#endif + break; + } + + return DefWindowProcW( hwnd, msg, wp, lp ); +} + +static void test_ncdestroy(void) +{ + HWND hwnd; + hwnd = create_tool_window( WS_POPUP, 0 ); + SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)ncdestroy_test_proc ); + MoveWindow( hwnd, 10, 20, 100, 200, FALSE ); + DestroyWindow(hwnd); +} + +static void test_WM_NCCALCSIZE(void) +{ + WNDCLASSA cls; + HWND hwnd; + NCCALCSIZE_PARAMS params; + WINDOWPOS winpos; + RECT client_rect, window_rect; + LRESULT ret; + + cls.style = CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW; + cls.lpfnWndProc = DefWindowProcA; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = GetModuleHandleA(0); + cls.hIcon = 0; + cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); + cls.hbrBackground = GetStockObject(WHITE_BRUSH); + cls.lpszMenuName = NULL; + cls.lpszClassName = "dummy_window_class"; + ret = RegisterClassA(&cls); + ok(ret, "RegisterClass error %lu\n", GetLastError()); + + hwnd = CreateWindowExA(0, "dummy_window_class", NULL, + WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP, + 100, 100, 200, 200, 0, 0, GetModuleHandleA(NULL), NULL); + ok(hwnd != 0, "CreateWindowEx error %lu\n", GetLastError()); + + GetWindowRect(hwnd, &window_rect); + params.rgrc[0] = window_rect; + params.rgrc[1] = window_rect; + GetClientRect(hwnd, &client_rect); + MapWindowPoints(hwnd, 0, (POINT *)&client_rect, 2); + params.rgrc[2] = client_rect; + + winpos.hwnd = hwnd; + winpos.hwndInsertAfter = HWND_TOP; + winpos.x = window_rect.left; + winpos.y = window_rect.top; + winpos.cx = window_rect.right - window_rect.left; + winpos.cy = window_rect.bottom - window_rect.top; + winpos.flags = SWP_NOMOVE; + params.lppos = &winpos; + + ret = SendMessageW(hwnd, WM_NCCALCSIZE, TRUE, (LPARAM)¶ms); + ok(!ret, "got %08Ix\n", ret); + ok(EqualRect(¶ms.rgrc[0], &client_rect), "got %s\n", wine_dbgstr_rect(¶ms.rgrc[0])); + + params.rgrc[0] = window_rect; + ret = DefWindowProcA(hwnd, WM_NCCALCSIZE, TRUE, (LPARAM)¶ms); + ok(!ret, "got %08Ix\n", ret); + ok(EqualRect(¶ms.rgrc[0], &client_rect), "got %s\n", wine_dbgstr_rect(¶ms.rgrc[0])); + + GetWindowRect(hwnd, &window_rect); + ret = SendMessageW(hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&window_rect); + ok(!ret, "got %08Ix\n", ret); + ok(EqualRect(&window_rect, &client_rect), "got %s\n", wine_dbgstr_rect(&window_rect)); + + GetWindowRect(hwnd, &window_rect); + ret = DefWindowProcA(hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&window_rect); + ok(!ret, "got %08Ix\n", ret); + ok(EqualRect(&window_rect, &client_rect), "got %s\n", wine_dbgstr_rect(&window_rect)); + + DestroyWindow(hwnd); +} + +#define TRAY_MINIMIZE_ALL 419 +#define TRAY_MINIMIZE_ALL_UNDO 416 + +static void test_shell_tray(void) +{ + HWND hwnd, traywnd; + + if (!(traywnd = FindWindowA( "Shell_TrayWnd", NULL ))) + { + skip( "Shell_TrayWnd not found, skipping tests.\n" ); + return; + } + + hwnd = CreateWindowW( L"static", L"parent", WS_OVERLAPPEDWINDOW|WS_VISIBLE, + 100, 100, 200, 200, 0, 0, 0, NULL ); + ok( !!hwnd, "failed, error %lu.\n", GetLastError() ); + flush_events( TRUE ); + + ok( !IsIconic( hwnd ), "window is minimized.\n" ); + + SendMessageA( traywnd, WM_COMMAND, TRAY_MINIMIZE_ALL, 0xdeadbeef ); + flush_events( TRUE ); + todo_wine ok( IsIconic( hwnd ), "window is not minimized.\n" ); + + SendMessageA( traywnd, WM_COMMAND, TRAY_MINIMIZE_ALL_UNDO, 0xdeadbeef ); + flush_events( TRUE ); + ok( !IsIconic( hwnd ), "window is minimized.\n" ); + + DestroyWindow(hwnd); +} + +static int wm_mousemove_count; +static BOOL do_release_capture; + +static LRESULT WINAPI test_ReleaseCapture_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) +{ + if (msg == WM_MOUSEMOVE) + { + wm_mousemove_count++; + if (wm_mousemove_count >= 100) + return 1; + + if (do_release_capture) + ReleaseCapture(); + return 0; + } + return DefWindowProcA(hwnd, msg, wp, lp); +} + +static void test_ReleaseCapture(void) +{ + WNDCLASSA cls = {0}; + ATOM atom; + HWND hwnd; + POINT pt; + BOOL ret; + + cls.lpfnWndProc = test_ReleaseCapture_proc; + cls.hInstance = GetModuleHandleA(0); + cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); + cls.hbrBackground = GetStockObject(BLACK_BRUSH); + cls.lpszClassName = "test_ReleaseCapture_class"; + atom = RegisterClassA(&cls); + ok(!!atom, "RegisterClassA failed, error %#lx.\n", GetLastError()); + + hwnd = CreateWindowExA(WS_EX_TOPMOST, cls.lpszClassName, "", WS_POPUP | WS_VISIBLE, 100, 100, + 100, 100, NULL, NULL, 0, NULL); + ok(!!hwnd, "CreateWindowA failed, error %#lx.\n", GetLastError()); + ret = SetForegroundWindow(hwnd); + ok(ret, "SetForegroundWindow failed, error %#lx.\n", GetLastError()); + GetCursorPos(&pt); + ret = SetCursorPos(150, 150); + ok(ret, "SetCursorPos failed, error %#lx.\n", GetLastError()); + flush_events(TRUE); + + /* Test a Wine bug that WM_MOUSEMOVE is post too many times when calling ReleaseCapture() during + * handling WM_MOUSEMOVE and the cursor is on the window */ + do_release_capture = TRUE; + ret = ReleaseCapture(); + ok(ret, "ReleaseCapture failed, error %#lx.\n", GetLastError()); + flush_events(TRUE); + do_release_capture = FALSE; + ok(wm_mousemove_count < 10, "Got too many WM_MOUSEMOVE.\n"); + + /* Test that ReleaseCapture() should send a WM_MOUSEMOVE if a window is captured */ + SetCapture(hwnd); + wm_mousemove_count = 0; + ret = ReleaseCapture(); + ok(ret, "ReleaseCapture failed, error %#lx.\n", GetLastError()); + flush_events(TRUE); + ok(wm_mousemove_count == 1, "Got no WM_MOUSEMOVE.\n"); + + /* Test that ReleaseCapture() shouldn't send WM_MOUSEMOVE if no window is captured */ + wm_mousemove_count = 0; + ret = ReleaseCapture(); + ok(ret, "ReleaseCapture failed, error %#lx.\n", GetLastError()); + flush_events(TRUE); + ok(wm_mousemove_count == 0, "Got WM_MOUSEMOVE.\n"); + + ret = SetCursorPos(pt.x, pt.y); + ok(ret, "SetCursorPos failed, error %#lx.\n", GetLastError()); + DestroyWindow(hwnd); + UnregisterClassA(cls.lpszClassName, GetModuleHandleA(0)); } START_TEST(win) @@ -9408,37 +13531,51 @@ START_TEST(win) int argc = winetest_get_mainargs( &argv ); HMODULE user32 = GetModuleHandleA( "user32.dll" ); HMODULE gdi32 = GetModuleHandleA("gdi32.dll"); - pGetAncestor = (void *)GetProcAddress( user32, "GetAncestor" ); pGetWindowInfo = (void *)GetProcAddress( user32, "GetWindowInfo" ); pGetWindowModuleFileNameA = (void *)GetProcAddress( user32, "GetWindowModuleFileNameA" ); pGetLayeredWindowAttributes = (void *)GetProcAddress( user32, "GetLayeredWindowAttributes" ); pSetLayeredWindowAttributes = (void *)GetProcAddress( user32, "SetLayeredWindowAttributes" ); pUpdateLayeredWindow = (void *)GetProcAddress( user32, "UpdateLayeredWindow" ); pUpdateLayeredWindowIndirect = (void *)GetProcAddress( user32, "UpdateLayeredWindowIndirect" ); - pGetMonitorInfoA = (void *)GetProcAddress( user32, "GetMonitorInfoA" ); - pMonitorFromPoint = (void *)GetProcAddress( user32, "MonitorFromPoint" ); pGetWindowRgnBox = (void *)GetProcAddress( user32, "GetWindowRgnBox" ); pGetGUIThreadInfo = (void *)GetProcAddress( user32, "GetGUIThreadInfo" ); pGetProcessDefaultLayout = (void *)GetProcAddress( user32, "GetProcessDefaultLayout" ); pSetProcessDefaultLayout = (void *)GetProcAddress( user32, "SetProcessDefaultLayout" ); pFlashWindow = (void *)GetProcAddress( user32, "FlashWindow" ); pFlashWindowEx = (void *)GetProcAddress( user32, "FlashWindowEx" ); - pGetLayout = (void *)GetProcAddress( gdi32, "GetLayout" ); - pSetLayout = (void *)GetProcAddress( gdi32, "SetLayout" ); pMirrorRgn = (void *)GetProcAddress( gdi32, "MirrorRgn" ); + pGetWindowDisplayAffinity = (void *)GetProcAddress( user32, "GetWindowDisplayAffinity" ); + pSetWindowDisplayAffinity = (void *)GetProcAddress( user32, "SetWindowDisplayAffinity" ); + pAdjustWindowRectExForDpi = (void *)GetProcAddress( user32, "AdjustWindowRectExForDpi" ); + pSystemParametersInfoForDpi = (void *)GetProcAddress( user32, "SystemParametersInfoForDpi" ); + pInternalGetWindowIcon = (void *)GetProcAddress( user32, "InternalGetWindowIcon" ); - if (argc==4 && !strcmp(argv[2], "create_children")) + if (argc == 4) { HWND hwnd; sscanf(argv[3], "%p", &hwnd); - window_from_point_proc(hwnd); + if (!strcmp(argv[2], "create_children")) + { + window_from_point_proc(hwnd); + return; + } + else if (!strcmp(argv[2], "test_other_process_window")) + { + other_process_proc(hwnd); + return; + } + } + + if (argc == 3 && !strcmp(argv[2], "winproc_limit")) + { + test_winproc_limit(); return; } - if (argc==3 && !strcmp(argv[2], "winproc_limit")) + if (argc == 4 && !strcmp( argv[2], "SetActiveWindow_0" )) { - test_winproc_limit(); + test_SetActiveWindow_0_proc( argv ); return; } @@ -9459,13 +13596,13 @@ START_TEST(win) SetLastError(0xdeafbeef); GetWindowLongPtrW(GetDesktopWindow(), GWLP_WNDPROC); - is_win9x = (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED); hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId()); if (!hhook) win_skip( "Cannot set CBT hook, skipping some tests\n" ); /* make sure that these tests are executed first */ test_FindWindowEx(); + test_FindWindow(); test_SetParent(); hwndMain2 = CreateWindowExA(/*WS_EX_TOOLWINDOW*/ 0, "MainWindowClass", "Main window 2", @@ -9477,12 +13614,17 @@ START_TEST(win) our_pid = GetWindowThreadProcessId(hwndMain, NULL); + /* This test is sensitive to other windows created with + * CW_USEDEFAULT position, execute it early too */ + test_mdi(); + /* Add the tests below this line */ test_child_window_from_point(); - test_window_from_point(argv[0]); + test_window_from_point(hwndMain, argv[0]); test_thick_child_size(hwndMain); test_fullscreen(); test_hwnd_message(); + test_message_window_topmost(); test_nonclient_area(hwndMain); test_params(); test_GetWindowModuleFileName(); @@ -9497,12 +13639,14 @@ START_TEST(win) test_CreateWindow(); test_parent_owner(); test_enum_thread_windows(); + test_thread_exit_destroy(); + test_ncdestroy(); - test_mdi(); test_icons(); test_SetWindowPos(hwndMain, hwndMain2); test_SetMenu(hwndMain); test_SetFocus(hwndMain); + test_SetActiveWindow_0( argv ); test_SetActiveWindow(hwndMain); test_NCRedraw(); @@ -9530,13 +13674,16 @@ START_TEST(win) test_SetWindowLong(); test_set_window_style(); test_ShowWindow(); + test_ShowWindow_owned(hwndMain); + test_ShowWindow_child(hwndMain); + test_ShowWindow_mdichild(hwndMain); + test_EnableWindow(); test_gettext(); test_GetUpdateRect(); test_Expose(); test_layered_window(); test_SetForegroundWindow(hwndMain); - test_shell_window(); test_handles( hwndMain ); test_winregion(); test_map_points(); @@ -9544,14 +13691,37 @@ START_TEST(win) test_window_without_child_style(); test_smresult(); test_GetMessagePos(); - test_activateapp(hwndMain); test_winproc_handles(argv[0]); test_deferwindowpos(); + test_LockWindowUpdate(hwndMain); + test_desktop(); + test_display_affinity(hwndMain); + test_hide_window(); + test_minimize_window(hwndMain); + test_destroy_quit(); + test_IsWindowEnabled(); + test_window_placement(); + test_arrange_iconic_windows(); + test_other_process_window(argv[0]); + test_SC_SIZE(); + test_cancel_mode(); + test_DragDetect(); + test_WM_NCCALCSIZE(); + test_ReleaseCapture(); /* add the tests above this line */ if (hhook) UnhookWindowsHookEx(hhook); DestroyWindow(hwndMain2); DestroyWindow(hwndMain); + + /* Make sure that following tests are executed last, under Windows they + * tend to break the tests which are sensitive to z-order and activation + * state of hwndMain and hwndMain2 windows. + */ + test_topmost(); + + test_shell_window(); + test_shell_tray(); } diff --git a/modules/rostests/winetests/user32/winstation.c b/modules/rostests/winetests/user32/winstation.c index 8522825a21c..0e012c7b9da 100644 --- a/modules/rostests/winetests/user32/winstation.c +++ b/modules/rostests/winetests/user32/winstation.c @@ -18,12 +18,18 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#ifdef __REACTOS__ +#define WIN32_NO_STATUS +#include +#endif #include "wine/test.h" #include "winbase.h" #include "wingdi.h" #include "winuser.h" #include "winnls.h" -#include "wine/winternl.h" +#ifndef __REACTOS__ +#include "winternl.h" +#endif static NTSTATUS (WINAPI *pNtQueryObject)(HANDLE, OBJECT_INFORMATION_CLASS, PVOID, ULONG, PULONG); @@ -51,7 +57,12 @@ static void register_class(void) WNDCLASSA cls; cls.style = CS_DBLCLKS; - cls.lpfnWndProc = DefWindowProcA; + /* Windows < Vista apparently checks lpfnWndProc against the address of + * DefWindowProcA(), and for some reason fails to change the thread desktop + * after creating and destroying a window if it doesn't match. Using an IAT + * (as is default) or a wrapper triggers this, so use GetProcAddress() as + * a workaround. */ + cls.lpfnWndProc = (void *)GetProcAddress(GetModuleHandleA("user32"), "DefWindowProcA"); cls.cbClsExtra = 0; cls.cbWndExtra = 0; cls.hInstance = GetModuleHandleA(0); @@ -76,11 +87,11 @@ static DWORD CALLBACK thread( LPVOID arg ) SetLastError( 0xdeadbeef ); ok( !CloseHandle( d1 ), "CloseHandle succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %ld\n", GetLastError() ); SetLastError( 0xdeadbeef ); ok( !CloseDesktop( d1 ), "CloseDesktop succeeded\n" ); ok( GetLastError() == ERROR_BUSY || broken(GetLastError() == 0xdeadbeef), /* wow64 */ - "bad last error %d\n", GetLastError() ); + "bad last error %ld\n", GetLastError() ); print_object( d1 ); d2 = CreateDesktopA( "foobar2", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ); trace( "created desktop %p\n", d2 ); @@ -89,7 +100,7 @@ static DWORD CALLBACK thread( LPVOID arg ) SetLastError( 0xdeadbeef ); ok( !SetThreadDesktop( d2 ), "set thread desktop succeeded with existing window\n" ); ok( GetLastError() == ERROR_BUSY || broken(GetLastError() == 0xdeadbeef), /* wow64 */ - "bad last error %d\n", GetLastError() ); + "bad last error %ld\n", GetLastError() ); DestroyWindow( hwnd ); ok( SetThreadDesktop( d2 ), "set thread desktop failed\n" ); @@ -113,9 +124,12 @@ static void test_handles(void) HANDLE hthread; DWORD id, flags, le; ATOM atom; - char buffer[20]; + char buffer[29], default_name[29] = ""; DWORD size; BOOL ret; + OBJECT_BASIC_INFORMATION info; + TOKEN_STATISTICS token_stats; + NTSTATUS status; /* win stations */ @@ -124,9 +138,14 @@ static void test_handles(void) ok( !CloseWindowStation(w1), "closing process win station succeeded\n" ); SetLastError( 0xdeadbeef ); ok( !CloseHandle(w1), "closing process win station handle succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %ld\n", GetLastError() ); print_object( w1 ); + status = NtQueryObject( w1, ObjectBasicInformation, &info, sizeof(info), NULL ); + ok( !status, "NtQueryObject failed, status %#lx\n", status ); + ok( info.GrantedAccess == (STANDARD_RIGHTS_REQUIRED | WINSTA_ALL_ACCESS), + "Got unexpected access %#lx\n", info.GrantedAccess ); + flags = 0; ok( GetHandleInformation( w1, &flags ), "GetHandleInformation failed\n" ); ok( !(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE) || @@ -143,14 +162,14 @@ static void test_handles(void) w2 = CreateWindowStationA("WinSta0", 0, WINSTA_ALL_ACCESS, NULL ); le = GetLastError(); - ok( w2 != 0 || le == ERROR_ACCESS_DENIED, "CreateWindowStation failed (%u)\n", le ); + ok( w2 != 0 || le == ERROR_ACCESS_DENIED, "CreateWindowStation failed (%lu)\n", le ); if (w2 != 0) { ok( w2 != w1, "CreateWindowStation returned default handle\n" ); SetLastError( 0xdeadbeef ); ok( !CloseDesktop( (HDESK)w2 ), "CloseDesktop succeeded on win station\n" ); ok( GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == 0xdeadbeef), /* wow64 */ - "bad last error %d\n", GetLastError() ); + "bad last error %ld\n", GetLastError() ); ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" ); w2 = CreateWindowStationA("WinSta0", 0, WINSTA_ALL_ACCESS, NULL ); @@ -170,7 +189,7 @@ static void test_handles(void) CreateMutexA( NULL, 0, "foobar" ); w2 = CreateWindowStationA("foobar", 0, WINSTA_ALL_ACCESS, NULL ); le = GetLastError(); - ok( w2 != 0 || le == ERROR_ACCESS_DENIED, "create foobar station failed (%u)\n", le ); + ok( w2 != 0 || le == ERROR_ACCESS_DENIED, "create foobar station failed (%lu)\n", le ); if (w2 != 0) { @@ -210,36 +229,49 @@ static void test_handles(void) SetLastError( 0xdeadbeef ); w2 = OpenWindowStationA( "", TRUE, WINSTA_ALL_ACCESS ); ok( !w2, "open station succeeded\n" ); - todo_wine - ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); w2 = CreateWindowStationA( "", 0, WINSTA_ALL_ACCESS, NULL ); - ok( w2 != 0, "create station failed err %u\n", GetLastError() ); + ok( w2 != 0, "create station failed err %lu\n", GetLastError() ); memset( buffer, 0, sizeof(buffer) ); ret = GetUserObjectInformationA( w2, UOI_NAME, buffer, sizeof(buffer), &size ); - ok( ret, "GetUserObjectInformationA failed with error %u\n", GetLastError() ); - ok( !memcmp(buffer, "Service-0x0-", 12), "unexpected window station name '%s'\n", buffer ); - ok( buffer[strlen(buffer) - 1] == '$', "unexpected window station name '%s'\n", buffer ); + ok( ret, "GetUserObjectInformationA failed with error %lu\n", GetLastError() ); + /* Get the logon session LUID */ + ret = GetTokenInformation( GetCurrentProcessToken(), TokenStatistics, &token_stats, sizeof(token_stats), NULL ); + if (ret) + sprintf( default_name, "Service-0x%lx-%lx$", token_stats.AuthenticationId.HighPart, + token_stats.AuthenticationId.LowPart ); + if (*default_name) + ok( !strcmp( buffer, default_name ), "unexpected window station name '%s' expected '%s'\n", buffer, default_name ); SetLastError( 0xdeadbeef ); w3 = OpenWindowStationA( "", TRUE, WINSTA_ALL_ACCESS ); - todo_wine - ok( w3 != 0, "open station failed err %u\n", GetLastError() ); + ok( w3 != 0, "open station failed err %lu\n", GetLastError() ); CloseWindowStation( w3 ); CloseWindowStation( w2 ); + w2 = CreateWindowStationA( NULL, 0, WINSTA_ALL_ACCESS, NULL ); + ok( w2 != 0, "create station failed err %lu\n", GetLastError() ); + + memset( buffer, 0, sizeof(buffer) ); + ret = GetUserObjectInformationA( w2, UOI_NAME, buffer, sizeof(buffer), &size ); + ok( ret, "GetUserObjectInformationA failed with error %lu\n", GetLastError() ); + if (*default_name) + ok( !strcmp( buffer, default_name ), "unexpected window station name '%s' expected '%s'\n", buffer, default_name ); + CloseWindowStation( w2 ); + SetLastError( 0xdeadbeef ); w2 = CreateWindowStationA( "foo\\bar", 0, WINSTA_ALL_ACCESS, NULL ); ok( !w2, "create station succeeded\n" ); ok( GetLastError() == ERROR_PATH_NOT_FOUND || GetLastError() == ERROR_ACCESS_DENIED, - "wrong error %u\n", GetLastError() ); + "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); w2 = OpenWindowStationA( "foo\\bar", TRUE, WINSTA_ALL_ACCESS ); ok( !w2, "create station succeeded\n" ); - ok( GetLastError() == ERROR_PATH_NOT_FOUND, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_PATH_NOT_FOUND, "wrong error %lu\n", GetLastError() ); /* desktops */ d1 = GetThreadDesktop(GetCurrentThreadId()); @@ -251,10 +283,15 @@ static void test_handles(void) ok( GetHandleInformation( d1, &flags ), "GetHandleInformation failed\n" ); ok( !(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE), "handle %p PROTECT_FROM_CLOSE set\n", d1 ); + status = NtQueryObject( d1, ObjectBasicInformation, &info, sizeof(info), NULL ); + ok( !status, "NtQueryObject failed, status %#lx\n", status ); + ok( info.GrantedAccess == (STANDARD_RIGHTS_REQUIRED | DESKTOP_ALL_ACCESS), + "Got unexpected access %#lx\n", info.GrantedAccess ); + SetLastError( 0xdeadbeef ); ok( !CloseDesktop(d1), "closing thread desktop succeeded\n" ); ok( GetLastError() == ERROR_BUSY || broken(GetLastError() == 0xdeadbeef), /* wow64 */ - "bad last error %d\n", GetLastError() ); + "bad last error %ld\n", GetLastError() ); SetLastError( 0xdeadbeef ); if (CloseHandle( d1 )) /* succeeds on nt4 */ @@ -262,7 +299,7 @@ static void test_handles(void) win_skip( "NT4 desktop handle management is completely different\n" ); return; } - ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %ld\n", GetLastError() ); ok( DuplicateHandle( GetCurrentProcess(), d1, GetCurrentProcess(), (PHANDLE)&d2, 0, TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" ); @@ -277,37 +314,35 @@ static void test_handles(void) SetLastError( 0xdeadbeef ); d2 = CreateDesktopA( "", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ); - todo_wine ok( !d2, "create empty desktop succeeded\n" ); - todo_wine - ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); d2 = OpenDesktopA( "", 0, TRUE, DESKTOP_ALL_ACCESS ); ok( !d2, "open empty desktop succeeded\n" ); - ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); d2 = CreateDesktopA( "foo\\bar", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ); ok( !d2, "create desktop succeeded\n" ); - ok( GetLastError() == ERROR_BAD_PATHNAME, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_BAD_PATHNAME, "wrong error %lu\n", GetLastError() ); SetLastError( 0xdeadbeef ); d2 = OpenDesktopA( "foo\\bar", 0, TRUE, DESKTOP_ALL_ACCESS ); ok( !d2, "open desktop succeeded\n" ); - ok( GetLastError() == ERROR_BAD_PATHNAME, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_BAD_PATHNAME, "wrong error %lu\n", GetLastError() ); d2 = CreateDesktopA( "foobar", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ); ok( d2 != 0, "create foobar desktop failed\n" ); SetLastError( 0xdeadbeef ); ok( !CloseWindowStation( (HWINSTA)d2 ), "CloseWindowStation succeeded on desktop\n" ); ok( GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == 0xdeadbeef), /* wow64 */ - "bad last error %d\n", GetLastError() ); + "bad last error %ld\n", GetLastError() ); SetLastError( 0xdeadbeef ); d3 = CreateDesktopA( "foobar", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ); ok( d3 != 0, "create foobar desktop again failed\n" ); - ok( GetLastError() == 0xdeadbeef, "bad last error %d\n", GetLastError() ); + ok( GetLastError() == 0xdeadbeef, "bad last error %ld\n", GetLastError() ); ok( CloseDesktop( d3 ), "CloseDesktop failed\n" ); d3 = OpenDesktopA( "foobar", 0, TRUE, DESKTOP_ALL_ACCESS ); @@ -366,12 +401,12 @@ static void test_enumstations(void) SetLastError(0xbabefeed); ret = EnumWindowStationsA(NULL, 0); ok(!ret, "EnumWindowStationsA returned successfully!\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "LastError is set to %08x\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "LastError is set to %08lx\n", GetLastError()); } hwinsta = CreateWindowStationA("winsta_test", 0, WINSTA_ALL_ACCESS, NULL); ret = GetLastError(); - ok(hwinsta != NULL || ret == ERROR_ACCESS_DENIED, "CreateWindowStation failed (%u)\n", ret); + ok(hwinsta != NULL || ret == ERROR_ACCESS_DENIED, "CreateWindowStation failed (%lu)\n", ret); if (!hwinsta) { win_skip("Not enough privileges for CreateWindowStation\n"); @@ -380,13 +415,13 @@ static void test_enumstations(void) SetLastError(0xdeadbeef); ret = EnumWindowStationsA(open_window_station_callbackA, 0x12345); - ok(ret == 0x12345, "EnumWindowStationsA returned %x\n", ret); - ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError()); + ok(ret == 0x12345, "EnumWindowStationsA returned %lx\n", ret); + ok(GetLastError() == 0xdeadbeef, "LastError is set to %08lx\n", GetLastError()); SetLastError(0xdeadbeef); ret = EnumWindowStationsA(window_station_callbackA, 0); - ok(!ret, "EnumWindowStationsA returned %x\n", ret); - ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError()); + ok(!ret, "EnumWindowStationsA returned %lx\n", ret); + ok(GetLastError() == 0xdeadbeef, "LastError is set to %08lx\n", GetLastError()); } static BOOL CALLBACK desktop_callbackA(LPSTR desktop, LPARAM lp) @@ -421,28 +456,28 @@ static void test_enumdesktops(void) SetLastError(0xbabefeed); ret = EnumDesktopsA(GetProcessWindowStation(), NULL, 0); ok(!ret, "EnumDesktopsA returned successfully!\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "LastError is set to %08x\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "LastError is set to %08lx\n", GetLastError()); } SetLastError(0xdeadbeef); ret = EnumDesktopsA(NULL, desktop_callbackA, 0x12345); ok(ret == 0x12345, "EnumDesktopsA returned %x\n", ret); - ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "LastError is set to %08lx\n", GetLastError()); SetLastError(0xdeadbeef); ret = EnumDesktopsA(GetProcessWindowStation(), open_desktop_callbackA, 0x12345); ok(ret == 0x12345, "EnumDesktopsA returned %x\n", ret); - ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "LastError is set to %08lx\n", GetLastError()); SetLastError(0xdeadbeef); ret = EnumDesktopsA(INVALID_HANDLE_VALUE, desktop_callbackA, 0x12345); ok(!ret, "EnumDesktopsA returned %x\n", ret); - ok(GetLastError() == ERROR_INVALID_HANDLE, "LastError is set to %08x\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HANDLE, "LastError is set to %08lx\n", GetLastError()); SetLastError(0xdeadbeef); ret = EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA, 0); ok(!ret, "EnumDesktopsA returned %x\n", ret); - ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "LastError is set to %08lx\n", GetLastError()); } /* Miscellaneous tests */ @@ -472,8 +507,8 @@ static void test_getuserobjectinformation(void) ret = GetUserObjectInformationA(desk, UOI_NAME, NULL, 0, &size); ok(!ret, "GetUserObjectInformationA returned %x\n", ret); - ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08x\n", GetLastError()); - ok(size == 22, "size is set to %d\n", size); /* Windows returns Unicode length (11*2) */ + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08lx\n", GetLastError()); + ok(size == 22, "size is set to %ld\n", size); /* Windows returns Unicode length (11*2) */ /* Get string */ SetLastError(0xdeadbeef); @@ -481,10 +516,10 @@ static void test_getuserobjectinformation(void) ret = GetUserObjectInformationA(desk, UOI_NAME, buffer, sizeof(buffer), &size); ok(ret, "GetUserObjectInformationA returned %x\n", ret); - ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "LastError is set to %08lx\n", GetLastError()); ok(strcmp(buffer, "foobarTest") == 0, "Buffer is set to '%s'\n", buffer); - ok(size == 11, "size is set to %d\n", size); /* 11 bytes in 'foobarTest\0' */ + ok(size == 11, "size is set to %ld\n", size); /* 11 bytes in 'foobarTest\0' */ /* Get size, test size and return value/error code (Unicode) */ SetLastError(0xdeadbeef); @@ -492,8 +527,8 @@ static void test_getuserobjectinformation(void) ret = GetUserObjectInformationW(desk, UOI_NAME, NULL, 0, &size); ok(!ret, "GetUserObjectInformationW returned %x\n", ret); - ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08x\n", GetLastError()); - ok(size == 22, "size is set to %d\n", size); /* 22 bytes in 'foobarTest\0' in Unicode */ + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08lx\n", GetLastError()); + ok(size == 22, "size is set to %ld\n", size); /* 22 bytes in 'foobarTest\0' in Unicode */ /* Get string (Unicode) */ SetLastError(0xdeadbeef); @@ -501,15 +536,15 @@ static void test_getuserobjectinformation(void) ret = GetUserObjectInformationW(desk, UOI_NAME, bufferW, sizeof(bufferW), &size); ok(ret, "GetUserObjectInformationW returned %x\n", ret); - ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "LastError is set to %08lx\n", GetLastError()); ok(lstrcmpW(bufferW, foobarTestW + 1) == 0, "Buffer is not set to 'foobarTest'\n"); - ok(size == 22, "size is set to %d\n", size); /* 22 bytes in 'foobarTest\0' in Unicode */ + ok(size == 22, "size is set to %ld\n", size); /* 22 bytes in 'foobarTest\0' in Unicode */ /* ObjectNameInformation does not return the full desktop name */ name_info = (OBJECT_NAME_INFORMATION *)buffer; status = pNtQueryObject(desk, ObjectNameInformation, name_info, sizeof(buffer), NULL); - ok(!status, "expected STATUS_SUCCESS, got %08x\n", status); + ok(!status, "expected STATUS_SUCCESS, got %08lx\n", status); ok(lstrcmpW(name_info->Name.Buffer, foobarTestW) == 0, "expected '\\foobarTest', got %s\n", wine_dbgstr_w(name_info->Name.Buffer)); @@ -521,8 +556,8 @@ static void test_getuserobjectinformation(void) ret = GetUserObjectInformationA(desk, UOI_TYPE, NULL, 0, &size); ok(!ret, "GetUserObjectInformationA returned %x\n", ret); - ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08x\n", GetLastError()); - ok(size == 16, "size is set to %d\n", size); /* Windows returns Unicode length (8*2) */ + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08lx\n", GetLastError()); + ok(size == 16, "size is set to %ld\n", size); /* Windows returns Unicode length (8*2) */ /* Get string */ SetLastError(0xdeadbeef); @@ -530,10 +565,10 @@ static void test_getuserobjectinformation(void) ret = GetUserObjectInformationA(desk, UOI_TYPE, buffer, sizeof(buffer), &size); ok(ret, "GetUserObjectInformationA returned %x\n", ret); - ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "LastError is set to %08lx\n", GetLastError()); ok(strcmp(buffer, "Desktop") == 0, "Buffer is set to '%s'\n", buffer); - ok(size == 8, "size is set to %d\n", size); /* 8 bytes in 'Desktop\0' */ + ok(size == 8, "size is set to %ld\n", size); /* 8 bytes in 'Desktop\0' */ /* Get size, test size and return value/error code (Unicode) */ size = 0xdeadbeef; @@ -541,8 +576,8 @@ static void test_getuserobjectinformation(void) ret = GetUserObjectInformationW(desk, UOI_TYPE, NULL, 0, &size); ok(!ret, "GetUserObjectInformationW returned %x\n", ret); - ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08x\n", GetLastError()); - ok(size == 16, "size is set to %d\n", size); /* 16 bytes in 'Desktop\0' in Unicode */ + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "LastError is set to %08lx\n", GetLastError()); + ok(size == 16, "size is set to %ld\n", size); /* 16 bytes in 'Desktop\0' in Unicode */ /* Get string (Unicode) */ SetLastError(0xdeadbeef); @@ -550,10 +585,10 @@ static void test_getuserobjectinformation(void) ret = GetUserObjectInformationW(desk, UOI_TYPE, bufferW, sizeof(bufferW), &size); ok(ret, "GetUserObjectInformationW returned %x\n", ret); - ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "LastError is set to %08lx\n", GetLastError()); ok(lstrcmpW(bufferW, DesktopW) == 0, "Buffer is not set to 'Desktop'\n"); - ok(size == 16, "size is set to %d\n", size); /* 16 bytes in 'Desktop\0' in Unicode */ + ok(size == 16, "size is set to %ld\n", size); /* 16 bytes in 'Desktop\0' in Unicode */ ok(CloseDesktop(desk), "CloseDesktop failed\n"); } @@ -566,9 +601,9 @@ static void test_inputdesktop(void) INPUT inputs[1]; inputs[0].type = INPUT_KEYBOARD; - U(inputs[0]).ki.wVk = 0; - U(inputs[0]).ki.wScan = 0x3c0; - U(inputs[0]).ki.dwFlags = KEYEVENTF_UNICODE; + inputs[0].ki.wVk = 0; + inputs[0].ki.wScan = 0x3c0; + inputs[0].ki.dwFlags = KEYEVENTF_UNICODE; /* OpenInputDesktop creates new handles for each calls */ old_input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS); @@ -591,15 +626,15 @@ static void test_inputdesktop(void) /* by default, GetThreadDesktop is the input desktop, SendInput should succeed. */ old_thread_desk = GetThreadDesktop(GetCurrentThreadId()); - ok(old_thread_desk != NULL, "GetThreadDesktop faile!\n"); + ok(old_thread_desk != NULL, "GetThreadDesktop failed!\n"); memset(name, 0, sizeof(name)); ret = GetUserObjectInformationA(old_thread_desk, UOI_NAME, name, 1024, NULL); ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name); SetLastError(0xdeadbeef); ret = SendInput(1, inputs, sizeof(INPUT)); - ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError()); - ok(ret == 1, "unexpected return count %d\n", ret); + ok(GetLastError() == 0xdeadbeef, "unexpected last error %08lx\n", GetLastError()); + ok(ret == 1, "unexpected return count %ld\n", ret); /* Set thread desktop to the new desktop, SendInput should fail. */ new_desk = CreateDesktopA("new_desk", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL); @@ -623,9 +658,8 @@ static void test_inputdesktop(void) win_skip("Skip tests on NT4\n"); return; } -todo_wine - ok(GetLastError() == ERROR_ACCESS_DENIED, "unexpected last error %08x\n", GetLastError()); - ok(ret == 1 || broken(ret == 0) /* Win64 */, "unexpected return count %d\n", ret); + ok(GetLastError() == ERROR_ACCESS_DENIED, "unexpected last error %08lx\n", GetLastError()); + ok(ret == 0 || broken(ret == 1) /* Win32 */, "unexpected return count %ld\n", ret); /* Set thread desktop back to the old thread desktop, SendInput should success. */ ret = SetThreadDesktop(old_thread_desk); @@ -638,8 +672,8 @@ todo_wine SetLastError(0xdeadbeef); ret = SendInput(1, inputs, sizeof(INPUT)); - ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError()); - ok(ret == 1, "unexpected return count %d\n", ret); + ok(GetLastError() == 0xdeadbeef, "unexpected last error %08lx\n", GetLastError()); + ok(ret == 1, "unexpected return count %ld\n", ret); /* Set thread desktop to the input desktop, SendInput should success. */ ret = SetThreadDesktop(old_input_desk); @@ -652,8 +686,8 @@ todo_wine SetLastError(0xdeadbeef); ret = SendInput(1, inputs, sizeof(INPUT)); - ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError()); - ok(ret == 1, "unexpected return count %d\n", ret); + ok(GetLastError() == 0xdeadbeef, "unexpected last error %08lx\n", GetLastError()); + ok(ret == 1, "unexpected return count %ld\n", ret); /* Switch input desktop to the new desktop, SendInput should fail. */ ret = SwitchDesktop(new_desk); @@ -664,16 +698,14 @@ todo_wine memset(name, 0, sizeof(name)); ret = GetUserObjectInformationA(input_desk, UOI_NAME, name, 1024, NULL); ok(ret, "GetUserObjectInformation failed!\n"); -todo_wine ok(!strcmp(name, "new_desk"), "unexpected desktop %s\n", name); ret = CloseDesktop(input_desk); ok(ret, "CloseDesktop failed!\n"); SetLastError(0xdeadbeef); ret = SendInput(1, inputs, sizeof(INPUT)); -todo_wine - ok(GetLastError() == ERROR_ACCESS_DENIED, "unexpected last error %08x\n", GetLastError()); - ok(ret == 1 || broken(ret == 0) /* Win64 */, "unexpected return count %d\n", ret); + ok(GetLastError() == ERROR_ACCESS_DENIED, "unexpected last error %08lx\n", GetLastError()); + ok(ret == 0 || broken(ret == 1) /* Win32 */, "unexpected return count %ld\n", ret); /* Set thread desktop to the new desktop, SendInput should success. */ ret = SetThreadDesktop(new_desk); @@ -686,8 +718,8 @@ todo_wine SetLastError(0xdeadbeef); ret = SendInput(1, inputs, sizeof(INPUT)); - ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError()); - ok(ret == 1, "unexpected return count %d\n", ret); + ok(GetLastError() == 0xdeadbeef, "unexpected last error %08lx\n", GetLastError()); + ok(ret == 1, "unexpected return count %ld\n", ret); /* Switch input desktop to the old input desktop, set thread desktop to the old * thread desktop, clean side effects. SendInput should success. */ @@ -710,8 +742,8 @@ todo_wine SetLastError(0xdeadbeef); ret = SendInput(1, inputs, sizeof(INPUT)); - ok(GetLastError() == 0xdeadbeef, "unexpected last error %08x\n", GetLastError()); - ok(ret == 1, "unexpected return count %d\n", ret); + ok(GetLastError() == 0xdeadbeef, "unexpected last error %08lx\n", GetLastError()); + ok(ret == 1, "unexpected return count %ld\n", ret); /* free resources */ ret = CloseDesktop(input_desk); @@ -735,7 +767,7 @@ static void test_inputdesktop2(void) SetLastError(0xdeadbeef); w2 = CreateWindowStationA("winsta_test", 0, WINSTA_ALL_ACCESS, NULL); ret = GetLastError(); - ok(w2 != NULL || ret == ERROR_ACCESS_DENIED, "CreateWindowStation failed (%u)\n", ret); + ok(w2 != NULL || ret == ERROR_ACCESS_DENIED, "CreateWindowStation failed (%lu)\n", ret); if (!w2) { win_skip("Not enough privileges for CreateWindowStation\n"); @@ -763,22 +795,21 @@ static void test_inputdesktop2(void) SetLastError(0xdeadbeef); input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS); ok(input_desk == NULL, "OpenInputDesktop should fail on non default winstation!\n"); - ok(GetLastError() == ERROR_INVALID_FUNCTION || broken(GetLastError() == 0xdeadbeef), "last error %08x\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_FUNCTION || broken(GetLastError() == 0xdeadbeef), "last error %08lx\n", GetLastError()); hdesk = OpenDesktopA("desk_test", 0, TRUE, DESKTOP_ALL_ACCESS); ok(hdesk != NULL, "OpenDesktop failed!\n"); SetLastError(0xdeadbeef); ret = SwitchDesktop(hdesk); -todo_wine ok(!ret, "Switch to desktop belong to non default winstation should fail!\n"); -todo_wine - ok(GetLastError() == ERROR_ACCESS_DENIED || broken(GetLastError() == 0xdeadbeef), "last error %08x\n", GetLastError()); + todo_wine + ok(GetLastError() == ERROR_ACCESS_DENIED || broken(GetLastError() == 0xdeadbeef), "last error %08lx\n", GetLastError()); ret = SetThreadDesktop(hdesk); ok(ret, "SetThreadDesktop failed!\n"); /* clean side effect */ ret = SetThreadDesktop(thread_desk); -todo_wine + todo_wine ok(ret, "SetThreadDesktop should success even desktop is not belong to process winstation!\n"); ret = SetProcessWindowStation(w1); ok(ret, "SetProcessWindowStation failed!\n"); @@ -843,17 +874,17 @@ static DWORD set_foreground(HWND hwnd) GetWindowTextA(hwnd_fore, win_text, 1024); set_id = GetWindowThreadProcessId(hwnd, NULL); fore_id = GetWindowThreadProcessId(hwnd_fore, NULL); - trace("\"%s\" %p %08x hwnd %p %08x\n", win_text, hwnd_fore, fore_id, hwnd, set_id); + trace("\"%s\" %p %08lx hwnd %p %08lx\n", win_text, hwnd_fore, fore_id, hwnd, set_id); ret = AttachThreadInput(set_id, fore_id, TRUE); - trace("AttachThreadInput returned %08x\n", ret); + trace("AttachThreadInput returned %08lx\n", ret); ret = ShowWindow(hwnd, SW_SHOWNORMAL); - trace("ShowWindow returned %08x\n", ret); + trace("ShowWindow returned %08lx\n", ret); ret = SetWindowPos(hwnd, HWND_TOPMOST, 0,0,0,0, SWP_NOSIZE|SWP_NOMOVE); - trace("set topmost returned %08x\n", ret); + trace("set topmost returned %08lx\n", ret); ret = SetWindowPos(hwnd, HWND_NOTOPMOST, 0,0,0,0, SWP_NOSIZE|SWP_NOMOVE); - trace("set notopmost returned %08x\n", ret); + trace("set notopmost returned %08lx\n", ret); ret = SetForegroundWindow(hwnd); - trace("SetForegroundWindow returned %08x\n", ret); + trace("SetForegroundWindow returned %08lx\n", ret); Sleep(250); AttachThreadInput(set_id, fore_id, FALSE); return ret; @@ -882,7 +913,7 @@ static void test_foregroundwindow(void) SetLastError(0xdeadbeef); hdesks[1] = CreateDesktopA("desk2", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL); ret = GetLastError(); - ok(hdesks[1] != NULL || ret == ERROR_ACCESS_DENIED, "CreateDesktop failed (%u)\n", ret); + ok(hdesks[1] != NULL || ret == ERROR_ACCESS_DENIED, "CreateDesktop failed (%lu)\n", ret); if(!hdesks[1]) { win_skip("Not enough privileges for CreateDesktop\n"); @@ -896,13 +927,13 @@ static void test_foregroundwindow(void) CloseDesktop(hdesks[1]); return; } - trace("old timeout %d\n", timeout_old); + trace("old timeout %ld\n", timeout_old); timeout = 0; ret = SystemParametersInfoA(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, SPIF_SENDCHANGE | SPIF_UPDATEINIFILE); ok(ret, "set foreground lock timeout failed!\n"); ret = SystemParametersInfoA(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &timeout, 0); ok(ret, "get foreground lock timeout failed!\n"); - ok(timeout == 0, "unexpected timeout %d\n", timeout); + ok(timeout == 0, "unexpected timeout %ld\n", timeout); for (thread_desk_id = 0; thread_desk_id < DESKTOPS; thread_desk_id++) { @@ -994,11 +1025,105 @@ static void test_foregroundwindow(void) ok(ret, "set foreground lock timeout failed!\n"); ret = SystemParametersInfoA(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &timeout, 0); ok(ret, "get foreground lock timeout failed!\n"); - ok(timeout == timeout_old, "unexpected timeout %d\n", timeout); + ok(timeout == timeout_old, "unexpected timeout %ld\n", timeout); +} + +static void test_invisible_winstation_child(char *expected_info) +{ + char buffer[MAX_PATH]; + HDESK desktop; + HWND hwnd; + int ret; + + desktop = GetThreadDesktop(GetCurrentThreadId()); + ok(!!desktop, "GetThreadDesktop failed, error %lu.\n", GetLastError()); + + ret = GetUserObjectInformationA(desktop, UOI_NAME, &buffer, sizeof(buffer), NULL); + ok(ret, "GetUserObjectInformationA failed, error %lu.\n", GetLastError()); + ok(!strcmp(buffer, "invisible_winstation_desktop"), "Got unexpected desktop %s.\n", buffer); + + sprintf(buffer, "%d,%d,%d,%d,%d", GetSystemMetrics(SM_XVIRTUALSCREEN), + GetSystemMetrics(SM_YVIRTUALSCREEN), GetSystemMetrics(SM_CXVIRTUALSCREEN), + GetSystemMetrics(SM_CYVIRTUALSCREEN), GetSystemMetrics(SM_CMONITORS)); + ok(!strcmp(buffer, expected_info), "Expected %s, got %s.\n", expected_info, buffer); + + hwnd = GetDesktopWindow(); + ok(!!hwnd, "GetDesktopWindow failed, error %lu.\n", GetLastError()); + + ret = SendMessageW(hwnd, WM_NCHITTEST, 0, 0); + ok(ret == HTCLIENT, "SendMessageW failed, error %lu.\n", GetLastError()); +} + +static void test_invisible_winstation(char **argv) +{ + char buffer[MAX_PATH], desktop_name[MAX_PATH]; + HWINSTA old_winstation, winstation; + PROCESS_INFORMATION pi = {0}; + STARTUPINFOA si = {0}; + HDESK desktop; + BOOL ret; + + old_winstation = GetProcessWindowStation(); + ok(!!old_winstation, "GetProcessWindowStation failed, error %lu.\n", GetLastError()); + winstation = CreateWindowStationW(NULL, 0, GENERIC_READ | WINSTA_CREATEDESKTOP, NULL); + ok(!!winstation, "CreateWindowStationW failed, error %lu.\n", GetLastError()); + ret = SetProcessWindowStation(winstation); + ok(ret, "SetProcessWindowStation failed, error %lu.\n", GetLastError()); + desktop = CreateDesktopA("invisible_winstation_desktop", NULL, NULL, 0, DESKTOP_CREATEWINDOW, NULL); + ok(!!desktop, "CreateDesktopA failed, error %lu.\n", GetLastError()); + + ret = GetUserObjectInformationA(winstation, UOI_NAME, buffer, sizeof(buffer), NULL); + ok(ret, "GetUserObjectInformationA failed, error %lu.\n", GetLastError()); + strcpy(desktop_name, buffer); + strcat(desktop_name, "\\invisible_winstation_desktop"); + + si.cb = sizeof(si); + si.lpDesktop = desktop_name; + + sprintf(buffer, "\"%s\" %s invisible %d,%d,%d,%d,%d", argv[0], argv[1], + GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN), + GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN), + GetSystemMetrics(SM_CMONITORS)); + ret = CreateProcessA(argv[0], buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + ok(ret, "CreateProcessA failed, error %lu.\n", GetLastError()); + + wait_child_process(pi.hProcess); + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + CloseDesktop(desktop); + CloseWindowStation(winstation); + SetProcessWindowStation(old_winstation); +} + +static void test_get_security(void) +{ + SECURITY_INFORMATION info = DACL_SECURITY_INFORMATION; + HDESK desktop = GetThreadDesktop(GetCurrentThreadId()); + DWORD size, expect_size; + char buffer[500]; + BOOL ret; + + size = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = GetUserObjectSecurity( desktop, &info, NULL, 0, &size ); + ok( !ret, "got %#x\n", ret ); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got error %lu\n", GetLastError() ); + ok( size && size < sizeof(buffer), "got size %lu\n", size ); + expect_size = size; + + size = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = GetUserObjectSecurity( desktop, &info, buffer, sizeof(buffer), &size ); + ok( ret == TRUE, "got %#x\n", ret ); + ok( GetLastError() == 0xdeadbeef, "got error %lu\n", GetLastError() ); + ok( size == expect_size, "got size %lu\n", size ); + ok( IsValidSecurityDescriptor(buffer), "expected valid SD\n" ); } START_TEST(winstation) { + char **argv; + int argc; HMODULE hntdll = GetModuleHandleA("ntdll.dll"); pNtQueryObject = (void *)GetProcAddress(hntdll, "NtQueryObject"); @@ -1012,6 +1137,14 @@ START_TEST(winstation) return; } + argc = winetest_get_mainargs(&argv); + if (argc > 2) + { + if (!lstrcmpA(argv[2], "invisible")) + test_invisible_winstation_child(argv[3]); + + return; + } test_inputdesktop(); test_inputdesktop2(); test_enumstations(); @@ -1019,4 +1152,6 @@ START_TEST(winstation) test_handles(); test_getuserobjectinformation(); test_foregroundwindow(); + test_invisible_winstation(argv); + test_get_security(); } diff --git a/modules/rostests/winetests/user32/wsprintf.c b/modules/rostests/winetests/user32/wsprintf.c index f79b6306a7c..d35138f4087 100644 --- a/modules/rostests/winetests/user32/wsprintf.c +++ b/modules/rostests/winetests/user32/wsprintf.c @@ -52,12 +52,34 @@ static const struct static void wsprintfATest(void) { - char buf[25]; + char buf[25], star[4], partial[4]; + static const WCHAR starW[] = L"\x2606"; + static const WCHAR fffeW[] = L"\xfffe"; + static const WCHAR wineW[] = L"\xd83c\xdf77"; /* U+1F377: wine glass */ + const struct { + const void *input; + const char *fmt; + const char *str; + int rc; + } + testcase[] = { + { starW, "%.1S", partial, 1 }, + { starW, "%.2S", star, 2 }, + { starW, "%.3S", star, 2 }, + { fffeW, "%.1S", "?", 1 }, + { fffeW, "%.2S", "?", 1 }, + { wineW, "%.2S", "??", 2 }, + { star, "%.1s", partial, 1 }, + { (void *)0x2606, "%2C", star, 2 }, + { (void *)0xfffd, "%C", "?", 1 }, + { (void *)0xe199, "%2c", " \x99", 2 }, + }; + CPINFO cpinfo; unsigned int i; int rc; rc=wsprintfA(buf, "%010ld", -1); - ok(rc == 10, "wsprintfA length failure: rc=%d error=%d\n",rc,GetLastError()); + ok(rc == 10, "wsprintfA length failure: rc=%d error=%ld\n",rc,GetLastError()); ok((lstrcmpA(buf, "-000000001") == 0), "wsprintfA zero padded negative value failure: buf=[%s]\n",buf); rc = wsprintfA(buf, "%I64X", (ULONGLONG)0); @@ -72,28 +94,74 @@ static void wsprintfATest(void) ok(rc == strlen(i64_formats[i].res), "%u: wsprintfA length failure: rc=%d\n", i, rc); ok(!strcmp(buf, i64_formats[i].res), "%u: wrong result [%s]\n", i, buf); } + + if (!GetCPInfo(CP_ACP, &cpinfo) || cpinfo.MaxCharSize != 2) + { + skip("Multi-byte wsprintfA test isn't available for the current codepage\n"); + return; + } + + rc = WideCharToMultiByte(CP_ACP, 0, starW, -1, star, sizeof(star), NULL, NULL); + ok(rc == 3, "unexpected rc, got %d\n", rc); + partial[0] = star[0]; + partial[1] = '\0'; + + for (i = 0; i < ARRAY_SIZE(testcase); i++) + { + memset(buf, 0x11, sizeof(buf)); + rc = wsprintfA(buf, testcase[i].fmt, testcase[i].input); + + ok(rc == testcase[i].rc, + "%u: expected %d, got %d\n", + i, testcase[i].rc, rc); + + ok(!strcmp(buf, testcase[i].str), + "%u: expected %s, got %s\n", + i, wine_dbgstr_a(testcase[i].str), wine_dbgstr_an(buf, rc)); + } +} + +static WCHAR my_btowc(BYTE c) +{ + WCHAR wc; + if (!IsDBCSLeadByte(c) && + MultiByteToWideChar(CP_ACP, 0, (const char *)&c, 1, &wc, 1) > 0) + return wc; + return 0; } static void wsprintfWTest(void) { - static const WCHAR fmt_010ld[] = {'%','0','1','0','l','d','\0'}; - static const WCHAR res_010ld[] = {'-','0','0','0','0','0','0','0','0','1', '\0'}; - static const WCHAR fmt_I64x[] = {'%','I','6','4','x',0}; - WCHAR buf[25], fmt[25], res[25]; + static const WCHAR stars[] = L"*\x2606\x2605"; + WCHAR def_spc[] = L"*?\x2605 "; + WCHAR buf[25], fmt[25], res[25], wcA1, wc99; + char stars_mb[8], partial00[8], partialFF[8]; + const struct { + const char *input; + const WCHAR *fmt; + const WCHAR *str; + int rc; + } + testcase[] = { + { stars_mb, L"%.3S", stars, 3 }, + { partial00, L"%-4S", L"*\0 ", 4 }, + { partialFF, L"%-4S", def_spc, 4 }, + }; + CPINFOEXW cpinfoex; unsigned int i; int rc; - rc=wsprintfW(buf, fmt_010ld, -1); + rc=wsprintfW(buf, L"%010ld", -1); if (rc==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) { win_skip("wsprintfW is not implemented\n"); return; } - ok(rc == 10, "wsPrintfW length failure: rc=%d error=%d\n",rc,GetLastError()); - ok((lstrcmpW(buf, res_010ld) == 0), + ok(rc == 10, "wsPrintfW length failure: rc=%d error=%ld\n",rc,GetLastError()); + ok((lstrcmpW(buf, L"-000000001") == 0), "wsprintfW zero padded negative value failure\n"); - rc = wsprintfW(buf, fmt_I64x, (ULONGLONG)0 ); - if (rc == 4 && !lstrcmpW(buf, fmt_I64x + 1)) + rc = wsprintfW(buf, L"%I64x", (ULONGLONG)0 ); + if (rc == 4 && !lstrcmpW(buf, L"I64x")) { win_skip( "I64 formats not supported\n" ); return; @@ -106,6 +174,59 @@ static void wsprintfWTest(void) ok(rc == lstrlenW(res), "%u: wsprintfW length failure: rc=%d\n", i, rc); ok(!lstrcmpW(buf, res), "%u: wrong result [%s]\n", i, wine_dbgstr_w(buf)); } + + rc = wsprintfW(buf, L"%2c", L'*'); + ok(rc == 2, "expected 2, got %d\n", rc); + ok(buf[0] == L' ', "expected \\x0020, got \\x%04x\n", buf[0]); + ok(buf[1] == L'*', "expected \\x%04x, got \\x%04x\n", L'*', buf[1]); + + rc = wsprintfW(buf, L"%c", L'\x2605'); + ok(rc == 1, "expected 1, got %d\n", rc); + ok(buf[0] == L'\x2605', "expected \\x%04x, got \\x%04x\n", L'\x2605', buf[0]); + + wcA1 = my_btowc(0xA1); + rc = wsprintfW(buf, L"%C", 0xA1); + ok(rc == 1, "expected 1, got %d\n", rc); + ok(buf[0] == wcA1, "expected \\x%04x, got \\x%04x\n", wcA1, buf[0]); + + rc = wsprintfW(buf, L"%C", 0x81A1); + ok(rc == 1, "expected 1, got %d\n", rc); + ok(buf[0] == wcA1, "expected \\x%04x, got \\x%04x\n", wcA1, buf[0]); + + wc99 = my_btowc(0x99); + rc = wsprintfW(buf, L"%2C", 0xe199); + ok(rc == 2, "expected 1, got %d\n", rc); + ok(buf[0] == L' ', "expected \\x0020, got \\x%04x\n", buf[0]); + ok(buf[1] == wc99, "expected \\x%04x, got \\x%04x\n", wc99, buf[1]); + + if (!GetCPInfoExW(CP_ACP, 0, &cpinfoex) || cpinfoex.MaxCharSize != 2) + { + skip("Multi-byte wsprintfW test isn't available for the current codepage\n"); + return; + } + def_spc[1] = cpinfoex.UnicodeDefaultChar; + + rc = WideCharToMultiByte(CP_ACP, 0, stars, -1, stars_mb, sizeof(stars_mb), NULL, NULL); + ok(rc == 6, "expected 6, got %d\n", rc); + strcpy(partial00, stars_mb); + partial00[2] = '\0'; + strcpy(partialFF, stars_mb); + partialFF[2] = 0xff; + + for (i = 0; i < ARRAY_SIZE(testcase); i++) + { + memset(buf, 0x11, sizeof(buf)); + rc = wsprintfW(buf, testcase[i].fmt, testcase[i].input); + + ok(rc == testcase[i].rc, + "%u: expected %d, got %d\n", + i, testcase[i].rc, rc); + + ok(!memcmp(buf, testcase[i].str, (testcase[i].rc + 1) * sizeof(WCHAR)), + "%u: expected %s, got %s\n", i, + wine_dbgstr_wn(testcase[i].str, testcase[i].rc + 1), + wine_dbgstr_wn(buf, rc + 1)); + } } /* Test if the CharUpper / CharLower functions return true 16 bit results, @@ -125,7 +246,7 @@ static void CharUpperTest(void) break; } } - ok(!failed,"CharUpper failed - 16bit input (0x%0lx) returned 32bit result (0x%0lx)\n",i,out); + ok(!failed,"CharUpper failed - 16bit input (0x%0Ix) returned 32bit result (0x%0Ix)\n",i,out); } static void CharLowerTest(void) @@ -142,7 +263,7 @@ static void CharLowerTest(void) break; } } - ok(!failed,"CharLower failed - 16bit input (0x%0lx) returned 32bit result (0x%0lx)\n",i,out); + ok(!failed,"CharLower failed - 16bit input (0x%0Ix) returned 32bit result (0x%0Ix)\n",i,out); }