diff --git a/modules/rostests/winetests/user32/CMakeLists.txt b/modules/rostests/winetests/user32/CMakeLists.txt index bf635ae328b..4bd525338c4 100644 --- a/modules/rostests/winetests/user32/CMakeLists.txt +++ b/modules/rostests/winetests/user32/CMakeLists.txt @@ -1,6 +1,6 @@ remove_definitions(-DWINVER=0x502 -D_WIN32_WINNT=0x502) -add_definitions(-DWINVER=0x600 -D_WIN32_WINNT=0x600) +add_definitions(-DWINVER=0x602 -D_WIN32_WINNT=0x602) if(MSVC) # Disable warning C4477 (printf format warnings) @@ -25,6 +25,7 @@ list(APPEND SOURCE menu.c monitor.c msg.c + rawinput.c resource.c scroll.c static.c diff --git a/modules/rostests/winetests/user32/broadcast.c b/modules/rostests/winetests/user32/broadcast.c index 949d1e865f8..91afcc28fdf 100644 --- a/modules/rostests/winetests/user32/broadcast.c +++ b/modules/rostests/winetests/user32/broadcast.c @@ -130,39 +130,15 @@ if (0) /* TODO: Check the hang flags */ ok(0, "Returned: %d\n", ret); } - recips = BSM_APPLICATIONS; - ResetEvent(hevent); - ret = broadcast( BSF_POSTMESSAGE|BSF_QUERY, &recips, WM_NULL, 100, 0 ); - ok(ret==1, "Returned: %d\n", ret); - ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); - PulseEvent(hevent); - SetLastError( 0xdeadbeef ); recips = BSM_APPLICATIONS; ret = broadcast( BSF_POSTMESSAGE|BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, 0 ); - if (ret) - { - ok(ret==1, "Returned: %d\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(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); - PulseEvent(hevent); - - recips = BSM_APPLICATIONS; - ret = broadcast( BSF_SENDNOTIFYMESSAGE|BSF_QUERY, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY ); - ok(!ret, "Returned: %d\n", ret); - ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); - PulseEvent(hevent); - } - else /* BSF_SENDNOTIFYMESSAGE not supported on NT4 */ - ok( GetLastError() == ERROR_INVALID_PARAMETER, "failed with err %u\n", GetLastError() ); + ok(ret==1, "Returned: %d\n", ret); + ok(WaitForSingleObject(hevent, 0) != WAIT_OBJECT_0, "Synchronous message sent instead\n"); + PulseEvent(hevent); recips = BSM_APPLICATIONS; - ret = broadcast( 0, &recips, WM_NULL, 100, 0 ); + ret = broadcast( BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY ); ok(ret==1, "Returned: %d\n", ret); ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); PulseEvent(hevent); @@ -216,13 +192,6 @@ if (0) /* TODO: Check the hang flags */ ok(0, "Returned: %d\n", ret); } - recips = BSM_APPLICATIONS; - ResetEvent(hevent); - ret = broadcastex( BSF_POSTMESSAGE|BSF_QUERY, &recips, WM_NULL, 100, 0, NULL ); - ok(ret==1, "Returned: %d\n", ret); - ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); - PulseEvent(hevent); - recips = BSM_APPLICATIONS; ret = broadcastex( BSF_POSTMESSAGE|BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, 0, NULL ); ok(ret==1, "Returned: %d\n", ret); @@ -234,84 +203,6 @@ if (0) /* TODO: Check the hang flags */ ok(ret==1, "Returned: %d\n", ret); ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); PulseEvent(hevent); - - recips = BSM_APPLICATIONS; - ret = broadcastex( BSF_SENDNOTIFYMESSAGE|BSF_QUERY, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY, NULL ); - ok(!ret, "Returned: %d\n", ret); - ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); - PulseEvent(hevent); - - recips = BSM_APPLICATIONS; - ret = broadcastex( 0, &recips, WM_NULL, 100, 0, NULL ); - ok(ret==1, "Returned: %d\n", ret); - ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); - PulseEvent(hevent); -} - -static void test_noprivileges(void) -{ - HANDLE token; - DWORD recips; - BOOL ret; - - static const DWORD BSM_ALL_RECIPS = BSM_VXDS | BSM_NETDRIVER | - BSM_INSTALLABLEDRIVERS | BSM_APPLICATIONS; - - if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token)) - { - skip("Can't open security token for process\n"); - return; - } - if (!AdjustTokenPrivileges(token, TRUE, NULL, 0, NULL, NULL)) - { - skip("Can't adjust security token for process\n"); - return; - } - - trace("Trying privileged edition!\n"); - SetLastError(0xcafebabe); - recips = BSM_ALLDESKTOPS; - ResetEvent(hevent); - ret = BroadcastSystemMessageExW( BSF_QUERY, &recips, WM_NULL, 100, 0, NULL ); - ok(ret==1, "Returned: %d error %u\n", ret, GetLastError()); - ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); - ok(recips == BSM_ALLDESKTOPS || - recips == BSM_ALL_RECIPS, /* win2k3 */ - "Received by: %08x\n", recips); - PulseEvent(hevent); - - SetLastError(0xcafebabe); - recips = BSM_ALLCOMPONENTS; - ResetEvent(hevent); - ret = BroadcastSystemMessageExW( BSF_QUERY, &recips, WM_NULL, 100, 0, NULL ); - ok(ret==1, "Returned: %d error %u\n", ret, GetLastError()); - ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); - ok(recips == BSM_ALLCOMPONENTS || - recips == BSM_ALL_RECIPS, /* win2k3 */ - "Received by: %08x\n", recips); - PulseEvent(hevent); - - SetLastError(0xcafebabe); - recips = BSM_ALLDESKTOPS|BSM_APPLICATIONS; - ResetEvent(hevent); - ret = BroadcastSystemMessageExW( BSF_QUERY, &recips, WM_NULL, 100, 0, NULL ); - ok(ret==1, "Returned: %d error %u\n", ret, GetLastError()); - ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); - ok(recips == (BSM_ALLDESKTOPS|BSM_APPLICATIONS) || - recips == BSM_APPLICATIONS, /* win2k3 */ - "Received by: %08x\n", recips); - PulseEvent(hevent); - - SetLastError(0xcafebabe); - recips = BSM_ALLDESKTOPS|BSM_APPLICATIONS; - ResetEvent(hevent); - ret = BroadcastSystemMessageExW( BSF_QUERY, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY, NULL ); - ok(!ret, "Returned: %d\n", ret); - ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); - ok(recips == (BSM_ALLDESKTOPS|BSM_APPLICATIONS) || - recips == BSM_APPLICATIONS, /* win2k3 */ - "Received by: %08x\n", recips); - PulseEvent(hevent); } START_TEST(broadcast) @@ -330,7 +221,4 @@ START_TEST(broadcast) trace("Running BroadcastSystemMessageExW tests\n"); test_parametersEx(BroadcastSystemMessageExW); - - trace("Attempting privileges checking tests\n"); - test_noprivileges(); } diff --git a/modules/rostests/winetests/user32/class.c b/modules/rostests/winetests/user32/class.c index 934ea0bfee3..d8cf14a3cda 100644 --- a/modules/rostests/winetests/user32/class.c +++ b/modules/rostests/winetests/user32/class.c @@ -117,6 +117,8 @@ static void ClassTest(HINSTANCE hInstance, BOOL global) return; ok(classatom, "failed to register class\n"); + ok(GetClipboardFormatNameW(classatom, str, ARRAY_SIZE(str)) != 0, "atom not found\n"); + ok(!RegisterClassW (&cls), "RegisterClass of the same class should fail for the second time\n"); @@ -171,7 +173,7 @@ static void ClassTest(HINSTANCE hInstance, BOOL global) } /* check GetClassName */ - i = GetClassNameW(hTestWnd, str, sizeof(str)/sizeof(str[0])); + i = GetClassNameW(hTestWnd, str, ARRAY_SIZE(str)); ok(i == lstrlenW(className), "GetClassName returned incorrect length\n"); ok(!lstrcmpW(className,str), @@ -232,6 +234,8 @@ static void ClassTest(HINSTANCE hInstance, BOOL global) ok(UnregisterClassW(className, hInstance), "UnregisterClass() failed\n"); + ok(GetClipboardFormatNameW(classatom, str, ARRAY_SIZE(str)) == 0, + "atom still found\n"); return; } @@ -647,7 +651,6 @@ static void test_builtinproc(void) "ScrollBar", "#32770", /* dialog */ }; - static const int NUM_NORMAL_CLASSES = (sizeof(NORMAL_CLASSES)/sizeof(NORMAL_CLASSES[0])); static const char classA[] = "deftest"; static const WCHAR classW[] = {'d','e','f','t','e','s','t',0}; WCHAR unistring[] = {0x142, 0x40e, 0x3b4, 0}; /* a string that would be destroyed by a W->A->W conversion */ @@ -658,7 +661,7 @@ static void test_builtinproc(void) WCHAR buf[128]; ATOM atom; HWND hwnd; - int i; + unsigned int i; pDefWindowProcA = (void *)GetProcAddress(GetModuleHandleA("user32.dll"), "DefWindowProcA"); pDefWindowProcW = (void *)GetProcAddress(GetModuleHandleA("user32.dll"), "DefWindowProcW"); @@ -728,7 +731,7 @@ static void test_builtinproc(void) ok(IsWindowUnicode(hwnd) || broken(!IsWindowUnicode(hwnd)) /* Windows 8 and 10 */, "Windows should be Unicode\n"); - SendMessageW(hwnd, WM_GETTEXT, sizeof(buf) / sizeof(buf[0]), (LPARAM)buf); + SendMessageW(hwnd, WM_GETTEXT, ARRAY_SIZE(buf), (LPARAM)buf); if (IsWindowUnicode(hwnd)) ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n"); else @@ -773,7 +776,7 @@ static void test_builtinproc(void) /* For most of the builtin controls both GetWindowLongPtrA and W returns a pointer that is executed directly * by CallWindowProcA/W */ - for (i = 0; i < NUM_NORMAL_CLASSES; i++) + for (i = 0; i < ARRAY_SIZE(NORMAL_CLASSES); i++) { WNDPROC procA, procW; hwnd = CreateWindowExA(0, NORMAL_CLASSES[i], classA, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, @@ -880,7 +883,7 @@ static void test_builtinproc(void) static LRESULT WINAPI TestDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - return DefWindowProcA(hWnd, uMsg, wParam, lParam); + return DefDlgProcA(hWnd, uMsg, wParam, lParam); } static BOOL RegisterTestDialog(HINSTANCE hInstance) @@ -942,7 +945,7 @@ static const struct static void test_extra_values(void) { int i; - for(i=0; i< sizeof(extra_values)/sizeof(extra_values[0]); i++) + for(i = 0; i < ARRAY_SIZE(extra_values); i++) { WNDCLASSEXA wcx; BOOL ret = GetClassInfoExA(NULL,extra_values[i].name,&wcx); @@ -1000,6 +1003,7 @@ if (0) { /* crashes under XP */ SetLastError(0xdeadbeef); ret = GetClassInfoExA(0, "static", &wcx); ok(ret, "GetClassInfoExA() error %d\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "Unexpected error code %d\n", GetLastError()); ok(wcx.cbSize == 0, "expected 0, got %u\n", wcx.cbSize); ok(wcx.lpfnWndProc != NULL, "got null proc\n"); @@ -1135,7 +1139,7 @@ static void test_comctl32_class( const char *name ) name++; - GetTempPathA(sizeof(path)/sizeof(path[0]), path); + GetTempPathA(ARRAY_SIZE(path), path); strcat(path, "comctl32_class.manifest"); create_manifest_file(path, comctl32_manifest); @@ -1163,7 +1167,7 @@ static void test_comctl32_class( const char *name ) if (!ret) goto skiptest; - MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, sizeof(nameW)/sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, ARRAY_SIZE(nameW)); ret = GetClassInfoW( 0, nameW, &wcW ); ok( ret, "GetClassInfoW failed for %s\n", name ); module = GetModuleHandleA( "comctl32" ); @@ -1189,7 +1193,7 @@ static void test_comctl32_class( const char *name ) ret = GetClassInfoA( 0, name, &wcA ); ok( ret || broken(!ret) /* <= winxp */, "GetClassInfoA failed for %s\n", name ); if (!ret) return; - MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, sizeof(nameW)/sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, ARRAY_SIZE(nameW)); ret = GetClassInfoW( 0, nameW, &wcW ); ok( ret, "GetClassInfoW failed for %s\n", name ); module = GetModuleHandleA( "comctl32" ); @@ -1245,7 +1249,7 @@ static void test_comctl32_classes(void) }; winetest_get_mainargs( &argv ); - for (i = 0; i < sizeof(classes) / sizeof(classes[0]); i++) + for (i = 0; i < ARRAY_SIZE(classes); i++) { memset( &startup, 0, sizeof(startup) ); startup.cb = sizeof( startup ); @@ -1321,10 +1325,10 @@ static void test_actctx_classes(void) ATOM class; HINSTANCE hinst; char buff[64]; - HWND hwnd; + HWND hwnd, hwnd2; char path[MAX_PATH]; - GetTempPathA(sizeof(path)/sizeof(path[0]), path); + GetTempPathA(ARRAY_SIZE(path), path); strcat(path, "actctx_classes.manifest"); create_manifest_file(path, main_manifest); @@ -1355,6 +1359,12 @@ static void test_actctx_classes(void) hwnd = CreateWindowExA(0, testclass, "test", 0, 0, 0, 0, 0, 0, 0, hinst, 0); ok(hwnd != NULL, "Failed to create a window.\n"); + hwnd2 = FindWindowExA(NULL, NULL, "MyTestClass", NULL); + ok(hwnd2 == hwnd, "Failed to find test window.\n"); + + hwnd2 = FindWindowExA(NULL, NULL, "4.3.2.1!MyTestClass", NULL); + ok(hwnd2 == NULL, "Unexpected find result %p.\n", hwnd2); + ret = GetClassNameA(hwnd, buff, sizeof(buff)); ok(ret, "Failed to get class name.\n"); ok(!strcmp(buff, testclass), "Unexpected class name.\n"); @@ -1380,6 +1390,17 @@ static void test_actctx_classes(void) DestroyWindow(hwnd); + hwnd = CreateWindowExA(0, "4.3.2.1!MyTestClass", "test", 0, 0, 0, 0, 0, 0, 0, hinst, 0); + ok(hwnd != NULL, "Failed to create a window.\n"); + + hwnd2 = FindWindowExA(NULL, NULL, "MyTestClass", NULL); + ok(hwnd2 == hwnd, "Failed to find test window.\n"); + + hwnd2 = FindWindowExA(NULL, NULL, "4.3.2.1!MyTestClass", NULL); + ok(hwnd2 == NULL, "Unexpected find result %p.\n", hwnd2); + + DestroyWindow(hwnd); + ret = UnregisterClassA("MyTestClass", hinst); ok(!ret, "Unexpected ret value %d.\n", ret); diff --git a/modules/rostests/winetests/user32/clipboard.c b/modules/rostests/winetests/user32/clipboard.c index 2dced095b2a..b00151271ad 100644 --- a/modules/rostests/winetests/user32/clipboard.c +++ b/modules/rostests/winetests/user32/clipboard.c @@ -715,7 +715,7 @@ static void test_synthesized(void) r = CloseClipboard(); ok(r, "gle %d\n", GetLastError()); - for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) + for (i = 0; i < ARRAY_SIZE(tests); i++) { r = OpenClipboard(NULL); ok(r, "%u: gle %d\n", i, GetLastError()); @@ -2054,7 +2054,7 @@ static void test_string_data(void) char bufferA[12]; WCHAR bufferW[12]; - for (i = 0; i < sizeof(test_data) / sizeof(test_data[0]); i++) + for (i = 0; i < ARRAY_SIZE(test_data); i++) { /* 1-byte Unicode strings crash on Win64 */ #ifdef _WIN64 diff --git a/modules/rostests/winetests/user32/cursoricon.c b/modules/rostests/winetests/user32/cursoricon.c index e42875f9256..8ce1eb163e1 100644 --- a/modules/rostests/winetests/user32/cursoricon.c +++ b/modules/rostests/winetests/user32/cursoricon.c @@ -1053,10 +1053,6 @@ static const DWORD biSize_tests[] = { 0xffffffff }; -#ifndef __REACTOS__ -#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) -#endif - static void test_LoadImageBitmap(const char * test_desc, HBITMAP hbm) { BITMAP bm; @@ -1207,6 +1203,126 @@ static void create_ico_file(const char *filename, const test_icon_entries_t *tes HeapFree(GetProcessHeap(), 0, buf); } +static void create_bitmap_file(const char *filename, const BITMAPINFO *bmi, const unsigned char *bits) +{ + unsigned int clr_used, bmi_size, bits_size, stride; + const BITMAPINFOHEADER *h = &bmi->bmiHeader; + BITMAPFILEHEADER hdr; + DWORD bytes_written; + HANDLE file; + BOOL ret; + + clr_used = h->biBitCount <= 8 ? 1u << h->biBitCount : 0; + stride = ((h->biBitCount * h->biWidth + 7) / 8 + 3) & ~3; + bits_size = h->biHeight * stride; + bmi_size = h->biSize + clr_used * sizeof(RGBQUAD); + + hdr.bfType = 0x4d42; + hdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + bmi_size; + hdr.bfSize = hdr.bfOffBits + bits_size; + hdr.bfReserved1 = 0; + 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()); + ret = WriteFile(file, &hdr, sizeof(hdr), &bytes_written, NULL); + ok(ret && bytes_written == sizeof(hdr), "Unexpected WriteFile() result, ret %#x, bytes_written %u.\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", + 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", + ret, bytes_written); + CloseHandle(file); +} + +static void test_LoadImage_working_directory_run(char *path) +{ + DWORD bytes_written; + HANDLE handle; + BOOL ret; + char path_icon[MAX_PATH]; + char path_image[MAX_PATH]; + static const test_icon_entries_t icon_desc = {32, 32}; + + sprintf(path_icon, "%s\\icon.ico", path); + sprintf(path_image, "%s\\test.bmp", path); + + /* Create Files */ + 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()); + 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); + + /* Test cursor */ + handle = LoadImageA(NULL, "icon.ico", IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE); + ok(handle != NULL, "run %s: LoadImage() failed.\n", path); + + ret = DestroyIcon(handle); + ok(ret, "run %s: DestroyIcon failed: %d\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()); + + /* Cleanup */ + ret = DeleteFileA(path_image); + ok(ret, "run %s: DeleteFileA failed: %d\n", path, GetLastError()); + ret = DeleteFileA(path_icon); + ok(ret, "run %s: DeleteFileA failed: %d\n", path, GetLastError()); +} + +static void test_LoadImage_working_directory(void) +{ + char old_working_dir[MAX_PATH]; + char temp_dir_current[MAX_PATH]; + char temp_dir_PATH[MAX_PATH]; + char executable_path[MAX_PATH]; + int pos_slash; + char old_PATH[10000]; + char new_PATH[10000]; + BOOL ret; + + GetCurrentDirectoryA(ARRAY_SIZE(old_working_dir), old_working_dir); + + GetTempPathA(ARRAY_SIZE(temp_dir_current), temp_dir_current); + strcat(temp_dir_current, "wine-test-dir-current\\"); + GetTempPathA(ARRAY_SIZE(temp_dir_PATH), temp_dir_PATH); + strcat(temp_dir_PATH, "wine-test-dir-path\\"); + + GetModuleFileNameA(NULL, executable_path, ARRAY_SIZE(executable_path)); + pos_slash = strrchr(executable_path, '\\') - executable_path; + executable_path[pos_slash + 1] = 0; + + CreateDirectoryA(temp_dir_current, NULL); + CreateDirectoryA(temp_dir_PATH, NULL); + + SetCurrentDirectoryA(temp_dir_current); + + GetEnvironmentVariableA("PATH", old_PATH, ARRAY_SIZE(old_PATH)); + sprintf(new_PATH, "%s;%s", old_PATH, temp_dir_PATH); + SetEnvironmentVariableA("PATH", new_PATH); + + test_LoadImage_working_directory_run(temp_dir_current); + test_LoadImage_working_directory_run(executable_path); + test_LoadImage_working_directory_run(temp_dir_PATH); + + SetCurrentDirectoryA(old_working_dir); + SetEnvironmentVariableA("PATH", old_PATH); + + ret = RemoveDirectoryA(temp_dir_current); + ok(ret, "RemoveDirectoryA failed: %d\n", GetLastError()); + ret = RemoveDirectoryA(temp_dir_PATH); + ok(ret, "RemoveDirectoryA failed: %d\n", GetLastError()); +} + static void test_LoadImage(void) { HANDLE handle; @@ -1330,9 +1446,10 @@ static void test_LoadImage(void) bitmap_header->biSize = sizeof(BITMAPINFOHEADER); test_LoadImageFile("Cursor (invalid dwDIBOffset)", invalid_dwDIBOffset, sizeof(invalid_dwDIBOffset), "cur", 0); -} -#undef ARRAY_SIZE + /* Test in which paths images with a relative path can be found */ + test_LoadImage_working_directory(); +} static void test_CreateIconFromResource(void) { @@ -2539,7 +2656,7 @@ static void test_PrivateExtractIcons(void) static const test_icon_entries_t icon_desc[] = {{0,0,TRUE}, {16,16,TRUE}, {32,32}, {64,64,TRUE}}; - create_ico_file("extract.ico", icon_desc, sizeof(icon_desc)/sizeof(*icon_desc)); + create_ico_file("extract.ico", icon_desc, ARRAY_SIZE(icon_desc)); ret = PrivateExtractIconsA("extract.ico", 0, 32, 32, &icon, NULL, 1, 0); ok(ret == 1, "PrivateExtractIconsA returned %u\n", ret); @@ -2668,6 +2785,205 @@ static void test_monochrome_icon(void) HeapFree(GetProcessHeap(), 0, icon_data); } +static COLORREF get_color_from_bits(const unsigned char *bits, const BITMAPINFO *bmi, + unsigned int row, unsigned int column) +{ + const BITMAPINFOHEADER *h = &bmi->bmiHeader; + unsigned int stride, shift, mask; + const unsigned char *data; + RGBQUAD color; + WORD color16; + + stride = ((h->biBitCount * h->biWidth + 7) / 8 + 3) & ~3; + data = bits + row * stride + column * h->biBitCount / 8; + if (h->biBitCount >= 24) + return RGB(data[2], data[1], data[0]); + + if (h->biBitCount == 16) + { + color16 = ((WORD)data[1] << 8) | data[0]; + return RGB(((color16 >> 10) & 0x1f) << 3, ((color16 >> 5) & 0x1f) << 3, + (color16 & 0x1f) << 3); + } + shift = 8 - h->biBitCount - (column * h->biBitCount) % 8; + mask = ~(~0u << h->biBitCount); + color = bmi->bmiColors[(data[0] >> shift) & mask]; + return RGB(color.rgbRed, color.rgbGreen, color.rgbBlue); +} + +#define compare_bitmap_bits(a, b, c, d, e, f, g) compare_bitmap_bits_(__LINE__, a, b, c, d, e, f, g) +static void compare_bitmap_bits_(unsigned int line, HDC hdc, HBITMAP bitmap, BITMAPINFO *bmi, + size_t result_bits_size, const unsigned char *expected_bits, unsigned int test_index, BOOL todo) +{ + unsigned char *result_bits; + unsigned int row, column; + int ret; + + result_bits = HeapAlloc(GetProcessHeap(), 0, result_bits_size); + ret = GetDIBits(hdc, bitmap, 0, bmi->bmiHeader.biHeight, + result_bits, bmi, DIB_RGB_COLORS); + ok(ret == bmi->bmiHeader.biHeight, "Unexpected GetDIBits result %d, GetLastError() %u.\n", + ret, GetLastError()); + for (row = 0; row < bmi->bmiHeader.biHeight; ++row) + for (column = 0; column < bmi->bmiHeader.biWidth; ++column) + { + COLORREF result, expected; + + 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", + result, expected, test_index, row, column); + } + HeapFree(GetProcessHeap(), 0, result_bits); +} + +static void test_Image_StretchMode(void) +{ + static const unsigned char test_bits_24[] = + { + 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, + 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, + 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[] = + { + 0x3f, 0xff, 0x00, 0x3f, 0xff, 0x3f, 0x00, 0x00, + 0x3f, 0xff, 0x7f, 0x00, 0xff, 0x3f, 0x00, 0x00, + }; +#define rgb16(r, g, b) ((WORD)(((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3))) + static const WORD test_bits_16[] = + { + rgb16(0x00, 0x20, 0x00), rgb16(0x00, 0x40, 0x00), rgb16(0x00, 0x40, 0xff), rgb16(0x00, 0x20, 0x00), + rgb16(0x00, 0x60, 0x00), rgb16(0xff, 0x80, 0x00), rgb16(0xff, 0x60, 0x00), rgb16(0x00, 0x80, 0x00), + rgb16(0x00, 0x20, 0xff), rgb16(0x00, 0x40, 0x00), rgb16(0x00, 0x40, 0xff), rgb16(0x00, 0x20, 0x00), + rgb16(0xff, 0x80, 0x00), rgb16(0x00, 0x60, 0xff), rgb16(0x00, 0x80, 0x00), rgb16(0x00, 0x60, 0x00), + }; + static const WORD expected_bits_16[] = + { + rgb16(0x00, 0x40, 0x00), rgb16(0x00, 0x20, 0x00), + rgb16(0x00, 0x40, 0x00), rgb16(0x00, 0x20, 0x00), + }; +#undef rgb16 + static const unsigned char test_bits_8[] = + { + 0x00, 0xff, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, + 0xff, 0x55, 0x00, 0xff, + 0x00, 0xff, 0xff, 0x00, + }; + static const unsigned char expected_bits_8[] = + { + 0xff, 0xff, 0x00, 0x00, + 0x55, 0xff, 0x00, 0x00, + }; + static const unsigned char test_bits_1[] = + { + 0x30, 0x0, 0x0, 0x0, + 0x30, 0x0, 0x0, 0x0, + 0x40, 0x0, 0x0, 0x0, + 0xc0, 0x0, 0x0, 0x0, + }; + static const unsigned char expected_bits_1[] = + { + 0x40, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + }; + static const RGBQUAD colors_bits_1[] = + { + {0, 0, 0}, + {0xff, 0xff, 0xff}, + }; + static RGBQUAD colors_bits_8[256]; + + static const struct + { + LONG width, height, output_width, output_height; + WORD bit_count; + const unsigned char *test_bits, *expected_bits; + size_t test_bits_size, result_bits_size; + const RGBQUAD *bmi_colors; + size_t bmi_colors_size; + BOOL todo; + } + tests[] = + { + {4, 4, 2, 2, 24, test_bits_24, expected_bits_24, + sizeof(test_bits_24), sizeof(expected_bits_24), NULL, 0, TRUE}, + {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}, + {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}, + {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}, + }; + static const char filename[] = "test.bmp"; + BITMAPINFO *bmi, *bmi_output; + HBITMAP bitmap, bitmap_copy; + unsigned int test_index; + unsigned char *bits; + size_t bmi_size; + unsigned int i; + 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->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi->bmiHeader.biPlanes = 1; + bmi->bmiHeader.biCompression = BI_RGB; + + for (i = 0; i < 256; ++i) + colors_bits_8[i].rgbRed = colors_bits_8[i].rgbGreen = colors_bits_8[i].rgbBlue = i; + + hdc = GetDC(NULL); + + for (test_index = 0; test_index < ARRAY_SIZE(tests); ++test_index) + { + if (tests[test_index].bmi_colors) + memcpy(bmi->bmiColors, tests[test_index].bmi_colors, tests[test_index].bmi_colors_size); + else + memset(bmi->bmiColors, 0, 256 * sizeof(RGBQUAD)); + + bmi->bmiHeader.biWidth = tests[test_index].width; + bmi->bmiHeader.biHeight = tests[test_index].height; + bmi->bmiHeader.biBitCount = tests[test_index].bit_count; + memcpy(bmi_output, bmi, bmi_size); + bmi_output->bmiHeader.biWidth = tests[test_index].output_width; + 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()); + 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()); + + 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); + 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()); + 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); + DeleteObject(bitmap); + } + ReleaseDC(0, hdc); + HeapFree(GetProcessHeap(), 0, bmi_output); + HeapFree(GetProcessHeap(), 0, bmi); +} + START_TEST(cursoricon) { pGetCursorInfo = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetCursorInfo" ); @@ -2695,6 +3011,7 @@ START_TEST(cursoricon) test_CopyImage_Bitmap(16); test_CopyImage_Bitmap(24); test_CopyImage_Bitmap(32); + test_Image_StretchMode(); test_initial_cursor(); test_CreateIcon(); test_LoadImage(); diff --git a/modules/rostests/winetests/user32/dde.c b/modules/rostests/winetests/user32/dde.c index d63a0f65aa2..eed2ac437e1 100644 --- a/modules/rostests/winetests/user32/dde.c +++ b/modules/rostests/winetests/user32/dde.c @@ -2396,7 +2396,7 @@ 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 + sizeof(test_cmd_w_to_w)/sizeof(test_cmd_w_to_w[0]); +static const int nb_callbacks = 5 + ARRAY_SIZE(test_cmd_w_to_w); static HDDEDATA CALLBACK server_end_to_end_callback(UINT uType, UINT uFmt, HCONV hconv, HSZ hsz1, HSZ hsz2, HDDEDATA hdata, @@ -2480,7 +2480,7 @@ static HDDEDATA CALLBACK server_end_to_end_callback(UINT uType, UINT uFmt, HCONV size_a = strlen(test_cmd_a_to_a) + 1; size_w = (lstrlenW(cmd_w) + 1) * sizeof(WCHAR); size_a_to_w = MultiByteToWideChar( CP_ACP, 0, test_cmd_a_to_a, -1, test_cmd_a_to_w, - sizeof(test_cmd_a_to_w)/sizeof(WCHAR) ) * sizeof(WCHAR); + ARRAY_SIZE(test_cmd_a_to_w)) * sizeof(WCHAR); size_w_to_a = WideCharToMultiByte( CP_ACP, 0, cmd_w, -1, test_cmd_w_to_a, sizeof(test_cmd_w_to_a), NULL, NULL ); switch (str_index) @@ -2528,7 +2528,7 @@ static HDDEDATA CALLBACK server_end_to_end_callback(UINT uType, UINT uFmt, HCONV /* double A->W mapping */ /* NT uses the full size, XP+ only until the first null */ DWORD nt_size = MultiByteToWideChar( CP_ACP, 0, (char *)cmd_w, size_w, test_cmd_a_to_w, - sizeof(test_cmd_a_to_w)/sizeof(WCHAR) ) * sizeof(WCHAR); + ARRAY_SIZE(test_cmd_a_to_w)) * sizeof(WCHAR); 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 */, @@ -2554,7 +2554,7 @@ static HDDEDATA CALLBACK server_end_to_end_callback(UINT uType, UINT uFmt, HCONV { todo_wine ok(size == size_w, "Wrong size %d expected %d, 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, - sizeof(test_cmd_a_to_w)/sizeof(WCHAR)); + ARRAY_SIZE(test_cmd_a_to_w)); todo_wine ok(!lstrcmpW((WCHAR*)buffer, cmd_w), "Expected %s got %s, msg_index=%d\n", wine_dbgstr_w(cmd_w), wine_dbgstr_w((WCHAR *)buffer), msg_index); } @@ -2562,7 +2562,7 @@ static HDDEDATA CALLBACK server_end_to_end_callback(UINT uType, UINT uFmt, HCONV { todo_wine ok(size == size_w, "Wrong size %d expected %d, 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, - sizeof(test_cmd_a_to_w)/sizeof(WCHAR)); + ARRAY_SIZE(test_cmd_a_to_w)); if (!is_cjk()) todo_wine ok(!lstrcmpW((WCHAR*)buffer, test_cmd_a_to_w), "Expected %s, got %s, msg_index=%d\n", wine_dbgstr_w(test_cmd_a_to_w), wine_dbgstr_w((WCHAR*)buffer), msg_index); @@ -2663,7 +2663,7 @@ static void test_end_to_end_client(BOOL type_a) err = DdeGetLastError(client_pid); ok(err == DMLERR_NO_ERROR, "wrong dde error %x\n", err); - for (i = 0; i < sizeof(test_cmd_w_to_w)/sizeof(test_cmd_w_to_w[0]); i++) + for (i = 0; i < ARRAY_SIZE(test_cmd_w_to_w); i++) { hdata = DdeClientTransaction((LPBYTE)test_cmd_w_to_w[i], (lstrlenW(test_cmd_w_to_w[i]) + 1) * sizeof(WCHAR), diff --git a/modules/rostests/winetests/user32/dialog.c b/modules/rostests/winetests/user32/dialog.c index 679a76204c8..3360b688bff 100644 --- a/modules/rostests/winetests/user32/dialog.c +++ b/modules/rostests/winetests/user32/dialog.c @@ -42,6 +42,7 @@ #include "winbase.h" #include "wingdi.h" #include "winuser.h" +#include "winnls.h" #define MAXHWNDS 1024 static HWND hwnd [MAXHWNDS]; @@ -57,6 +58,7 @@ static LONG g_styleInitialFocusT1, g_styleInitialFocusT2; static BOOL g_bInitialFocusInitDlgResult, g_bReceivedCommand; static BOOL g_terminated; +static BOOL g_button1Clicked; typedef struct { INT_PTR id; @@ -149,6 +151,11 @@ static const h_entry hierarchy [] = { {0, 0, 0, 0} }; +static DWORD get_button_style(HWND button) +{ + return GetWindowLongW(button, GWL_STYLE) & BS_TYPEMASK; +} + static BOOL CreateWindows (HINSTANCE hinst) { const h_entry *p = hierarchy; @@ -156,14 +163,14 @@ static BOOL CreateWindows (HINSTANCE hinst) while (p->id != 0) { DWORD style, exstyle; - char ctrlname[9]; + char ctrlname[16]; /* Basically assert that the hierarchy is valid and track the * maximum control number */ if (p->id >= numwnds) { - if (p->id >= sizeof(hwnd)/sizeof(hwnd[0])) + if (p->id >= ARRAY_SIZE(hwnd)) { trace ("Control %ld is out of range\n", p->id); return FALSE; @@ -476,6 +483,10 @@ static LRESULT CALLBACK main_window_procA (HWND hwnd, UINT uiMsg, WPARAM wParam, g_terminated = TRUE; return 0; } + else if ((wParam == 100 || wParam == 0xFFFF) && lParam) + { + g_button1Clicked = TRUE; + } break; } @@ -630,76 +641,47 @@ static void test_WM_NEXTDLGCTL(void) * BS_DEFPUSHBUTTON with out making it default. */ + /* Keep the focus on Edit control. */ + SetFocus(g_hwndTestDlgEdit); + ok((GetFocus() == g_hwndTestDlgEdit), "Focus didn't set on Edit control\n"); + + /* Test message WM_NEXTDLGCTL */ + DefDlgProcA(g_hwndTestDlg, WM_NEXTDLGCTL, 0, 0); + ok((GetFocus() == g_hwndTestDlgBut1), "Focus didn't move to first button\n"); + + /* Check whether the default button ID got changed by sending message "WM_NEXTDLGCTL" */ + dwVal = DefDlgProcA(g_hwndTestDlg, DM_GETDEFID, 0, 0); + ok(IDCANCEL == (LOWORD(dwVal)), "WM_NEXTDLGCTL changed default button\n"); + /* - * Keep the focus on Edit control. + * 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"); - if ( SetFocus( g_hwndTestDlgEdit ) ) - { - ok ((GetFocus() == g_hwndTestDlgEdit), "Focus didn't set on Edit control\n"); + /* Move focus to Button2 using "WM_NEXTDLGCTL" */ + DefDlgProcA(g_hwndTestDlg, WM_NEXTDLGCTL, 0, 0); + ok((GetFocus() == g_hwndTestDlgBut2), "Focus didn't move to second button\n"); - /* - * Test message WM_NEXTDLGCTL - */ - DefDlgProcA( g_hwndTestDlg, WM_NEXTDLGCTL, 0, 0 ); - ok ((GetFocus() == g_hwndTestDlgBut1), "Focus didn't move to first button\n"); + /* Check whether the default button ID got changed by sending message "WM_NEXTDLGCTL" */ + dwVal = DefDlgProcA(g_hwndTestDlg, DM_GETDEFID, 0, 0); + ok(IDCANCEL == (LOWORD(dwVal)), "WM_NEXTDLGCTL changed default button\n"); - /* - * Check whether the default button ID got changed by sending message "WM_NEXTDLGCTL" - */ - dwVal = DefDlgProcA(g_hwndTestDlg, DM_GETDEFID, 0, 0); - ok ( IDCANCEL == (LOWORD(dwVal)), "WM_NEXTDLGCTL changed default button\n"); + /* + * 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"); - /* - * 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. - */ - if ( IDCANCEL == (LOWORD(dwVal)) ) - { - ok ( ((GetWindowLongA( g_hwndTestDlgBut1, GWL_STYLE)) & BS_DEFPUSHBUTTON), - "Button1 style not set to BS_DEFPUSHBUTTON\n" ); + /* Move focus to Edit control using "WM_NEXTDLGCTL" */ + DefDlgProcA(g_hwndTestDlg, WM_NEXTDLGCTL, 0, 0); + ok((GetFocus() == g_hwndTestDlgEdit), "Focus didn't move to Edit control\n"); - ok ( !((GetWindowLongA( g_hwndTestDlgBut2, GWL_STYLE)) & BS_DEFPUSHBUTTON), - "Button2's style not changed to BS_PUSHBUTTON\n" ); - } - - /* - * Move focus to Button2 using "WM_NEXTDLGCTL" - */ - DefDlgProcA( g_hwndTestDlg, WM_NEXTDLGCTL, 0, 0 ); - ok ((GetFocus() == g_hwndTestDlgBut2), "Focus didn't move to second button\n"); - - /* - * Check whether the default button ID got changed by sending message "WM_NEXTDLGCTL" - */ - dwVal = DefDlgProcA(g_hwndTestDlg, DM_GETDEFID, 0, 0); - ok ( IDCANCEL == (LOWORD(dwVal)), "WM_NEXTDLGCTL changed default button\n"); - - /* - * 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. - */ - if ( IDCANCEL == (LOWORD(dwVal)) ) - { - ok ( ((GetWindowLongA( g_hwndTestDlgBut2, GWL_STYLE)) & BS_DEFPUSHBUTTON), - "Button2 style not set to BS_DEFPUSHBUTTON\n" ); - - ok ( !((GetWindowLongA( g_hwndTestDlgBut1, GWL_STYLE)) & BS_DEFPUSHBUTTON), - "Button1's style not changed to BS_PUSHBUTTON\n" ); - } - - /* - * Move focus to Edit control using "WM_NEXTDLGCTL" - */ - DefDlgProcA( g_hwndTestDlg, WM_NEXTDLGCTL, 0, 0 ); - ok ((GetFocus() == g_hwndTestDlgEdit), "Focus didn't move to Edit control\n"); - - /* - * Check whether the default button ID got changed by sending message "WM_NEXTDLGCTL" - */ - dwVal = DefDlgProcA(g_hwndTestDlg, DM_GETDEFID, 0, 0); - ok ( IDCANCEL == (LOWORD(dwVal)), "WM_NEXTDLGCTL changed default button\n"); - } + /* Check whether the default button ID got changed by sending message "WM_NEXTDLGCTL" */ + dwVal = DefDlgProcA(g_hwndTestDlg, DM_GETDEFID, 0, 0); + ok(IDCANCEL == (LOWORD(dwVal)), "WM_NEXTDLGCTL changed default button\n"); /* test nested default buttons */ @@ -812,6 +794,34 @@ static void test_IsDialogMessage(void) ok (!IsDialogMessageA(msg.hwnd, &msg), "expected failure\n"); UnhookWindowsHookEx(hook); + DestroyWindow(g_hwndMain); + + g_hwndMain = CreateWindowA("IsDialogMessageWindowClass", "IsDialogMessageWindowClass", WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, g_hinst, 0); + SetFocus(g_hwndButton1); + g_button1Clicked = FALSE; + FormEnterMsg(&msg, g_hwndButton1); + ok(IsDialogMessageA(g_hwndMain, &msg), "Did not handle the ENTER\n"); + ok(g_button1Clicked, "Did not receive button 1 click notification\n"); + + g_button1Clicked = FALSE; + FormEnterMsg(&msg, g_hwndMain); + ok(IsDialogMessageA(g_hwndMain, &msg), "Did not handle the ENTER\n"); + ok(g_button1Clicked, "Did not receive button 1 click notification\n"); + + g_button1Clicked = FALSE; + FormEnterMsg(&msg, g_hwndButton2); + ok(IsDialogMessageA(g_hwndMain, &msg), "Did not handle the ENTER\n"); + ok(g_button1Clicked, "Did not receive button 1 click notification\n"); + + /* Button with id larger than 0xFFFF should also work */ + g_button1Clicked = FALSE; + FormEnterMsg(&msg, g_hwndMain); + SetWindowLongPtrW(g_hwndButton1, GWLP_ID, 0x1FFFF); + ok(IsDialogMessageA(g_hwndMain, &msg), "Did not handle the ENTER\n"); + ok(g_button1Clicked, "Did not receive button 1 click notification\n"); + + DestroyWindow(g_hwndMain); } @@ -876,6 +886,56 @@ static INT_PTR CALLBACK focusDlgWinProc (HWND hDlg, UINT uiMsg, WPARAM wParam, return FALSE; } +static INT_PTR CALLBACK EmptyProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) { + case WM_INITDIALOG: + return TRUE; + } + return FALSE; +} + +static INT_PTR CALLBACK focusChildDlgWinProc (HWND hwnd, UINT uiMsg, WPARAM wParam, + LPARAM lParam) +{ + static HWND hChildDlg; + + switch (uiMsg) + { + case WM_INITDIALOG: + { + RECT rectHwnd; + struct { + DLGTEMPLATE tmplate; + WORD menu,class,title; + } temp; + + SetFocus( GetDlgItem(hwnd, 200) ); + + GetClientRect(hwnd,&rectHwnd); + temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK; + temp.tmplate.dwExtendedStyle = 0; + temp.tmplate.cdit = 0; + temp.tmplate.x = 0; + temp.tmplate.y = 0; + temp.tmplate.cx = 0; + temp.tmplate.cy = 0; + temp.menu = temp.class = temp.title = 0; + + hChildDlg = CreateDialogIndirectParamA(g_hinst, &temp.tmplate, + hwnd, (DLGPROC)EmptyProcUserTemplate, 0); + ok(hChildDlg != 0, "Failed to create test dialog.\n"); + + return FALSE; + } + case WM_CLOSE: + DestroyWindow(hChildDlg); + return TRUE; + } + + return FALSE; +} + /* Helper for InitialFocusTest */ static const char * GetHwndString(HWND hw) { @@ -1062,6 +1122,29 @@ static void test_focus(void) DestroyWindow(hDlg); } + + /* Test 6: + * Select textbox's text on creation when WM_INITDIALOG creates a child dialog. */ + { + HWND hDlg; + HRSRC hResource; + HANDLE hTemplate; + DLGTEMPLATE* pTemplate; + HWND edit; + + hResource = FindResourceA(g_hinst,"FOCUS_TEST_DIALOG_3", (LPCSTR)RT_DIALOG); + hTemplate = LoadResource(g_hinst, hResource); + pTemplate = LockResource(hTemplate); + + hDlg = CreateDialogIndirectParamA(g_hinst, pTemplate, NULL, focusChildDlgWinProc, 0); + ok(hDlg != 0, "Failed to create test dialog.\n"); + edit = GetDlgItem(hDlg, 200); + + ok(GetFocus() == edit, "Focus not set to edit, focus=%p, dialog=%p, edit=%p\n", + GetFocus(), hDlg, edit); + + DestroyWindow(hDlg); + } } static void test_GetDlgItemText(void) @@ -1070,16 +1153,54 @@ static void test_GetDlgItemText(void) BOOL ret; strcpy(string, "Overwrite Me"); - ret = GetDlgItemTextA(NULL, 0, string, sizeof(string)/sizeof(string[0])); + ret = GetDlgItemTextA(NULL, 0, string, ARRAY_SIZE(string)); ok(!ret, "GetDlgItemText(NULL) shouldn't have succeeded\n"); ok(string[0] == '\0' || broken(!strcmp(string, "Overwrite Me")), "string retrieved using GetDlgItemText should have been NULL terminated\n"); } +static INT_PTR CALLBACK getdlgitem_test_dialog_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if (msg == WM_INITDIALOG) + { + char text[64]; + LONG_PTR val; + HWND hwnd; + BOOL ret; + + hwnd = GetDlgItem(hdlg, -1); + ok(hwnd != NULL, "Expected dialog item.\n"); + + *text = 0; + ret = GetDlgItemTextA(hdlg, -1, text, ARRAY_SIZE(text)); + ok(ret && !strcmp(text, "Text1"), "Unexpected item text.\n"); + + val = GetWindowLongA(hwnd, GWLP_ID); + ok(val == -1, "Unexpected id.\n"); + + val = GetWindowLongPtrA(hwnd, GWLP_ID); + ok(val == -1, "Unexpected id %ld.\n", val); + + hwnd = GetDlgItem(hdlg, -2); + ok(hwnd != NULL, "Expected dialog item.\n"); + + val = GetWindowLongA(hwnd, GWLP_ID); + ok(val == -2, "Unexpected id.\n"); + + val = GetWindowLongPtrA(hwnd, GWLP_ID); + ok(val == -2, "Unexpected id %ld.\n", val); + + EndDialog(hdlg, 0xdead); + } + + return FALSE; +} + static void test_GetDlgItem(void) { HWND hwnd, child1, child2, hwnd2; + INT_PTR retval; BOOL ret; hwnd = CreateWindowA("button", "parent", WS_VISIBLE, 0, 0, 100, 100, NULL, 0, g_hinst, NULL); @@ -1126,6 +1247,9 @@ static void test_GetDlgItem(void) DestroyWindow(child1); DestroyWindow(child2); DestroyWindow(hwnd); + + retval = DialogBoxParamA(g_hinst, "GETDLGITEM_TEST_DIALOG", NULL, getdlgitem_test_dialog_proc, 0); + ok(retval == 0xdead, "Unexpected return value.\n"); } static INT_PTR CALLBACK DestroyDlgWinProc (HWND hDlg, UINT uiMsg, @@ -1486,7 +1610,7 @@ static INT_PTR CALLBACK test_aw_conversion_dlgproc(HWND hdlg, UINT msg, WPARAM w (BYTE)buff[0], (BYTE)buff[1], len); memset(buffW, 0xff, sizeof(buffW)); - len = GetWindowTextW(hdlg, buffW, sizeof(buffW)/sizeof(buffW[0])); + len = GetWindowTextW(hdlg, buffW, ARRAY_SIZE(buffW)); ok(buffW[0] == 'W' && buffW[1] == 0xffff && len == 0, "Unexpected window text %#x, %#x, len %d\n", buffW[0], buffW[1], len); @@ -1592,7 +1716,7 @@ static INT_PTR CALLBACK test_aw_conversion_dlgproc2(HWND hdlg, UINT msg, WPARAM ok(!strcmp(buff, testtext) && len == 0, "Unexpected window text %s, len %d\n", buff, len); memset(buffW, 0xff, sizeof(buffW)); - len = GetWindowTextW(hdlg, buffW, sizeof(buffW)/sizeof(buffW[0])); + len = GetWindowTextW(hdlg, buffW, ARRAY_SIZE(buffW)); ok(buffW[0] == 0 && buffW[1] == 0xffff && len == 0, "Unexpected window text %#x, %#x, len %d\n", buffW[0], buffW[1], len); @@ -1869,6 +1993,187 @@ static void test_MessageBoxFontTest(void) 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; @@ -2178,4 +2483,5 @@ START_TEST(dialog) test_SaveRestoreFocus(); test_timer_message(); test_MessageBox(); + test_MessageBox_WM_COPY_Test(); } diff --git a/modules/rostests/winetests/user32/edit.c b/modules/rostests/winetests/user32/edit.c index 01418bf551a..d0374c02a35 100644 --- a/modules/rostests/winetests/user32/edit.c +++ b/modules/rostests/winetests/user32/edit.c @@ -1435,16 +1435,27 @@ static void test_edit_control_scroll(void) DestroyWindow (hwEdit); } +static BOOL is_cjk_charset(HDC dc) +{ + switch (GdiGetCodePage(dc)) { + case 932: case 936: case 949: case 950: case 1361: + return TRUE; + default: + return FALSE; + } +} + static void test_margins_usefontinfo(UINT charset) { HWND hwnd; HDC hdc; + TEXTMETRICW tm; SIZE size; - BOOL cjk = FALSE; LOGFONTA lf; HFONT hfont; RECT rect; - INT margins, threshold, expect, empty_expect, small_expect; + INT margins, threshold, expect, empty_expect; + const UINT small_margins = MAKELONG(1, 5); memset(&lf, 0, sizeof(lf)); lf.lfHeight = -11; @@ -1463,40 +1474,31 @@ static void test_margins_usefontinfo(UINT charset) hdc = GetDC(hwnd); hfont = SelectObject(hdc, hfont); - size.cx = GdiGetCharDimensions( hdc, NULL, &size.cy ); - expect = MAKELONG(size.cx / 2, size.cx / 2); - small_expect = 0; - empty_expect = size.cx >= 28 ? small_expect : expect; - - charset = GetTextCharset(hdc); - switch (charset) - { - case SHIFTJIS_CHARSET: - case HANGUL_CHARSET: - case GB2312_CHARSET: - case CHINESEBIG5_CHARSET: - cjk = TRUE; + size.cx = GdiGetCharDimensions( hdc, &tm, &size.cy ); + if ((charset != tm.tmCharSet && charset != DEFAULT_CHARSET) || + !(tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR))) { + skip("%s for charset %d isn't available\n", lf.lfFaceName, charset); + hfont = SelectObject(hdc, hfont); + ReleaseDC(hwnd, hdc); + DestroyWindow(hwnd); + DeleteObject(hfont); + return; } - + expect = MAKELONG(size.cx / 2, size.cx / 2); hfont = SelectObject(hdc, hfont); ReleaseDC(hwnd, hdc); margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); ok(margins == 0, "got %x\n", margins); SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); - margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); - if (!cjk) - ok(margins == expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins)); - else - { - ok(HIWORD(margins) > 0 && LOWORD(margins) > 0, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins)); - expect = empty_expect = small_expect = margins; - } + SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO)); + expect = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); DestroyWindow(hwnd); - threshold = (size.cx / 2 + size.cx) * 2; + threshold = HIWORD(expect) + LOWORD(expect) + size.cx * 2; + empty_expect = threshold > 80 ? small_margins : expect; - /* Size below which non-cjk margins are zero */ + /* Size below the threshold, margins remain unchanged */ hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, threshold - 1, 100, NULL, NULL, NULL, NULL); ok(hwnd != NULL, "got %p\n", hwnd); GetClientRect(hwnd, &rect); @@ -1506,11 +1508,13 @@ static void test_margins_usefontinfo(UINT charset) ok(margins == 0, "got %x\n", margins); SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); + SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins); + SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO)); margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); - ok(margins == small_expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins)); + ok(margins == small_margins, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins)); DestroyWindow(hwnd); - /* Size at which non-cjk margins become non-zero */ + /* Size at the threshold, margins become non-zero */ hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, threshold, 100, NULL, NULL, NULL, NULL); ok(hwnd != NULL, "got %p\n", hwnd); GetClientRect(hwnd, &rect); @@ -1520,6 +1524,8 @@ static void test_margins_usefontinfo(UINT charset) ok(margins == 0, "got %x\n", margins); SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); + SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins); + SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO)); margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); ok(margins == expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins)); DestroyWindow(hwnd); @@ -1534,6 +1540,8 @@ static void test_margins_usefontinfo(UINT charset) ok(margins == 0, "got %x\n", margins); SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); + SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins); + SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO)); margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); ok(margins == empty_expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins)); DestroyWindow(hwnd); @@ -1541,6 +1549,180 @@ static void test_margins_usefontinfo(UINT charset) DeleteObject(hfont); } +static BOOL is_cjk_font(HDC dc) +{ + const DWORD FS_DBCS_MASK = FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD|FS_JOHAB; + FONTSIGNATURE fs; + return (GetTextCharsetInfo(dc, &fs, 0) != DEFAULT_CHARSET && + (fs.fsCsb[0] & FS_DBCS_MASK)); +} + +static INT get_cjk_fontinfo_margin(INT width, INT side_bearing) +{ + INT margin; + if (side_bearing < 0) + margin = min(-side_bearing, width/2); + else + margin = 0; + return margin; +} + +static DWORD get_cjk_font_margins(HDC hdc, BOOL unicode) +{ + ABC abc[256]; + SHORT left, right; + UINT i; + + left = right = 0; + if (unicode) { + if (!GetCharABCWidthsW(hdc, 0, 255, abc)) + return 0; + } + else { + if (!GetCharABCWidthsA(hdc, 0, 255, abc)) + return 0; + } + for (i = 0; i < ARRAY_SIZE(abc); i++) { + if (-abc[i].abcA > right) right = -abc[i].abcA; + if (-abc[i].abcC > left) left = -abc[i].abcC; + } + return MAKELONG(left, right); +} + +static void test_margins_default(const char* facename, UINT charset) +{ + HWND hwnd; + HDC hdc; + TEXTMETRICW tm; + SIZE size; + BOOL cjk_charset, cjk_font; + LOGFONTA lf; + HFONT hfont; + RECT rect; + INT margins, expect, font_expect; + const UINT small_margins = MAKELONG(1, 5); + const WCHAR EditW[] = {'E','d','i','t',0}, strW[] = {'W',0}; + struct char_width_info { + INT lsb, rsb, unknown; + } info; + HMODULE hgdi32; + BOOL (WINAPI *pGetCharWidthInfo)(HDC, struct char_width_info *); + + hgdi32 = GetModuleHandleA("gdi32.dll"); + pGetCharWidthInfo = (void *)GetProcAddress(hgdi32, "GetCharWidthInfo"); + + memset(&lf, 0, sizeof(lf)); + lf.lfHeight = -11; + lf.lfWeight = FW_NORMAL; + lf.lfCharSet = charset; + strcpy(lf.lfFaceName, facename); + + hfont = CreateFontIndirectA(&lf); + ok(hfont != NULL, "got %p\n", hfont); + + /* Unicode version */ + hwnd = CreateWindowExW(0, EditW, strW, WS_POPUP, 0, 0, 5000, 1000, NULL, NULL, NULL, NULL); + ok(hwnd != NULL, "got %p\n", hwnd); + GetClientRect(hwnd, &rect); + ok(!IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect)); + + hdc = GetDC(hwnd); + hfont = SelectObject(hdc, hfont); + size.cx = GdiGetCharDimensions( hdc, &tm, &size.cy ); + if ((charset != tm.tmCharSet && charset != DEFAULT_CHARSET) || + !(tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR))) { + skip("%s for charset %d isn't available\n", lf.lfFaceName, charset); + hfont = SelectObject(hdc, hfont); + ReleaseDC(hwnd, hdc); + DestroyWindow(hwnd); + DeleteObject(hfont); + return; + } + cjk_charset = is_cjk_charset(hdc); + cjk_font = is_cjk_font(hdc); + if ((cjk_charset || cjk_font) && + pGetCharWidthInfo && pGetCharWidthInfo(hdc, &info)) { + short left, right; + + left = get_cjk_fontinfo_margin(size.cx, info.lsb); + right = get_cjk_fontinfo_margin(size.cx, info.rsb); + expect = MAKELONG(left, right); + + font_expect = get_cjk_font_margins(hdc, TRUE); + if (!font_expect) + /* In this case, margins aren't updated */ + font_expect = small_margins; + } + else + font_expect = expect = MAKELONG(size.cx / 2, size.cx / 2); + + hfont = SelectObject(hdc, hfont); + ReleaseDC(hwnd, hdc); + + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == 0, "got %x\n", margins); + SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins); + SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == font_expect, "%s:%d: expected %d, %d, got %d, %d\n", facename, charset, HIWORD(font_expect), LOWORD(font_expect), HIWORD(margins), LOWORD(margins)); + SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins); + SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO)); + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == expect, "%s:%d: expected %d, %d, got %d, %d\n", facename, charset, HIWORD(expect), LOWORD(expect), HIWORD(margins), LOWORD(margins)); + DestroyWindow(hwnd); + + /* ANSI version */ + hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, 5000, 1000, NULL, NULL, NULL, NULL); + ok(hwnd != NULL, "got %p\n", hwnd); + GetClientRect(hwnd, &rect); + ok(!IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect)); + + if (cjk_charset) { + hdc = GetDC(hwnd); + hfont = SelectObject(hdc, hfont); + font_expect = get_cjk_font_margins(hdc, FALSE); + if (!font_expect) + /* In this case, margins aren't updated */ + font_expect = small_margins; + hfont = SelectObject(hdc, hfont); + ReleaseDC(hwnd, hdc); + } + else + /* we expect EC_USEFONTINFO size */ + font_expect = expect; + + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == 0, "got %x\n", margins); + SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins); + SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == font_expect, "%s:%d: expected %d, %d, got %d, %d\n", facename, charset, HIWORD(font_expect), LOWORD(font_expect), HIWORD(margins), LOWORD(margins)); + SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, small_margins); + SendMessageA(hwnd, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO)); + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == expect, "%s:%d: expected %d, %d, got %d, %d\n", facename, charset, HIWORD(expect), LOWORD(expect), HIWORD(margins), LOWORD(margins)); + DestroyWindow(hwnd); + + DeleteObject(hfont); +} + +static INT CALLBACK find_font_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam) +{ + return 0; +} + +static BOOL is_font_installed(const char*name) +{ + HDC hdc = GetDC(NULL); + BOOL ret = FALSE; + + if (!EnumFontFamiliesA(hdc, name, find_font_proc, 0)) + ret = TRUE; + + ReleaseDC(NULL, hdc); + return ret; +} + static void test_margins(void) { HWND hwEdit; @@ -1615,11 +1797,33 @@ static void test_margins(void) but not by < Win 8 and Win 10. */ test_margins_usefontinfo(DEFAULT_CHARSET); -} -static INT CALLBACK find_font_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam) -{ - return 0; + test_margins_default("Tahoma", ANSI_CHARSET); + test_margins_default("Tahoma", EASTEUROPE_CHARSET); + + test_margins_default("Tahoma", HANGUL_CHARSET); + test_margins_default("Tahoma", CHINESEBIG5_CHARSET); + + if (is_font_installed("MS PGothic")) { + test_margins_default("MS PGothic", SHIFTJIS_CHARSET); + test_margins_default("MS PGothic", GREEK_CHARSET); + } + else + skip("MS PGothic is not available, skipping some margin tests\n"); + + if (is_font_installed("Ume P Gothic")) { + test_margins_default("Ume P Gothic", SHIFTJIS_CHARSET); + test_margins_default("Ume P Gothic", GREEK_CHARSET); + } + else + skip("Ume P Gothic is not available, skipping some margin tests\n"); + + if (is_font_installed("SimSun")) { + test_margins_default("SimSun", GB2312_CHARSET); + test_margins_default("SimSun", ANSI_CHARSET); + } + else + skip("SimSun is not available, skipping some margin tests\n"); } static void test_margins_font_change(void) @@ -1628,15 +1832,12 @@ static void test_margins_font_change(void) DWORD margins, font_margins; LOGFONTA lf; HFONT hfont, hfont2; - HDC hdc = GetDC(0); - if(EnumFontFamiliesA(hdc, "Arial", find_font_proc, 0)) + if (!is_font_installed("Arial")) { - trace("Arial not found - skipping font change margin tests\n"); - ReleaseDC(0, hdc); + skip("Arial not found - skipping font change margin tests\n"); return; } - ReleaseDC(0, hdc); hwEdit = create_child_editcontrol(0, 0); @@ -1645,7 +1846,7 @@ static void test_margins_font_change(void) memset(&lf, 0, sizeof(lf)); strcpy(lf.lfFaceName, "Arial"); lf.lfHeight = 16; - lf.lfCharSet = DEFAULT_CHARSET; + lf.lfCharSet = GREEK_CHARSET; /* to avoid associated charset feature */ hfont = CreateFontIndirectA(&lf); lf.lfHeight = 30; hfont2 = CreateFontIndirectA(&lf); @@ -1660,39 +1861,39 @@ static void test_margins_font_change(void) SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(0,0)); SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0); margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); - ok(LOWORD(margins) == 0 || broken(LOWORD(margins) == LOWORD(font_margins)), /* win95 */ + ok(LOWORD(margins) == 0, "got %d\n", LOWORD(margins)); - ok(HIWORD(margins) == 0 || broken(HIWORD(margins) == HIWORD(font_margins)), /* win95 */ + ok(HIWORD(margins) == 0, "got %d\n", HIWORD(margins)); SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(1,0)); SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0); margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); - ok(LOWORD(margins) == 1 || broken(LOWORD(margins) == LOWORD(font_margins)), /* win95 */ + ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins)); - ok(HIWORD(margins) == 0 || broken(HIWORD(margins) == HIWORD(font_margins)), /* win95 */ + ok(HIWORD(margins) == 0, "got %d\n", HIWORD(margins)); SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(1,1)); SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0); margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); - ok(LOWORD(margins) == 1 || broken(LOWORD(margins) == LOWORD(font_margins)), /* win95 */ + ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins)); - ok(HIWORD(margins) == 1 || broken(HIWORD(margins) == HIWORD(font_margins)), /* win95 */ + ok(HIWORD(margins) == 1, "got %d\n", HIWORD(margins)); SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO,EC_USEFONTINFO)); margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); - ok(LOWORD(margins) == 1 || broken(LOWORD(margins) == LOWORD(font_margins)), /* win95 */ + ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins)); - ok(HIWORD(margins) == 1 || broken(HIWORD(margins) == HIWORD(font_margins)), /* win95 */ + ok(HIWORD(margins) == 1, "got %d\n", HIWORD(margins)); SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont2, 0); margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); - ok(LOWORD(margins) == 1 || broken(LOWORD(margins) != 1 && LOWORD(margins) != LOWORD(font_margins)), /* win95 */ + ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins)); - ok(HIWORD(margins) == 1 || broken(HIWORD(margins) != 1 && HIWORD(margins) != HIWORD(font_margins)), /* win95 */ + ok(HIWORD(margins) == 1, "got %d\n", HIWORD(margins)); /* Above a certain size threshold then the margin is updated */ @@ -1716,7 +1917,7 @@ static void test_margins_font_change(void) ok(HIWORD(margins) == HIWORD(font_margins), "got %d\n", HIWORD(margins)); SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont2, 0); margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); - ok(LOWORD(margins) != LOWORD(font_margins) || broken(LOWORD(margins) == LOWORD(font_margins)), /* win98 */ + ok(LOWORD(margins) != LOWORD(font_margins), "got %d\n", LOWORD(margins)); ok(HIWORD(margins) != HIWORD(font_margins), "got %d\n", HIWORD(margins)); @@ -2956,7 +3157,7 @@ static void test_EM_GETLINE(void) hwnd[0] = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); hwnd[1] = create_editcontrolW(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); - for (i = 0; i < sizeof(hwnd)/sizeof(hwnd[0]); i++) + for (i = 0; i < ARRAY_SIZE(hwnd); i++) { static const WCHAR strW[] = {'t','e','x','t',0}; static const char *str = "text"; @@ -2984,13 +3185,13 @@ static void test_EM_GETLINE(void) ok(!strcmp(buff, str), "Unexpected line data %s.\n", buff); memset(buffW, 0, sizeof(buffW)); - *(WORD *)buffW = sizeof(buffW)/sizeof(buffW[0]); + *(WORD *)buffW = ARRAY_SIZE(buffW); r = SendMessageW(hwnd[i], EM_GETLINE, 0, (LPARAM)buffW); ok(r == lstrlenW(strW), "Failed to get a line %d.\n", r); ok(!lstrcmpW(buffW, strW), "Unexpected line data %s.\n", wine_dbgstr_w(buffW)); memset(buffW, 0, sizeof(buffW)); - *(WORD *)buffW = sizeof(buffW)/sizeof(buffW[0]); + *(WORD *)buffW = ARRAY_SIZE(buffW); r = SendMessageW(hwnd[i], EM_GETLINE, 1, (LPARAM)buffW); ok(r == lstrlenW(strW), "Failed to get a line %d.\n", r); ok(!lstrcmpW(buffW, strW), "Unexpected line data %s.\n", wine_dbgstr_w(buffW)); diff --git a/modules/rostests/winetests/user32/input.c b/modules/rostests/winetests/user32/input.c index 37fe0cee877..d856e6916dc 100644 --- a/modules/rostests/winetests/user32/input.c +++ b/modules/rostests/winetests/user32/input.c @@ -79,13 +79,17 @@ static struct { LONG last_hook_up; LONG last_hook_syskey_down; LONG last_hook_syskey_up; + WORD vk; BOOL expect_alt; BOOL sendinput_broken; } key_status; -static UINT (WINAPI *pSendInput) (UINT, INPUT*, size_t); +static BOOL (WINAPI *pGetCurrentInputMessageSource)( INPUT_MESSAGE_SOURCE *source ); +static BOOL (WINAPI *pGetPointerType)(UINT32, POINTER_INPUT_TYPE*); 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 @@ -120,15 +124,6 @@ typedef struct } u; } TEST_INPUT; -#define ADDTOINPUTS(kev) \ -inputs[evtctr].type = INPUT_KEYBOARD; \ - ((TEST_INPUT*)inputs)[evtctr].u.ki.wVk = GETVKEY[ kev]; \ - ((TEST_INPUT*)inputs)[evtctr].u.ki.wScan = GETSCAN[ kev]; \ - ((TEST_INPUT*)inputs)[evtctr].u.ki.dwFlags = GETFLAGS[ kev]; \ - ((TEST_INPUT*)inputs)[evtctr].u.ki.dwExtraInfo = 0; \ - ((TEST_INPUT*)inputs)[evtctr].u.ki.time = ++timetag; \ - if( kev) evtctr++; - typedef struct { UINT message; WPARAM wParam; @@ -164,15 +159,16 @@ static void init_function_pointers(void) HMODULE hdll = GetModuleHandleA("user32"); #define GET_PROC(func) \ - p ## func = (void*)GetProcAddress(hdll, #func); \ - if(!p ## func) \ - trace("GetProcAddress(%s) failed\n", #func); - - GET_PROC(SendInput) - GET_PROC(GetMouseMovePointsEx) - GET_PROC(GetRawInputDeviceList) - GET_PROC(GetWindowRgnBox) + if (!(p ## func = (void*)GetProcAddress(hdll, #func))) \ + trace("GetProcAddress(%s) failed\n", #func) + GET_PROC(GetCurrentInputMessageSource); + GET_PROC(GetMouseMovePointsEx); + GET_PROC(GetPointerType); + GET_PROC(GetRawInputDeviceList); + GET_PROC(GetRawInputDeviceInfoW); + GET_PROC(GetRawInputDeviceInfoA); + GET_PROC(GetWindowRgnBox); #undef GET_PROC } @@ -232,17 +228,25 @@ static int KbdMessage( KEV kev, WPARAM *pwParam, LPARAM *plParam ) */ static BOOL do_test( HWND hwnd, int seqnr, const KEV td[] ) { - INPUT inputs[MAXKEYEVENTS]; + TEST_INPUT inputs[MAXKEYEVENTS]; KMSG expmsg[MAXKEYEVENTS]; MSG msg; char buf[100]; - UINT evtctr=0; + UINT evtctr=0, ret; int kmctr, i; buf[0]='\0'; TrackSysKey=0; /* see input.c */ - for( i = 0; i < MAXKEYEVENTS; i++) { - ADDTOINPUTS(td[i]) + for (i = 0; i < MAXKEYEVENTS; i++) + { + 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)); @@ -252,8 +256,8 @@ static BOOL do_test( HWND hwnd, int seqnr, const KEV td[] ) for( kmctr = 0; kmctr < MAXKEYEVENTS && expmsg[kmctr].message; kmctr++) ; ok( evtctr <= MAXKEYEVENTS, "evtctr is above MAXKEYEVENTS\n" ); - if( evtctr != pSendInput(evtctr, &inputs[0], sizeof(INPUT))) - ok (FALSE, "SendInput failed to send some events\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", @@ -700,14 +704,17 @@ 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) +static void compare_and_check(int id, BYTE *ks1, BYTE *ks2, + const struct sendinput_test_s *test, BOOL foreground) { int i, failcount = 0; const struct transition_s *t = test->expected_transitions; UINT actual_cnt = 0; const struct message *expected = test->expected_messages; - while (t->wVk) { + 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)); @@ -790,6 +797,13 @@ static void compare_and_check(int id, BYTE *ks1, BYTE *ks2, const struct sendinp 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) && @@ -826,7 +840,7 @@ static void compare_and_check(int id, BYTE *ks1, BYTE *ks2, const struct sendinp expected++; } /* skip all optional trailing messages */ - while (expected->message && (expected->flags & optional)) + while (expected->message && ((expected->flags & optional) || (!(expected->flags & hook) && !foreground))) expected++; @@ -857,16 +871,7 @@ static LRESULT CALLBACK WndProc2(HWND hWnd, UINT Msg, WPARAM wParam, { if (winetest_debug > 1) trace("MSG: %8x W:%8lx L:%8lx\n", Msg, wParam, lParam); - if (Msg != WM_PAINT && - Msg != WM_NCPAINT && - Msg != WM_SYNCPAINT && - Msg != WM_ERASEBKGND && - Msg != WM_NCHITTEST && - Msg != WM_GETTEXT && - Msg != WM_GETICON && - Msg != WM_IME_SELECT && - Msg != WM_DEVICECHANGE && - Msg != WM_TIMECHANGE) + if ((Msg >= WM_KEYFIRST && Msg <= WM_KEYLAST) || Msg == WM_SYSCOMMAND) { ok(sent_messages_cnt < MAXKEYMESSAGES, "Too many messages\n"); if (sent_messages_cnt < MAXKEYMESSAGES) @@ -915,6 +920,7 @@ static void test_Input_blackbox(void) int ii; BYTE ks1[256], ks2[256]; LONG_PTR prevWndProc; + BOOL foreground; HWND window; HHOOK hook; @@ -928,7 +934,9 @@ static void test_Input_blackbox(void) NULL, NULL); ok(window != NULL, "error: %d\n", (int) GetLastError()); SetWindowPos( window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE ); - SetForegroundWindow( window ); + foreground = SetForegroundWindow( window ); + if (!foreground) + skip("Failed to set foreground window; some tests will be skipped.\n"); if (!(hook = SetWindowsHookExA(WH_KEYBOARD_LL, hook_proc, GetModuleHandleA( NULL ), 0))) { @@ -948,24 +956,15 @@ static void test_Input_blackbox(void) i.u.ki.time = 0; i.u.ki.dwExtraInfo = 0; - for (ii = 0; ii < sizeof(sendinput_test)/sizeof(struct sendinput_test_s)-1; - ii++) { + 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; - pSendInput(1, (INPUT*)&i, sizeof(TEST_INPUT)); + SendInput(1, (INPUT*)&i, sizeof(TEST_INPUT)); empty_message_queue(); GetKeyboardState(ks2); - if (!ii && sent_messages_cnt <= 1 && !memcmp( ks1, ks2, sizeof(ks1) )) - { - win_skip( "window doesn't receive the queued input\n" ); - /* release the key */ - i.u.ki.dwFlags |= KEYEVENTF_KEYUP; - pSendInput(1, (INPUT*)&i, sizeof(TEST_INPUT)); - break; - } - compare_and_check(ii, ks1, ks2, &sendinput_test[ii]); + compare_and_check(ii, ks1, ks2, &sendinput_test[ii], foreground); } empty_message_queue(); @@ -973,7 +972,7 @@ static void test_Input_blackbox(void) UnhookWindowsHookEx(hook); } -static void reset_key_status(void) +static void reset_key_status(WORD vk) { key_status.last_key_down = -1; key_status.last_key_up = -1; @@ -985,6 +984,7 @@ static void reset_key_status(void) 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; } @@ -1004,8 +1004,8 @@ static void test_unicode_keys(HWND hwnd, HHOOK hook) inputs[0].u.ki.wScan = 0x3c0; inputs[0].u.ki.dwFlags = KEYEVENTF_UNICODE; - reset_key_status(); - pSendInput(1, (INPUT*)inputs, sizeof(INPUT)); + 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); @@ -1026,8 +1026,8 @@ static void test_unicode_keys(HWND hwnd, HHOOK hook) inputs[1].u.ki.wScan = 0x3c0; inputs[1].u.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP; - reset_key_status(); - pSendInput(1, (INPUT*)(inputs+1), sizeof(INPUT)); + 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); @@ -1051,9 +1051,9 @@ static void test_unicode_keys(HWND hwnd, HHOOK hook) inputs[1].u.ki.wScan = 0x3041; inputs[1].u.ki.dwFlags = KEYEVENTF_UNICODE; - reset_key_status(); + reset_key_status(VK_PACKET); key_status.expect_alt = TRUE; - pSendInput(2, (INPUT*)inputs, sizeof(INPUT)); + 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); @@ -1078,9 +1078,9 @@ static void test_unicode_keys(HWND hwnd, HHOOK hook) inputs[0].u.ki.wScan = 0; inputs[0].u.ki.dwFlags = KEYEVENTF_KEYUP; - reset_key_status(); + reset_key_status(VK_PACKET); key_status.expect_alt = TRUE; - pSendInput(2, (INPUT*)inputs, sizeof(INPUT)); + 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); @@ -1094,6 +1094,32 @@ static void test_unicode_keys(HWND hwnd, HHOOK 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, @@ -1134,7 +1160,8 @@ static LRESULT CALLBACK llkbd_unicode_hook(int nCode, WPARAM wParam, LPARAM lPar 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 - ok(info->vkCode == VK_PACKET, "vkCode should have been VK_PACKET[0x%04x], was: 0x%x\n", VK_PACKET, info->vkCode); + 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: @@ -1569,7 +1596,7 @@ static void test_GetMouseMovePointsEx(void) static void test_GetRawInputDeviceList(void) { RAWINPUTDEVICELIST devices[32]; - UINT ret, oret, devcount, odevcount; + UINT ret, oret, devcount, odevcount, i; DWORD err; SetLastError(0xdeadbeef); @@ -1601,18 +1628,84 @@ static void test_GetRawInputDeviceList(void) ret = pGetRawInputDeviceList(devices, &devcount, sizeof(devices[0])); ok(ret > 0, "expected non-zero\n"); + for(i = 0; i < devcount; ++i) + { + WCHAR name[128]; + char nameA[128]; + UINT sz, len; + RID_DEVICE_INFO info; + HANDLE file; + + /* 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(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); + 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); + len = strlen(nameA); + ok(len + 1 == ret, "GetRawInputDeviceInfoA returned wrong length (name: %u, ret: %u)\n", len + 1, ret); + + /* buffer size for RIDI_DEVICEINFO is in BYTEs */ + memset(&info, 0, sizeof(info)); + 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(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(sz == sizeof(info), "GetRawInputDeviceInfo set wrong size\n"); + ok(info.dwType == devices[i].dwType, "GetRawInputDeviceInfo set wrong type: 0x%x\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(sz == sizeof(info), "GetRawInputDeviceInfo set wrong size\n"); + ok(info.dwType == devices[i].dwType, "GetRawInputDeviceInfo set wrong type: 0x%x\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()); + CloseHandle(file); + } + /* check if variable changes from larger to smaller value */ - devcount = odevcount = sizeof(devices) / sizeof(devices[0]); + devcount = odevcount = ARRAY_SIZE(devices); oret = ret = pGetRawInputDeviceList(devices, &odevcount, sizeof(devices[0])); ok(ret > 0, "expected non-zero\n"); ok(devcount == odevcount, "expected %d, got %d\n", devcount, odevcount); devcount = odevcount; - odevcount = sizeof(devices) / sizeof(devices[0]); + odevcount = ARRAY_SIZE(devices); ret = pGetRawInputDeviceList(NULL, &odevcount, sizeof(devices[0])); ok(ret == 0, "expected 0, got %d\n", ret); ok(odevcount == oret, "expected %d, got %d\n", oret, odevcount); } +static void test_GetRawInputData(void) +{ + UINT size; + UINT ret; + + /* Null raw input handle */ + ret = GetRawInputData(NULL, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)); + ok(ret == ~0U, "Expect ret %u, got %u\n", ~0U, ret); +} + static void test_key_map(void) { HKL kl = GetKeyboardLayout(0); @@ -1649,7 +1742,7 @@ static void test_key_map(void) "Scan code -> vKey = %x (not VK_RSHIFT)\n", kR); /* test that MAPVK_VSC_TO_VK prefers the non-numpad vkey if there's ambiguity */ - for (i = 0; i < sizeof(numpad_collisions)/sizeof(numpad_collisions[0]); i++) + for (i = 0; i < ARRAY_SIZE(numpad_collisions); i++) { UINT numpad_scan = MapVirtualKeyExA(numpad_collisions[i][0], MAPVK_VK_TO_VSC, kl); UINT other_scan = MapVirtualKeyExA(numpad_collisions[i][1], MAPVK_VK_TO_VSC, kl); @@ -1747,7 +1840,7 @@ static void test_ToUnicode(void) "ToUnicode didn't null-terminate the buffer when there was room.\n"); } - for (i = 0; i < sizeof(utests) / sizeof(utests[0]); i++) + for (i = 0; i < ARRAY_SIZE(utests); i++) { UINT vk = utests[i].vk, mod = utests[i].modifiers, scan; @@ -1890,7 +1983,7 @@ static void test_key_names(void) ok( buffer[0] == 0, "wrong string '%s'\n", buffer ); memset( bufferW, 0xcc, sizeof(bufferW) ); - ret = GetKeyNameTextW( lparam, bufferW, sizeof(bufferW)/sizeof(WCHAR) ); + ret = GetKeyNameTextW( lparam, bufferW, ARRAY_SIZE(bufferW)); ok( ret > 0, "wrong len %u for %s\n", ret, wine_dbgstr_w(bufferW) ); ok( ret == lstrlenW(bufferW), "wrong len %u for %s\n", ret, wine_dbgstr_w(bufferW) ); @@ -2274,6 +2367,25 @@ static void test_Input_mouse(void) ok(region_type == ERROR, "expected ERROR, got %d\n", region_type); } + 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)); + got_button_down = got_button_up = FALSE; simulate_click(TRUE, 150, 150); while (wait_for_message(&msg)) @@ -2314,13 +2426,11 @@ static void test_Input_mouse(void) 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; @@ -2372,25 +2482,6 @@ static void test_Input_mouse(void) ok(region_type == ERROR, "expected ERROR, got %d\n", region_type); } - 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)); - got_button_down = got_button_up = FALSE; simulate_click(TRUE, 150, 150); while (wait_for_message(&msg)) @@ -2399,11 +2490,13 @@ static void test_Input_mouse(void) 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; @@ -2832,6 +2925,7 @@ static void test_GetKeyState(void) result = WaitForSingleObject(semaphores[0], 1000); ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result); + SetForegroundWindow(hwnd); SetFocus(hwnd); keybd_event('X', 0, 0, 0); @@ -2885,19 +2979,205 @@ static void test_OemKeyScan(void) } } +static INPUT_MESSAGE_SOURCE expect_src; + +static LRESULT WINAPI msg_source_proc( HWND hwnd, UINT message, WPARAM wp, LPARAM lp ) +{ + INPUT_MESSAGE_SOURCE source; + MSG msg; + + ok( pGetCurrentInputMessageSource( &source ), "GetCurrentInputMessageSource failed\n" ); + switch (message) + { + case WM_KEYDOWN: + case WM_KEYUP: + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + case WM_MOUSEMOVE: + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + ok( source.deviceType == expect_src.deviceType || /* also accept system-generated WM_MOUSEMOVE */ + (message == WM_MOUSEMOVE && source.deviceType == IMDT_UNAVAILABLE), + "%x: wrong deviceType %x/%x\n", message, source.deviceType, expect_src.deviceType ); + ok( source.originId == expect_src.originId || + (message == WM_MOUSEMOVE && source.originId == IMO_SYSTEM), + "%x: wrong originId %x/%x\n", message, source.originId, expect_src.originId ); + SendMessageA( hwnd, WM_USER, 0, 0 ); + PostMessageA( hwnd, WM_USER, 0, 0 ); + if (PeekMessageW( &msg, hwnd, WM_USER, WM_USER, PM_REMOVE )) DispatchMessageW( &msg ); + ok( source.deviceType == expect_src.deviceType || /* also accept system-generated WM_MOUSEMOVE */ + (message == WM_MOUSEMOVE && source.deviceType == IMDT_UNAVAILABLE), + "%x: wrong deviceType %x/%x\n", message, source.deviceType, expect_src.deviceType ); + ok( source.originId == expect_src.originId || + (message == WM_MOUSEMOVE && source.originId == IMO_SYSTEM), + "%x: wrong originId %x/%x\n", message, source.originId, expect_src.originId ); + break; + default: + ok( source.deviceType == IMDT_UNAVAILABLE, "%x: wrong deviceType %x\n", + message, source.deviceType ); + ok( source.originId == 0, "%x: wrong originId %x\n", message, source.originId ); + break; + } + + return DefWindowProcA( hwnd, message, wp, lp ); +} + +static void test_input_message_source(void) +{ + WNDCLASSA cls; + TEST_INPUT inputs[2]; + HWND hwnd; + RECT rc; + MSG msg; + + cls.style = 0; + cls.lpfnWndProc = msg_source_proc; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = GetModuleHandleA(0); + cls.hIcon = 0; + cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); + cls.hbrBackground = 0; + cls.lpszMenuName = NULL; + cls.lpszClassName = "message source class"; + RegisterClassA(&cls); + hwnd = CreateWindowA( cls.lpszClassName, "test", WS_OVERLAPPED, 0, 0, 100, 100, + 0, 0, 0, 0 ); + ShowWindow( hwnd, SW_SHOWNORMAL ); + UpdateWindow( hwnd ); + SetForegroundWindow( hwnd ); + 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[1] = inputs[0]; + inputs[1].u.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) ); + while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE )) + { + expect_src.deviceType = IMDT_KEYBOARD; + expect_src.originId = IMO_INJECTED; + TranslateMessage( &msg ); + DispatchMessageW( &msg ); + } + GetWindowRect( hwnd, &rc ); + simulate_click( TRUE, (rc.left + rc.right) / 2, (rc.top + rc.bottom) / 2 ); + simulate_click( FALSE, (rc.left + rc.right) / 2 + 1, (rc.top + rc.bottom) / 2 + 1 ); + while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE )) + { + expect_src.deviceType = IMDT_MOUSE; + expect_src.originId = IMO_INJECTED; + TranslateMessage( &msg ); + DispatchMessageW( &msg ); + } + + expect_src.deviceType = IMDT_UNAVAILABLE; + expect_src.originId = IMO_UNAVAILABLE; + SendMessageA( hwnd, WM_KEYDOWN, 0, 0 ); + SendMessageA( hwnd, WM_LBUTTONDOWN, 0, 0 ); + PostMessageA( hwnd, WM_KEYUP, 0, 0 ); + PostMessageA( hwnd, WM_LBUTTONUP, 0, 0 ); + while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE )) + { + TranslateMessage( &msg ); + DispatchMessageW( &msg ); + } + + expect_src.deviceType = IMDT_UNAVAILABLE; + expect_src.originId = IMO_SYSTEM; + SetCursorPos( (rc.left + rc.right) / 2 - 1, (rc.top + rc.bottom) / 2 - 1 ); + while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE )) + { + TranslateMessage( &msg ); + DispatchMessageW( &msg ); + } + + DestroyWindow( hwnd ); + UnregisterClassA( cls.lpszClassName, GetModuleHandleA(0) ); +} + +static void test_GetPointerType(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 ); +} + +static void test_GetKeyboardLayoutList(void) +{ + 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) + { + layouts = HeapAlloc(GetProcessHeap(), 0, sizeof(*layouts) * cnt ); + + 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"); + + HeapFree(GetProcessHeap(), 0, layouts); + } +} + START_TEST(input) { + POINT pos; + init_function_pointers(); + GetCursorPos( &pos ); - if (pSendInput) - { - test_Input_blackbox(); - test_Input_whitebox(); - test_Input_unicode(); - test_Input_mouse(); - } - else win_skip("SendInput is not available\n"); - + test_Input_blackbox(); + test_Input_whitebox(); + test_Input_unicode(); + test_Input_mouse(); test_keynames(); test_mouse_ll_hook(); test_key_map(); @@ -2909,6 +3189,8 @@ START_TEST(input) test_attach_input(); test_GetKeyState(); test_OemKeyScan(); + test_GetRawInputData(); + test_GetKeyboardLayoutList(); if(pGetMouseMovePointsEx) test_GetMouseMovePointsEx(); @@ -2919,4 +3201,16 @@ START_TEST(input) test_GetRawInputDeviceList(); else win_skip("GetRawInputDeviceList is not available\n"); + + if (pGetCurrentInputMessageSource) + test_input_message_source(); + else + win_skip("GetCurrentInputMessageSource is not available\n"); + + SetCursorPos( pos.x, pos.y ); + + if(pGetPointerType) + test_GetPointerType(); + else + win_skip("GetPointerType is not available\n"); } diff --git a/modules/rostests/winetests/user32/listbox.c b/modules/rostests/winetests/user32/listbox.c index 88d3adb728e..8d8115131ef 100644 --- a/modules/rostests/winetests/user32/listbox.c +++ b/modules/rostests/winetests/user32/listbox.c @@ -51,7 +51,7 @@ static int strcmp_aw(LPCWSTR strw, const char *stra) WCHAR buf[1024]; if (!stra) return 1; - MultiByteToWideChar(CP_ACP, 0, stra, -1, buf, sizeof(buf)/sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, stra, -1, buf, ARRAY_SIZE(buf)); return lstrcmpW(strw, buf); } @@ -90,7 +90,6 @@ struct listbox_stat { }; struct listbox_test { - struct listbox_prop prop; struct listbox_stat init, init_todo; struct listbox_stat click, click_todo; struct listbox_stat step, step_todo; @@ -130,8 +129,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 \ - ": expected %d, got %d\n", (unsigned int)t.prop.add_style, \ - t.s.f, got.f) + ": expected %d, got %d\n", style, t.s.f, got.f) #define listbox_todo_field_ok(t, s, f, got) \ todo_wine_if (t.s##_todo.f) { listbox_field_ok(t, s, f, got); } @@ -143,13 +141,15 @@ keypress (HWND handle, WPARAM keycode, BYTE scancode, BOOL extended) listbox_todo_field_ok(t, s, selcount, got) static void -check (const struct listbox_test test) +check (DWORD style, const struct listbox_test test) { struct listbox_stat answer; - HWND hLB=create_listbox (test.prop.add_style, 0); RECT second_item; int i; int res; + HWND hLB; + + hLB = create_listbox (style, 0); listbox_query (hLB, &answer); listbox_ok (test, init, answer); @@ -166,13 +166,13 @@ check (const struct listbox_test test) listbox_ok (test, step, answer); DestroyWindow (hLB); - hLB=create_listbox (test.prop.add_style, 0); + hLB = create_listbox(style, 0); SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 2)); listbox_query (hLB, &answer); listbox_ok (test, sel, answer); - for (i=0;i<4;i++) { + for (i = 0; i < 4 && !(style & LBS_NODATA); i++) { DWORD size = SendMessageA(hLB, LB_GETTEXTLEN, i, 0); CHAR *txt; WCHAR *txtw; @@ -184,13 +184,9 @@ check (const struct listbox_test test) txtw = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, 2*size+2); resW=SendMessageW(hLB, LB_GETTEXT, i, (LPARAM)txtw); - if (resA != resW) { - trace("SendMessageW(LB_GETTEXT) not supported on this platform (resA=%d resW=%d), skipping...\n", - resA, resW); - } else { - 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]); - } + 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); @@ -342,35 +338,73 @@ static HWND create_parent( void ) static void test_ownerdraw(void) { + static const DWORD styles[] = + { + 0, + LBS_NODATA + }; HWND parent, hLB; INT ret; RECT rc; + UINT i; parent = create_parent(); assert(parent); - hLB = create_listbox(LBS_OWNERDRAWFIXED | WS_CHILD | WS_VISIBLE, parent); - assert(hLB); + for (i = 0; i < ARRAY_SIZE(styles); i++) + { + hLB = create_listbox(LBS_OWNERDRAWFIXED | WS_CHILD | WS_VISIBLE | styles[i], parent); + assert(hLB); - SetForegroundWindow(hLB); - UpdateWindow(hLB); + SetForegroundWindow(hLB); + UpdateWindow(hLB); - /* make height short enough */ - SendMessageA(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc); - SetWindowPos(hLB, 0, 0, 0, 100, rc.bottom - rc.top + 1, - SWP_NOZORDER | SWP_NOMOVE); + /* make height short enough */ + SendMessageA(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc); + SetWindowPos(hLB, 0, 0, 0, 100, rc.bottom - rc.top + 1, + SWP_NOZORDER | SWP_NOMOVE); - /* make 0 item invisible */ - SendMessageA(hLB, LB_SETTOPINDEX, 1, 0); - ret = SendMessageA(hLB, LB_GETTOPINDEX, 0, 0); - ok(ret == 1, "wrong top index %d\n", ret); + /* make 0 item invisible */ + SendMessageA(hLB, LB_SETTOPINDEX, 1, 0); + ret = SendMessageA(hLB, LB_GETTOPINDEX, 0, 0); + ok(ret == 1, "wrong top index %d\n", ret); - 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); + 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); - DestroyWindow(hLB); + 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(GetWindowLongA(hLB, GWL_STYLE) & LBS_OWNERDRAWVARIABLE, "Unexpected window style.\n"); + + ret = SendMessageA(hLB, LB_INSERTSTRING, -1, 0); + ok(ret == 0, "Unexpected return value %d.\n", ret); + ret = SendMessageA(hLB, LB_INSERTSTRING, -1, 0); + ok(ret == 1, "Unexpected return value %d.\n", ret); + + ret = SendMessageA(hLB, LB_SETITEMHEIGHT, 0, 13); + ok(ret == LB_OKAY, "Failed to set item height, %d.\n", ret); + + ret = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0); + ok(ret == 13, "Unexpected item height %d.\n", ret); + + ret = SendMessageA(hLB, LB_SETITEMHEIGHT, 1, 42); + ok(ret == LB_OKAY, "Failed to set item height, %d.\n", ret); + + ret = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0); + ok(ret == 42, "Unexpected item height %d.\n", ret); + + ret = SendMessageA(hLB, LB_GETITEMHEIGHT, 1, 0); + ok(ret == 42, "Unexpected item height %d.\n", ret); + + DestroyWindow (hLB); + } DestroyWindow(parent); } @@ -475,17 +509,121 @@ static void test_LB_SETCURSEL(void) SendMessageA(hLB, LB_SETITEMHEIGHT, 0, 32); + ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0); + ok(ret == -1, "Unexpected anchor index %d.\n", ret); + ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0); ok(ret == 2, "LB_SETCURSEL returned %d instead of 2\n", ret); ret = GetScrollPos(hLB, SB_VERT); ok(ret == 0, "expected vscroll 0, got %d\n", ret); + ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0); + ok(ret == -1, "Unexpected anchor index %d.\n", ret); + ret = SendMessageA(hLB, LB_SETCURSEL, 3, 0); ok(ret == 3, "LB_SETCURSEL returned %d instead of 3\n", ret); ret = GetScrollPos(hLB, SB_VERT); ok(ret == 1, "expected vscroll 1, got %d\n", ret); + ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0); + ok(ret == -1, "Unexpected anchor index %d.\n", ret); + DestroyWindow(hLB); + + hLB = create_listbox(0, 0); + ok(hLB != NULL, "Failed to create ListBox window.\n"); + + ret = SendMessageA(hLB, LB_SETCURSEL, 1, 0); + ok(ret == 1, "Unexpected return value %d.\n", ret); + + ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0); + ok(ret == -1, "Unexpected anchor index %d.\n", ret); + + DestroyWindow(hLB); + + /* LBS_EXTENDEDSEL */ + hLB = create_listbox(LBS_EXTENDEDSEL, 0); + ok(hLB != NULL, "Failed to create ListBox window.\n"); + + ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0); + ok(ret == -1, "Unexpected anchor index %d.\n", ret); + + ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0); + ok(ret == -1, "Unexpected return value %d.\n", ret); + + ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0); + ok(ret == -1, "Unexpected anchor index %d.\n", ret); + + DestroyWindow(hLB); + + /* LBS_MULTIPLESEL */ + hLB = create_listbox(LBS_MULTIPLESEL, 0); + ok(hLB != NULL, "Failed to create ListBox window.\n"); + + ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0); + ok(ret == -1, "Unexpected anchor index %d.\n", ret); + + ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0); + ok(ret == -1, "Unexpected return value %d.\n", ret); + + ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0); + ok(ret == -1, "Unexpected anchor index %d.\n", ret); + + DestroyWindow(hLB); +} + +static void test_LB_SETSEL(void) +{ + HWND list; + int ret; + + /* LBS_EXTENDEDSEL */ + list = create_listbox(LBS_EXTENDEDSEL, 0); + ok(list != NULL, "Failed to create ListBox window.\n"); + + ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0); + ok(ret == -1, "Unexpected anchor 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_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_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); + + DestroyWindow(list); + + /* LBS_MULTIPLESEL */ + list = create_listbox(LBS_MULTIPLESEL, 0); + ok(list != NULL, "Failed to create ListBox window.\n"); + + ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0); + ok(ret == -1, "Unexpected anchor 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_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_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); + + DestroyWindow(list); } static void test_listbox_height(void) @@ -527,6 +665,135 @@ static void test_listbox_height(void) DestroyWindow( hList ); } +static void test_changing_selection_styles(void) +{ + static const DWORD styles[] = + { + 0, + LBS_NODATA | LBS_OWNERDRAWFIXED + }; + static const DWORD selstyles[] = + { + 0, + LBS_MULTIPLESEL, + LBS_EXTENDEDSEL, + LBS_MULTIPLESEL | LBS_EXTENDEDSEL + }; + static const LONG selexpect_single[] = { 0, 0, 1 }; + static const LONG selexpect_single2[] = { 1, 0, 0 }; + static const LONG selexpect_multi[] = { 1, 0, 1 }; + static const LONG selexpect_multi2[] = { 1, 1, 0 }; + + HWND parent, listbox; + DWORD style; + LONG ret; + UINT i, j, k; + + parent = create_parent(); + ok(parent != NULL, "Failed to create parent window.\n"); + for (i = 0; i < ARRAY_SIZE(styles); i++) + { + /* Test if changing selection styles affects selection storage */ + for (j = 0; j < ARRAY_SIZE(selstyles); j++) + { + LONG setcursel_expect, selitemrange_expect, getselcount_expect; + const LONG *selexpect; + + listbox = CreateWindowA("listbox", "TestList", styles[i] | selstyles[j] | WS_CHILD | WS_VISIBLE, + 0, 0, 100, 100, parent, (HMENU)1, NULL, 0); + ok(listbox != NULL, "%u: Failed to create ListBox window.\n", j); + + if (selstyles[j] & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) + { + setcursel_expect = LB_ERR; + selitemrange_expect = LB_OKAY; + getselcount_expect = 2; + selexpect = selexpect_multi; + } + else + { + setcursel_expect = 2; + selitemrange_expect = LB_ERR; + getselcount_expect = LB_ERR; + selexpect = selexpect_single; + } + + 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); + } + ret = SendMessageA(listbox, LB_GETCOUNT, 0, 0); + ok(ret == ARRAY_SIZE(selexpect_multi), "%u: Unexpected count %d.\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); + ret = SendMessageA(listbox, LB_SELITEMRANGE, TRUE, MAKELPARAM(0, 0)); + ok(ret == selitemrange_expect, "%u: Unexpected return value %d.\n", j, ret); + ret = SendMessageA(listbox, LB_SELITEMRANGE, TRUE, MAKELPARAM(2, 2)); + ok(ret == selitemrange_expect, "%u: Unexpected return value %d.\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", + 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); + 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); + + /* 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", + 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", + 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); + ret = SendMessageA(listbox, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 1)); + ok(ret == selitemrange_expect, "%u: Unexpected return value %d.\n", j, ret); + ret = SendMessageA(listbox, LB_SELITEMRANGE, FALSE, MAKELPARAM(2, 2)); + ok(ret == selitemrange_expect, "%u: Unexpected return value %d.\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", + 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", + j, ret, selexpect[k]); + } + + DestroyWindow(listbox); + } + } + DestroyWindow(parent); +} + static void test_itemfrompoint(void) { /* WS_POPUP is required in order to have a more accurate size calculation ( @@ -637,6 +904,7 @@ static void test_listbox_item_data(void) static void test_listbox_LB_DIR(void) { + char path[MAX_PATH], curdir[MAX_PATH]; HWND hList; int res, itemCount; int itemCount_justFiles; @@ -649,6 +917,16 @@ static void test_listbox_LB_DIR(void) char driveletter; const char *wildcard = "*"; HANDLE file; + BOOL ret; + + GetCurrentDirectoryA(ARRAY_SIZE(curdir), curdir); + + GetTempPathA(ARRAY_SIZE(path), path); + ret = SetCurrentDirectoryA(path); + ok(ret, "Failed to set current directory.\n"); + + ret = CreateDirectoryA("lb_dir_test", NULL); + 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()); @@ -980,11 +1258,11 @@ static void test_listbox_LB_DIR(void) itemCount, itemCount_allDirs); ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) returned incorrect index!\n"); - if (itemCount && GetCurrentDirectoryA( MAX_PATH, pathBuffer ) > 3) /* there's no [..] in drive root */ + if (itemCount) { memset(pathBuffer, 0, MAX_PATH); SendMessageA(hList, LB_GETTEXT, 0, (LPARAM)pathBuffer); - ok( !strcmp(pathBuffer, "[..]"), "First element is not [..]\n"); + ok( !strcmp(pathBuffer, "[..]"), "First element is %s, not [..]\n", pathBuffer); } /* This tests behavior when no files match the wildcard */ @@ -1068,6 +1346,9 @@ static void test_listbox_LB_DIR(void) DestroyWindow(hList); DeleteFileA( "wtest1.tmp.c" ); + RemoveDirectoryA("lb_dir_test"); + + SetCurrentDirectoryA(curdir); } static HWND g_listBox; @@ -1555,7 +1836,7 @@ static void test_listbox_dlgdir(void) strcpy(pathBuffer, "C:\\"); res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE); ok(res || broken(!res) /* NT4/W2K */, "DlgDirList failed to list C:\\ folders\n"); - todo_wine ok(!strcmp(pathBuffer, "*") || broken(!res) /* NT4/W2K */, + ok(!strcmp(pathBuffer, "*") || broken(!res) /* NT4/W2K */, "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer); strcpy(pathBuffer, "C:\\*"); @@ -1568,8 +1849,8 @@ static void test_listbox_dlgdir(void) SetLastError(0xdeadbeef); strcpy(pathBuffer, "C:\\INVALID$$DIR"); res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE); - todo_wine ok(!res, "DlgDirList should have failed with 0 but %d was returned\n", res); - todo_wine ok(GetLastError() == ERROR_NO_WILDCARD_CHARACTERS, + 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()); DestroyWindow(hWnd); @@ -1577,7 +1858,13 @@ static void test_listbox_dlgdir(void) static void test_set_count( void ) { + static const DWORD styles[] = + { + LBS_OWNERDRAWFIXED, + LBS_HASSTRINGS, + }; HWND parent, listbox; + unsigned int i; LONG ret; RECT r; @@ -1606,7 +1893,25 @@ static void test_set_count( void ) 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 ); + ret = SendMessageA( listbox, LB_GETCOUNT, 0, 0 ); + ok( ret == -5, "got %d\n", ret ); + DestroyWindow( listbox ); + + for (i = 0; i < ARRAY_SIZE(styles); ++i) + { + listbox = create_listbox( styles[i] | WS_CHILD | WS_VISIBLE, parent ); + + 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() ); + + DestroyWindow( listbox ); + } + DestroyWindow( parent ); } @@ -1653,6 +1958,69 @@ todo_wine DestroyWindow(parent); } +static void test_init_storage( void ) +{ + static const DWORD styles[] = + { + LBS_HASSTRINGS, + LBS_NODATA | LBS_OWNERDRAWFIXED, + }; + HWND parent, listbox; + LONG ret, items_size; + int i, j; + + parent = create_parent(); + for (i = 0; i < ARRAY_SIZE(styles); i++) + { + listbox = CreateWindowA("listbox", "TestList", styles[i] | WS_CHILD, + 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); + + ret = SendMessageA(listbox, LB_INITSTORAGE, 0, 0); + ok(ret == items_size, "expected %d, got %d\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); + + /* 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); + + /* 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); + } + 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); + } + } + + /* 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); + + /* 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); + ret = SendMessageA(listbox, LB_INITSTORAGE, 0, 0); + ok(ret == items_size, "expected %d, got %d\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); + + DestroyWindow(listbox); + } + DestroyWindow(parent); +} + static void test_missing_lbuttonup( void ) { HWND listbox, parent, capture; @@ -1876,88 +2244,216 @@ static void test_WM_MEASUREITEM(void) DestroyWindow(parent); } +static void test_LBS_NODATA(void) +{ + static const DWORD invalid_styles[] = + { + 0, + LBS_OWNERDRAWVARIABLE, + LBS_SORT, + LBS_HASSTRINGS, + LBS_OWNERDRAWFIXED | LBS_SORT, + LBS_OWNERDRAWFIXED | LBS_HASSTRINGS, + }; + static const UINT invalid_idx[] = { -2, 2 }; + static const UINT valid_idx[] = { 0, 1 }; + static const ULONG_PTR zero_data; + HWND listbox, parent; + unsigned int i; + ULONG_PTR data; + INT ret; + + listbox = CreateWindowA("listbox", "TestList", LBS_NODATA | LBS_OWNERDRAWFIXED | WS_VISIBLE, + 0, 0, 100, 100, NULL, NULL, NULL, 0); + ok(listbox != NULL, "Failed to create ListBox window.\n"); + + ret = SendMessageA(listbox, LB_INSERTSTRING, -1, 0); + ok(ret == 0, "Unexpected return value %d.\n", ret); + ret = SendMessageA(listbox, LB_INSERTSTRING, -1, 0); + ok(ret == 1, "Unexpected return value %d.\n", ret); + ret = SendMessageA(listbox, LB_GETCOUNT, 0, 0); + ok(ret == 2, "Unexpected return value %d.\n", ret); + + /* Invalid indices. */ + for (i = 0; i < ARRAY_SIZE(invalid_idx); ++i) + { + ret = SendMessageA(listbox, LB_SETITEMDATA, invalid_idx[i], 42); + ok(ret == LB_ERR, "Unexpected return value %d.\n", ret); + ret = SendMessageA(listbox, LB_GETTEXTLEN, invalid_idx[i], 0); + ok(ret == LB_ERR, "Unexpected return value %d.\n", ret); + if (ret == LB_ERR) + { + ret = SendMessageA(listbox, LB_GETTEXT, invalid_idx[i], (LPARAM)&data); + ok(ret == LB_ERR, "Unexpected return value %d.\n", ret); + } + ret = SendMessageA(listbox, LB_GETITEMDATA, invalid_idx[i], 0); + ok(ret == LB_ERR, "Unexpected return value %d.\n", ret); + } + + /* Valid indices. */ + for (i = 0; i < ARRAY_SIZE(valid_idx); ++i) + { + ret = SendMessageA(listbox, LB_SETITEMDATA, valid_idx[i], 42); + ok(ret == TRUE, "Unexpected return value %d.\n", ret); + ret = SendMessageA(listbox, LB_GETTEXTLEN, valid_idx[i], 0); + ok(ret == sizeof(data), "Unexpected return value %d.\n", ret); + + memset(&data, 0xee, sizeof(data)); + ret = SendMessageA(listbox, LB_GETTEXT, valid_idx[i], (LPARAM)&data); + ok(ret == sizeof(data), "Unexpected return value %d.\n", ret); + ok(!memcmp(&data, &zero_data, sizeof(data)), "Unexpected item data.\n"); + + ret = SendMessageA(listbox, LB_GETITEMDATA, valid_idx[i], 0); + ok(ret == 0, "Unexpected return value %d.\n", ret); + } + + /* More messages that don't work with LBS_NODATA. */ + 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()); + 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()); + 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()); + 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()); + 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()); + 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()); + + DestroyWindow(listbox); + + /* Invalid window style combinations. */ + parent = create_parent(); + ok(parent != NULL, "Failed to create parent window.\n"); + + for (i = 0; i < ARRAY_SIZE(invalid_styles); ++i) + { + DWORD style; + + listbox = CreateWindowA("listbox", "TestList", LBS_NODATA | WS_CHILD | invalid_styles[i], + 0, 0, 100, 100, parent, (HMENU)1, NULL, 0); + 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); + ret = SendMessageA(listbox, LB_SETCOUNT, 100, 0); + ok(ret == LB_ERR, "%u: unexpected return value %d.\n", i, ret); + DestroyWindow(listbox); + } + + DestroyWindow(parent); +} + START_TEST(listbox) { const struct listbox_test SS = /* {add_style} */ - {{0}, - {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}, + {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}, { 1, 1, 1, LB_ERR}, {0,0,0,0}, { 2, 2, 2, LB_ERR}, {0,0,0,0}, {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}}; /* {selected, anchor, caret, selcount}{TODO fields} */ const struct listbox_test SS_NS = - {{LBS_NOSEL}, - {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}, + {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}, { 1, 1, 1, LB_ERR}, {0,0,0,0}, { 2, 2, 2, LB_ERR}, {0,0,0,0}, {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}}; const struct listbox_test MS = - {{LBS_MULTIPLESEL}, - { 0, LB_ERR, 0, 0}, {0,0,0,0}, + {{ 0, LB_ERR, 0, 0}, {0,0,0,0}, { 1, 1, 1, 1}, {0,0,0,0}, { 2, 1, 2, 1}, {0,0,0,0}, { 0, LB_ERR, 0, 2}, {0,0,0,0}}; const struct listbox_test MS_NS = - {{LBS_MULTIPLESEL | LBS_NOSEL}, - {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}, + {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}, { 1, 1, 1, LB_ERR}, {0,0,0,0}, { 2, 2, 2, LB_ERR}, {0,0,0,0}, {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}}; const struct listbox_test ES = - {{LBS_EXTENDEDSEL}, - { 0, LB_ERR, 0, 0}, {0,0,0,0}, + {{ 0, LB_ERR, 0, 0}, {0,0,0,0}, { 1, 1, 1, 1}, {0,0,0,0}, { 2, 2, 2, 1}, {0,0,0,0}, { 0, LB_ERR, 0, 2}, {0,0,0,0}}; const struct listbox_test ES_NS = - {{LBS_EXTENDEDSEL | LBS_NOSEL}, - {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}, + {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}, { 1, 1, 1, LB_ERR}, {0,0,0,0}, { 2, 2, 2, LB_ERR}, {0,0,0,0}, {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}}; const struct listbox_test EMS = - {{LBS_EXTENDEDSEL | LBS_MULTIPLESEL}, - { 0, LB_ERR, 0, 0}, {0,0,0,0}, + {{ 0, LB_ERR, 0, 0}, {0,0,0,0}, { 1, 1, 1, 1}, {0,0,0,0}, { 2, 2, 2, 1}, {0,0,0,0}, { 0, LB_ERR, 0, 2}, {0,0,0,0}}; const struct listbox_test EMS_NS = - {{LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL}, - {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}, + {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}, { 1, 1, 1, LB_ERR}, {0,0,0,0}, { 2, 2, 2, LB_ERR}, {0,0,0,0}, {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}}; trace (" Testing single selection...\n"); - check (SS); + check (0, SS); trace (" ... with NOSEL\n"); - check (SS_NS); + check (LBS_NOSEL, SS_NS); + trace (" ... LBS_NODATA variant ...\n"); + check (LBS_NODATA | LBS_OWNERDRAWFIXED, SS); + trace (" ... with NOSEL\n"); + check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_NOSEL, SS_NS); + trace (" Testing multiple selection...\n"); - check (MS); + check (LBS_MULTIPLESEL, MS); trace (" ... with NOSEL\n"); - check (MS_NS); + check (LBS_MULTIPLESEL | LBS_NOSEL, MS_NS); + trace (" ... LBS_NODATA variant ...\n"); + check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_MULTIPLESEL, MS); + trace (" ... with NOSEL\n"); + check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_MULTIPLESEL | LBS_NOSEL, MS_NS); + trace (" Testing extended selection...\n"); - check (ES); + check (LBS_EXTENDEDSEL, ES); trace (" ... with NOSEL\n"); - check (ES_NS); + check (LBS_EXTENDEDSEL | LBS_NOSEL, ES_NS); + trace (" ... LBS_NODATA variant ...\n"); + check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL, ES); + trace (" ... with NOSEL\n"); + check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL | LBS_NOSEL, ES_NS); + trace (" Testing extended and multiple selection...\n"); - check (EMS); + check (LBS_EXTENDEDSEL | LBS_MULTIPLESEL, EMS); trace (" ... with NOSEL\n"); - check (EMS_NS); + check (LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL, EMS_NS); + trace (" ... LBS_NODATA variant ...\n"); + check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL | LBS_MULTIPLESEL, EMS); + trace (" ... with NOSEL\n"); + check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL, EMS_NS); check_item_height(); test_ownerdraw(); test_LB_SELITEMRANGE(); test_LB_SETCURSEL(); test_listbox_height(); + test_changing_selection_styles(); test_itemfrompoint(); test_listbox_item_data(); test_listbox_LB_DIR(); test_listbox_dlgdir(); test_set_count(); + test_init_storage(); test_GetListBoxInfo(); test_missing_lbuttonup(); test_extents(); test_WM_MEASUREITEM(); + test_LB_SETSEL(); + test_LBS_NODATA(); } diff --git a/modules/rostests/winetests/user32/menu.c b/modules/rostests/winetests/user32/menu.c index 3430ed687ef..a7a8b8a4f24 100644 --- a/modules/rostests/winetests/user32/menu.c +++ b/modules/rostests/winetests/user32/menu.c @@ -39,55 +39,6 @@ static ATOM atomMenuCheckClass; -static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO); -static BOOL (WINAPI *pGetMenuBarInfo)(HWND,LONG,LONG,PMENUBARINFO); -static UINT (WINAPI *pSendInput)(UINT, INPUT*, size_t); -static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO); - -static void init_function_pointers(void) -{ - HMODULE hdll = GetModuleHandleA("user32"); - -#define GET_PROC(func) \ - p ## func = (void*)GetProcAddress(hdll, #func); \ - if(!p ## func) \ - trace("GetProcAddress(%s) failed\n", #func); - - GET_PROC(GetMenuInfo) - GET_PROC(GetMenuBarInfo) - GET_PROC(SendInput) - GET_PROC(SetMenuInfo) - -#undef GET_PROC -} - -static BOOL correct_behavior(void) -{ - HMENU hmenu; - MENUITEMINFOA info; - BOOL rc; - - hmenu = CreateMenu(); - - memset(&info, 0, sizeof(MENUITEMINFOA)); - info.cbSize= sizeof(MENUITEMINFOA); - SetLastError(0xdeadbeef); - rc = GetMenuItemInfoA(hmenu, 0, TRUE, &info); - /* Win9x : 0xdeadbeef - * NT4 : ERROR_INVALID_PARAMETER - * >= W2K : ERROR_MENU_ITEM_NOT_FOUND - */ - if (!rc && GetLastError() != ERROR_MENU_ITEM_NOT_FOUND) - { - win_skip("NT4 and below can't handle a bigger MENUITEMINFO struct\n"); - DestroyMenu(hmenu); - return FALSE; - } - - DestroyMenu(hmenu); - return TRUE; -} - static LRESULT WINAPI menu_check_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { switch (msg) @@ -284,11 +235,6 @@ static void test_getmenubarinfo(void) HWND hwnd; INT err; - if (!pGetMenuBarInfo) { - win_skip("GetMenuBarInfo is not available\n"); - return; - } - mbi.cbSize = sizeof(MENUBARINFO); hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL, @@ -298,7 +244,7 @@ static void test_getmenubarinfo(void) /* no menu: getmenubarinfo should fail */ SetLastError(0xdeadbeef); - ret = pGetMenuBarInfo(hwnd, OBJID_MENU, 0, &mbi); + ret = GetMenuBarInfo(hwnd, OBJID_MENU, 0, &mbi); err = GetLastError(); ok(ret == FALSE, "GetMenuBarInfo should not have been successful\n"); ok(err == 0xdeadbeef, "err = %d\n", err); @@ -311,38 +257,38 @@ static void test_getmenubarinfo(void) ok(ret, "SetMenu failed with error %d\n", GetLastError()); SetLastError(0xdeadbeef); - ret = pGetMenuBarInfo(NULL, OBJID_CLIENT, 0, &mbi); + ret = GetMenuBarInfo(NULL, OBJID_CLIENT, 0, &mbi); err = GetLastError(); ok(!ret, "GetMenuBarInfo succeeded\n"); ok(err == ERROR_INVALID_WINDOW_HANDLE, "err = %d\n", err); SetLastError(0xdeadbeef); - ret = pGetMenuBarInfo(hwnd, OBJID_CLIENT, 0, &mbi); + ret = GetMenuBarInfo(hwnd, OBJID_CLIENT, 0, &mbi); err = GetLastError(); ok(!ret, "GetMenuBarInfo succeeded\n"); ok(err==ERROR_INVALID_MENU_HANDLE || broken(err==0xdeadbeef) /* NT, W2K, XP */, "err = %d\n", err); SetLastError(0xdeadbeef); - ret = pGetMenuBarInfo(hwnd, OBJID_MENU, -1, &mbi); + ret = GetMenuBarInfo(hwnd, OBJID_MENU, -1, &mbi); err = GetLastError(); ok(ret == FALSE, "GetMenuBarInfo should have failed\n"); ok(err == 0xdeadbeef, "err = %d\n", err); mbi.cbSize = 1000; SetLastError(0xdeadbeef); - ret = pGetMenuBarInfo(hwnd, OBJID_MENU, 0, &mbi); + ret = GetMenuBarInfo(hwnd, OBJID_MENU, 0, &mbi); err = GetLastError(); ok(ret == FALSE, "GetMenuBarInfo should have failed\n"); ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err); mbi.cbSize = sizeof(MENUBARINFO); SetLastError(0xdeadbeef); - ret = pGetMenuBarInfo(hwnd, 123, 0, &mbi); + ret = GetMenuBarInfo(hwnd, 123, 0, &mbi); err = GetLastError(); ok(ret == FALSE, "GetMenuBarInfo should have failed\n"); ok(err == 0xdeadbeef, "err = %d\n", err); - ret = pGetMenuBarInfo(hwnd, OBJID_MENU, 0, &mbi); + ret = GetMenuBarInfo(hwnd, OBJID_MENU, 0, &mbi); ok(ret, "GetMenuBarInfo failed with error %d\n", GetLastError()); ok(mbi.rcBar.left == 0 && mbi.rcBar.top == 0 && mbi.rcBar.bottom == 0 && mbi.rcBar.right == 0, @@ -361,13 +307,13 @@ static void test_getmenubarinfo(void) ok(ret, "SetMenu failed with error %d\n", GetLastError()); SetLastError(0xdeadbeef); - ret = pGetMenuBarInfo(hwnd, OBJID_MENU, 200, &mbi); + ret = GetMenuBarInfo(hwnd, OBJID_MENU, 200, &mbi); err = GetLastError(); ok(ret == FALSE, "GetMenuBarInfo should have failed\n"); ok(err == 0xdeadbeef, "err = %d\n", err); /* get info for the whole menu */ - ret = pGetMenuBarInfo(hwnd, OBJID_MENU, 0, &mbi); + ret = GetMenuBarInfo(hwnd, OBJID_MENU, 0, &mbi); ok(ret, "GetMenuBarInfo failed with error %d\n", GetLastError()); /* calculate menu rectangle, from window rectangle and the position of the first item */ @@ -384,7 +330,7 @@ static void test_getmenubarinfo(void) ok(mbi.fFocused == 0, "fFocused: got %d instead of 0\n", mbi.fFocused); /* get info for item nr.2 */ - ret = pGetMenuBarInfo(hwnd, OBJID_MENU, 2, &mbi); + ret = GetMenuBarInfo(hwnd, OBJID_MENU, 2, &mbi); ok(ret, "GetMenuBarInfo failed with error %d\n", GetLastError()); ret = GetMenuItemRect(hwnd, hmenu, 1, &rci); ok(ret, "GetMenuItemRect failed.\n"); @@ -397,6 +343,62 @@ static void test_getmenubarinfo(void) DestroyWindow(hwnd); } +static void test_GetMenuItemRect(void) +{ + HWND hwnd; + HMENU hmenu; + HMENU popup_hmenu; + RECT window_rect; + RECT item_rect; + POINT client_top_left; + INT caption_height; + BOOL ret; + + 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()); + hmenu = CreateMenu(); + ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); + popup_hmenu = CreatePopupMenu(); + ok(popup_hmenu != NULL, "CreatePopupMenu failed with error %d\n", GetLastError()); + ret = AppendMenuA(popup_hmenu, MF_STRING, 0, "Popup"); + ok(ret, "AppendMenu failed with error %d\n", GetLastError()); + ret = AppendMenuA(hmenu, MF_STRING | MF_POPUP, (UINT_PTR)popup_hmenu, "Menu"); + ok(ret, "AppendMenu failed with error %d\n", GetLastError()); + ret = SetMenu(hwnd, hmenu); + ok(ret, "SetMenu failed with error %d\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()); + GetWindowRect(hwnd, &window_rect); + /* Get the screen coordinate of the left top corner of the client rectangle */ + client_top_left.x = 0; + client_top_left.y = 0; + 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); + /* 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, + 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, + 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, + client_top_left.y); + + DestroyWindow(hwnd); +} + static void test_system_menu(void) { WCHAR testW[] = {'t','e','s','t',0}; @@ -636,18 +638,13 @@ static LRESULT WINAPI subpopuplocked_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam static void test_subpopup_locked_by_menu(void) { - DWORD gle; BOOL ret; HMENU hmenu, hsubmenu; MENUINFO mi = { sizeof( MENUINFO)}; MENUITEMINFOA mii = { sizeof( MENUITEMINFOA)}; HWND hwnd; const int itemid = 0x1234567; - if( !pGetMenuInfo) - { - win_skip("GetMenuInfo is not available\n"); - return; - } + /* create window, popupmenu with one subpopup */ hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL, WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, @@ -669,48 +666,36 @@ static void test_subpopup_locked_by_menu(void) ok( ret, "GetMenuItemInfo failed error %d\n", GetLastError()); ok( mii.hSubMenu == hsubmenu, "submenu is %p\n", mii.hSubMenu); mi.fMask |= MIM_STYLE; - ret = pGetMenuInfo( hsubmenu, &mi); + ret = GetMenuInfo( hsubmenu, &mi); ok( ret , "GetMenuInfo returned 0 with error %d\n", GetLastError()); ret = IsMenu( hsubmenu); ok( ret , "Menu handle is not valid\n"); - SetLastError( 0xdeadbeef); + ret = TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL); - if( ret == (itemid & 0xffff)) { - win_skip("not on 16 bit menu subsystem\n"); - DestroyMenu( hsubmenu); - } else { - gle = GetLastError(); - ok( ret == itemid , "TrackPopupMenu returned %d error is %d\n", ret, gle); - ok( gle == 0 || - broken( gle == 0xdeadbeef), /* win2k0 */ - "Last error is %d\n", gle); - /* then destroy the sub-popup */ - ret = DestroyMenu( hsubmenu); - ok(ret, "DestroyMenu failed with error %d\n", GetLastError()); - /* and repeat the tests */ - mii.fMask = MIIM_SUBMENU; - ret = GetMenuItemInfoA( hmenu, 0, TRUE, &mii); - ok( ret, "GetMenuItemInfo failed error %d\n", GetLastError()); - /* GetMenuInfo fails now */ - ok( mii.hSubMenu == hsubmenu, "submenu is %p\n", mii.hSubMenu); - mi.fMask |= MIM_STYLE; - ret = pGetMenuInfo( hsubmenu, &mi); - ok( !ret , "GetMenuInfo should have failed\n"); - /* IsMenu says it is not */ - ret = IsMenu( hsubmenu); - ok( !ret , "Menu handle should be invalid\n"); - /* but TrackPopupMenu still works! */ - SetLastError( 0xdeadbeef); - ret = TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL); - gle = GetLastError(); - todo_wine { - ok( ret == itemid , "TrackPopupMenu returned %d error is %d\n", ret, gle); - } - ok( gle == 0 || - broken(gle == 0xdeadbeef) || /* wow64 */ - broken(gle == ERROR_INVALID_PARAMETER), /* win2k0 */ - "Last error is %d\n", gle); + ok( ret == itemid , "TrackPopupMenu returned %d error is %d\n", ret, GetLastError()); + + /* then destroy the sub-popup */ + ret = DestroyMenu( hsubmenu); + ok(ret, "DestroyMenu failed with error %d\n", GetLastError()); + /* and repeat the tests */ + mii.fMask = MIIM_SUBMENU; + ret = GetMenuItemInfoA( hmenu, 0, TRUE, &mii); + ok( ret, "GetMenuItemInfo failed error %d\n", GetLastError()); + /* GetMenuInfo fails now */ + ok( mii.hSubMenu == hsubmenu, "submenu is %p\n", mii.hSubMenu); + mi.fMask |= MIM_STYLE; + ret = GetMenuInfo( hsubmenu, &mi); + ok( !ret , "GetMenuInfo should have failed\n"); + /* IsMenu says it is not */ + ret = IsMenu( hsubmenu); + ok( !ret , "Menu handle should be invalid\n"); + + /* 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()); } + /* clean up */ DestroyMenu( hmenu); DestroyWindow(hwnd); @@ -741,7 +726,7 @@ static void test_menu_ownerdraw(void) ok( ret, "AppendMenu failed for %d\n", k-1); } MOD_maxid = k-1; - assert( k <= sizeof(MOD_rc)/sizeof(RECT)); + assert( k <= ARRAY_SIZE(MOD_rc)); /* display the menu */ TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL); @@ -873,9 +858,9 @@ static void test_mbs_help( int ispop, int hassub, int mnuopt, if( mnuopt) { mi.cbSize = sizeof(mi); mi.fMask = MIM_STYLE; - pGetMenuInfo( hmenu, &mi); + GetMenuInfo( hmenu, &mi); if( mnuopt) mi.dwStyle |= mnuopt == 1 ? MNS_NOCHECK : MNS_CHECKORBMP; - ret = pSetMenuInfo( hmenu, &mi); + ret = SetMenuInfo( hmenu, &mi); ok( ret, "SetMenuInfo failed with error %d\n", GetLastError()); } ret = InsertMenuItemA( hmenu, 0, FALSE, &mii); @@ -992,12 +977,6 @@ static void test_menu_bmp_and_string(void) int count, szidx, txtidx, bmpidx, hassub, mnuopt, ispop; BOOL got; - if( !pGetMenuInfo) - { - win_skip("GetMenuInfo is not available\n"); - return; - } - memset( bmfill, 0xcc, sizeof( bmfill)); hwnd = CreateWindowExA(0, (LPCSTR)MAKEINTATOM(atomMenuCheckClass), NULL, WS_SYSMENU | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, @@ -1012,7 +991,7 @@ static void test_menu_bmp_and_string(void) ok( hsysmenu != NULL, "GetSystemMenu failed with error %d\n", GetLastError()); mi.fMask = MIM_STYLE; mi.dwStyle = 0; - got = pGetMenuInfo( hsysmenu, &mi); + 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", mi.dwStyle, MNS_CHECKORBMP); @@ -1065,14 +1044,14 @@ static void test_menu_bmp_and_string(void) for( ispop=1; ispop >= 0; ispop--){ static SIZE bmsizes[]= { {10,10},{38,38},{1,30},{55,5}}; - for( szidx=0; szidx < sizeof( bmsizes) / sizeof( SIZE); szidx++) { + 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()); - for( txtidx = 0; txtidx < sizeof(MOD_txtsizes)/sizeof(MOD_txtsizes[0]); txtidx++) { + 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 */ - for( bmpidx = 0; bmpidx 0) continue; /* the HBMMENU_POPUP not to test for menu bars */ @@ -1149,15 +1128,9 @@ static void test_menu_add_string( void ) ok (GetMenuStringA( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n"); ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n"); - SetLastError(0xdeadbeef); ret = GetMenuStringW( hmenu, 0, strbackW, 99, MF_BYPOSITION ); - if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) - win_skip("GetMenuStringW is not implemented\n"); - else - { - ok (ret, "GetMenuStringW on ownerdraw entry failed\n"); - ok (!lstrcmpW( strbackW, expectedString ), "Menu text from Unicode version incorrect\n"); - } + ok (ret, "GetMenuStringW on ownerdraw entry failed\n"); + ok (!lstrcmpW( strbackW, expectedString ), "Menu text from Unicode version incorrect\n"); /* Just try some invalid parameter tests */ SetLastError(0xdeadbeef); @@ -1225,12 +1198,8 @@ static void test_menu_add_string( void ) ok (rc, "InsertMenuItem failed\n"); ok (!GetMenuStringA( hmenu, 0, NULL, 0, MF_BYPOSITION), "GetMenuString on ownerdraw entry succeeded.\n"); - SetLastError(0xdeadbeef); ret = GetMenuStringW( hmenu, 0, NULL, 0, MF_BYPOSITION); - if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) - win_skip("GetMenuStringW is not implemented\n"); - else - ok (!ret, "GetMenuStringW on ownerdraw entry succeeded.\n"); + ok (!ret, "GetMenuStringW on ownerdraw entry succeeded.\n"); DestroyMenu( hmenu ); } @@ -1823,7 +1792,7 @@ static void test_menu_iteminfo( void ) Only the low word of the dwTypeData is used. Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */ TMII_INSMI( MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, 0, 0, 0, -1, - (HMENU)MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, 0, OK ); + (HMENU)MAKELPARAM(HBMMENU_MBAR_CLOSE, 0x1234), -1, 0, OK ); TMII_GMII ( MIIM_TYPE, 80, MFT_BITMAP | MFT_RIGHTJUSTIFY, 0, 0, 0, 0, 0, 0, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE, NULL, OK, OK ); @@ -1869,7 +1838,7 @@ static void test_menu_iteminfo( void ) Only the low word of the dwTypeData is used. Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */ TMII_INSMI( MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, 0, 0, 0, -1, - (HMENU)MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, 0, OK ); + (HMENU)MAKELPARAM(HBMMENU_MBAR_CLOSE, 0x1234), -1, 0, OK ); TMII_GMII ( MIIM_TYPE, 80, MFT_BITMAP | MFT_RIGHTJUSTIFY, 0, 0, 0, 0, 0, 0, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE, NULL, OK, OK ); @@ -2277,16 +2246,16 @@ static struct menu_mouse_tests_s { { INPUT_KEYBOARD, {{0}}, {VK_F10, 0}, TRUE, FALSE }, { INPUT_KEYBOARD, {{0}}, {VK_F10, 0}, FALSE, FALSE }, - { INPUT_MOUSE, {{1, 2}, {0}}, {0}, TRUE, TRUE }, /* test 20 */ + { INPUT_MOUSE, {{1, 2}, {0}}, {0}, TRUE, FALSE }, /* test 20 */ { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE }, - { INPUT_MOUSE, {{1, 0}, {0}}, {0}, TRUE, TRUE }, + { INPUT_MOUSE, {{1, 0}, {0}}, {0}, TRUE, FALSE }, { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE }, - { INPUT_MOUSE, {{1, 0}, {2, 2}, {0}}, {0}, TRUE, TRUE }, + { INPUT_MOUSE, {{1, 0}, {2, 2}, {0}}, {0}, TRUE, FALSE }, { INPUT_MOUSE, {{2, 1}, {0}}, {0}, FALSE, FALSE }, - { INPUT_MOUSE, {{1, 0}, {2, 0}, {0}}, {0}, TRUE, TRUE }, + { INPUT_MOUSE, {{1, 0}, {2, 0}, {0}}, {0}, TRUE, FALSE }, { INPUT_MOUSE, {{3, 0}, {0}}, {0}, FALSE, FALSE }, - { INPUT_MOUSE, {{1, 0}, {2, 0}, {0}}, {0}, TRUE, TRUE }, - { INPUT_MOUSE, {{3, 1}, {0}}, {0}, TRUE, TRUE }, + { INPUT_MOUSE, {{1, 0}, {2, 0}, {0}}, {0}, TRUE, FALSE }, + { INPUT_MOUSE, {{3, 1}, {0}}, {0}, TRUE, FALSE }, { INPUT_MOUSE, {{1, 1}, {0}}, {0}, FALSE, FALSE }, { -1 } }; @@ -2298,7 +2267,7 @@ static void send_key(WORD wVk) 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; - pSendInput(2, (INPUT *) i, sizeof(INPUT)); + SendInput(2, (INPUT *) i, sizeof(INPUT)); } static BOOL click_menu(HANDLE hWnd, struct menu_item_pair_s *mi) @@ -2323,7 +2292,7 @@ static BOOL click_menu(HANDLE hWnd, struct menu_item_pair_s *mi) i[0].u.mi.dwFlags |= MOUSEEVENTF_MOVE; i[1].u.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN; i[2].u.mi.dwFlags |= MOUSEEVENTF_LEFTUP; - ret = pSendInput(3, (INPUT *) i, sizeof(INPUT)); + ret = SendInput(3, (INPUT *) i, sizeof(INPUT)); /* hack to prevent mouse message buildup in Wine */ while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg ); @@ -2340,7 +2309,7 @@ static DWORD WINAPI test_menu_input_thread(LPVOID lpParameter) for (i = 0; menu_tests[i].type != -1; i++) { BOOL ret = TRUE; - int elapsed = 0; + int elapsed; got_input = i && menu_tests[i-1].bMenuVisible; @@ -2349,7 +2318,16 @@ static DWORD WINAPI test_menu_input_thread(LPVOID lpParameter) send_key(menu_tests[i].wVk[j]); else for (j = 0; menu_tests[i].menu_item_pairs[j].uMenu != 0; j++) - if (!(ret = click_menu(hWnd, &menu_tests[i].menu_item_pairs[j]))) break; + { + /* Maybe clicking too fast before menu is initialized. Sleep 100 ms and retry */ + elapsed = 0; + while (!(ret = click_menu(hWnd, &menu_tests[i].menu_item_pairs[j]))) + { + if (elapsed > 1000) break; + elapsed += 100; + Sleep(100); + } + } if (!ret) { @@ -2357,6 +2335,8 @@ static DWORD WINAPI test_menu_input_thread(LPVOID lpParameter) PostMessageA( hWnd, WM_CANCELMODE, 0, 0 ); return 0; } + + elapsed = 0; while (menu_tests[i].bMenuVisible != bMenuVisible) { if (elapsed > 200) @@ -2381,6 +2361,11 @@ static DWORD WINAPI test_menu_input_thread(LPVOID lpParameter) static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { + MENUBARINFO mbi; + HMENU hmenu; + UINT state; + BOOL br; + switch (msg) { case WM_ENTERMENULOOP: bMenuVisible = TRUE; @@ -2405,47 +2390,36 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, return( DefWindowProcA( hWnd, msg, wParam, lParam ) ); } - if(pGetMenuBarInfo) - { - MENUBARINFO mbi; - HMENU hmenu; - UINT state; - BOOL br; + mbi.cbSize = sizeof(MENUBARINFO); - mbi.cbSize = sizeof(MENUBARINFO); + /* get info for the menu */ + br = GetMenuBarInfo(hWnd, OBJID_MENU, 0, &mbi); + ok(br, "msg %x: GetMenuBarInfo failed\n", msg); + hmenu = GetMenu(hWnd); + ok(!mbi.hwndMenu, "msg %x: GetMenuBarInfo.hwndMenu wrong: %p expected NULL\n", + msg, mbi.hwndMenu); + ok(mbi.hMenu == hmenu, "msg %x: GetMenuBarInfo got wrong menu: %p expected %p\n", + msg, mbi.hMenu, hmenu); + ok(!bMenuVisible == !mbi.fBarFocused, "msg %x: GetMenuBarInfo.fBarFocused (%d) is wrong\n", + msg, mbi.fBarFocused != 0); + ok(!bMenuVisible == !mbi.fFocused, "msg %x: GetMenuBarInfo.fFocused (%d) is wrong\n", + msg, mbi.fFocused != 0); - /* get info for the menu */ - br = pGetMenuBarInfo(hWnd, OBJID_MENU, 0, &mbi); - ok(br, "msg %x: GetMenuBarInfo failed\n", msg); - hmenu = GetMenu(hWnd); - ok(!mbi.hwndMenu, "msg %x: GetMenuBarInfo.hwndMenu wrong: %p expected NULL\n", - msg, mbi.hwndMenu); - ok(mbi.hMenu == hmenu, "msg %x: GetMenuBarInfo got wrong menu: %p expected %p\n", - msg, mbi.hMenu, hmenu); - ok(!bMenuVisible == !mbi.fBarFocused, "msg %x: GetMenuBarInfo.fBarFocused (%d) is wrong\n", - msg, mbi.fBarFocused != 0); - ok(!bMenuVisible == !mbi.fFocused, "msg %x: GetMenuBarInfo.fFocused (%d) is wrong\n", - msg, mbi.fFocused != 0); - - /* get info for the menu's first item */ - br = pGetMenuBarInfo(hWnd, OBJID_MENU, 1, &mbi); - ok(br, "msg %x: GetMenuBarInfo failed\n", msg); - state = GetMenuState(hmenu, 0, MF_BYPOSITION); - if (pGetMenuInfo) /* Skip on NT */ - { - /* Native returns handle to destroyed window */ - todo_wine_if (msg==WM_UNINITMENUPOPUP && popmenu==1) - ok(!mbi.hwndMenu == !popmenu, - "msg %x: GetMenuBarInfo.hwndMenu wrong: %p expected %sNULL\n", - msg, mbi.hwndMenu, popmenu ? "not " : ""); - } - ok(mbi.hMenu == hmenu, "msg %x: GetMenuBarInfo got wrong menu: %p expected %p\n", - msg, mbi.hMenu, hmenu); - ok(!bMenuVisible == !mbi.fBarFocused, "nsg %x: GetMenuBarInfo.fBarFocused (%d) is wrong\n", - msg, mbi.fBarFocused != 0); - ok(!(bMenuVisible && (state & MF_HILITE)) == !mbi.fFocused, - "msg %x: GetMenuBarInfo.fFocused (%d) is wrong\n", msg, mbi.fFocused != 0); - } + /* get info for the menu's first item */ + br = GetMenuBarInfo(hWnd, OBJID_MENU, 1, &mbi); + ok(br, "msg %x: GetMenuBarInfo failed\n", msg); + state = GetMenuState(hmenu, 0, MF_BYPOSITION); + /* Native returns handle to destroyed window */ + todo_wine_if (msg==WM_UNINITMENUPOPUP && popmenu==1) + ok(!mbi.hwndMenu == !popmenu, + "msg %x: GetMenuBarInfo.hwndMenu wrong: %p expected %sNULL\n", + msg, mbi.hwndMenu, popmenu ? "not " : ""); + ok(mbi.hMenu == hmenu, "msg %x: GetMenuBarInfo got wrong menu: %p expected %p\n", + msg, mbi.hMenu, hmenu); + ok(!bMenuVisible == !mbi.fBarFocused, "nsg %x: GetMenuBarInfo.fBarFocused (%d) is wrong\n", + msg, mbi.fBarFocused != 0); + ok(!(bMenuVisible && (state & MF_HILITE)) == !mbi.fFocused, + "msg %x: GetMenuBarInfo.fFocused (%d) is wrong\n", msg, mbi.fFocused != 0); if (msg == WM_EXITMENULOOP) bMenuVisible = FALSE; @@ -2465,12 +2439,6 @@ static void test_menu_input(void) { ATOM aclass; POINT orig_pos; - if (!pSendInput) - { - win_skip("SendInput is not available\n"); - return; - } - wclass.lpszClassName = "MenuTestClass"; wclass.style = CS_HREDRAW | CS_VREDRAW; wclass.lpfnWndProc = WndProc; @@ -2858,9 +2826,8 @@ static void test_menu_resource_layout(void) ok(ret, "AppendMenu failed\n"); count = GetMenuItemCount(hmenu); - ok(count == sizeof(menu_data)/sizeof(menu_data[0]), - "expected %u menu items, got %u\n", - (UINT)(sizeof(menu_data)/sizeof(menu_data[0])), count); + ok(count == ARRAY_SIZE(menu_data), "expected %u menu items, got %u\n", + (UINT) ARRAY_SIZE(menu_data), count); for (i = 0; i < count; i++) { @@ -3079,9 +3046,9 @@ static void test_InsertMenu(void) }; HMENU hmenu; -#define create_menu(a) create_menu_from_data((a), sizeof(a)/sizeof((a)[0])) -#define create_menuitem(a) create_menuitem_from_data((a), sizeof(a)/sizeof((a)[0])) -#define compare_menu(h, a) compare_menu_data((h), (a), sizeof(a)/sizeof((a)[0])) +#define create_menu(a) create_menu_from_data((a), ARRAY_SIZE(a)) +#define create_menuitem(a) create_menuitem_from_data((a), ARRAY_SIZE(a)) +#define compare_menu(h, a) compare_menu_data((h), (a), ARRAY_SIZE(a)) hmenu = create_menu(in1); compare_menu(hmenu, out1); @@ -3128,18 +3095,12 @@ static void test_menu_getmenuinfo(void) BOOL ret; DWORD gle; - if (!pGetMenuInfo) - { - win_skip("GetMenuInfo is not available\n"); - return; - } - /* create a menu */ hmenu = CreateMenu(); assert( hmenu); /* test some parameter errors */ SetLastError(0xdeadbeef); - ret = pGetMenuInfo( hmenu, NULL); + ret = GetMenuInfo( hmenu, NULL); gle= GetLastError(); ok( !ret, "GetMenuInfo() should have failed\n"); ok( gle == ERROR_INVALID_PARAMETER || @@ -3147,7 +3108,7 @@ static void test_menu_getmenuinfo(void) "GetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER); SetLastError(0xdeadbeef); mi.cbSize = 0; - ret = pGetMenuInfo( hmenu, &mi); + ret = GetMenuInfo( hmenu, &mi); gle= GetLastError(); ok( !ret, "GetMenuInfo() should have failed\n"); ok( gle == ERROR_INVALID_PARAMETER || @@ -3155,13 +3116,13 @@ static void test_menu_getmenuinfo(void) "GetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER); SetLastError(0xdeadbeef); mi.cbSize = sizeof( MENUINFO); - ret = pGetMenuInfo( hmenu, &mi); + ret = GetMenuInfo( hmenu, &mi); gle= GetLastError(); ok( ret, "GetMenuInfo() should have succeeded\n"); ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); SetLastError(0xdeadbeef); mi.cbSize = 0; - ret = pGetMenuInfo( NULL, &mi); + ret = GetMenuInfo( NULL, &mi); gle= GetLastError(); ok( !ret, "GetMenuInfo() should have failed\n"); ok( gle == ERROR_INVALID_PARAMETER || @@ -3181,12 +3142,6 @@ static void test_menu_setmenuinfo(void) DWORD gle; HBRUSH brush; - if (!pGetMenuInfo || !pSetMenuInfo) - { - win_skip("Get/SetMenuInfo are not available\n"); - return; - } - /* create a menu with a submenu */ hmenu = CreateMenu(); hsubmenu = CreateMenu(); @@ -3197,7 +3152,7 @@ static void test_menu_setmenuinfo(void) ok( ret, "InsertMenuItem failed with error %d\n", GetLastError()); /* test some parameter errors */ SetLastError(0xdeadbeef); - ret = pSetMenuInfo( hmenu, NULL); + ret = SetMenuInfo( hmenu, NULL); gle= GetLastError(); ok( !ret, "SetMenuInfo() should have failed\n"); ok( gle == ERROR_INVALID_PARAMETER || @@ -3205,7 +3160,7 @@ static void test_menu_setmenuinfo(void) "SetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER); SetLastError(0xdeadbeef); mi.cbSize = 0; - ret = pSetMenuInfo( hmenu, &mi); + ret = SetMenuInfo( hmenu, &mi); gle= GetLastError(); ok( !ret, "SetMenuInfo() should have failed\n"); ok( gle == ERROR_INVALID_PARAMETER || @@ -3213,13 +3168,13 @@ static void test_menu_setmenuinfo(void) "SetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER); SetLastError(0xdeadbeef); mi.cbSize = sizeof( MENUINFO); - ret = pSetMenuInfo( hmenu, &mi); + ret = SetMenuInfo( hmenu, &mi); gle= GetLastError(); ok( ret, "SetMenuInfo() should have succeeded\n"); ok( gle == 0xdeadbeef, "SetMenuInfo() error got %u\n", gle); SetLastError(0xdeadbeef); mi.cbSize = 0; - ret = pSetMenuInfo( NULL, &mi); + ret = SetMenuInfo( NULL, &mi); gle= GetLastError(); ok( !ret, "SetMenuInfo() should have failed\n"); ok( gle == ERROR_INVALID_PARAMETER || @@ -3230,7 +3185,7 @@ static void test_menu_setmenuinfo(void) SetLastError(0xdeadbeef); mi.cbSize = sizeof( MENUINFO); mi.fMask = MIM_STYLE; - ret = pGetMenuInfo( hmenu, &mi); + ret = GetMenuInfo( hmenu, &mi); gle= GetLastError(); ok( ret, "GetMenuInfo() should have succeeded\n"); ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); @@ -3238,7 +3193,7 @@ static void test_menu_setmenuinfo(void) SetLastError(0xdeadbeef); mi.cbSize = sizeof( MENUINFO); mi.fMask = MIM_STYLE; - ret = pGetMenuInfo( hsubmenu, &mi); + ret = GetMenuInfo( hsubmenu, &mi); gle= GetLastError(); ok( ret, "GetMenuInfo() should have succeeded\n"); ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); @@ -3248,7 +3203,7 @@ static void test_menu_setmenuinfo(void) mi.cbSize = sizeof( MENUINFO); mi.fMask = MIM_STYLE | MIM_APPLYTOSUBMENUS; mi.dwStyle = MNS_CHECKORBMP; - ret = pSetMenuInfo( hmenu, &mi); + ret = SetMenuInfo( hmenu, &mi); gle= GetLastError(); ok( ret, "SetMenuInfo() should have succeeded\n"); ok( gle == 0xdeadbeef, "SetMenuInfo() error got %u\n", gle); @@ -3256,7 +3211,7 @@ static void test_menu_setmenuinfo(void) SetLastError(0xdeadbeef); mi.cbSize = sizeof( MENUINFO); mi.fMask = MIM_STYLE; - ret = pGetMenuInfo( hmenu, &mi); + ret = GetMenuInfo( hmenu, &mi); gle= GetLastError(); ok( ret, "GetMenuInfo() should have succeeded\n"); ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); @@ -3264,7 +3219,7 @@ static void test_menu_setmenuinfo(void) SetLastError(0xdeadbeef); mi.cbSize = sizeof( MENUINFO); mi.fMask = MIM_STYLE; - ret = pGetMenuInfo( hsubmenu, &mi); + ret = GetMenuInfo( hsubmenu, &mi); gle= GetLastError(); ok( ret, "GetMenuInfo() should have succeeded\n"); ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); @@ -3274,7 +3229,7 @@ static void test_menu_setmenuinfo(void) mi.cbSize = sizeof( MENUINFO); mi.fMask = MIM_STYLE ; mi.dwStyle = MNS_NOCHECK; - ret = pSetMenuInfo( hmenu, &mi); + ret = SetMenuInfo( hmenu, &mi); gle= GetLastError(); ok( ret, "SetMenuInfo() should have succeeded\n"); ok( gle == 0xdeadbeef, "SetMenuInfo() error got %u\n", gle); @@ -3282,7 +3237,7 @@ static void test_menu_setmenuinfo(void) SetLastError(0xdeadbeef); mi.cbSize = sizeof( MENUINFO); mi.fMask = MIM_STYLE; - ret = pGetMenuInfo( hmenu, &mi); + ret = GetMenuInfo( hmenu, &mi); gle= GetLastError(); ok( ret, "GetMenuInfo() should have succeeded\n"); ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); @@ -3290,7 +3245,7 @@ static void test_menu_setmenuinfo(void) SetLastError(0xdeadbeef); mi.cbSize = sizeof( MENUINFO); mi.fMask = MIM_STYLE; - ret = pGetMenuInfo( hsubmenu, &mi); + ret = GetMenuInfo( hsubmenu, &mi); gle= GetLastError(); ok( ret, "GetMenuInfo() should have succeeded\n"); ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); @@ -3299,23 +3254,23 @@ static void test_menu_setmenuinfo(void) /* test background brush */ mi.cbSize = sizeof(mi); mi.fMask = MIM_BACKGROUND; - ret = pGetMenuInfo( hmenu, &mi ); + ret = GetMenuInfo( hmenu, &mi ); ok( ret, "GetMenuInfo() should have succeeded\n" ); ok( mi.hbrBack == NULL, "got %p\n", mi.hbrBack ); brush = CreateSolidBrush( RGB(0xff, 0, 0) ); mi.hbrBack = brush; - ret = pSetMenuInfo( hmenu, &mi ); + ret = SetMenuInfo( hmenu, &mi ); ok( ret, "SetMenuInfo() should have succeeded\n" ); mi.hbrBack = NULL; - ret = pGetMenuInfo( hmenu, &mi ); + ret = GetMenuInfo( hmenu, &mi ); ok( ret, "GetMenuInfo() should have succeeded\n" ); ok( mi.hbrBack == brush, "got %p original %p\n", mi.hbrBack, brush ); mi.hbrBack = NULL; - ret = pSetMenuInfo( hmenu, &mi ); + ret = SetMenuInfo( hmenu, &mi ); ok( ret, "SetMenuInfo() should have succeeded\n" ); - ret = pGetMenuInfo( hmenu, &mi ); + ret = GetMenuInfo( hmenu, &mi ); ok( ret, "GetMenuInfo() should have succeeded\n" ); ok( mi.hbrBack == NULL, "got %p\n", mi.hbrBack ); DeleteObject( brush ); @@ -3682,13 +3637,13 @@ static void test_menualign(void) ok( hbm1 && hbm2 && hbm3, "Creating bitmaps failed\n"); menu = CreatePopupMenu(); ok( menu != NULL, "CreatePopupMenu() failed\n"); - if( pGetMenuInfo) { - mi.fMask = MIM_STYLE; - ret = pGetMenuInfo( menu, &mi); - ok( ret, "GetMenuInfo failed: %d\n", GetLastError()); - ok( menu != NULL, "GetMenuInfo() failed\n"); - ok( 0 == mi.dwStyle, "menuinfo style is %x\n", mi.dwStyle); - } + + mi.fMask = MIM_STYLE; + ret = GetMenuInfo( menu, &mi); + ok( ret, "GetMenuInfo failed: %d\n", GetLastError()); + ok( menu != NULL, "GetMenuInfo() failed\n"); + ok( 0 == mi.dwStyle, "menuinfo style is %x\n", mi.dwStyle); + /* test 1 */ mii.fMask = MIIM_BITMAP | MIIM_STRING | MIIM_ID; mii.wID = 1; @@ -4298,28 +4253,22 @@ if (0) /* FIXME: uncomment once Wine is fixed */ { START_TEST(menu) { - init_function_pointers(); register_menu_check_class(); - /* Wine defines MENUITEMINFO for W2K and above. NT4 and below can't - * handle that. - */ - if (correct_behavior()) - { - test_menu_add_string(); - test_menu_iteminfo(); - test_menu_search_bycommand(); - test_CheckMenuRadioItem(); - test_menu_resource_layout(); - test_InsertMenu(); - test_menualign(); - test_system_menu(); - } + test_menu_add_string(); + test_menu_iteminfo(); + test_menu_search_bycommand(); + test_CheckMenuRadioItem(); + test_menu_resource_layout(); + test_InsertMenu(); + test_menualign(); + test_system_menu(); test_menu_locked_by_window(); test_subpopup_locked_by_menu(); test_menu_ownerdraw(); test_getmenubarinfo(); + test_GetMenuItemRect(); test_menu_bmp_and_string(); test_menu_getmenuinfo(); test_menu_setmenuinfo(); diff --git a/modules/rostests/winetests/user32/monitor.c b/modules/rostests/winetests/user32/monitor.c index 886d63ccfe2..26ee28a122d 100644 --- a/modules/rostests/winetests/user32/monitor.c +++ b/modules/rostests/winetests/user32/monitor.c @@ -23,6 +23,8 @@ #include "winbase.h" #include "wingdi.h" #include "winuser.h" +#include "winreg.h" +#include static HMODULE hdll; static LONG (WINAPI *pChangeDisplaySettingsExA)(LPCSTR, LPDEVMODEA, HWND, DWORD, LPVOID); @@ -74,12 +76,154 @@ static BOOL CALLBACK monitor_enum_proc(HMONITOR hmon, HDC hdc, LPRECT lprc, return TRUE; } +static int adapter_count = 0; +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++; + + /* DeviceName */ + ok(sscanf(device->DeviceName, "\\\\.\\DISPLAY%d", &number) == 1, "#%d: wrong DeviceName %s\n", index, + 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); + + /* 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); + + /* 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()); + DeleteDC(hdc); + } + + /* DeviceID */ + /* DeviceID should equal to the first string of HardwareID value data in PCI GPU instance. You can verify this + * by changing the data and rerun EnumDisplayDevices. But it's difficult to find corresponding PCI device on + * userland. So here we check the expected format instead. */ + if (flags & EDD_GET_DEVICE_INTERFACE_NAME) + ok(strlen(device->DeviceID) == 0 || /* vista+ */ + sscanf(device->DeviceID, "PCI\\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X", + &vendor_id, &device_id, &subsys_id, &revision_id) == 4, /* XP/2003 ignores EDD_GET_DEVICE_INTERFACE_NAME */ + "#%d: got %s\n", index, device->DeviceID); + else + { + ok(broken(strlen(device->DeviceID) == 0) || /* XP on Testbot returns an empty string, whereas real machine doesn't */ + sscanf(device->DeviceID, "PCI\\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X", &vendor_id, &device_id, &subsys_id, + &revision_id) == 4, "#%d: wrong DeviceID %s\n", index, device->DeviceID); + } +} + +static void test_enumdisplaydevices_monitor(int adapter_index, int monitor_index, const char *adapter_name, + const 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]; + char buffer[128]; + int number; + + monitor_count++; + + /* DeviceName */ + lstrcpyA(monitor_name, adapter_name); + sprintf(monitor_name + strlen(monitor_name), "\\Monitor%d", 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); + + /* 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); + + /* DeviceID */ + lstrcpynA(buffer, device->DeviceID, sizeof(device_id_prefix)); + 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} */ + 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); + } + else + { + /* Expect HarewareID value data + Driver value data in HKLM\SYSTEM\CurrentControlSet\Enum\DISPLAY\Default_Monitor\{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); + } + + /* DeviceKey */ + lstrcpynA(buffer, device->DeviceKey, sizeof(device_key_prefix)); + ok(!lstrcmpiA(buffer, device_key_prefix), "#%d: wrong DeviceKey : %s\n", monitor_index, device->DeviceKey); + ok(sscanf(device->DeviceKey + sizeof(device_key_prefix) - 1, "%04d", &number) == 1, + "#%d wrong DeviceKey : %s\n", monitor_index, device->DeviceKey); +} + 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]; - DWORD primary_num = -1, num = 0; + char adapter_name[32]; + int number; + int flag_index; + int adapter_index; + int monitor_index; BOOL ret; if (!pEnumDisplayDevicesA) @@ -88,50 +232,50 @@ static void test_enumdisplaydevices(void) return; } + /* Doesn't accept \\.\DISPLAY */ dd.cb = sizeof(dd); - for (num = 0;; num++) - { - HDC dc; - ret = pEnumDisplayDevicesA(NULL, num, &dd, 0); - if(!ret) break; + ret = pEnumDisplayDevicesA("\\\\.\\DISPLAY", 0, &dd, 0); + ok(!ret, "Expect failure\n"); - if(dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) + /* 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++) { - strcpy(primary_device_name, dd.DeviceName); - primary_num = num; - } - if(dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) - { - /* test creating DC */ - dc = CreateDCA(dd.DeviceName, NULL, NULL, NULL); - ok(dc != NULL, "Failed to CreateDC(\"%s\") err=%d\n", dd.DeviceName, GetLastError()); - DeleteDC(dc); - } - } + lstrcpyA(adapter_name, dd.DeviceName); - if (primary_num == -1 || !pEnumDisplayMonitors || !pGetMonitorInfoA) + if (sscanf(adapter_name, "\\\\.\\DISPLAYV%d", &number) == 1) + { + skip("Skipping software devices %s:%s\n", adapter_name, dd.DeviceString); + continue; + } + + test_enumdisplaydevices_adapter(adapter_index, &dd, flags[flag_index]); + + for (monitor_index = 0; pEnumDisplayDevicesA(adapter_name, monitor_index, &dd, flags[flag_index]); + monitor_index++) + test_enumdisplaydevices_monitor(adapter_index, 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); - - dd.cb = sizeof(dd); - for (num = 0;; num++) - { - ret = pEnumDisplayDevicesA(primary_device_name, num, &dd, 0); - if (!ret) break; - - dd.DeviceID[63] = 0; - ok(!strcasecmp(dd.DeviceID, "Monitor\\Default_Monitor\\{4D36E96E-E325-11CE-BFC1-08002BE10318}\\"), - "DeviceID \"%s\" does not start with \"Monitor\\Default_Monitor\\...\" prefix\n", dd.DeviceID); - } } struct vid_mode @@ -160,7 +304,6 @@ static const struct vid_mode vid_modes_test[] = { {0, 0, 0, 0, DM_DISPLAYFREQUENCY, 0} */ }; -#define vid_modes_cnt (sizeof(vid_modes_test) / sizeof(vid_modes_test[0])) static void test_ChangeDisplaySettingsEx(void) { @@ -247,7 +390,7 @@ static void test_ChangeDisplaySettingsEx(void) memset(&dm, 0, sizeof(dm)); dm.dmSize = sizeof(dm); - for (i = 0; i < vid_modes_cnt; i++) + for (i = 0; i < ARRAY_SIZE(vid_modes_test); i++) { dm.dmPelsWidth = vid_modes_test[i].w; dm.dmPelsHeight = vid_modes_test[i].h; @@ -409,7 +552,7 @@ static void test_monitors(void) /* tests for cbSize in MONITORINFO */ monitor = pMonitorFromWindow( 0, MONITOR_DEFAULTTOPRIMARY ); - for (i = 0; i < (sizeof(testdatami) / sizeof(testdatami[0])); i++) + for (i = 0; i < ARRAY_SIZE(testdatami); i++) { memset( &mi, 0, sizeof(mi) ); mi.cbSize = testdatami[i].cbSize; @@ -431,7 +574,7 @@ static void test_monitors(void) } /* tests for cbSize in MONITORINFOEXA */ - for (i = 0; i < (sizeof(testdatamiexa) / sizeof(testdatamiexa[0])); i++) + for (i = 0; i < ARRAY_SIZE(testdatamiexa); i++) { memset( &miexa, 0, sizeof(miexa) ); miexa.cbSize = testdatamiexa[i].cbSize; @@ -444,7 +587,7 @@ static void test_monitors(void) } /* tests for cbSize in MONITORINFOEXW */ - for (i = 0; i < (sizeof(testdatamiexw) / sizeof(testdatamiexw[0])); i++) + for (i = 0; i < ARRAY_SIZE(testdatamiexw); i++) { memset( &miexw, 0, sizeof(miexw) ); miexw.cbSize = testdatamiexw[i].cbSize; @@ -596,7 +739,7 @@ static void test_display_config(void) paths = modes = 100; ret = pGetDisplayConfigBufferSizes(0, &paths, &modes); ok(ret == ERROR_INVALID_PARAMETER || ret == ERROR_NOT_SUPPORTED, "got %d\n", ret); - ok(modes == 0 && paths == 0, "got %u, %u\n", modes, paths); + ok((modes == 0 || modes == 100) && paths == 0, "got %u, %u\n", modes, paths); } START_TEST(monitor) diff --git a/modules/rostests/winetests/user32/msg.c b/modules/rostests/winetests/user32/msg.c index 39ce1525825..e66d0dcdcf1 100644 --- a/modules/rostests/winetests/user32/msg.c +++ b/modules/rostests/winetests/user32/msg.c @@ -569,6 +569,7 @@ static const struct message WmShowRestoreMaxOverlappedSeq[] = { { WM_GETTITLEBARINFOEX, sent|optional }, { WM_NCPAINT, sent|beginpaint|optional }, { WM_ERASEBKGND, sent|beginpaint|optional }, + { WM_SYNCPAINT, sent|optional }, { 0 } }; /* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */ @@ -778,37 +779,6 @@ static const struct message WmCreateInvisibleMaxPopupSeq[] = { { 0 } }; /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */ -static const struct message WmShowMaxPopupResizedSeq_todo[] = { - { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE }, - { WM_GETMINMAXINFO, sent }, - { WM_WINDOWPOSCHANGING, sent|wparam, 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_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, - { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, - { WM_NCPAINT, sent|wparam|optional, 1 }, - { WM_ERASEBKGND, sent|optional }, - { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, - { WM_ACTIVATEAPP, sent|wparam, 1 }, - { WM_NCACTIVATE, sent }, - { WM_ACTIVATE, sent|wparam, 1 }, - { 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_GETTEXT, sent|optional }, - { WM_NCPAINT, sent|wparam|optional, 1 }, - { WM_ERASEBKGND, sent|optional }, - { WM_WINDOWPOSCHANGED, sent }, - /* WinNT4.0 sends WM_MOVE */ - { WM_MOVE, sent|defwinproc|optional }, - { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, - { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, - { 0 } -}; static const struct message WmShowMaxPopupResizedSeq[] = { { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE }, { WM_GETMINMAXINFO, sent }, @@ -831,7 +801,7 @@ static const struct message WmShowMaxPopupResizedSeq[] = { { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|wparam|defwinproc, 0 }, { WM_GETTEXT, sent|optional }, - { WM_NCPAINT, sent|optional }, /* We'll check WM_NCPAINT behaviour in another test */ + { WM_NCPAINT, sent|wparam|optional, 1 }, { WM_ERASEBKGND, sent|optional }, { WM_WINDOWPOSCHANGED, sent }, /* WinNT4.0 sends WM_MOVE */ @@ -870,6 +840,7 @@ static const struct message WmShowMaxPopupSeq[] = { { 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_SIZE, sent|defwinproc|optional }, { 0 } }; /* CreateWindow(WS_VISIBLE) for popup window */ @@ -3510,6 +3481,7 @@ static const struct message WmMaximizeMDIchildInvisibleSeq2[] = { { 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_SIZE, sent|defwinproc|optional }, { 0 } }; /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */ @@ -4017,7 +3989,7 @@ static void test_mdi_messages(void) ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus()); ShowWindow(mdi_child2, SW_MINIMIZE); - ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE); + ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", FALSE); ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow()); ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus()); @@ -4756,18 +4728,6 @@ static void test_showwindow(void) DestroyWindow(hwnd); flush_sequence(); - /* Test again, this time the NC_PAINT message */ - 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"); - SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE); - flush_sequence(); - ShowWindow(hwnd, SW_SHOWMAXIMIZED); - ok_sequence(WmShowMaxPopupResizedSeq_todo, - "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup TODO", TRUE); - DestroyWindow(hwnd); - flush_sequence(); - /* Test 2: * 1. Create invisible maximized popup window. * 2. Show it maximized. @@ -4817,6 +4777,39 @@ static void test_showwindow(void) 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; + + 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); + + flush_sequence(); + SetActiveWindow(recursive); + ok_sequence(seq, "Recursive Activation", FALSE); + + DestroyWindow(recursive); + DestroyWindow(hwnd); + flush_sequence(); +} + static void test_sys_menu(void) { HWND hwnd; @@ -5066,7 +5059,7 @@ static void test_WM_DEVICECHANGE(HWND hwnd) DBT_DEVICETYPESPECIFIC, DBT_CUSTOMEVENT}; - for (i = 0; i < sizeof(wparams)/sizeof(wparams[0]); i++) + for (i = 0; i < ARRAY_SIZE(wparams); i++) { SetLastError(0xdeadbeef); ret = PostMessageA(hwnd, WM_DEVICECHANGE, wparams[i], 0); @@ -5187,7 +5180,7 @@ static void test_messages(void) ShowWindow(hwnd, SW_MINIMIZE); flush_events(); - ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE); + ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", FALSE); flush_sequence(); if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE) @@ -5343,7 +5336,7 @@ static void test_messages(void) hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE, -10, -10, 10000, 10000, NULL, 0, 0, NULL ); ok (hwnd != 0, "Failed to create popup window\n"); - ok_sequence(WmShowPopupExtremeLocationSeq, "RedrawWindow:show_popup_extreme_location", TRUE); + ok_sequence(WmShowPopupExtremeLocationSeq, "RedrawWindow:show_popup_extreme_location", FALSE); DestroyWindow(hwnd); @@ -6390,7 +6383,7 @@ static void test_button_messages(void) hfont2 = CreateFontIndirectA(&logfont); ok(hfont2 != NULL, "Failed to create Tahoma font\n"); - for (i = 0; i < sizeof(button)/sizeof(button[0]); i++) + for (i = 0; i < ARRAY_SIZE(button); i++) { MSG msg; DWORD style, state; @@ -6619,6 +6612,121 @@ static void test_button_messages(void) DestroyWindow(parent); } +static void test_button_bm_get_set_image(void) +{ + HWND hwnd; + HDC hdc; + HBITMAP hbmp1x1; + HBITMAP hbmp2x2; + HBITMAP hmask2x2; + ICONINFO icon_info2x2; + HICON hicon2x2; + HBITMAP hbmp; + HICON hicon; + ICONINFO icon_info; + BITMAP bm; + DWORD default_style = BS_PUSHBUTTON | WS_TABSTOP | WS_POPUP | WS_VISIBLE; + LRESULT ret; + + hdc = GetDC(0); + hbmp1x1 = CreateCompatibleBitmap(hdc, 1, 1); + hbmp2x2 = CreateCompatibleBitmap(hdc, 2, 2); + ZeroMemory(&bm, sizeof(bm)); + ok(GetObjectW(hbmp1x1, sizeof(bm), &bm), "Expect GetObjectW() success\n"); + ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1, + bm.bmWidth, bm.bmHeight); + ZeroMemory(&bm, sizeof(bm)); + ok(GetObjectW(hbmp2x2, sizeof(bm), &bm), "Expect GetObjectW() success\n"); + ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2, + bm.bmWidth, bm.bmHeight); + + hmask2x2 = CreateCompatibleBitmap(hdc, 2, 2); + ZeroMemory(&icon_info2x2, sizeof(icon_info2x2)); + icon_info2x2.fIcon = TRUE; + icon_info2x2.hbmMask = hmask2x2; + icon_info2x2.hbmColor = hbmp2x2; + hicon2x2 = CreateIconIndirect(&icon_info2x2); + + ZeroMemory(&icon_info, sizeof(icon_info)); + ok(GetIconInfo(hicon2x2, &icon_info), "Expect GetIconInfo() success\n"); + ZeroMemory(&bm, sizeof(bm)); + ok(GetObjectW(icon_info.hbmColor, sizeof(bm), &bm), "Expect GetObjectW() success\n"); + ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2, + bm.bmWidth, bm.bmHeight); + DeleteObject(icon_info.hbmColor); + DeleteObject(icon_info.hbmMask); + + /* Set bitmap with BS_BITMAP */ + hwnd = CreateWindowA("Button", "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0, 0, 0); + ok(hwnd != NULL, "Expect hwnd not NULL\n"); + SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp1x1); + hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0); + ok(hbmp != 0, "Expect hbmp not 0\n"); + ZeroMemory(&bm, sizeof(bm)); + ok(GetObjectW(hbmp, sizeof(bm), &bm), "Expect GetObjectW() success\n"); + ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1, + bm.bmWidth, bm.bmHeight); + DestroyWindow(hwnd); + + /* Set bitmap without BS_BITMAP */ + hwnd = CreateWindowA("Button", "test", default_style, 0, 0, 100, 100, 0, 0, 0, 0); + ok(hwnd != NULL, "Expect hwnd not NULL\n"); + ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp1x1); + ok(ret == 0, "Expect ret to be 0\n"); + hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0); + ok(hbmp == NULL, "Expect hbmp to be NULL\n"); + DestroyWindow(hwnd); + + /* Set icon with BS_ICON */ + hwnd = CreateWindowA("Button", "test", default_style | BS_ICON, 0, 0, 100, 100, 0, 0, 0, 0); + ok(hwnd != NULL, "Expect hwnd not NULL\n"); + SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon2x2); + hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_ICON, 0); + ok(hicon != NULL, "Expect hicon not NULL\n"); + ZeroMemory(&icon_info, sizeof(icon_info)); + ok(GetIconInfo(hicon, &icon_info), "Expect GetIconInfo() success\n"); + ZeroMemory(&bm, sizeof(bm)); + ok(GetObjectW(icon_info.hbmColor, sizeof(bm), &bm), "Expect GetObjectW() success\n"); + ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2, + bm.bmWidth, bm.bmHeight); + DeleteObject(icon_info.hbmColor); + DeleteObject(icon_info.hbmMask); + DestroyWindow(hwnd); + + /* Set icon without BS_ICON */ + hwnd = CreateWindowA("Button", "test", default_style, 0, 0, 100, 100, 0, 0, 0, 0); + ok(hwnd != NULL, "Expect hwnd not NULL\n"); + ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon2x2); + ok(ret == 0, "Expect ret to be 0\n"); + hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_ICON, 0); + ok(hicon == NULL, "Expect hicon to be NULL\n"); + DestroyWindow(hwnd); + + /* Set icon with BS_BITMAP */ + hwnd = CreateWindowA("Button", "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0, 0, 0); + ok(hwnd != NULL, "Expect hwnd to be not NULL\n"); + ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon2x2); + ok(ret == 0, "Expect ret to be 0\n"); + hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_ICON, 0); + ok(hicon == NULL, "Expect hicon to be NULL\n"); + DestroyWindow(hwnd); + + /* Set bitmap with BS_ICON */ + hwnd = CreateWindowA("Button", "test", default_style | BS_ICON, 0, 0, 100, 100, 0, 0, 0, 0); + ok(hwnd != NULL, "Expect hwnd to be not NULL\n"); + ret = SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp1x1); + ok(ret == 0, "Expect ret to be 0\n"); + hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0); + ok(hbmp == NULL, "Expect hbmp to be NULL\n"); + DestroyWindow(hwnd); + + DestroyIcon(hicon2x2); + DeleteObject(hmask2x2); + DeleteObject(hbmp2x2); + DeleteObject(hbmp1x1); + ReleaseDC(0, hdc); +} + #define ID_RADIO1 501 #define ID_RADIO2 502 #define ID_RADIO3 503 @@ -7119,7 +7227,7 @@ static void test_static_messages(void) subclass_static(); - for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++) + for (i = 0; i < ARRAY_SIZE(static_ctrl); i++) { hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP, 0, 0, 50, 14, 0, 0, 0, NULL); @@ -7609,7 +7717,8 @@ void dump_region(HRGN hrgn) HeapFree( GetProcessHeap(), 0, data ); } -static void check_update_rgn( HWND hwnd, HRGN hrgn ) +#define check_update_rgn( hwnd, hrgn ) check_update_rgn_( __LINE__, hwnd, hrgn ) +static void check_update_rgn_( int line, HWND hwnd, HRGN hrgn ) { INT ret; RECT r1, r2; @@ -7620,13 +7729,13 @@ static void check_update_rgn( HWND hwnd, HRGN hrgn ) ok( ret != ERROR, "GetUpdateRgn failed\n" ); if (ret == NULLREGION) { - ok( !hrgn, "Update region shouldn't be empty\n" ); + ok_(__FILE__,line)( !hrgn, "Update region shouldn't be empty\n" ); } else { if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION) { - ok( 0, "Regions are different\n" ); + ok_(__FILE__,line)( 0, "Regions are different\n" ); if (winetest_debug > 0) { printf( "Update region: " ); @@ -7638,8 +7747,8 @@ static void check_update_rgn( HWND hwnd, HRGN hrgn ) } GetRgnBox( update, &r1 ); GetUpdateRect( hwnd, &r2, FALSE ); - ok( EqualRect( &r1, &r2 ), "Rectangles are different: %s / %s\n", wine_dbgstr_rect( &r1 ), - wine_dbgstr_rect( &r2 )); + ok_(__FILE__,line)( EqualRect( &r1, &r2 ), "Rectangles are different: %s / %s\n", + wine_dbgstr_rect( &r1 ), wine_dbgstr_rect( &r2 )); DeleteObject( tmp ); DeleteObject( update ); @@ -7835,9 +7944,76 @@ static void test_paint_messages(void) /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws * all windows and sends WM_ERASEBKGND and WM_NCPAINT. */ - trace("testing InvalidateRect(0, NULL, FALSE)\n"); SetRectEmpty( &rect ); - ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n"); + ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) failed\n"); + check_update_rgn( hwnd, hrgn ); + ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE ); + flush_events(); + ok_sequence( WmPaint, "Paint", FALSE ); + RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE ); + check_update_rgn( hwnd, 0 ); + + SetRectEmpty( &rect ); + ok(RedrawWindow(0, &rect, 0, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ), + "RedrawWindow failed\n"); + check_update_rgn( hwnd, 0 ); + + SetRectEmpty( &rect ); + ok(RedrawWindow(0, &rect, 0, RDW_ALLCHILDREN | RDW_VALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ), + "RedrawWindow failed\n"); + check_update_rgn( hwnd, 0 ); + + GetWindowRect( hwnd, &rect ); + ok(RedrawWindow(0, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ), + "RedrawWindow failed\n"); + check_update_rgn( hwnd, 0 ); + + flush_events(); + ok(RedrawWindow(0, &rect, 0, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ), + "RedrawWindow failed\n"); + check_update_rgn( hwnd, hrgn ); + ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE ); + flush_events(); + ok_sequence( WmPaint, "Paint", FALSE ); + RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE ); + check_update_rgn( hwnd, 0 ); + + ok(RedrawWindow(GetDesktopWindow(), &rect, 0, + RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ), + "RedrawWindow failed\n"); + ret = GetUpdateRgn( hwnd, hrgn2, FALSE ); + ok( ret == NULLREGION || broken(ret == SIMPLEREGION), /* <= win7 */ + "region should be null (%d)\n", ret ); + if (ret == SIMPLEREGION) ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE ); + RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE ); + flush_events(); + + ok(RedrawWindow(GetDesktopWindow(), NULL, 0, + RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ), + "RedrawWindow failed\n"); + ret = GetUpdateRgn( hwnd, hrgn2, FALSE ); + ok( ret == NULLREGION || broken(ret == SIMPLEREGION), /* <= win7 */ + "region should be null (%d)\n", ret ); + if (ret == SIMPLEREGION) ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE ); + RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE ); + flush_events(); + + SetRectRgn( hrgn2, rect.left, rect.top, rect.right, rect.bottom ); + ok(RedrawWindow(0, NULL, hrgn2, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW ), + "RedrawWindow failed\n"); + check_update_rgn( hwnd, hrgn ); + ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE ); + flush_events(); + ok_sequence( WmPaint, "Paint", FALSE ); + RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE ); + check_update_rgn( hwnd, 0 ); + + ok(RedrawWindow(0, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW ), + "RedrawWindow failed\n"); + check_update_rgn( hwnd, 0 ); + + ok(RedrawWindow(0, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW ), + "RedrawWindow failed\n"); check_update_rgn( hwnd, hrgn ); ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE ); flush_events(); @@ -7848,7 +8024,6 @@ static void test_paint_messages(void) /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws * all windows and sends WM_ERASEBKGND and WM_NCPAINT. */ - trace("testing ValidateRect(0, NULL)\n"); SetRectEmpty( &rect ); if (ValidateRect(0, &rect) && /* not supported on Win9x */ GetUpdateRect(hwnd, NULL, FALSE)) /* or >= Win 8 */ @@ -7861,7 +8036,6 @@ static void test_paint_messages(void) check_update_rgn( hwnd, 0 ); } - trace("testing InvalidateRgn(0, NULL, FALSE)\n"); SetLastError(0xdeadbeef); ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n"); ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef, @@ -7870,7 +8044,6 @@ static void test_paint_messages(void) flush_events(); ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE ); - trace("testing ValidateRgn(0, NULL)\n"); SetLastError(0xdeadbeef); ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n"); ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || @@ -7880,7 +8053,6 @@ static void test_paint_messages(void) flush_events(); ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE ); - trace("testing UpdateWindow(NULL)\n"); SetLastError(0xdeadbeef); ok(!UpdateWindow(NULL), "UpdateWindow(NULL) should fail\n"); ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || @@ -9565,6 +9737,48 @@ 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) @@ -9662,6 +9876,10 @@ static BOOL RegisterWindowClasses(void) cls.lpszClassName = "ShowWindowClass"; if(!RegisterClassA(&cls)) return FALSE; + cls.lpfnWndProc = recursive_activation_wndprocA; + cls.lpszClassName = "RecursiveActivationClass"; + if(!RegisterClassA(&cls)) return FALSE; + cls.lpfnWndProc = PopupMsgCheckProcA; cls.lpszClassName = "TestPopupClass"; if(!RegisterClassA(&cls)) return FALSE; @@ -9717,6 +9935,7 @@ 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") || @@ -10164,13 +10383,13 @@ todo_wine win_skip("SetCoalescableTimer not available.\n"); /* Check what happens when we're running out of timers */ - for (i=0; i 0) KillTimer(NULL, ids[--i]); @@ -10548,7 +10767,7 @@ static void test_winevents(void) ok_sequence(WmEmptySeq, "empty notify winevents", FALSE); } - for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++) + for (i = 0; i < ARRAY_SIZE(WmWinEventsSeq); i++) pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam); ok_sequence(WmWinEventsSeq, "notify winevents", FALSE); @@ -12038,6 +12257,31 @@ todo_wine { qstatus = GetQueueStatus(qs_all_input); ok(qstatus == 0, "wrong qstatus %08x\n", qstatus); } + + PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0); + ret = PeekMessageA(&msg, (HWND)-1, 0, 0, PM_NOREMOVE); + ok(ret == TRUE, "wrong ret %d\n", ret); + ok(msg.message == WM_USER, "wrong message %u\n", msg.message); + ret = GetMessageA(&msg, (HWND)-1, 0, 0); + ok(ret == TRUE, "wrong ret %d\n", ret); + ok(msg.message == WM_USER, "wrong message %u\n", msg.message); + + PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0); + ret = PeekMessageA(&msg, (HWND)1, 0, 0, PM_NOREMOVE); + ok(ret == TRUE, "wrong ret %d\n", ret); + ok(msg.message == WM_USER, "wrong message %u\n", msg.message); + ret = GetMessageA(&msg, (HWND)1, 0, 0); + ok(ret == TRUE, "wrong ret %d\n", ret); + ok(msg.message == WM_USER, "wrong message %u\n", msg.message); + + PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0); + ret = PeekMessageA(&msg, (HWND)0xffff, 0, 0, PM_NOREMOVE); + ok(ret == TRUE, "wrong ret %d\n", ret); + ok(msg.message == WM_USER, "wrong message %u\n", msg.message); + ret = GetMessageA(&msg, (HWND)0xffff, 0, 0); + ok(ret == TRUE, "wrong ret %d\n", ret); + ok(msg.message == WM_USER, "wrong message %u\n", msg.message); + done: trace("signalling to exit\n"); SetEvent(info.hevent[EV_STOP]); @@ -13243,7 +13487,7 @@ static void test_ShowWindow(void) ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n", wine_dbgstr_rect(&win_rc), wine_dbgstr_rect(&wp.rcNormalPosition)); - for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++) + for (i = 0; i < ARRAY_SIZE(sw); i++) { static const char * const sw_cmd_name[13] = { @@ -13492,6 +13736,8 @@ static const struct message WmCreateDialogParamSeq_3[] = { { 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_ACTIVATEAPP, sent|parent|wparam, 1 }, { WM_NCACTIVATE, sent|parent }, { WM_ACTIVATE, sent|parent|wparam, 1 }, @@ -15224,6 +15470,46 @@ static const struct message NCXBUTTONUPSeq2[] = { 0 } }; +/* DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0) to minimized visible window */ +static const struct message WmRestoreMinimizedOverlappedSeq[] = +{ + { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_RESTORE, 0 }, + { HCBT_MINMAX, hook }, + { WM_QUERYOPEN, sent }, + { WM_GETTEXT, sent|optional }, + { WM_NCACTIVATE, sent|optional }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { WM_WINDOWPOSCHANGED, sent|optional }, + { WM_WINDOWPOSCHANGING, sent|optional }, + { WM_GETMINMAXINFO, sent|defwinproc }, + { WM_NCCALCSIZE, sent|optional }, + { WM_NCPAINT, sent|optional }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ERASEBKGND, sent|optional }, + { WM_WINDOWPOSCHANGED, sent|optional }, + { HCBT_ACTIVATE, hook }, + { 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 }, + { WM_SETFOCUS, sent|defwinproc }, + { WM_NCPAINT, sent }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ERASEBKGND, sent }, + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_FRAMECHANGED|SWP_STATECHANGED }, + { WM_MOVE, sent|defwinproc }, + { WM_SIZE, sent|defwinproc }, + { WM_NCCALCSIZE, sent|optional }, + { WM_NCPAINT, sent|optional }, + { WM_ERASEBKGND, sent|optional }, + { WM_ACTIVATE, sent|wparam, TRUE }, + { WM_SYNCPAINT, sent|optional }, + { WM_PAINT, sent }, + { 0 } +}; + struct rbuttonup_thread_data { HWND hwnd; @@ -15262,22 +15548,31 @@ static void test_defwinproc(void) flush_events(); buffA[0] = 0; - GetWindowTextA(hwnd, buffA, sizeof(buffA)/sizeof(*buffA)); + GetWindowTextA(hwnd, buffA, ARRAY_SIZE(buffA)); ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA); /* 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); - GetWindowTextA(hwnd, buffA, sizeof(buffA)/sizeof(*buffA)); + 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); - GetWindowTextA(hwnd, buffA, sizeof(buffA)/sizeof(*buffA)); + GetWindowTextA(hwnd, buffA, ARRAY_SIZE(buffA)); ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA); + ShowWindow(hwnd, SW_MINIMIZE); + flush_events(); + flush_sequence(); + + DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0); + flush_events(); + ok_sequence(WmRestoreMinimizedOverlappedSeq, "DefWindowProcA(SC_RESTORE):overlapped", TRUE); + flush_sequence(); + GetCursorPos(&pos); GetWindowRect(hwnd, &rect); x = (rect.left+rect.right) / 2; @@ -15333,6 +15628,67 @@ static void test_defwinproc(void) DestroyWindow( hwnd); } +static void test_desktop_winproc(void) +{ + HINSTANCE instance = GetModuleHandleA(NULL); + RECT rect, default_rect; + WNDPROC desktop_proc; + char buffer[256]; + WNDCLASSA cls; + LRESULT res; + HWND hwnd; + BOOL ret; + + ret = GetClassInfoA(instance, (const CHAR *)MAKEINTATOM(32769), &cls); + ok(ret, "Failed to get desktop class.\n"); + desktop_proc = cls.lpfnWndProc; + + memset(&cls, 0, sizeof(cls)); + cls.lpfnWndProc = desktop_proc; + cls.hInstance = instance; + 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"); + + hwnd = CreateWindowExA(0, cls.lpszClassName, "test_desktop_wndproc", + WS_VISIBLE | WS_CAPTION | WS_OVERLAPPEDWINDOW, 0, 0, 500, 100, 0, 0, 0, NULL); + if (!hwnd) /* win2003 */ + { + skip("Failed to create window with desktop window procedure.\n"); + goto out_unregister; + } + + memset(&cls, 0, sizeof(cls)); + ret = GetClassInfoA(instance, "TestDesktopClass", &cls); + ok(ret, "Failed to get class info.\n"); + ok(cls.lpfnWndProc == desktop_proc, "Got %p, expected %p.\n", cls.lpfnWndProc, desktop_proc); + + GetWindowTextA(hwnd, buffer, ARRAY_SIZE(buffer)); + 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); + 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); + + SetRect(&rect, 0, 0, 100, 100); + res = CallWindowProcA(desktop_proc, hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rect); + ok(!res, "Got unexpected result %ld.\n", res); + todo_wine ok(EqualRect(&rect, &default_rect), "rect Got %s, expected %s.\n", + wine_dbgstr_rect(&rect), wine_dbgstr_rect(&default_rect)); + + DestroyWindow(hwnd); + +out_unregister: + UnregisterClassA("TestDesktopClass", instance); +} + #define clear_clipboard(hwnd) clear_clipboard_(__LINE__, (hwnd)) static void clear_clipboard_(int line, HWND hWnd) { @@ -15535,7 +15891,7 @@ static void test_PostMessage(void) PostMessageA(hwnd, WM_USER+1, 0x1234, 0x5678); PostMessageA(0, WM_USER+2, 0x5678, 0x1234); - for (i = 0; i < sizeof(data)/sizeof(data[0]); i++) + for (i = 0; i < ARRAY_SIZE(data); i++) { memset(&msg, 0xab, sizeof(msg)); ret = PeekMessageA(&msg, data[i].hwnd, 0, 0, PM_NOREMOVE); @@ -15593,7 +15949,7 @@ static void test_broadcast(void) oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)broadcast_test_proc); SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc); - for (i = 0; i < sizeof(messages)/sizeof(messages[0]); i++) + for (i = 0; i < ARRAY_SIZE(messages); i++) { BOOL ret; MSG msg; @@ -15923,14 +16279,14 @@ static void test_WaitForInputIdle( char *argv0 ) thread = CreateThread( NULL, 0, wait_idle_thread, NULL, 0, &id ); - for (i = 0; i < sizeof(wait_idle_expect)/sizeof(wait_idle_expect[0]); i++) + for (i = 0; i < ARRAY_SIZE(wait_idle_expect); i++) { ResetEvent( start_event ); ResetEvent( end_event ); -#ifndef __REACTOS__ - sprintf( path, "%s msg %u", argv0, i ); -#else +#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() ); @@ -16039,7 +16395,7 @@ static void test_SetParent(void) SetParent(child, parent2); flush_events(); - ok_sequence(WmSetParentSeq_1, "SetParent() visible WS_CHILD", TRUE); + ok_sequence(WmSetParentSeq_1, "SetParent() visible WS_CHILD", FALSE); ok(GetWindowLongA(child, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n"); ok(!IsWindowVisible(child), "IsWindowVisible() should return FALSE\n"); @@ -16314,16 +16670,16 @@ static void test_hotkey(void) SetLastError(0xdeadbeef); ret = UnregisterHotKey(NULL, 0); - ok(ret == FALSE, "expected FALSE, got %i\n", ret); - ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef), - "unexpected error %d\n", GetLastError()); - if (ret == TRUE) { skip("hotkeys not supported\n"); return; } + ok(ret == FALSE, "expected FALSE, got %i\n", ret); + ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef), + "unexpected error %d\n", GetLastError()); + test_window = CreateWindowExA(0, "HotkeyWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 200, 200, 0, 0, 0, NULL); @@ -17344,6 +17700,112 @@ static void test_DoubleSetCapture(void) DestroyWindow(hwnd); } +static const struct message WmRestoreMinimizedSeq[] = +{ + { HCBT_ACTIVATE, hook }, + { 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 }, + { WM_NCACTIVATE, sent|wparam, 0x200001 }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ACTIVATE, sent|wparam, 0x200001 }, /* Note that activate messages are after WM_WINDOWPOSCHANGED and before WM_SYSCOMMAND */ + { HCBT_KEYSKIPPED, hook|optional }, + { WM_SYSKEYUP, sent|optional }, + { WM_SYSCOMMAND, sent|wparam, SC_RESTORE }, + { HCBT_SYSCOMMAND, hook|wparam, SC_RESTORE }, + { HCBT_SYSCOMMAND, hook|wparam|optional, SC_RESTORE }, + { HCBT_MINMAX, hook }, + { HCBT_MINMAX, hook|optional }, + { WM_QUERYOPEN, sent|defwinproc }, + { WM_QUERYOPEN, sent|optional }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { WM_GETMINMAXINFO, sent|defwinproc }, + { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, + { 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 }, + { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, + { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 }, + { WM_ERASEBKGND, sent|defwinproc|optional }, + { HCBT_SETFOCUS, hook }, + { WM_SETFOCUS, sent|defwinproc }, + { WM_ACTIVATE, sent|wparam|defwinproc, 1 }, + { WM_PAINT, sent| optional }, + { WM_SETFOCUS, sent|defwinproc|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 } +}; + +static void test_restore_messages(void) +{ + INPUT ip = {0}; + HWND hwnd; + INT i; + + 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"); + SetForegroundWindow(hwnd); + ShowWindow(hwnd, SW_MINIMIZE); + flush_events(); + flush_sequence(); + + for (i = 0; i < 5; i++) + { + /* Send Alt+Tab to restore test window from minimized state */ + ip.type = INPUT_KEYBOARD; + ip.ki.wVk = VK_MENU; + SendInput(1, &ip, sizeof(INPUT)); + ip.ki.wVk = VK_TAB; + SendInput(1, &ip, sizeof(INPUT)); + ip.ki.wVk = VK_MENU; + ip.ki.dwFlags = KEYEVENTF_KEYUP; + SendInput(1, &ip, sizeof(INPUT)); + ip.ki.wVk = VK_TAB; + ip.ki.dwFlags = KEYEVENTF_KEYUP; + SendInput(1, &ip, sizeof(INPUT)); + flush_events(); + if (!IsIconic(hwnd)) + break; + } + + if (IsIconic(hwnd)) + { + skip("Alt+Tab failed to bring up test window.\n"); + goto done; + } + ok_sequence(WmRestoreMinimizedSeq, "Restore minimized window", TRUE); + +done: + DestroyWindow(hwnd); +} + +static void test_invalid_window(void) +{ + MSG msg; + BOOL ret; + + 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()); + + 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()); +} + static void init_funcs(void) { HMODULE hKernel32 = GetModuleHandleA("kernel32.dll"); @@ -17440,9 +17902,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_autoradio_BM_CLICK(); test_autoradio_kbd_move(); test_static_messages(); @@ -17468,6 +17932,8 @@ START_TEST(msg) test_quit_message(); test_notify_message(); test_SetActiveWindow(); + test_restore_messages(); + test_invalid_window(); if (!pTrackMouseEvent) win_skip("TrackMouseEvent is not available\n"); @@ -17484,6 +17950,7 @@ START_TEST(msg) test_menu_messages(); test_paintingloop(); test_defwinproc(); + test_desktop_winproc(); test_clipboard_viewers(); test_keyflags(); test_hotkey(); @@ -17598,6 +18065,7 @@ START_TEST(msg_messages) test_dbcs_wm_char(); test_unicode_wm_char(); test_defwinproc(); + test_desktop_winproc(); cleanup_tests(); } @@ -17619,6 +18087,9 @@ START_TEST(msg_focus) 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 @@ -17635,6 +18106,7 @@ START_TEST(msg_winpos) test_ShowWindow(); test_setwindowpos(); test_showwindow(); + test_recursive_activation(); test_SetWindowRgn(); invisible_parent_tests(); cleanup_tests(); @@ -17745,6 +18217,7 @@ 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(); diff --git a/modules/rostests/winetests/user32/rawinput.c b/modules/rostests/winetests/user32/rawinput.c new file mode 100644 index 00000000000..f4c8eb6738b --- /dev/null +++ b/modules/rostests/winetests/user32/rawinput.c @@ -0,0 +1,101 @@ +/* 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 2388adb64f3..5d4c4e2f968 100644 --- a/modules/rostests/winetests/user32/resource.c +++ b/modules/rostests/winetests/user32/resource.c @@ -50,7 +50,7 @@ static void test_LoadStringW(void) win_skip( "LoadStringW does not return a pointer to the resource\n" ); return; } - length2 = LoadStringW(hInst, 2, returnedstringw, sizeof(returnedstringw) /sizeof(WCHAR)); /* get resource string */ + 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(length1 == length2, "LoadStringW returned different values dependent on buflen. ret1 %d, ret2 %d\n", length1, length2); @@ -93,7 +93,7 @@ static void test_LoadStringA (void) int ret, ret2; assert (sizeof str < sizeof buf); - for (i = 0; i < sizeof tests / sizeof tests[0]; i++) { + for (i = 0; i < ARRAY_SIZE(tests); i++) { const unsigned int bufsiz = tests[i].bufsiz; const unsigned int expected = tests[i].expected; const int len = LoadStringA (hInst, 0, buf, bufsiz); diff --git a/modules/rostests/winetests/user32/resource.rc b/modules/rostests/winetests/user32/resource.rc index 3823ed39e42..4301af6d687 100644 --- a/modules/rostests/winetests/user32/resource.rc +++ b/modules/rostests/winetests/user32/resource.rc @@ -237,6 +237,15 @@ FONT 8, "MS Sans Serif" CONTROL "oddlengthtext", -1, "TESTCONTROL", WS_CHILD|WS_VISIBLE|WS_BORDER|WS_TABSTOP, 10,60,100,50 { 1,2,3,4,5 } } +GETDLGITEM_TEST_DIALOG DIALOGEX 6, 15, 207, 111 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Test Dialog" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Text1",-1,10,10,100,50 + LTEXT "Text2",-2,10,10,100,50 +} + /* @makedep: test_mono.bmp */ 100 BITMAP test_mono.bmp diff --git a/modules/rostests/winetests/user32/scroll.c b/modules/rostests/winetests/user32/scroll.c index 0bda5dd0f44..fbc94a6d680 100644 --- a/modules/rostests/winetests/user32/scroll.c +++ b/modules/rostests/winetests/user32/scroll.c @@ -114,6 +114,14 @@ static void test_EnableScrollBar(void) ok( ret, "The scrollbar should be enabled.\n" ); ok( IsWindowEnabled( hScroll ), "The scrollbar window should be enabled.\n" ); + SetLastError( 0xdeadbeef ); + ret = EnableScrollBar( mainwnd, SB_CTL, ESB_ENABLE_BOTH ); + ok( !ret, "EnableScrollBar should fail.\n" ); + todo_wine + ok( GetLastError() == ERROR_INVALID_PARAMETER + || broken(GetLastError() == 0xdeadbeef), /* winxp */ + "GetLastError() = %u\n", GetLastError() ); + /* disable window, try to re-enable */ ret = EnableWindow( hScroll, FALSE ); ok( !ret, "got %d\n", ret ); @@ -170,6 +178,16 @@ static void test_SetScrollPos(void) ret = GetScrollPos( hScroll, SB_CTL); ok( ret == 30, "The position should not be equal to zero\n"); + 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() ); + + SetLastError( 0xdeadbeef ); + ret = GetScrollPos( mainwnd, SB_CTL ); + ok( !ret, "The position should be equal to zero\n"); + ok( GetLastError() == 0xdeadbeef, "GetLastError() = %u\n", GetLastError() ); + DestroyWindow(hScroll); DestroyWindow(mainwnd); } @@ -192,6 +210,9 @@ static void test_ShowScrollBar(void) ret = ShowScrollBar( NULL, SB_CTL, TRUE ); ok( !ret, "The ShowScrollBar() should failed.\n" ); + ret = ShowScrollBar( mainwnd, SB_CTL, TRUE ); + ok( ret, "The ShowScrollBar() should not fail.\n" ); + DestroyWindow(hScroll); DestroyWindow(mainwnd); } @@ -514,7 +535,7 @@ static void scrollbar_test_init(void) wc.lpfnWndProc = scroll_init_proc; RegisterClassExA(&wc); - for(i = 0; i < sizeof style / sizeof style[0]; i++) + for(i = 0; i < ARRAY_SIZE(style); i++) { /* need not to destroy these windows due creation abort */ CreateWindowExA(0, cls_name, NULL, style[i], @@ -581,6 +602,105 @@ static void test_SetScrollInfo(void) DestroyWindow(mainwnd); } +static WNDPROC scrollbar_wndproc; + +static SCROLLINFO set_scrollinfo; + +static LRESULT CALLBACK subclass_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if (msg == WM_CREATE && ((CREATESTRUCTA*)lparam)->lpCreateParams) + return DefWindowProcA(hwnd, msg, wparam, lparam); + + if (msg == SBM_SETSCROLLINFO) + set_scrollinfo = *(SCROLLINFO*)lparam; + + return CallWindowProcA(scrollbar_wndproc, hwnd, msg, wparam, lparam); +} + +static void test_subclass(void) +{ + SCROLLBARINFO scroll_info; + WNDCLASSEXA class_info; + WNDCLASSA wc; + LRESULT res; + HWND hwnd; + BOOL r; + + r = GetClassInfoExA(GetModuleHandleA(NULL), "SCROLLBAR", &class_info); + ok(r, "GetClassInfoEx failed: %u\n", GetLastError()); + scrollbar_wndproc = class_info.lpfnWndProc; + + memset(&wc, 0, sizeof(wc)); + wc.cbWndExtra = class_info.cbWndExtra + 3; /* more space than needed works */ + wc.hInstance = GetModuleHandleA(NULL); + wc.lpszClassName = "MyTestSubclass"; + wc.lpfnWndProc = subclass_proc; + r = RegisterClassA(&wc); + ok(r, "RegisterClass failed: %u\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()); + + r = SetScrollRange(hwnd, SB_CTL, 0, 100, TRUE); + ok(r, "SetScrollRange failed: %u\n", GetLastError()); + + res = SetScrollPos(hwnd, SB_CTL, 2, FALSE); + ok(!res, "SetScrollPos returned %lu\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(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); + + 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()); + + 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); + + DestroyWindow(hwnd); + + /* not enough space in extra data */ + wc.cbWndExtra = class_info.cbWndExtra - 1; + wc.lpszClassName = "MyTestSubclass2"; + r = RegisterClassA(&wc); + ok(r, "RegisterClass failed: %u\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()); + + 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); + + memset(&set_scrollinfo, 0xcc, sizeof(set_scrollinfo)); + res = SetScrollPos(hwnd, SB_CTL, 1, FALSE); + ok(res == 0, "SetScrollPos returned %lu\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); +} + START_TEST ( scroll ) { WNDCLASSA wc; @@ -605,6 +725,7 @@ START_TEST ( scroll ) test_GetScrollBarInfo(); scrollbar_test_track(); test_SetScrollInfo(); + test_subclass(); /* Some test results vary depending of theming being active or not */ hUxtheme = LoadLibraryA("uxtheme.dll"); diff --git a/modules/rostests/winetests/user32/sysparams.c b/modules/rostests/winetests/user32/sysparams.c index 9ed85a24d08..bd107891279 100644 --- a/modules/rostests/winetests/user32/sysparams.c +++ b/modules/rostests/winetests/user32/sysparams.c @@ -43,12 +43,26 @@ 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); +static BOOL (WINAPI *pGetProcessDpiAwarenessInternal)(HANDLE,DPI_AWARENESS*); +static BOOL (WINAPI *pSetProcessDpiAwarenessInternal)(DPI_AWARENESS); +static UINT (WINAPI *pGetDpiForSystem)(void); +static UINT (WINAPI *pGetDpiForWindow)(HWND); +static BOOL (WINAPI *pGetDpiForMonitorInternal)(HMONITOR,UINT,UINT*,UINT*); +static DPI_AWARENESS_CONTEXT (WINAPI *pGetThreadDpiAwarenessContext)(void); +static DPI_AWARENESS_CONTEXT (WINAPI *pSetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); +static DPI_AWARENESS_CONTEXT (WINAPI *pGetWindowDpiAwarenessContext)(HWND); +static DPI_AWARENESS (WINAPI *pGetAwarenessFromDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); +static BOOL (WINAPI *pIsValidDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); +static INT (WINAPI *pGetSystemMetricsForDpi)(INT,UINT); +static BOOL (WINAPI *pSystemParametersInfoForDpi)(UINT,UINT,void*,UINT,UINT); +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 strict; static int dpi, real_dpi; -static BOOL iswin9x; -static HDC hdc; #define eq(received, expected, label, type) \ ok((received) == (expected), "%s: got " type " instead of " type "\n", (label),(received),(expected)) @@ -193,6 +207,13 @@ static DWORD get_real_dpi(void) { DWORD dpi; + if (pSetThreadDpiAwarenessContext) + { + DPI_AWARENESS_CONTEXT context = pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ); + dpi = pGetDpiForSystem(); + pSetThreadDpiAwarenessContext( context ); + return dpi; + } if (get_reg_dword(HKEY_CURRENT_USER, "Control Panel\\Desktop", "LogPixels", &dpi)) return dpi; if (get_reg_dword(HKEY_CURRENT_CONFIG, "Software\\Fonts", "LogPixels", &dpi)) @@ -622,30 +643,17 @@ static BOOL run_spi_setmouse_test( int curr_val[], POINT *req_change, POINT *pro BOOL rc; INT mi[3]; static int aw_turn = 0; - static BOOL w_implemented = TRUE; char buf[20]; int i; aw_turn++; rc = FALSE; - if ((aw_turn % 2!=0) && (w_implemented)) - { - /* call unicode on odd (non even) calls */ - SetLastError(0xdeadbeef); + SetLastError(0xdeadbeef); + if (aw_turn % 2) /* call unicode on odd (non even) calls */ rc=SystemParametersInfoW( SPI_SETMOUSE, 0, curr_val, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); - if (rc == FALSE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) - { - w_implemented = FALSE; - trace("SystemParametersInfoW not supported on this platform\n"); - } - } - - if ((aw_turn % 2==0) || (!w_implemented)) - { - /* call ascii version on even calls or if unicode is not available */ + else 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()); @@ -664,15 +672,12 @@ static BOOL run_spi_setmouse_test( int curr_val[], POINT *req_change, POINT *pro "incorrect value for %d: %d != %d\n", i, mi[i], curr_val[i]); } - if (w_implemented) - { - 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]); - } + 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]); } if (0) @@ -710,7 +715,7 @@ static void test_SPI_SETMOUSE( void ) /* 4 */ POINT proj_change7[] = { {6, 6}, {14, 6}, {32, 6}, {40, 40}, {44, 40}, {400, 400} }; POINT proj_change8[] = { {6, 6}, {28, 6}, {32, 6}, {40, 40}, {44, 40}, {400, 400} }; - int nchange = sizeof( req_change ) / sizeof( POINT ); + int nchange = ARRAY_SIZE(req_change); trace("testing SPI_{GET,SET}MOUSE\n"); SetLastError(0xdeadbeef); @@ -848,15 +853,10 @@ static void test_SPI_SETBORDER( void ) /* 6 */ if ( old_border == 7 || old_border == 20 ) old_border = 1; - /* The SPI_SETBORDER seems to be buggy on Win9x/ME (looks like you need to - * do it twice to make the intended change). So skip parts of the tests on - * those platforms */ - if( !iswin9x) { - /* win2k3 fails if you set the same border twice, or if size is 0 */ - if (!test_setborder(2, 1, dpi)) return; - test_setborder(1, 1, dpi); - test_setborder(3, 1, dpi); - } + /* win2k3 fails if you set the same border twice, or if size is 0 */ + if (!test_setborder(2, 1, dpi)) return; + test_setborder(1, 1, dpi); + test_setborder(3, 1, dpi); if (!test_setborder(1, 0, dpi)) return; test_setborder(0, 0, dpi); test_setborder(3, 0, dpi); @@ -880,7 +880,7 @@ static void test_SPI_SETKEYBOARDSPEED( void ) /* 10 */ if (!test_error_msg(rc,"SPI_{GET,SET}KEYBOARDSPEED")) return; - for (i=0;ilfHeight == MulDiv( lf2->lfHeight, dpi, custom_dpi ), + "wrong lfHeight %d vs %d\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 ); + ok_(__FILE__,line)( !memcmp( &lf1->lfEscapement, &lf2->lfEscapement, + offsetof( LOGFONTW, lfFaceName ) - offsetof( LOGFONTW, lfEscapement )), + "font differs\n" ); + ok_(__FILE__,line)( !lstrcmpW( lf1->lfFaceName, lf2->lfFaceName ), "wrong face name %s vs %s\n", + wine_dbgstr_w( lf1->lfFaceName ), wine_dbgstr_w( lf2->lfFaceName )); +} + +static void test_metrics_for_dpi( int custom_dpi ) +{ + int i, val; + NONCLIENTMETRICSW ncm1, ncm2; + ICONMETRICSW im1, im2; + LOGFONTW lf1, lf2; + BOOL ret; + + if (!pSystemParametersInfoForDpi) + { + win_skip( "custom dpi metrics not supported\n" ); + return; + } + + ncm1.cbSize = sizeof(ncm1); + ret = SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, sizeof(ncm1), &ncm1, FALSE ); + ok( ret, "SystemParametersInfoW failed err %u\n", GetLastError() ); + ncm2.cbSize = sizeof(ncm2); + ret = pSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, sizeof(ncm2), &ncm2, FALSE, custom_dpi ); + ok( ret, "SystemParametersInfoForDpi failed err %u\n", GetLastError() ); + + for (i = 0; i < 92; i++) + { + int ret1 = GetSystemMetrics( i ); + int ret2 = pGetSystemMetricsForDpi( i, custom_dpi ); + switch (i) + { + case SM_CXVSCROLL: + case SM_CYHSCROLL: + case SM_CYVTHUMB: + case SM_CXHTHUMB: + case SM_CXICON: + case SM_CYICON: + case SM_CYVSCROLL: + case SM_CXHSCROLL: + case SM_CYSIZE: + case SM_CXICONSPACING: + case SM_CYICONSPACING: + case SM_CXSMSIZE: + case SM_CYSMSIZE: + case SM_CYMENUSIZE: + ok( ret1 == MulDiv( ret2, dpi, custom_dpi ), "%u: wrong value %u vs %u\n", i, ret1, ret2 ); + break; + case SM_CXSIZE: + ok( ret1 == ncm1.iCaptionWidth && ret2 == ncm2.iCaptionWidth, + "%u: wrong value %u vs %u caption %u vs %u\n", + i, ret1, ret2, ncm1.iCaptionWidth, ncm2.iCaptionWidth ); + break; + case SM_CXCURSOR: + case SM_CYCURSOR: + val = MulDiv( 32, custom_dpi, USER_DEFAULT_SCREEN_DPI ); + if (val < 48) val = 32; + else if (val < 64) val = 48; + else val = 64; + ok( val == ret2, "%u: wrong value %u vs %u\n", i, ret1, ret2 ); + break; + case SM_CYCAPTION: + case SM_CYSMCAPTION: + case SM_CYMENU: + ok( ret1 - 1 == MulDiv( ret2 - 1, dpi, custom_dpi ), "%u: wrong value %u vs %u\n", i, ret1, ret2 ); + break; + case SM_CXMENUSIZE: + ok( ret1 / 8 == MulDiv( ret2, dpi, custom_dpi ) / 8, "%u: wrong value %u vs %u\n", i, ret1, ret2 ); + break; + case SM_CXFRAME: + case SM_CYFRAME: + ok( ret1 == ncm1.iBorderWidth + 3 && ret2 == ncm2.iBorderWidth + 3, + "%u: wrong value %u vs %u borders %u+%u vs %u+%u\n", i, ret1, ret2, + ncm1.iBorderWidth, ncm1.iPaddedBorderWidth, ncm2.iBorderWidth, ncm2.iPaddedBorderWidth ); + break; + case SM_CXSMICON: + case SM_CYSMICON: + ok( ret1 == (MulDiv( 16, dpi, USER_DEFAULT_SCREEN_DPI ) & ~1) && + ret2 == (MulDiv( 16, custom_dpi, USER_DEFAULT_SCREEN_DPI ) & ~1), + "%u: wrong value %u vs %u\n", i, ret1, ret2 ); + break; + case SM_CXMENUCHECK: + case SM_CYMENUCHECK: + ok( ret1 == ((get_tmheightW( &ncm1.lfMenuFont, 1 ) - 1) | 1) && + ret2 == ((get_tmheightW( &ncm2.lfMenuFont, 1 ) - 1) | 1), + "%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; + default: + ok( ret1 == ret2, "%u: wrong value %u vs %u\n", i, ret1, ret2 ); + break; + } + } + im1.cbSize = sizeof(im1); + ret = SystemParametersInfoW( SPI_GETICONMETRICS, sizeof(im1), &im1, FALSE ); + ok( ret, "SystemParametersInfoW failed err %u\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( 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", + im1.iVertSpacing, im2.iVertSpacing ); + ok( im1.iTitleWrap == im2.iTitleWrap, "wrong iTitleWrap %u vs %u\n", + im1.iTitleWrap, im2.iTitleWrap ); + 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() ); + ret = pSystemParametersInfoForDpi( SPI_GETICONTITLELOGFONT, sizeof(lf2), &lf2, FALSE, custom_dpi ); + ok( ret, "SystemParametersInfoForDpi failed err %u\n", GetLastError() ); + compare_font( &lf1, &lf2, dpi, custom_dpi, __LINE__ ); + + /* on high-dpi iPaddedBorderWidth is used in addition to iBorderWidth */ + ok( ncm1.iBorderWidth + ncm1.iPaddedBorderWidth == MulDiv( ncm2.iBorderWidth + ncm2.iPaddedBorderWidth, dpi, custom_dpi ), + "wrong iBorderWidth %u+%u vs %u+%u\n", + ncm1.iBorderWidth, ncm1.iPaddedBorderWidth, ncm2.iBorderWidth, ncm2.iPaddedBorderWidth ); + ok( ncm1.iScrollWidth == MulDiv( ncm2.iScrollWidth, dpi, custom_dpi ), + "wrong iScrollWidth %u vs %u\n", ncm1.iScrollWidth, ncm2.iScrollWidth ); + ok( ncm1.iScrollHeight == MulDiv( ncm2.iScrollHeight, dpi, custom_dpi ), + "wrong iScrollHeight %u vs %u\n", ncm1.iScrollHeight, ncm2.iScrollHeight ); + ok( ((ncm1.iCaptionWidth + 1) & ~1) == ((MulDiv( ncm2.iCaptionWidth, dpi, custom_dpi ) + 1) & ~1), + "wrong iCaptionWidth %u vs %u\n", ncm1.iCaptionWidth, ncm2.iCaptionWidth ); + ok( ncm1.iCaptionHeight == MulDiv( ncm2.iCaptionHeight, dpi, custom_dpi ), + "wrong iCaptionHeight %u vs %u\n", ncm1.iCaptionHeight, ncm2.iCaptionHeight ); + compare_font( &ncm1.lfCaptionFont, &ncm2.lfCaptionFont, dpi, custom_dpi, __LINE__ ); + ok( ncm1.iSmCaptionHeight == MulDiv( ncm2.iSmCaptionHeight, dpi, custom_dpi ), + "wrong iSmCaptionHeight %u vs %u\n", ncm1.iSmCaptionHeight, ncm2.iSmCaptionHeight ); + compare_font( &ncm1.lfSmCaptionFont, &ncm2.lfSmCaptionFont, dpi, custom_dpi, __LINE__ ); + ok( ncm1.iMenuHeight == MulDiv( ncm2.iMenuHeight, dpi, custom_dpi ), + "wrong iMenuHeight %u vs %u\n", ncm1.iMenuHeight, ncm2.iMenuHeight ); + /* iSmCaptionWidth and iMenuWidth apparently need to be multiples of 8 */ + ok( ncm1.iSmCaptionWidth / 8 == MulDiv( ncm2.iSmCaptionWidth, dpi, custom_dpi ) / 8, + "wrong iSmCaptionWidth %u vs %u\n", ncm1.iSmCaptionWidth, ncm2.iSmCaptionWidth ); + ok( ncm1.iMenuWidth / 8 == MulDiv( ncm2.iMenuWidth, dpi, custom_dpi ) / 8, + "wrong iMenuWidth %u vs %u\n", ncm1.iMenuWidth, ncm2.iMenuWidth ); + compare_font( &ncm1.lfMenuFont, &ncm2.lfMenuFont, dpi, custom_dpi, __LINE__ ); + compare_font( &ncm1.lfStatusFont, &ncm2.lfStatusFont, dpi, custom_dpi, __LINE__ ); + compare_font( &ncm1.lfMessageFont, &ncm2.lfMessageFont, dpi, custom_dpi, __LINE__ ); + + for (i = 1; i < 120; i++) + { + if (i == SPI_GETICONTITLELOGFONT || i == SPI_GETNONCLIENTMETRICS || i == SPI_GETICONMETRICS) + continue; + 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() ); + } +} + static void test_EnumDisplaySettings(void) { DEVMODEA devmode; @@ -2933,13 +3088,11 @@ static void test_EnumDisplaySettings(void) DWORD num; memset(&devmode, 0, sizeof(devmode)); - /* Win95 doesn't handle ENUM_CURRENT_SETTINGS correctly */ EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &devmode); hdc = GetDC(0); val = GetDeviceCaps(hdc, BITSPIXEL); - ok(devmode.dmBitsPerPel == val || - broken(devmode.dmDeviceName[0] == 0), /* Win95 */ + ok(devmode.dmBitsPerPel == val, "GetDeviceCaps(BITSPIXEL) returned %d, EnumDisplaySettings returned %d\n", val, devmode.dmBitsPerPel); @@ -2988,6 +3141,378 @@ static void test_GetSysColorBrush(void) win_skip("COLOR_MENUBAR unsupported\n"); } +static void test_dpi_stock_objects( HDC hdc ) +{ + DPI_AWARENESS_CONTEXT context; + HGDIOBJ obj[STOCK_LAST + 1], obj2[STOCK_LAST + 1]; + LOGFONTW lf, lf2; + UINT i, dpi; + + context = pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_UNAWARE ); + dpi = GetDeviceCaps( hdc, LOGPIXELSX ); + ok( dpi == USER_DEFAULT_SCREEN_DPI, "wrong dpi %u\n", dpi ); + ok( !pIsProcessDPIAware(), "not aware\n" ); + for (i = 0; i <= STOCK_LAST; i++) obj[i] = GetStockObject( i ); + + pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ); + dpi = GetDeviceCaps( hdc, LOGPIXELSX ); + ok( dpi == real_dpi, "wrong dpi %u\n", dpi ); + ok( pIsProcessDPIAware(), "not aware\n" ); + for (i = 0; i <= STOCK_LAST; i++) obj2[i] = GetStockObject( i ); + + for (i = 0; i <= STOCK_LAST; i++) + { + switch (i) + { + case OEM_FIXED_FONT: + case SYSTEM_FIXED_FONT: + ok( obj[i] != obj2[i], "%u: same object\n", i ); + break; + case SYSTEM_FONT: + case DEFAULT_GUI_FONT: + ok( obj[i] != obj2[i], "%u: same object\n", i ); + 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 ); + break; + default: + ok( obj[i] == obj2[i], "%u: different object\n", i ); + break; + } + } + + pSetThreadDpiAwarenessContext( context ); +} + +static void scale_point_dpi( POINT *pt, UINT src_dpi, UINT target_dpi ) +{ + pt->x = MulDiv( pt->x, target_dpi, src_dpi ); + pt->y = MulDiv( pt->y, target_dpi, src_dpi ); +} + +static void scale_rect_dpi( RECT *rect, UINT src_dpi, UINT target_dpi ) +{ + rect->left = MulDiv( rect->left, target_dpi, src_dpi ); + rect->top = MulDiv( rect->top, target_dpi, src_dpi ); + rect->right = MulDiv( rect->right, target_dpi, src_dpi ); + rect->bottom = MulDiv( rect->bottom, target_dpi, src_dpi ); +} + +static void scale_point_dpi_aware( POINT *pt, DPI_AWARENESS from, DPI_AWARENESS to ) +{ + if (from == DPI_AWARENESS_UNAWARE && to != DPI_AWARENESS_UNAWARE) + scale_point_dpi( pt, USER_DEFAULT_SCREEN_DPI, real_dpi ); + else if (from != DPI_AWARENESS_UNAWARE && to == DPI_AWARENESS_UNAWARE) + scale_point_dpi( pt, real_dpi, USER_DEFAULT_SCREEN_DPI ); +} + +static void scale_rect_dpi_aware( RECT *rect, DPI_AWARENESS from, DPI_AWARENESS to ) +{ + if (from == DPI_AWARENESS_UNAWARE && to != DPI_AWARENESS_UNAWARE) + scale_rect_dpi( rect, USER_DEFAULT_SCREEN_DPI, real_dpi ); + else if (from != DPI_AWARENESS_UNAWARE && to == DPI_AWARENESS_UNAWARE) + scale_rect_dpi( rect, real_dpi, USER_DEFAULT_SCREEN_DPI ); +} + +static void test_dpi_mapping(void) +{ + HWND hwnd, child; + HDC hdc; + UINT win_dpi, units; + POINT point; + BOOL ret; + HRGN rgn, update; + RECT rect, orig, client, desktop, expect; + ULONG_PTR i, j, k; + WINDOWPLACEMENT wpl_orig, wpl; + HMONITOR monitor; + MONITORINFO mon_info; + DPI_AWARENESS_CONTEXT context; + + if (!pLogicalToPhysicalPointForPerMonitorDPI) + { + win_skip( "LogicalToPhysicalPointForPerMonitorDPI not supported\n" ); + return; + } + context = pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ); + GetWindowRect( GetDesktopWindow(), &desktop ); + for (i = DPI_AWARENESS_UNAWARE; i <= DPI_AWARENESS_PER_MONITOR_AWARE; i++) + { + pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~i ); + /* test desktop rect */ + 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", + 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", + 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", + 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", + 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", + i, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&desktop) ); + DeleteDC( hdc ); + /* test message window rect */ + hwnd = CreateWindowA( "SysParamsTestClass", "test", WS_CHILD, + 10, 10, 20, 20, HWND_MESSAGE, 0, GetModuleHandleA(0), NULL ); + 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", + i, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); + DestroyWindow( hwnd ); + } + for (i = DPI_AWARENESS_UNAWARE; i <= DPI_AWARENESS_PER_MONITOR_AWARE; i++) + { + 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()); + 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()); + GetWindowRect( hwnd, &orig ); + SetRect( &rect, 0, 0, 0, 0 ); + pAdjustWindowRectExForDpi( &rect, WS_OVERLAPPEDWINDOW, FALSE, 0, pGetDpiForWindow( hwnd )); + SetRect( &client, orig.left - rect.left, orig.top - rect.top, + orig.right - rect.right, orig.bottom - rect.bottom ); + ShowWindow( hwnd, SW_MINIMIZE ); + ShowWindow( hwnd, SW_RESTORE ); + GetWindowPlacement( hwnd, &wpl_orig ); + units = GetDialogBaseUnits(); + + for (j = DPI_AWARENESS_UNAWARE; j <= DPI_AWARENESS_PER_MONITOR_AWARE; j++) + { + pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~j ); + /* test window rect */ + 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", + 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", + 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, + 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, + 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, + 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", + 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", + 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", + i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&desktop) ); + ReleaseDC( hwnd, hdc ); + /* test DC win rect */ + hdc = GetWindowDC( hwnd ); + 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", + i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); + ReleaseDC( hwnd, hdc ); + /* test window invalidation */ + UpdateWindow( hwnd ); + update = CreateRectRgn( 0, 0, 0, 0 ); + ret = GetUpdateRgn( hwnd, update, FALSE ); + ok( ret == NULLREGION, "update region not empty\n" ); + rgn = CreateRectRgn( 20, 20, 25, 25 ); + for (k = DPI_AWARENESS_UNAWARE; k <= DPI_AWARENESS_PER_MONITOR_AWARE; k++) + { + pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~k ); + RedrawWindow( hwnd, 0, rgn, RDW_INVALIDATE ); + pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~j ); + 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", + 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", + i, j, k, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); + UpdateWindow( hwnd ); + } + for (k = DPI_AWARENESS_UNAWARE; k <= DPI_AWARENESS_PER_MONITOR_AWARE; k++) + { + RedrawWindow( hwnd, 0, rgn, RDW_INVALIDATE ); + pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~k ); + GetUpdateRgn( hwnd, update, FALSE ); + 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", + 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", + i, j, k, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); + UpdateWindow( hwnd ); + } + /* test desktop window invalidation */ + pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ); + GetClientRect( hwnd, &rect ); + InflateRect( &rect, -50, -50 ); + expect = rect; + MapWindowPoints( hwnd, 0, (POINT *)&rect, 2 ); + pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~j ); + RedrawWindow( 0, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN ); + 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", + 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", + i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); + UpdateWindow( hwnd ); + DeleteObject( update ); + /* test dialog units */ + ret = GetDialogBaseUnits(); + 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", + i, j, LOWORD(ret), HIWORD(ret), point.x, point.y ); + /* test window points mapping */ + SetRect( &rect, 0, 0, 100, 100 ); + rect.right = rect.left + 100; + rect.bottom = rect.top + 100; + MapWindowPoints( hwnd, 0, (POINT *)&rect, 2 ); + expect = client; + 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", + i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); + SetRect( &rect, 50, 60, 70, 80 ); + scale_rect_dpi_aware( &rect, i, j ); + SetRect( &expect, 40, 30, 60, 80 ); + 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", + i, j, wine_dbgstr_rect(&rect), wine_dbgstr_rect(&expect) ); + /* test logical<->physical coords mapping */ + win_dpi = pGetDpiForWindow( hwnd ); + if (i == DPI_AWARENESS_UNAWARE) + ok( win_dpi == USER_DEFAULT_SCREEN_DPI, "wrong dpi %u\n", win_dpi ); + else if (i == DPI_AWARENESS_SYSTEM_AWARE) + ok( win_dpi == real_dpi, "wrong dpi %u / %u\n", win_dpi, real_dpi ); + point.x = 373; + point.y = 377; + ret = pLogicalToPhysicalPointForPerMonitorDPI( hwnd, &point ); + ok( ret, "%lu/%lu: 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 ); + point.x = 405; + point.y = 423; + ret = pPhysicalToLogicalPointForPerMonitorDPI( hwnd, &point ); + ok( ret, "%lu/%lu: 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 ); + /* 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 ); + point.x++; + point.y--; + ret = pLogicalToPhysicalPointForPerMonitorDPI( hwnd, &point ); + ok( !ret, "%lu/%lu: LogicalToPhysicalPointForPerMonitorDPI succeeded\n", i, j ); + point.y++; + ret = pLogicalToPhysicalPointForPerMonitorDPI( hwnd, &point ); + ok( ret, "%lu/%lu: 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 ); + point.x++; + point.y--; + ret = pLogicalToPhysicalPointForPerMonitorDPI( hwnd, &point ); + ok( !ret, "%lu/%lu: LogicalToPhysicalPointForPerMonitorDPI succeeded\n", i, j ); + point.x--; + ret = pLogicalToPhysicalPointForPerMonitorDPI( hwnd, &point ); + ok( ret, "%lu/%lu: LogicalToPhysicalPointForPerMonitorDPI failed\n", i, j ); + /* get physical window rect */ + pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ); + GetWindowRect( hwnd, &rect ); + pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~j ); + point.x = rect.left - 1; + point.y = rect.top; + ret = pPhysicalToLogicalPointForPerMonitorDPI( hwnd, &point ); + ok( !ret, "%lu/%lu: PhysicalToLogicalPointForPerMonitorDPI succeeded\n", i, j ); + point.x++; + point.y--; + ret = pPhysicalToLogicalPointForPerMonitorDPI( hwnd, &point ); + ok( !ret, "%lu/%lu: PhysicalToLogicalPointForPerMonitorDPI succeeded\n", i, j ); + point.y++; + ret = pPhysicalToLogicalPointForPerMonitorDPI( hwnd, &point ); + ok( ret, "%lu/%lu: 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 ); + point.x++; + point.y--; + ret = pPhysicalToLogicalPointForPerMonitorDPI( hwnd, &point ); + ok( !ret, "%lu/%lu: PhysicalToLogicalPointForPerMonitorDPI succeeded\n", i, j ); + point.x--; + ret = pPhysicalToLogicalPointForPerMonitorDPI( hwnd, &point ); + ok( ret, "%lu/%lu: PhysicalToLogicalPointForPerMonitorDPI failed\n", i, j ); + } + DestroyWindow( hwnd ); + } + pSetThreadDpiAwarenessContext( context ); +} + static void test_dpi_aware(void) { BOOL ret; @@ -3006,6 +3531,347 @@ static void test_dpi_aware(void) dpi = real_dpi; test_GetSystemMetrics(); + test_metrics_for_dpi( 96 ); + test_metrics_for_dpi( 192 ); +} + +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 ); + awareness = pGetAwarenessFromDpiAwarenessContext( context ); + todo_wine + ok( awareness == DPI_AWARENESS_UNAWARE, "wrong awareness %u\n", awareness ); + todo_wine + 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 ); + dpi = GetDeviceCaps( hdc, LOGPIXELSX ); + todo_wine_if (real_dpi != USER_DEFAULT_SCREEN_DPI) + ok( dpi == USER_DEFAULT_SCREEN_DPI, "wrong dpi %u\n", dpi ); + SetLastError( 0xdeadbeef ); + ret = pSetProcessDpiAwarenessContext( NULL ); + ok( !ret, "got %d\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\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() ); + 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() ); + SetLastError( 0xdeadbeef ); + ret = pSetProcessDpiAwarenessContext( DPI_AWARENESS_CONTEXT_UNAWARE ); + ok( !ret, "got %d\n", ret ); + ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %u\n", GetLastError() ); + + ret = pSetProcessDpiAwarenessInternal( DPI_AWARENESS_INVALID ); + ok( !ret, "got %d\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ret = pSetProcessDpiAwarenessInternal( DPI_AWARENESS_UNAWARE ); + ok( !ret, "got %d\n", ret ); + ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %u\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 ); + ret = pGetProcessDpiAwarenessInternal( (HANDLE)0xdeadbeef, &awareness ); + ok( ret, "got %d\n", ret ); + 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 ); + 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() ); + SetLastError( 0xdeadbeef ); + context = pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)-6 ); + ok( !context, "got %p\n", context ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + context = pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_UNAWARE ); + todo_wine + ok( context == (DPI_AWARENESS_CONTEXT)(0x80000011 | flags), "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 ); + dpi = GetDeviceCaps( hdc, LOGPIXELSX ); + 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 ); + 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 ); + awareness = pGetAwarenessFromDpiAwarenessContext( context ); + ok( awareness == DPI_AWARENESS_UNAWARE, "wrong awareness %u\n", awareness ); + dpi = pGetDpiForSystem(); + ok( dpi == real_dpi, "wrong dpi %u/%u\n", dpi, real_dpi ); + dpi = GetDeviceCaps( hdc, LOGPIXELSX ); + ok( dpi == real_dpi, "wrong dpi %u\n", dpi ); + context = pGetThreadDpiAwarenessContext(); + ok( context == (DPI_AWARENESS_CONTEXT)0x12, "wrong context %p\n", context ); + awareness = pGetAwarenessFromDpiAwarenessContext( context ); + ok( awareness == DPI_AWARENESS_PER_MONITOR_AWARE, "wrong awareness %u\n", awareness ); + context = pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ); + ok( context == (DPI_AWARENESS_CONTEXT)0x12, "wrong context %p\n", context ); + awareness = pGetAwarenessFromDpiAwarenessContext( context ); + ok( awareness == DPI_AWARENESS_PER_MONITOR_AWARE, "wrong awareness %u\n", awareness ); + dpi = pGetDpiForSystem(); + ok( dpi == real_dpi, "wrong dpi %u/%u\n", dpi, real_dpi ); + dpi = GetDeviceCaps( hdc, LOGPIXELSX ); + 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 ); + 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 ); + context = pGetThreadDpiAwarenessContext(); + todo_wine + ok( context == (DPI_AWARENESS_CONTEXT)(0x11 | flags), "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 ); + context = pSetThreadDpiAwarenessContext( 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; + } + } + if (real_dpi != USER_DEFAULT_SCREEN_DPI) test_dpi_stock_objects( hdc ); + ReleaseDC( 0, hdc ); +} + +static LRESULT CALLBACK dpi_winproc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) +{ + DPI_AWARENESS_CONTEXT ctx = pGetWindowDpiAwarenessContext( hwnd ); + DPI_AWARENESS_CONTEXT ctx2 = pGetThreadDpiAwarenessContext(); + DWORD pos, pos2; + + ok( pGetAwarenessFromDpiAwarenessContext( ctx ) == pGetAwarenessFromDpiAwarenessContext( ctx2 ), + "msg %04x wrong awareness %p / %p\n", msg, ctx, ctx2 ); + pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_UNAWARE ); + pos = GetMessagePos(); + pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ); + pos2 = GetMessagePos(); + ok( pos == pos2, "wrong pos %08x / %08x\n", pos, pos2 ); + pSetThreadDpiAwarenessContext( ctx2 ); + return DefWindowProcA( hwnd, msg, wp, lp ); +} + +static void test_dpi_window(void) +{ + DPI_AWARENESS_CONTEXT context, orig; + DPI_AWARENESS awareness; + ULONG_PTR i, j; + UINT dpi; + HWND hwnd, child, ret; + MSG msg = { 0, WM_USER + 1, 0, 0 }; + + if (!pGetWindowDpiAwarenessContext) + { + win_skip( "GetWindowDpiAwarenessContext not supported\n" ); + return; + } + orig = pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_UNAWARE ); + for (i = DPI_AWARENESS_UNAWARE; i <= DPI_AWARENESS_PER_MONITOR_AWARE; i++) + { + pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~i ); + hwnd = CreateWindowA( "DpiTestClass", "Test", + WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL ); + ok( hwnd != 0, "failed to create window\n" ); + context = pGetWindowDpiAwarenessContext( hwnd ); + awareness = pGetAwarenessFromDpiAwarenessContext( context ); + ok( awareness == i, "%lu: 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 ); + 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() ); + SetLastError( 0xdeadbeef ); + res = pGetDpiForMonitorInternal( MonitorFromWindow( hwnd, 0 ), 3, &dpi, &dpi ); + ok( !res, "succeeded\n" ); + ok( GetLastError() == ERROR_BAD_ARGUMENTS, "wrong error %u\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() ); + res = pGetDpiForMonitorInternal( MonitorFromWindow( hwnd, 0 ), 0, &dpi, &dpi ); + ok( res, "failed err %u\n", GetLastError() ); + ok( dpi == (i == DPI_AWARENESS_UNAWARE ? USER_DEFAULT_SCREEN_DPI : real_dpi), + "%lu: got %u / %u\n", i, dpi, real_dpi ); + } + msg.hwnd = hwnd; + for (j = DPI_AWARENESS_UNAWARE; j <= DPI_AWARENESS_PER_MONITOR_AWARE; j++) + { + pSetThreadDpiAwarenessContext( (DPI_AWARENESS_CONTEXT)~j ); + SendMessageA( hwnd, WM_USER, 0, 0 ); + DispatchMessageA( &msg ); + CallWindowProcA( dpi_winproc, hwnd, WM_USER + 2, 0, 0 ); + child = CreateWindowA( "DpiTestClass", "Test", + 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 ); + 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 ); + ret = SetParent( child, NULL ); + ok( ret != 0, "SetParent failed err %u\n", GetLastError() ); + context = pGetWindowDpiAwarenessContext( child ); + awareness = pGetAwarenessFromDpiAwarenessContext( context ); + ok( awareness == i, "%lu/%lu: 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 ); + 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 ); + 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 ); + ret = SetParent( child, hwnd ); + ok( ret != 0 || GetLastError() == ERROR_INVALID_STATE, + "SetParent failed err %u\n", GetLastError() ); + context = pGetWindowDpiAwarenessContext( child ); + awareness = pGetAwarenessFromDpiAwarenessContext( context ); + ok( awareness == (ret ? i : j), "%lu/%lu: 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 ); + DestroyWindow( child ); + } + DestroyWindow( hwnd ); + } + + SetLastError( 0xdeadbeef ); + context = pGetWindowDpiAwarenessContext( (HWND)0xdeadbeef ); + ok( !context, "got %p\n", context ); + ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\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() ); + + SetLastError( 0xdeadbeef ); + context = pGetWindowDpiAwarenessContext( GetDesktopWindow() ); + awareness = pGetAwarenessFromDpiAwarenessContext( context ); + ok( awareness == DPI_AWARENESS_PER_MONITOR_AWARE, "wrong awareness %u\n", awareness ); + dpi = pGetDpiForWindow( GetDesktopWindow() ); + ok( dpi == real_dpi, "got %u / %u\n", dpi, real_dpi ); + + pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_UNAWARE ); + SetLastError( 0xdeadbeef ); + context = pGetWindowDpiAwarenessContext( GetDesktopWindow() ); + awareness = pGetAwarenessFromDpiAwarenessContext( context ); + ok( awareness == DPI_AWARENESS_PER_MONITOR_AWARE, "wrong awareness %u\n", awareness ); + dpi = pGetDpiForWindow( GetDesktopWindow() ); + ok( dpi == real_dpi, "got %u / %u\n", dpi, real_dpi ); + + pSetThreadDpiAwarenessContext( orig ); } static void test_GetAutoRotationState(void) @@ -3027,7 +3893,6 @@ static void test_GetAutoRotationState(void) state = 0; ret = pGetAutoRotationState(&state); ok(ret, "Expected GetAutoRotationState to succeed, error %d\n", GetLastError()); - ok((state & AR_NOSENSOR) != 0, "Expected AR_NOSENSOR, got %d\n", state); } START_TEST(sysparams) @@ -3036,6 +3901,7 @@ START_TEST(sysparams) char** argv; WNDCLASSA wc; MSG msg; + HDC hdc; HANDLE hThread; DWORD dwThreadId; HANDLE hInstance, hdll; @@ -3044,6 +3910,22 @@ START_TEST(sysparams) pChangeDisplaySettingsExA = (void*)GetProcAddress(hdll, "ChangeDisplaySettingsExA"); pIsProcessDPIAware = (void*)GetProcAddress(hdll, "IsProcessDPIAware"); pSetProcessDPIAware = (void*)GetProcAddress(hdll, "SetProcessDPIAware"); + pGetDpiForSystem = (void*)GetProcAddress(hdll, "GetDpiForSystem"); + pGetDpiForWindow = (void*)GetProcAddress(hdll, "GetDpiForWindow"); + pGetDpiForMonitorInternal = (void*)GetProcAddress(hdll, "GetDpiForMonitorInternal"); + pSetProcessDpiAwarenessContext = (void*)GetProcAddress(hdll, "SetProcessDpiAwarenessContext"); + pGetProcessDpiAwarenessInternal = (void*)GetProcAddress(hdll, "GetProcessDpiAwarenessInternal"); + pSetProcessDpiAwarenessInternal = (void*)GetProcAddress(hdll, "SetProcessDpiAwarenessInternal"); + pGetThreadDpiAwarenessContext = (void*)GetProcAddress(hdll, "GetThreadDpiAwarenessContext"); + pSetThreadDpiAwarenessContext = (void*)GetProcAddress(hdll, "SetThreadDpiAwarenessContext"); + pGetWindowDpiAwarenessContext = (void*)GetProcAddress(hdll, "GetWindowDpiAwarenessContext"); + pGetAwarenessFromDpiAwarenessContext = (void*)GetProcAddress(hdll, "GetAwarenessFromDpiAwarenessContext"); + pIsValidDpiAwarenessContext = (void*)GetProcAddress(hdll, "IsValidDpiAwarenessContext"); + pGetSystemMetricsForDpi = (void*)GetProcAddress(hdll, "GetSystemMetricsForDpi"); + pSystemParametersInfoForDpi = (void*)GetProcAddress(hdll, "SystemParametersInfoForDpi"); + pAdjustWindowRectExForDpi = (void*)GetProcAddress(hdll, "AdjustWindowRectExForDpi"); + pLogicalToPhysicalPointForPerMonitorDPI = (void*)GetProcAddress(hdll, "LogicalToPhysicalPointForPerMonitorDPI"); + pPhysicalToLogicalPointForPerMonitorDPI = (void*)GetProcAddress(hdll, "PhysicalToLogicalPointForPerMonitorDPI"); pGetAutoRotationState = (void*)GetProcAddress(hdll, "GetAutoRotationState"); hInstance = GetModuleHandleA( NULL ); @@ -3051,7 +3933,7 @@ START_TEST(sysparams) dpi = GetDeviceCaps( hdc, LOGPIXELSY); real_dpi = get_real_dpi(); trace("dpi %d real_dpi %d\n", dpi, real_dpi); - iswin9x = GetVersion() & 0x80000000; + ReleaseDC( 0, hdc); /* This test requires interactivity, if we don't have it, give up */ if (!SystemParametersInfoA( SPI_SETBEEP, TRUE, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ) && @@ -3063,7 +3945,7 @@ START_TEST(sysparams) trace("testing GetSystemMetrics with your current desktop settings\n"); test_GetSystemMetrics( ); - trace("testing EnumDisplaySettings vs GetDeviceCaps\n"); + test_metrics_for_dpi( 192 ); test_EnumDisplaySettings( ); test_GetSysColorBrush( ); test_GetAutoRotationState( ); @@ -3082,6 +3964,9 @@ START_TEST(sysparams) wc.cbClsExtra = 0; wc.cbWndExtra = 0; RegisterClassA( &wc ); + wc.lpszClassName = "DpiTestClass"; + wc.lpfnWndProc = dpi_winproc; + RegisterClassA( &wc ); ghTestWnd = CreateWindowA( "SysParamsTestClass", "Test System Parameters Application", WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, hInstance, NULL ); @@ -3094,7 +3979,14 @@ START_TEST(sysparams) TranslateMessage( &msg ); DispatchMessageA( &msg ); } - ReleaseDC( 0, hdc); + + if (pSetThreadDpiAwarenessContext) + { + test_dpi_context(); + test_dpi_mapping(); + test_dpi_window(); + } + else win_skip( "SetThreadDpiAwarenessContext not supported\n" ); test_dpi_aware(); } diff --git a/modules/rostests/winetests/user32/testlist.c b/modules/rostests/winetests/user32/testlist.c index 3923a38612c..d3d99a72d1a 100644 --- a/modules/rostests/winetests/user32/testlist.c +++ b/modules/rostests/winetests/user32/testlist.c @@ -32,6 +32,7 @@ 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_resource(void); extern void func_scroll(void); extern void func_static(void); @@ -72,6 +73,7 @@ const struct test winetest_testlist[] = { "msg_layered_window", func_msg_layered_window}, { "msg_dialog", func_msg_dialog}, { "msg_clipboard", func_msg_clipboard}, + { "rawinput", func_rawinput }, { "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 3cc95715217..359721fcd91 100644 --- a/modules/rostests/winetests/user32/text.c +++ b/modules/rostests/winetests/user32/text.c @@ -277,6 +277,21 @@ static void test_DrawTextCalcRect(void) ok(textheight==0,"Got textheight from DrawTextA\n"); ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + /* When offset to top is zero, return 1 */ + SetRectEmpty(&rect); + textheight = DrawTextExW(hdc, textW, -1, &rect, DT_SINGLELINE | DT_CALCRECT | DT_BOTTOM, NULL); + ok(textheight == 1, "Expect returned height:1 got:%d\n", textheight); + + SetRect(&rect, 0, 100, 0, 100); + textheight = DrawTextExW(hdc, textW, -1, &rect, DT_SINGLELINE | DT_CALCRECT | DT_BOTTOM, NULL); + ok(textheight == 1, "Expect returned height:1 got:%d\n", textheight); + + SetRectEmpty(&rect); + textheight = DrawTextExW(hdc, textW, -1, &rect, DT_SINGLELINE | DT_CALCRECT | DT_TOP, NULL); + /* Set top to text height and bottom zero, so bottom of drawn text to top is zero when DT_VCENTER is used */ + SetRect(&rect, 0, textheight, 0, 0); + textheight = DrawTextExW(hdc, textW, -1, &rect, DT_SINGLELINE | DT_CALCRECT | DT_VCENTER, NULL); + ok(textheight == 1, "Expect returned height:1 got:%d\n", textheight); /* invalid dtp size test */ dtp.cbSize = -1; /* Invalid */ @@ -750,7 +765,7 @@ static void test_CharToOem_OemToChar(void) char oem; WCHAR uni, expect; - for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) + for (i = 0; i < ARRAY_SIZE(tests); i++) { const char *expected = tests[i].ret ? helloWorld : ""; const char *src = tests[i].src ? helloWorld : NULL; @@ -777,7 +792,7 @@ static void test_CharToOem_OemToChar(void) ok(!strcmp(buf, expected), "test %d: got '%s'\n", i, buf); } - for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) + for (i = 0; i < ARRAY_SIZE(tests); i++) { const char *expected = tests[i].ret ? helloWorld : ""; const WCHAR *src = tests[i].src ? helloWorldW : NULL; @@ -789,12 +804,12 @@ static void test_CharToOem_OemToChar(void) ok(!strcmp(buf, expected), "test %d: got '%s'\n", i, buf); memset(buf, 0, sizeof(buf)); - ret = CharToOemBuffW(src, dst, sizeof(helloWorldW)/sizeof(WCHAR)); + ret = CharToOemBuffW(src, dst, ARRAY_SIZE(helloWorldW)); ok(ret == tests[i].ret, "test %d: expected %d, got %d\n", i, tests[i].ret, ret); ok(!strcmp(buf, expected), "test %d: got '%s'\n", i, buf); } - for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) + for (i = 0; i < ARRAY_SIZE(tests); i++) { const WCHAR *expected = tests[i].ret ? helloWorldW : emptyW; const char *src = tests[i].src ? helloWorld : NULL; diff --git a/modules/rostests/winetests/user32/uitools.c b/modules/rostests/winetests/user32/uitools.c index b52fe3a03ae..07cf776a952 100644 --- a/modules/rostests/winetests/user32/uitools.c +++ b/modules/rostests/winetests/user32/uitools.c @@ -175,7 +175,7 @@ static void test_IsRectEmpty(void) {{-109, -107, -103, -101}, FALSE}, }; - for (i = 0; i < sizeof(rtest)/sizeof(rtest[0]); i++) { + for (i = 0; i < ARRAY_SIZE(rtest); i++) { ret = IsRectEmpty(&rtest[i].rect); ok(ret == rtest[i].ret, "Test %d: IsRectEmpty returned %s for %s\n", i, ret ? "TRUE" : "FALSE", wine_dbgstr_rect(&rtest[i].rect)); diff --git a/modules/rostests/winetests/user32/wsprintf.c b/modules/rostests/winetests/user32/wsprintf.c index f0e80b2ad65..f79b6306a7c 100644 --- a/modules/rostests/winetests/user32/wsprintf.c +++ b/modules/rostests/winetests/user32/wsprintf.c @@ -66,7 +66,7 @@ static void wsprintfATest(void) win_skip( "I64 formats not supported\n" ); return; } - for (i = 0; i < sizeof(i64_formats)/sizeof(i64_formats[0]); i++) + for (i = 0; i < ARRAY_SIZE(i64_formats); i++) { rc = wsprintfA(buf, i64_formats[i].fmt, i64_formats[i].value); ok(rc == strlen(i64_formats[i].res), "%u: wsprintfA length failure: rc=%d\n", i, rc); @@ -98,10 +98,10 @@ static void wsprintfWTest(void) win_skip( "I64 formats not supported\n" ); return; } - for (i = 0; i < sizeof(i64_formats)/sizeof(i64_formats[0]); i++) + for (i = 0; i < ARRAY_SIZE(i64_formats); i++) { - MultiByteToWideChar( CP_ACP, 0, i64_formats[i].fmt, -1, fmt, sizeof(fmt)/sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, i64_formats[i].res, -1, res, sizeof(res)/sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, i64_formats[i].fmt, -1, fmt, ARRAY_SIZE(fmt)); + MultiByteToWideChar( CP_ACP, 0, i64_formats[i].res, -1, res, ARRAY_SIZE(res)); rc = wsprintfW(buf, fmt, i64_formats[i].value); 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));