From: Anton Baskanov baskanov@gmail.com
--- dlls/user32/tests/monitor.c | 257 +++++++++++++++++++++++++++++++++--- 1 file changed, 239 insertions(+), 18 deletions(-)
diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c index e93a84242c4..fd78d9ff9ba 100644 --- a/dlls/user32/tests/monitor.c +++ b/dlls/user32/tests/monitor.c @@ -50,6 +50,9 @@ static DPI_AWARENESS_CONTEXT (WINAPI *pSetThreadDpiAwarenessContext)(DPI_AWARENE static NTSTATUS (WINAPI *pD3DKMTCloseAdapter)(const D3DKMT_CLOSEADAPTER*); static NTSTATUS (WINAPI *pD3DKMTOpenAdapterFromGdiDisplayName)(D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME*);
+char** myARGV; +int myARGC; + static void init_function_pointers(void) { HMODULE user32 = GetModuleHandleA("user32.dll"); @@ -291,8 +294,8 @@ struct device_info DEVMODEA original_mode; };
-#define expect_dm(a, b, c) _expect_dm(__LINE__, a, b, c) -static void _expect_dm(INT line, const DEVMODEA *expected, const CHAR *device, DWORD test) +#define expect_dm(a, b, c, d) _expect_dm(__LINE__, a, b, c, d) +static void _expect_dm(INT line, const DEVMODEA *expected, const CHAR *device, DWORD test, BOOL todo) { DEVMODEA dm; BOOL ret; @@ -307,9 +310,9 @@ static void _expect_dm(INT line, const DEVMODEA *expected, const CHAR *device, D "Device %s test %ld expect dmFields to contain %#lx, got %#lx\n", device, test, expected->dmFields, dm.dmFields); ok_(__FILE__, line)(!(expected->dmFields & DM_BITSPERPEL) || dm.dmBitsPerPel == expected->dmBitsPerPel, "Device %s test %ld expect dmBitsPerPel %lu, got %lu\n", device, test, expected->dmBitsPerPel, dm.dmBitsPerPel); - ok_(__FILE__, line)(!(expected->dmFields & DM_PELSWIDTH) || dm.dmPelsWidth == expected->dmPelsWidth, + todo_wine_if(todo) ok_(__FILE__, line)(!(expected->dmFields & DM_PELSWIDTH) || dm.dmPelsWidth == expected->dmPelsWidth, "Device %s test %ld expect dmPelsWidth %lu, got %lu\n", device, test, expected->dmPelsWidth, dm.dmPelsWidth); - ok_(__FILE__, line)(!(expected->dmFields & DM_PELSHEIGHT) || dm.dmPelsHeight == expected->dmPelsHeight, + todo_wine_if(todo) ok_(__FILE__, line)(!(expected->dmFields & DM_PELSHEIGHT) || dm.dmPelsHeight == expected->dmPelsHeight, "Device %s test %ld expect dmPelsHeight %lu, got %lu\n", device, test, expected->dmPelsHeight, dm.dmPelsHeight); ok_(__FILE__, line)(!(expected->dmFields & DM_POSITION) || dm.dmPosition.x == expected->dmPosition.x, "Device %s test %ld expect dmPosition.x %ld, got %ld\n", device, test, expected->dmPosition.x, dm.dmPosition.x); @@ -325,6 +328,35 @@ static void _expect_dm(INT line, const DEVMODEA *expected, const CHAR *device, D dm.dmDisplayOrientation); }
+#define wait_for_dm(a, b, c, d) wait_for_dm_(__LINE__, a, b, c, d) +static void wait_for_dm_(int line, const char *device, DWORD expectedWidth, DWORD expectedHeight, BOOL todo) +{ + DEVMODEA dm; + BOOL ret; + int i; + + for (i = 0; i < 100; ++i) + { + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + SetLastError(0xdeadbeef); + ret = EnumDisplaySettingsA(device, ENUM_CURRENT_SETTINGS, &dm); + ok_(__FILE__, line)(ret, "Device %s EnumDisplaySettingsA failed, error %#lx\n", device, GetLastError()); + ok_(__FILE__, line)((dm.dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) == (DM_PELSWIDTH | DM_PELSHEIGHT), + "Device %s expect dmFields to contain %#lx, got %#lx\n", device, DM_PELSWIDTH | DM_PELSHEIGHT, dm.dmFields); + + if (dm.dmPelsWidth == expectedWidth && dm.dmPelsHeight == expectedHeight) + break; + + Sleep(100); + } + + todo_wine_if(todo) ok_(__FILE__, line)(dm.dmPelsWidth == expectedWidth, + "Device %s expect dmPelsWidth %lu, got %lu\n", device, expectedWidth, dm.dmPelsWidth); + todo_wine_if(todo) ok_(__FILE__, line)(dm.dmPelsHeight == expectedHeight, + "Device %s expect dmPelsHeight %lu, got %lu\n", device, expectedHeight, dm.dmPelsHeight); +} + static void test_ChangeDisplaySettingsEx(void) { static const DWORD registry_fields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | @@ -332,11 +364,16 @@ static void test_ChangeDisplaySettingsEx(void) static const DWORD depths[] = {8, 16, 32}; DPI_AWARENESS_CONTEXT context = NULL; UINT primary, device, test, mode; + PROCESS_INFORMATION info0, info1; UINT device_size, device_count; + HANDLE event0, event1, event2; struct device_info *devices; DEVMODEA dm, dm2, dm3; + char buffer[MAX_PATH]; + STARTUPINFOA startup; INT count, old_count; DISPLAY_DEVICEA dd; + DWORD wait_result; POINTL position; DEVMODEW dmW; BOOL found; @@ -668,7 +705,7 @@ static void test_ChangeDisplaySettingsEx(void) continue; } flush_events(); - expect_dm(&dm3, devices[device].name, test); + expect_dm(&dm3, devices[device].name, test, FALSE);
/* Change the registry mode to the second mode */ res = ChangeDisplaySettingsExA(devices[device].name, &dm2, NULL, CDS_UPDATEREGISTRY | CDS_NORESET, NULL); @@ -802,7 +839,7 @@ static void test_ChangeDisplaySettingsEx(void) }
flush_events(); - expect_dm(&dm, devices[device].name, mode); + expect_dm(&dm, devices[device].name, mode, FALSE); }
/* Restore settings */ @@ -875,7 +912,7 @@ static void test_ChangeDisplaySettingsEx(void) }
flush_events(); - expect_dm(&dm, devices[device].name, 0); + expect_dm(&dm, devices[device].name, 0, FALSE);
/* Test specifying only position, width and height */ memset(&dm, 0, sizeof(dm)); @@ -920,7 +957,7 @@ static void test_ChangeDisplaySettingsEx(void) ok(dm.dmBitsPerPel, "Expected dmBitsPerPel not zero.\n"); ok(dm.dmDisplayFrequency, "Expected dmDisplayFrequency not zero.\n");
- expect_dm(&dm, devices[device].name, 0); + expect_dm(&dm, devices[device].name, 0, FALSE); }
/* Test dmPosition */ @@ -992,7 +1029,7 @@ static void test_ChangeDisplaySettingsEx(void) ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned unexpected %ld\n", devices[1].name, res);
dm2.dmPosition.x = dm.dmPosition.x + dm.dmPelsWidth; - expect_dm(&dm2, devices[1].name, 0); + expect_dm(&dm2, devices[1].name, 0, FALSE);
/* Test placing the secondary adapter to all sides of the primary adapter */ for (test = 0; test < 8; ++test) @@ -1051,7 +1088,7 @@ static void test_ChangeDisplaySettingsEx(void) }
flush_events(); - expect_dm(&dm2, devices[1].name, test); + expect_dm(&dm2, devices[1].name, test, FALSE); }
/* Test automatic position update when other adapters change resolution */ @@ -1116,7 +1153,7 @@ static void test_ChangeDisplaySettingsEx(void) ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s mode %d returned unexpected %ld.\n", devices[device].name, mode, res); flush_events(); - expect_dm(&dm2, devices[device].name, mode); + expect_dm(&dm2, devices[device].name, mode, FALSE);
/* EnumDisplaySettingsEx without EDS_ROTATEDMODE reports modes with current orientation */ memset(&dm3, 0, sizeof(dm3)); @@ -1162,7 +1199,153 @@ static void test_ChangeDisplaySettingsEx(void) broken(res == DISP_CHANGE_FAILED), /* win8 TestBot */ "ChangeDisplaySettingsExA returned unexpected %ld\n", res); for (device = 0; device < device_count; ++device) - expect_dm(&devices[device].original_mode, devices[device].name, 0); + expect_dm(&devices[device].original_mode, devices[device].name, 0, FALSE); + + event0 = CreateEventW(NULL, FALSE, FALSE, L"test_ChangeDisplaySettingsEx_event0"); + ok(!!event0, "OpenEventA failed, error %#lx\n", GetLastError()); + event1 = CreateEventW(NULL, FALSE, FALSE, L"test_ChangeDisplaySettingsEx_event1"); + ok(!!event1, "OpenEventA failed, error %#lx\n", GetLastError()); + event2 = CreateEventW(NULL, FALSE, FALSE, L"test_ChangeDisplaySettingsEx_event2"); + ok(!!event2, "OpenEventA failed, error %#lx\n", GetLastError()); + + memset(&startup, 0, sizeof(startup)); + startup.cb = sizeof(startup); + startup.dwFlags = STARTF_USESHOWWINDOW; + startup.wShowWindow = SW_SHOWNORMAL; + + /* Test that if the most recent ChangeDisplaySettingsEx call had + * CDS_FULLSCREEN set, the the settings are restored when the caller + * process exits */ + + snprintf(buffer, sizeof(buffer), "%s monitor fullscreen %s %s %s", myARGV[0], devices[0].name, + "test_ChangeDisplaySettingsEx_event2", "test_ChangeDisplaySettingsEx_event0"); + res = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info0); + ok(res, "CreateProcessA returned unexpected %ld\n", res); + wait_result = WaitForSingleObject(event2, 10000); + ok(wait_result == WAIT_OBJECT_0, "WaitForSingleObject returned %lx.\n", wait_result); + + snprintf(buffer, sizeof(buffer), "%s monitor fullscreen %s %s %s", myARGV[0], devices[0].name, + "test_ChangeDisplaySettingsEx_event2", "test_ChangeDisplaySettingsEx_event1"); + res = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info1); + ok(res, "CreateProcessA returned unexpected %ld\n", res); + wait_result = WaitForSingleObject(event2, 10000); + ok(wait_result == WAIT_OBJECT_0, "WaitForSingleObject returned %lx.\n", wait_result); + + SetEvent(event0); + wait_result = WaitForSingleObject(info0.hProcess, 10000); + ok(wait_result == WAIT_OBJECT_0, "WaitForSingleObject returned %lx.\n", wait_result); + + Sleep(100); + + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + dm.dmPelsWidth = 640; + dm.dmPelsHeight = 480; + dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; + expect_dm(&dm, devices[0].name, 0, TRUE); + + SetEvent(event1); + wait_result = WaitForSingleObject(info1.hProcess, 10000); + ok(wait_result == WAIT_OBJECT_0, "WaitForSingleObject returned %lx.\n", wait_result); + + wait_for_dm(devices[0].name, devices[0].original_mode.dmPelsWidth, devices[0].original_mode.dmPelsHeight, FALSE); + + CloseHandle(info1.hProcess); + CloseHandle(info1.hThread); + CloseHandle(info0.hProcess); + CloseHandle(info0.hThread); + + /* Test processes exiting in reverse order */ + + snprintf(buffer, sizeof(buffer), "%s monitor fullscreen %s %s %s", myARGV[0], devices[0].name, + "test_ChangeDisplaySettingsEx_event2", "test_ChangeDisplaySettingsEx_event0"); + res = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info0); + ok(res, "CreateProcessA returned unexpected %ld\n", res); + wait_result = WaitForSingleObject(event2, 10000); + ok(wait_result == WAIT_OBJECT_0, "WaitForSingleObject returned %lx.\n", wait_result); + + snprintf(buffer, sizeof(buffer), "%s monitor fullscreen %s %s %s", myARGV[0], devices[0].name, + "test_ChangeDisplaySettingsEx_event2", "test_ChangeDisplaySettingsEx_event1"); + res = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info1); + ok(res, "CreateProcessA returned unexpected %ld\n", res); + wait_result = WaitForSingleObject(event2, 10000); + ok(wait_result == WAIT_OBJECT_0, "WaitForSingleObject returned %lx.\n", wait_result); + + SetEvent(event1); + wait_result = WaitForSingleObject(info1.hProcess, 10000); + ok(wait_result == WAIT_OBJECT_0, "WaitForSingleObject returned %lx.\n", wait_result); + + wait_for_dm(devices[0].name, devices[0].original_mode.dmPelsWidth, devices[0].original_mode.dmPelsHeight, FALSE); + + SetEvent(event0); + wait_result = WaitForSingleObject(info0.hProcess, 10000); + ok(wait_result == WAIT_OBJECT_0, "WaitForSingleObject returned %lx.\n", wait_result); + + Sleep(100); + + expect_dm(&devices[0].original_mode, devices[0].name, 0, FALSE); + + CloseHandle(info1.hProcess); + CloseHandle(info1.hThread); + CloseHandle(info0.hProcess); + CloseHandle(info0.hThread); + + if (device_count < 2) + { + skip("Only one device found.\n"); + } + else + { + /* Test that the settings are restored for all devices, regardless of + * the process that changed them */ + + snprintf(buffer, sizeof(buffer), "%s monitor fullscreen %s %s %s", myARGV[0], devices[0].name, + "test_ChangeDisplaySettingsEx_event2", "test_ChangeDisplaySettingsEx_event0"); + res = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info0); + ok(res, "CreateProcessA returned unexpected %ld\n", res); + wait_result = WaitForSingleObject(event2, 10000); + ok(wait_result == WAIT_OBJECT_0, "WaitForSingleObject returned %lx.\n", wait_result); + + snprintf(buffer, sizeof(buffer), "%s monitor fullscreen %s %s %s", myARGV[0], devices[1].name, + "test_ChangeDisplaySettingsEx_event2", "test_ChangeDisplaySettingsEx_event1"); + res = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info1); + ok(res, "CreateProcessA returned unexpected %ld\n", res); + wait_result = WaitForSingleObject(event2, 10000); + ok(wait_result == WAIT_OBJECT_0, "WaitForSingleObject returned %lx.\n", wait_result); + + SetEvent(event1); + wait_result = WaitForSingleObject(info1.hProcess, 10000); + ok(wait_result == WAIT_OBJECT_0, "WaitForSingleObject returned %lx.\n", wait_result); + + wait_for_dm(devices[0].name, devices[0].original_mode.dmPelsWidth, devices[0].original_mode.dmPelsHeight, FALSE); + wait_for_dm(devices[1].name, devices[1].original_mode.dmPelsWidth, devices[1].original_mode.dmPelsHeight, FALSE); + + SetEvent(event0); + wait_result = WaitForSingleObject(info0.hProcess, 10000); + ok(wait_result == WAIT_OBJECT_0, "WaitForSingleObject returned %lx.\n", wait_result); + + Sleep(100); + + dm = devices[0].original_mode; + dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; + expect_dm(&dm, devices[0].name, 0, FALSE); + dm = devices[1].original_mode; + dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; + expect_dm(&dm, devices[1].name, 0, FALSE); + + CloseHandle(info1.hProcess); + CloseHandle(info1.hThread); + CloseHandle(info0.hProcess); + CloseHandle(info0.hThread); + } + + CloseHandle(event2); + CloseHandle(event1); + CloseHandle(event0); + + /* Restore all adapters to their original settings */ + res = ChangeDisplaySettingsExA(NULL, NULL, NULL, 0, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA returned unexpected %ld\n", res);
free(devices); } @@ -2665,16 +2848,54 @@ BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor,
START_TEST(monitor) { - char** myARGV; - int myARGC = winetest_get_mainargs(&myARGV); + myARGC = winetest_get_mainargs(&myARGV);
init_function_pointers();
- if (myARGC >= 3 && strcmp(myARGV[2], "info") == 0) + if (myARGC >= 3) { - printf("Monitor information:\n"); - EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, 0); - return; + if (strcmp(myARGV[2], "info") == 0) + { + printf("Monitor information:\n"); + EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, 0); + return; + } + else if (strcmp(myARGV[2], "fullscreen") == 0) + { + HANDLE event0, event1; + DWORD wait_result; + DEVMODEA dm; + LONG res; + + if (myARGC < 6) + { + ok(0, "too few arguments.\n"); + return; + } + + event0 = OpenEventA(EVENT_MODIFY_STATE, FALSE, myARGV[4]); + ok(!!event0, "OpenEventA failed, error %#lx\n", GetLastError()); + event1 = OpenEventA(SYNCHRONIZE, FALSE, myARGV[5]); + ok(!!event1, "OpenEventA failed, error %#lx\n", GetLastError()); + + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; + dm.dmPelsWidth = 640; + dm.dmPelsHeight = 480; + res = ChangeDisplaySettingsExA(myARGV[3], &dm, NULL, CDS_FULLSCREEN, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, + "ChangeDisplaySettingsExA %s returned unexpected %ld.\n", myARGV[3], res); + + SetEvent(event0); + CloseHandle(event0); + + wait_result = WaitForSingleObject(event1, 20000); + ok(wait_result == WAIT_OBJECT_0, "WaitForSingleObject returned %lx.\n", wait_result); + CloseHandle(event1); + + return; + } }
test_enumdisplaydevices();