Wine-Devel
Threads by month
- ----- 2026 -----
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- 3 participants
- 84543 discussions
Oct. 30, 2020
Mostly to test that when doing mode restoration, all display outputs get restored to their display
settings in the registry, not just one output gets restored.
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/dxgi/tests/dxgi.c | 427 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 427 insertions(+)
diff --git a/dlls/dxgi/tests/dxgi.c b/dlls/dxgi/tests/dxgi.c
index 43c4247dc2a..4d9677b3762 100644
--- a/dlls/dxgi/tests/dxgi.c
+++ b/dlls/dxgi/tests/dxgi.c
@@ -134,6 +134,77 @@ static void get_virtual_rect(RECT *rect)
rect->bottom = rect->top + GetSystemMetrics(SM_CYVIRTUALSCREEN);
}
+static BOOL equal_mode_rect(const DEVMODEW *mode1, const DEVMODEW *mode2)
+{
+ return mode1->dmPosition.x == mode2->dmPosition.x
+ && mode1->dmPosition.y == mode2->dmPosition.y
+ && mode1->dmPelsWidth == mode2->dmPelsWidth
+ && mode1->dmPelsHeight == mode2->dmPelsHeight;
+}
+
+/* Free original_modes after finished using it */
+static BOOL save_display_modes(DEVMODEW **original_modes, unsigned int *display_count)
+{
+ unsigned int number, size = 2, count = 0, index = 0;
+ DISPLAY_DEVICEW display_device;
+ DEVMODEW *modes, *tmp;
+
+ if (!(modes = heap_alloc(size * sizeof(*modes))))
+ return FALSE;
+
+ display_device.cb = sizeof(display_device);
+ while (EnumDisplayDevicesW(NULL, index++, &display_device, 0))
+ {
+ /* Skip software devices */
+ if (swscanf(display_device.DeviceName, L"\\\\.\\DISPLAY%u", &number) != 1)
+ continue;
+
+ if (!(display_device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
+ continue;
+
+ if (count >= size)
+ {
+ size *= 2;
+ if (!(tmp = heap_realloc(modes, size * sizeof(*modes))))
+ {
+ heap_free(modes);
+ return FALSE;
+ }
+ modes = tmp;
+ }
+
+ memset(&modes[count], 0, sizeof(modes[count]));
+ modes[count].dmSize = sizeof(modes[count]);
+ if (!EnumDisplaySettingsW(display_device.DeviceName, ENUM_CURRENT_SETTINGS, &modes[count]))
+ {
+ heap_free(modes);
+ return FALSE;
+ }
+
+ lstrcpyW(modes[count++].dmDeviceName, display_device.DeviceName);
+ }
+
+ *original_modes = modes;
+ *display_count = count;
+ return TRUE;
+}
+
+static BOOL restore_display_modes(DEVMODEW *modes, unsigned int count)
+{
+ unsigned int index;
+ LONG ret;
+
+ for (index = 0; index < count; ++index)
+ {
+ ret = ChangeDisplaySettingsExW(modes[index].dmDeviceName, &modes[index], NULL,
+ CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
+ if (ret != DISP_CHANGE_SUCCESSFUL)
+ return FALSE;
+ }
+ ret = ChangeDisplaySettingsExW(NULL, NULL, NULL, 0, NULL);
+ return ret == DISP_CHANGE_SUCCESSFUL;
+}
+
/* try to make sure pending X events have been processed before continuing */
static void flush_events(void)
{
@@ -6897,6 +6968,360 @@ static void test_colour_space_support(IUnknown *device, BOOL is_d3d12)
ok(ref_count == !is_d3d12, "Factory has %u references left.\n", ref_count);
}
+static void test_mode_change(IUnknown *device, BOOL is_d3d12)
+{
+ unsigned int user32_width = 0, user32_height = 0, d3d_width = 0, d3d_height = 0;
+ unsigned int display_count = 0, mode_idx = 0, adapter_idx, output_idx;
+ DEVMODEW *original_modes = NULL, old_devmode, devmode, devmode2;
+ DXGI_SWAP_CHAIN_DESC swapchain_desc, swapchain_desc2;
+ IDXGIOutput *output, *second_output = NULL;
+ WCHAR second_monitor_name[CCHDEVICENAME];
+ IDXGISwapChain *swapchain, *swapchain2;
+ DXGI_OUTPUT_DESC output_desc;
+ IDXGIAdapter *adapter;
+ IDXGIFactory *factory;
+ BOOL fullscreen, ret;
+ LONG change_ret;
+ ULONG refcount;
+ HRESULT hr;
+
+ memset(&devmode, 0, sizeof(devmode));
+ devmode.dmSize = sizeof(devmode);
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(equal_mode_rect(&devmode, ®istry_mode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(equal_mode_rect(&devmode, ®istry_mode), "Got a different mode.\n");
+
+ while (EnumDisplaySettingsW(NULL, mode_idx++, &devmode))
+ {
+ if (devmode.dmPelsWidth == registry_mode.dmPelsWidth
+ && devmode.dmPelsHeight == registry_mode.dmPelsHeight)
+ continue;
+
+ if (!d3d_width && !d3d_height)
+ {
+ d3d_width = devmode.dmPelsWidth;
+ d3d_height = devmode.dmPelsHeight;
+ continue;
+ }
+
+ if (devmode.dmPelsWidth == d3d_width && devmode.dmPelsHeight == d3d_height)
+ continue;
+
+ user32_width = devmode.dmPelsWidth;
+ user32_height = devmode.dmPelsHeight;
+ break;
+ }
+ if (!user32_width || !user32_height)
+ {
+ skip("Failed to find three different display modes for the primary output.\n");
+ return;
+ }
+
+ ret = save_display_modes(&original_modes, &display_count);
+ ok(ret, "Failed to save original display modes.\n");
+
+ get_factory(device, is_d3d12, &factory);
+
+ /* Test that no mode restorations if no mode changes actually happened */
+ change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
+
+ swapchain_desc.BufferDesc.Width = registry_mode.dmPelsWidth;
+ swapchain_desc.BufferDesc.Height = registry_mode.dmPelsHeight;
+ swapchain_desc.BufferDesc.RefreshRate.Numerator = 60;
+ swapchain_desc.BufferDesc.RefreshRate.Denominator = 1;
+ swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
+ swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
+ swapchain_desc.SampleDesc.Count = 1;
+ swapchain_desc.SampleDesc.Quality = 0;
+ swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ swapchain_desc.BufferCount = is_d3d12 ? 2 : 1;
+ swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
+ swapchain_desc.Windowed = TRUE;
+ swapchain_desc.SwapEffect = is_d3d12 ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
+ swapchain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
+
+ hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
+ ok(hr == S_OK, "CreateSwapChain failed, hr %#x.\n", hr);
+ refcount = IDXGISwapChain_Release(swapchain);
+ ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
+
+ memset(&devmode2, 0, sizeof(devmode2));
+ devmode2.dmSize = sizeof(devmode2);
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(equal_mode_rect(&devmode2, ®istry_mode), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* If current display settings are different than the display settings in registry before
+ * calling SetFullscreenState() */
+ change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
+
+ hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
+ ok(hr == S_OK, "CreateSwapChain failed, hr %#x.\n", hr);
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
+ ok(hr == DXGI_ERROR_UNSUPPORTED /* Win7 */
+ || hr == S_OK /* Win8~Win10 1909 */
+ || hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE, /* Win10 2004 */
+ "Got unexpected hr %#x.\n", hr);
+
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ refcount = IDXGISwapChain_Release(swapchain);
+ ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations use display settings in the registry with a fullscreen device */
+ hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
+ ok(hr == S_OK, "CreateSwapChain failed, hr %#x.\n", hr);
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
+ if (FAILED(hr))
+ {
+ skip("SetFullscreenState failed, hr %#x.\n", hr);
+ refcount = IDXGISwapChain_Release(swapchain);
+ ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
+ goto done;
+ }
+
+ change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(equal_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(equal_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+ refcount = IDXGISwapChain_Release(swapchain);
+ ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ for (adapter_idx = 0; SUCCEEDED(IDXGIFactory_EnumAdapters(factory, adapter_idx, &adapter)); ++adapter_idx)
+ {
+ for (output_idx = 0; SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, output_idx, &output)); ++output_idx)
+ {
+ hr = IDXGIOutput_GetDesc(output, &output_desc);
+ ok(hr == S_OK, "Adapter %u output %u: Got unexpected hr %#x.\n", adapter_idx, output_idx, hr);
+
+ if ((adapter_idx || output_idx) && output_desc.AttachedToDesktop)
+ {
+ second_output = output;
+ break;
+ }
+
+ IDXGIOutput_Release(output);
+ }
+
+ IDXGIAdapter_Release(adapter);
+ if (second_output)
+ break;
+ }
+
+ if (!second_output)
+ {
+ skip("Following tests require two monitors.\n");
+ goto done;
+ }
+ lstrcpyW(second_monitor_name, output_desc.DeviceName);
+
+ memset(&old_devmode, 0, sizeof(old_devmode));
+ old_devmode.dmSize = sizeof(old_devmode);
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &old_devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+
+ mode_idx = 0;
+ d3d_width = 0;
+ d3d_height = 0;
+ user32_width = 0;
+ user32_height = 0;
+ while (EnumDisplaySettingsW(second_monitor_name, mode_idx++, &devmode))
+ {
+ if (devmode.dmPelsWidth == old_devmode.dmPelsWidth
+ && devmode.dmPelsHeight == old_devmode.dmPelsHeight)
+ continue;
+
+ if (!d3d_width && !d3d_height)
+ {
+ d3d_width = devmode.dmPelsWidth;
+ d3d_height = devmode.dmPelsHeight;
+ continue;
+ }
+
+ if (devmode.dmPelsWidth == d3d_width && devmode.dmPelsHeight == d3d_height)
+ continue;
+
+ user32_width = devmode.dmPelsWidth;
+ user32_height = devmode.dmPelsHeight;
+ break;
+ }
+ if (!user32_width || !user32_height)
+ {
+ skip("Failed to find three different display modes for the second output.\n");
+ goto done;
+ }
+
+ /* Test that mode restorations for non-primary outputs upon fullscreen state changes */
+ hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
+ ok(hr == S_OK, "CreateSwapChain failed, hr %#x.\n", hr);
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ if (devmode2.dmPelsWidth == old_devmode.dmPelsWidth
+ && devmode2.dmPelsHeight == old_devmode.dmPelsHeight)
+ {
+ skip("Failed to change display settings of the second monitor.\n");
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ refcount = IDXGISwapChain_Release(swapchain);
+ ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
+ goto done;
+ }
+
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ hr = IDXGIOutput_GetDesc(second_output, &output_desc);
+ ok(hr == S_OK, "GetDesc failed, hr %#x.\n", hr);
+ todo_wine ok(output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left ==
+ old_devmode.dmPelsWidth, "Expected width %u, got %u.\n", old_devmode.dmPelsWidth,
+ output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left);
+ todo_wine ok(output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top ==
+ old_devmode.dmPelsHeight, "Expected height %u, got %u.\n", old_devmode.dmPelsHeight,
+ output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top);
+
+ refcount = IDXGISwapChain_Release(swapchain);
+ ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations for non-primary outputs use display settings in the registry */
+ hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
+ ok(hr == S_OK, "CreateSwapChain failed, hr %#x.\n", hr);
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
+ ok(hr == S_OK, "SetFullscreenState failed, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL,
+ CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
+ ok(hr == S_OK, "SetFullscreenState failed, hr %#x.\n", hr);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(devmode2.dmPelsWidth == devmode.dmPelsWidth && devmode2.dmPelsHeight == devmode.dmPelsHeight,
+ "Expected resolution %ux%u, got %ux%u.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
+ devmode2.dmPelsWidth, devmode2.dmPelsHeight);
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(devmode2.dmPelsWidth == devmode.dmPelsWidth && devmode2.dmPelsHeight == devmode.dmPelsHeight,
+ "Expected resolution %ux%u, got %ux%u.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
+ devmode2.dmPelsWidth, devmode2.dmPelsHeight);
+ hr = IDXGIOutput_GetDesc(second_output, &output_desc);
+ ok(hr == S_OK, "GetDesc failed, hr %#x.\n", hr);
+ todo_wine ok(output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left ==
+ devmode.dmPelsWidth, "Expected width %u, got %u.\n", devmode.dmPelsWidth,
+ output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left);
+ todo_wine ok(output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top ==
+ devmode.dmPelsHeight, "Expected height %u, got %u.\n", devmode.dmPelsHeight,
+ output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top);
+
+ refcount = IDXGISwapChain_Release(swapchain);
+ ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations for non-primary outputs on fullscreen state changes when there
+ * are two fullscreen swapchains on different outputs */
+ hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
+ ok(hr == S_OK, "CreateSwapChain failed, hr %#x.\n", hr);
+
+ swapchain_desc2 = swapchain_desc;
+ swapchain_desc.BufferDesc.Width = d3d_width;
+ swapchain_desc.BufferDesc.Height = d3d_height;
+ swapchain_desc2.OutputWindow = CreateWindowA("static", "dxgi_test2", 0,
+ old_devmode.dmPosition.x, old_devmode.dmPosition.y, 400, 200, 0, 0, 0, 0);
+ hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc2, &swapchain2);
+ ok(hr == S_OK, "CreateSwapChain failed, hr %#x.\n", hr);
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
+ ok(hr == S_OK, "SetFullscreenState failed, hr %#x.\n", hr);
+ hr = IDXGISwapChain_SetFullscreenState(swapchain2, TRUE, NULL);
+ if (FAILED(hr))
+ {
+ skip("SetFullscreenState failed, hr %#x.\n", hr);
+ refcount = IDXGISwapChain_Release(swapchain2);
+ ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
+ ok(hr == S_OK, "SetFullscreenState failed, hr %#x.\n", hr);
+ refcount = IDXGISwapChain_Release(swapchain);
+ ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
+ goto done;
+ }
+
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
+ ok(hr == S_OK, "SetFullscreenState failed, hr %#x.\n", hr);
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ ok(hr == S_OK, "GetFullscreenState failed, hr %#x.\n", hr);
+ ok(!fullscreen, "Expected swapchain not fullscreen.\n");
+ hr = IDXGISwapChain_GetFullscreenState(swapchain2, &fullscreen, NULL);
+ ok(hr == S_OK, "GetFullscreenState failed, hr %#x.\n", hr);
+ ok(fullscreen, "Expected swapchain fullscreen.\n");
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ hr = IDXGIOutput_GetDesc(second_output, &output_desc);
+ ok(hr == S_OK, "GetDesc failed, hr %#x.\n", hr);
+ ok(output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left ==
+ old_devmode.dmPelsWidth, "Expected width %u, got %u.\n", old_devmode.dmPelsWidth,
+ output_desc.DesktopCoordinates.right - output_desc.DesktopCoordinates.left);
+ ok(output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top ==
+ old_devmode.dmPelsHeight, "Expected height %u, got %u.\n", old_devmode.dmPelsHeight,
+ output_desc.DesktopCoordinates.bottom - output_desc.DesktopCoordinates.top);
+
+ hr = IDXGISwapChain_SetFullscreenState(swapchain2, FALSE, NULL);
+ ok(hr == S_OK, "SetFullscreenState failed, hr %#x.\n", hr);
+ refcount = IDXGISwapChain_Release(swapchain2);
+ ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
+ refcount = IDXGISwapChain_Release(swapchain);
+ ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
+ DestroyWindow(swapchain_desc2.OutputWindow);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+done:
+ if (second_output)
+ IDXGIOutput_Release(second_output);
+ DestroyWindow(swapchain_desc.OutputWindow);
+ refcount = IDXGIFactory_Release(factory);
+ ok(refcount == !is_d3d12, "Got unexpected refcount %u.\n", refcount);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+ heap_free(original_modes);
+}
+
static void run_on_d3d10(void (*test_func)(IUnknown *device, BOOL is_d3d12))
{
IDXGIDevice *device;
@@ -7013,6 +7438,7 @@ START_TEST(dxgi)
run_on_d3d10(test_get_containing_output);
run_on_d3d10(test_window_association);
run_on_d3d10(test_default_fullscreen_target_output);
+ run_on_d3d10(test_mode_change);
if (!(d3d12_module = LoadLibraryA("d3d12.dll")))
{
@@ -7042,6 +7468,7 @@ START_TEST(dxgi)
run_on_d3d12(test_get_containing_output);
run_on_d3d12(test_window_association);
run_on_d3d12(test_default_fullscreen_target_output);
+ run_on_d3d12(test_mode_change);
FreeLibrary(d3d12_module);
}
--
2.27.0
2
1
Oct. 30, 2020
Mostly to test that when doing mode restoration, all display outputs get restored to their display
settings in the registry, not just one output gets restored.
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/d3d9/tests/device.c | 411 +++++++++++++++++++++++++++++++++++++--
1 file changed, 400 insertions(+), 11 deletions(-)
diff --git a/dlls/d3d9/tests/device.c b/dlls/d3d9/tests/device.c
index 2efb6ddc2e5..3f18678291e 100644
--- a/dlls/d3d9/tests/device.c
+++ b/dlls/d3d9/tests/device.c
@@ -25,6 +25,7 @@
#define COBJMACROS
#include <d3d9.h>
#include "utils.h"
+#include "wine/heap.h"
struct vec3
{
@@ -158,6 +159,77 @@ static BOOL adapter_is_warp(const D3DADAPTER_IDENTIFIER9 *identifier)
return !strcmp(identifier->Driver, "d3d10warp.dll");
}
+static BOOL equal_mode_rect(const DEVMODEW *mode1, const DEVMODEW *mode2)
+{
+ return mode1->dmPosition.x == mode2->dmPosition.x
+ && mode1->dmPosition.y == mode2->dmPosition.y
+ && mode1->dmPelsWidth == mode2->dmPelsWidth
+ && mode1->dmPelsHeight == mode2->dmPelsHeight;
+}
+
+/* Free original_modes after finished using it */
+static BOOL save_display_modes(DEVMODEW **original_modes, unsigned int *display_count)
+{
+ unsigned int number, size = 2, count = 0, index = 0;
+ DISPLAY_DEVICEW display_device;
+ DEVMODEW *modes, *tmp;
+
+ if (!(modes = heap_alloc(size * sizeof(*modes))))
+ return FALSE;
+
+ display_device.cb = sizeof(display_device);
+ while (EnumDisplayDevicesW(NULL, index++, &display_device, 0))
+ {
+ /* Skip software devices */
+ if (swscanf(display_device.DeviceName, L"\\\\.\\DISPLAY%u", &number) != 1)
+ continue;
+
+ if (!(display_device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
+ continue;
+
+ if (count >= size)
+ {
+ size *= 2;
+ if (!(tmp = heap_realloc(modes, size * sizeof(*modes))))
+ {
+ heap_free(modes);
+ return FALSE;
+ }
+ modes = tmp;
+ }
+
+ memset(&modes[count], 0, sizeof(modes[count]));
+ modes[count].dmSize = sizeof(modes[count]);
+ if (!EnumDisplaySettingsW(display_device.DeviceName, ENUM_CURRENT_SETTINGS, &modes[count]))
+ {
+ heap_free(modes);
+ return FALSE;
+ }
+
+ lstrcpyW(modes[count++].dmDeviceName, display_device.DeviceName);
+ }
+
+ *original_modes = modes;
+ *display_count = count;
+ return TRUE;
+}
+
+static BOOL restore_display_modes(DEVMODEW *modes, unsigned int count)
+{
+ unsigned int index;
+ LONG ret;
+
+ for (index = 0; index < count; ++index)
+ {
+ ret = ChangeDisplaySettingsExW(modes[index].dmDeviceName, &modes[index], NULL,
+ CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
+ if (ret != DISP_CHANGE_SUCCESSFUL)
+ return FALSE;
+ }
+ ret = ChangeDisplaySettingsExW(NULL, NULL, NULL, 0, NULL);
+ return ret == DISP_CHANGE_SUCCESSFUL;
+}
+
static IDirect3DDevice9 *create_device(IDirect3D9 *d3d9, HWND focus_window, const struct device_desc *desc)
{
D3DPRESENT_PARAMETERS present_parameters = {0};
@@ -5198,21 +5270,34 @@ done:
static void test_mode_change(void)
{
+ DEVMODEW old_devmode, devmode, devmode2, *original_modes = NULL;
+ struct device_desc device_desc, device_desc2;
+ WCHAR second_monitor_name[CCHDEVICENAME];
+ IDirect3DDevice9 *device, *device2;
+ unsigned int display_count = 0;
RECT d3d_rect, focus_rect, r;
- struct device_desc device_desc;
IDirect3DSurface9 *backbuffer;
- IDirect3DDevice9 *device;
+ MONITORINFOEXW monitor_info;
+ HMONITOR second_monitor;
D3DSURFACE_DESC desc;
IDirect3D9 *d3d9;
- DEVMODEW devmode;
ULONG refcount;
UINT adapter_mode_count, i;
HRESULT hr;
- DWORD ret;
+ BOOL ret;
LONG change_ret;
D3DDISPLAYMODE d3ddm;
DWORD d3d_width = 0, d3d_height = 0, user32_width = 0, user32_height = 0;
+ memset(&devmode, 0, sizeof(devmode));
+ devmode.dmSize = sizeof(devmode);
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(equal_mode_rect(&devmode, ®istry_mode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(equal_mode_rect(&devmode, ®istry_mode), "Got a different mode.\n");
+
d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
ok(!!d3d9, "Failed to create a D3D object.\n");
@@ -5265,6 +5350,9 @@ static void test_mode_change(void)
return;
}
+ ret = save_display_modes(&original_modes, &display_count);
+ ok(ret, "Failed to save original display modes.\n");
+
memset(&devmode, 0, sizeof(devmode));
devmode.dmSize = sizeof(devmode);
devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
@@ -5289,8 +5377,6 @@ static void test_mode_change(void)
if (!(device = create_device(d3d9, focus_window, &device_desc)))
{
skip("Failed to create a D3D device, skipping tests.\n");
- change_ret = ChangeDisplaySettingsW(NULL, CDS_FULLSCREEN);
- ok(change_ret == DISP_CHANGE_SUCCESSFUL, "Failed to change display mode, ret %#x.\n", change_ret);
goto done;
}
@@ -5344,6 +5430,7 @@ static void test_mode_change(void)
device_desc.flags = CREATE_DEVICE_FULLSCREEN;
ok(!!(device = create_device(d3d9, focus_window, &device_desc)), "Failed to create a D3D device.\n");
+ devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
devmode.dmPelsWidth = user32_width;
devmode.dmPelsHeight = user32_height;
change_ret = ChangeDisplaySettingsW(&devmode, CDS_FULLSCREEN);
@@ -5352,17 +5439,319 @@ static void test_mode_change(void)
refcount = IDirect3DDevice9_Release(device);
ok(!refcount, "Device has %u references left.\n", refcount);
- ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
+ memset(&devmode2, 0, sizeof(devmode2));
+ devmode2.dmSize = sizeof(devmode2);
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
ok(ret, "Failed to get display mode.\n");
- ok(devmode.dmPelsWidth == registry_mode.dmPelsWidth
- && devmode.dmPelsHeight == registry_mode.dmPelsHeight,
- "Expected resolution %ux%u, got %ux%u.\n",
- registry_mode.dmPelsWidth, registry_mode.dmPelsHeight, devmode.dmPelsWidth, devmode.dmPelsHeight);
+ ok(devmode2.dmPelsWidth == registry_mode.dmPelsWidth
+ && devmode2.dmPelsHeight == registry_mode.dmPelsHeight,
+ "Expected resolution %ux%u, got %ux%u.\n", registry_mode.dmPelsWidth,
+ registry_mode.dmPelsHeight, devmode2.dmPelsWidth, devmode2.dmPelsHeight);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that no mode restorations if no mode changes happened */
+ change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
+
+ device_desc.adapter_ordinal = D3DADAPTER_DEFAULT;
+ device_desc.device_window = device_window;
+ device_desc.width = d3d_width;
+ device_desc.height = d3d_height;
+ device_desc.flags = 0;
+ device = create_device(d3d9, device_window, &device_desc);
+ ok(!!device, "Failed to create a D3D device.\n");
+ refcount = IDirect3DDevice9_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(equal_mode_rect(&devmode2, ®istry_mode), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations use display settings in the registry with a fullscreen device */
+ change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
+
+ device_desc.adapter_ordinal = D3DADAPTER_DEFAULT;
+ device_desc.device_window = device_window;
+ device_desc.width = registry_mode.dmPelsWidth;
+ device_desc.height = registry_mode.dmPelsHeight;
+ device_desc.flags = CREATE_DEVICE_FULLSCREEN;
+ device = create_device(d3d9, device_window, &device_desc);
+ ok(!!device, "Failed to create a D3D device.\n");
+ refcount = IDirect3DDevice9_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(equal_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(equal_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations use display settings in the registry with a fullscreen device
+ * having the same display mode and then reset to a different mode */
+ change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
+
+ device_desc.adapter_ordinal = D3DADAPTER_DEFAULT;
+ device_desc.device_window = device_window;
+ device_desc.width = registry_mode.dmPelsWidth;
+ device_desc.height = registry_mode.dmPelsHeight;
+ device_desc.flags = CREATE_DEVICE_FULLSCREEN;
+ device = create_device(d3d9, device_window, &device_desc);
+ ok(!!device, "Failed to create a D3D device.\n");
+
+ device_desc.width = d3d_width;
+ device_desc.height = d3d_height;
+ hr = reset_device(device, &device_desc);
+ ok(hr == D3D_OK, "Failed to reset device, hr %#x.\n", hr);
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(devmode2.dmPelsWidth == d3d_width && devmode2.dmPelsHeight == d3d_height,
+ "Expected resolution %ux%u, got %ux%u.\n", d3d_width, d3d_height,
+ devmode2.dmPelsWidth, devmode2.dmPelsHeight);
+
+ refcount = IDirect3DDevice9_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(equal_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(equal_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ if (IDirect3D9_GetAdapterCount(d3d9) < 2)
+ {
+ skip("Following tests require two adapters.\n");
+ goto done;
+ }
+
+ second_monitor = IDirect3D9_GetAdapterMonitor(d3d9, 1);
+ monitor_info.cbSize = sizeof(monitor_info);
+ ret = GetMonitorInfoW(second_monitor, (MONITORINFO *)&monitor_info);
+ ok(ret, "GetMonitorInfoW failed, error %#x.\n", GetLastError());
+ lstrcpyW(second_monitor_name, monitor_info.szDevice);
+
+ memset(&old_devmode, 0, sizeof(old_devmode));
+ old_devmode.dmSize = sizeof(old_devmode);
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &old_devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+
+ i = 0;
+ d3d_width = 0;
+ d3d_height = 0;
+ user32_width = 0;
+ user32_height = 0;
+ while (EnumDisplaySettingsW(second_monitor_name, i++, &devmode))
+ {
+ if (devmode.dmPelsWidth == old_devmode.dmPelsWidth
+ && devmode.dmPelsHeight == old_devmode.dmPelsHeight)
+ continue;
+
+ if (!d3d_width && !d3d_height)
+ {
+ d3d_width = devmode.dmPelsWidth;
+ d3d_height = devmode.dmPelsHeight;
+ continue;
+ }
+
+ if (devmode.dmPelsWidth == d3d_width && devmode.dmPelsHeight == d3d_height)
+ continue;
+
+ user32_width = devmode.dmPelsWidth;
+ user32_height = devmode.dmPelsHeight;
+ break;
+ }
+ if (!user32_width || !user32_height)
+ {
+ skip("Failed to find three different display modes for the second monitor.\n");
+ goto done;
+ }
+
+ /* Test that mode restorations also happen for non-primary monitors on device resets */
+ device_desc.adapter_ordinal = D3DADAPTER_DEFAULT;
+ device_desc.device_window = device_window;
+ device_desc.width = registry_mode.dmPelsWidth;
+ device_desc.height = registry_mode.dmPelsHeight;
+ device_desc.flags = CREATE_DEVICE_FULLSCREEN;
+ device = create_device(d3d9, device_window, &device_desc);
+ ok(!!device, "Failed to create a D3D device.\n");
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ if (devmode2.dmPelsWidth == old_devmode.dmPelsWidth
+ && devmode2.dmPelsHeight == old_devmode.dmPelsHeight)
+ {
+ skip("Failed to change display settings of the second monitor.\n");
+ refcount = IDirect3DDevice9_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+ goto done;
+ }
+
+ device_desc.flags = 0;
+ hr = reset_device(device, &device_desc);
+ ok(hr == D3D_OK, "Failed to reset device, hr %#x.\n", hr);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ hr = IDirect3D9_GetAdapterDisplayMode(d3d9, 1, &d3ddm);
+ ok(hr == S_OK, "GetAdapterDisplayMode failed, hr %#x.\n", hr);
+ todo_wine ok(d3ddm.Width == old_devmode.dmPelsWidth, "Expected width %u, got %u.\n",
+ old_devmode.dmPelsWidth, d3ddm.Width);
+ todo_wine ok(d3ddm.Height == old_devmode.dmPelsHeight, "Expected height %u, got %u.\n",
+ old_devmode.dmPelsHeight, d3ddm.Height);
+
+ refcount = IDirect3DDevice9_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations happen for non-primary monitors on device releases */
+ device_desc.adapter_ordinal = D3DADAPTER_DEFAULT;
+ device_desc.device_window = device_window;
+ device_desc.width = registry_mode.dmPelsWidth;
+ device_desc.height = registry_mode.dmPelsHeight;
+ device_desc.flags = CREATE_DEVICE_FULLSCREEN;
+ device = create_device(d3d9, device_window, &device_desc);
+ ok(!!device, "Failed to create a D3D device.\n");
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ refcount = IDirect3DDevice9_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ hr = IDirect3D9_GetAdapterDisplayMode(d3d9, 1, &d3ddm);
+ ok(hr == S_OK, "GetAdapterDisplayMode failed, hr %#x.\n", hr);
+ todo_wine ok(d3ddm.Width == old_devmode.dmPelsWidth, "Expected width %u, got %u.\n",
+ old_devmode.dmPelsWidth, d3ddm.Width);
+ todo_wine ok(d3ddm.Height == old_devmode.dmPelsHeight, "Expected height %u, got %u.\n",
+ old_devmode.dmPelsHeight, d3ddm.Height);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations for non-primary monitors use display settings in the registry */
+ device = create_device(d3d9, device_window, &device_desc);
+ ok(!!device, "Failed to create a D3D device.\n");
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL,
+ CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ refcount = IDirect3DDevice9_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(devmode2.dmPelsWidth == devmode.dmPelsWidth && devmode2.dmPelsHeight == devmode.dmPelsHeight,
+ "Expected resolution %ux%u, got %ux%u.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
+ devmode2.dmPelsWidth, devmode2.dmPelsHeight);
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(devmode2.dmPelsWidth == devmode.dmPelsWidth && devmode2.dmPelsHeight == devmode.dmPelsHeight,
+ "Expected resolution %ux%u, got %ux%u.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
+ devmode2.dmPelsWidth, devmode2.dmPelsHeight);
+ hr = IDirect3D9_GetAdapterDisplayMode(d3d9, 1, &d3ddm);
+ ok(hr == S_OK, "GetAdapterDisplayMode failed, hr %#x.\n", hr);
+ todo_wine ok(d3ddm.Width == devmode.dmPelsWidth && d3ddm.Height == devmode.dmPelsHeight,
+ "Expected resolution %ux%u, got %ux%u.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
+ d3ddm.Width, d3ddm.Height);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test mode restorations when there are two fullscreen devices and one of them got reset */
+ device = create_device(d3d9, focus_window, &device_desc);
+ ok(!!device, "Failed to create a D3D device.\n");
+
+ device_desc2.adapter_ordinal = 1;
+ device_desc2.device_window = device_window;
+ device_desc2.width = d3d_width;
+ device_desc2.height = d3d_height;
+ device_desc2.flags = CREATE_DEVICE_FULLSCREEN;
+ device2 = create_device(d3d9, focus_window, &device_desc2);
+ ok(!!device2, "Failed to create a D3D device.\n");
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ device_desc.flags = 0;
+ hr = reset_device(device, &device_desc);
+ ok(hr == D3D_OK, "Failed to reset device, hr %#x.\n", hr);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ hr = IDirect3D9_GetAdapterDisplayMode(d3d9, 1, &d3ddm);
+ ok(hr == S_OK, "GetAdapterDisplayMode failed, hr %#x.\n", hr);
+ todo_wine ok(d3ddm.Width == old_devmode.dmPelsWidth && d3ddm.Height == old_devmode.dmPelsHeight,
+ "Expected resolution %ux%u, got %ux%u.\n", old_devmode.dmPelsWidth,
+ old_devmode.dmPelsHeight, d3ddm.Width, d3ddm.Height);
+
+ refcount = IDirect3DDevice9_Release(device2);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+ refcount = IDirect3DDevice9_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test mode restoration when there are two fullscreen devices and one of them got released */
+ device_desc.flags = CREATE_DEVICE_FULLSCREEN;
+ device = create_device(d3d9, focus_window, &device_desc);
+ ok(!!device, "Failed to create a D3D device.\n");
+ device2 = create_device(d3d9, focus_window, &device_desc2);
+ ok(!!device2, "Failed to create a D3D device.\n");
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ refcount = IDirect3DDevice9_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ hr = IDirect3D9_GetAdapterDisplayMode(d3d9, 1, &d3ddm);
+ ok(hr == S_OK, "GetAdapterDisplayMode failed, hr %#x.\n", hr);
+ todo_wine ok(d3ddm.Width == old_devmode.dmPelsWidth && d3ddm.Height == old_devmode.dmPelsHeight,
+ "Expected resolution %ux%u, got %ux%u.\n", old_devmode.dmPelsWidth,
+ old_devmode.dmPelsHeight, d3ddm.Width, d3ddm.Height);
+
+ refcount = IDirect3DDevice9_Release(device2);
+ ok(!refcount, "Device has %u references left.\n", refcount);
done:
DestroyWindow(device_window);
DestroyWindow(focus_window);
IDirect3D9_Release(d3d9);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+ heap_free(original_modes);
}
static void test_device_window_reset(void)
--
2.27.0
3
2
Oct. 30, 2020
Mostly to test that when doing mode restoration, all display outputs get restored to their display
settings in the registry, not just one output gets restored.
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/d3d8/tests/device.c | 408 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 398 insertions(+), 10 deletions(-)
diff --git a/dlls/d3d8/tests/device.c b/dlls/d3d8/tests/device.c
index 3e933143332..8d33026d6e5 100644
--- a/dlls/d3d8/tests/device.c
+++ b/dlls/d3d8/tests/device.c
@@ -114,6 +114,77 @@ static BOOL adapter_is_warp(const D3DADAPTER_IDENTIFIER8 *identifier)
return !strcmp(identifier->Driver, "d3d10warp.dll");
}
+static BOOL equal_mode_rect(const DEVMODEW *mode1, const DEVMODEW *mode2)
+{
+ return mode1->dmPosition.x == mode2->dmPosition.x
+ && mode1->dmPosition.y == mode2->dmPosition.y
+ && mode1->dmPelsWidth == mode2->dmPelsWidth
+ && mode1->dmPelsHeight == mode2->dmPelsHeight;
+}
+
+/* Free original_modes after finished using it */
+static BOOL save_display_modes(DEVMODEW **original_modes, unsigned int *display_count)
+{
+ unsigned int number, size = 2, count = 0, index = 0;
+ DISPLAY_DEVICEW display_device;
+ DEVMODEW *modes, *tmp;
+
+ if (!(modes = heap_alloc(size * sizeof(*modes))))
+ return FALSE;
+
+ display_device.cb = sizeof(display_device);
+ while (EnumDisplayDevicesW(NULL, index++, &display_device, 0))
+ {
+ /* Skip software devices */
+ if (swscanf(display_device.DeviceName, L"\\\\.\\DISPLAY%u", &number) != 1)
+ continue;
+
+ if (!(display_device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
+ continue;
+
+ if (count >= size)
+ {
+ size *= 2;
+ if (!(tmp = heap_realloc(modes, size * sizeof(*modes))))
+ {
+ heap_free(modes);
+ return FALSE;
+ }
+ modes = tmp;
+ }
+
+ memset(&modes[count], 0, sizeof(modes[count]));
+ modes[count].dmSize = sizeof(modes[count]);
+ if (!EnumDisplaySettingsW(display_device.DeviceName, ENUM_CURRENT_SETTINGS, &modes[count]))
+ {
+ heap_free(modes);
+ return FALSE;
+ }
+
+ lstrcpyW(modes[count++].dmDeviceName, display_device.DeviceName);
+ }
+
+ *original_modes = modes;
+ *display_count = count;
+ return TRUE;
+}
+
+static BOOL restore_display_modes(DEVMODEW *modes, unsigned int count)
+{
+ unsigned int index;
+ LONG ret;
+
+ for (index = 0; index < count; ++index)
+ {
+ ret = ChangeDisplaySettingsExW(modes[index].dmDeviceName, &modes[index], NULL,
+ CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
+ if (ret != DISP_CHANGE_SUCCESSFUL)
+ return FALSE;
+ }
+ ret = ChangeDisplaySettingsExW(NULL, NULL, NULL, 0, NULL);
+ return ret == DISP_CHANGE_SUCCESSFUL;
+}
+
static IDirect3DDevice8 *create_device(IDirect3D8 *d3d8, HWND focus_window, const struct device_desc *desc)
{
D3DPRESENT_PARAMETERS present_parameters = {0};
@@ -4108,13 +4179,17 @@ static void test_unsupported_shaders(void)
static void test_mode_change(void)
{
+ DEVMODEW old_devmode, devmode, devmode2, *original_modes = NULL;
+ struct device_desc device_desc, device_desc2;
+ WCHAR second_monitor_name[CCHDEVICENAME];
+ IDirect3DDevice8 *device, *device2;
+ unsigned int display_count = 0;
RECT d3d_rect, focus_rect, r;
- struct device_desc device_desc;
IDirect3DSurface8 *backbuffer;
- IDirect3DDevice8 *device;
+ MONITORINFOEXW monitor_info;
+ HMONITOR second_monitor;
D3DSURFACE_DESC desc;
IDirect3D8 *d3d8;
- DEVMODEW devmode;
ULONG refcount;
UINT adapter_mode_count, i;
HRESULT hr;
@@ -4123,6 +4198,15 @@ static void test_mode_change(void)
D3DDISPLAYMODE d3ddm;
DWORD d3d_width = 0, d3d_height = 0, user32_width = 0, user32_height = 0;
+ memset(&devmode, 0, sizeof(devmode));
+ devmode.dmSize = sizeof(devmode);
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(equal_mode_rect(&devmode, ®istry_mode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(equal_mode_rect(&devmode, ®istry_mode), "Got a different mode.\n");
+
d3d8 = Direct3DCreate8(D3D_SDK_VERSION);
ok(!!d3d8, "Failed to create a D3D object.\n");
@@ -4177,6 +4261,9 @@ static void test_mode_change(void)
return;
}
+ ret = save_display_modes(&original_modes, &display_count);
+ ok(ret, "Failed to save original display modes.\n");
+
memset(&devmode, 0, sizeof(devmode));
devmode.dmSize = sizeof(devmode);
devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
@@ -4203,8 +4290,6 @@ static void test_mode_change(void)
if (!(device = create_device(d3d8, focus_window, &device_desc)))
{
skip("Failed to create a D3D device, skipping tests.\n");
- change_ret = ChangeDisplaySettingsW(NULL, CDS_FULLSCREEN);
- ok(change_ret == DISP_CHANGE_SUCCESSFUL, "Failed to change display mode, ret %#x.\n", change_ret);
goto done;
}
@@ -4258,6 +4343,7 @@ static void test_mode_change(void)
device_desc.flags = CREATE_DEVICE_FULLSCREEN;
ok(!!(device = create_device(d3d8, focus_window, &device_desc)), "Failed to create a D3D device.\n");
+ devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
devmode.dmPelsWidth = user32_width;
devmode.dmPelsHeight = user32_height;
change_ret = ChangeDisplaySettingsW(&devmode, CDS_FULLSCREEN);
@@ -4266,17 +4352,319 @@ static void test_mode_change(void)
refcount = IDirect3DDevice8_Release(device);
ok(!refcount, "Device has %u references left.\n", refcount);
- ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
+ memset(&devmode2, 0, sizeof(devmode2));
+ devmode2.dmSize = sizeof(devmode2);
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
ok(ret, "Failed to get display mode.\n");
- ok(devmode.dmPelsWidth == registry_mode.dmPelsWidth
- && devmode.dmPelsHeight == registry_mode.dmPelsHeight,
- "Expected resolution %ux%u, got %ux%u.\n",
- registry_mode.dmPelsWidth, registry_mode.dmPelsHeight, devmode.dmPelsWidth, devmode.dmPelsHeight);
+ ok(devmode2.dmPelsWidth == registry_mode.dmPelsWidth
+ && devmode2.dmPelsHeight == registry_mode.dmPelsHeight,
+ "Expected resolution %ux%u, got %ux%u.\n", registry_mode.dmPelsWidth,
+ registry_mode.dmPelsHeight, devmode2.dmPelsWidth, devmode2.dmPelsHeight);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that no mode restorations if no mode changes happened */
+ change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
+
+ device_desc.adapter_ordinal = D3DADAPTER_DEFAULT;
+ device_desc.device_window = device_window;
+ device_desc.width = d3d_width;
+ device_desc.height = d3d_height;
+ device_desc.flags = 0;
+ device = create_device(d3d8, device_window, &device_desc);
+ ok(!!device, "Failed to create a D3D device.\n");
+ refcount = IDirect3DDevice8_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(equal_mode_rect(&devmode2, ®istry_mode), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations use display settings in the registry with a fullscreen device */
+ change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
+
+ device_desc.adapter_ordinal = D3DADAPTER_DEFAULT;
+ device_desc.device_window = device_window;
+ device_desc.width = registry_mode.dmPelsWidth;
+ device_desc.height = registry_mode.dmPelsHeight;
+ device_desc.flags = CREATE_DEVICE_FULLSCREEN;
+ device = create_device(d3d8, device_window, &device_desc);
+ ok(!!device, "Failed to create a D3D device.\n");
+ refcount = IDirect3DDevice8_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(equal_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(equal_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations use display settings in the registry with a fullscreen device
+ * having the same display mode and then reset to a different mode */
+ change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
+
+ device_desc.adapter_ordinal = D3DADAPTER_DEFAULT;
+ device_desc.device_window = device_window;
+ device_desc.width = registry_mode.dmPelsWidth;
+ device_desc.height = registry_mode.dmPelsHeight;
+ device_desc.flags = CREATE_DEVICE_FULLSCREEN;
+ device = create_device(d3d8, device_window, &device_desc);
+ ok(!!device, "Failed to create a D3D device.\n");
+
+ device_desc.width = d3d_width;
+ device_desc.height = d3d_height;
+ hr = reset_device(device, &device_desc);
+ ok(hr == D3D_OK, "Failed to reset device, hr %#x.\n", hr);
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(devmode2.dmPelsWidth == d3d_width && devmode2.dmPelsHeight == d3d_height,
+ "Expected resolution %ux%u, got %ux%u.\n", d3d_width, d3d_height,
+ devmode2.dmPelsWidth, devmode2.dmPelsHeight);
+
+ refcount = IDirect3DDevice8_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(equal_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(equal_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ if (IDirect3D8_GetAdapterCount(d3d8) < 2)
+ {
+ skip("Following tests require two adapters.\n");
+ goto done;
+ }
+
+ second_monitor = IDirect3D8_GetAdapterMonitor(d3d8, 1);
+ monitor_info.cbSize = sizeof(monitor_info);
+ ret = GetMonitorInfoW(second_monitor, (MONITORINFO *)&monitor_info);
+ ok(ret, "GetMonitorInfoW failed, error %#x.\n", GetLastError());
+ lstrcpyW(second_monitor_name, monitor_info.szDevice);
+
+ memset(&old_devmode, 0, sizeof(old_devmode));
+ old_devmode.dmSize = sizeof(old_devmode);
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &old_devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+
+ i = 0;
+ d3d_width = 0;
+ d3d_height = 0;
+ user32_width = 0;
+ user32_height = 0;
+ while (EnumDisplaySettingsW(second_monitor_name, i++, &devmode))
+ {
+ if (devmode.dmPelsWidth == old_devmode.dmPelsWidth
+ && devmode.dmPelsHeight == old_devmode.dmPelsHeight)
+ continue;
+
+ if (!d3d_width && !d3d_height)
+ {
+ d3d_width = devmode.dmPelsWidth;
+ d3d_height = devmode.dmPelsHeight;
+ continue;
+ }
+
+ if (devmode.dmPelsWidth == d3d_width && devmode.dmPelsHeight == d3d_height)
+ continue;
+
+ user32_width = devmode.dmPelsWidth;
+ user32_height = devmode.dmPelsHeight;
+ break;
+ }
+ if (!user32_width || !user32_height)
+ {
+ skip("Failed to find three different display modes for the second monitor.\n");
+ goto done;
+ }
+
+ /* Test that mode restorations also happen for non-primary monitors on device resets */
+ device_desc.adapter_ordinal = D3DADAPTER_DEFAULT;
+ device_desc.device_window = device_window;
+ device_desc.width = registry_mode.dmPelsWidth;
+ device_desc.height = registry_mode.dmPelsHeight;
+ device_desc.flags = CREATE_DEVICE_FULLSCREEN;
+ device = create_device(d3d8, device_window, &device_desc);
+ ok(!!device, "Failed to create a D3D device.\n");
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ if (devmode2.dmPelsWidth == old_devmode.dmPelsWidth
+ && devmode2.dmPelsHeight == old_devmode.dmPelsHeight)
+ {
+ skip("Failed to change display settings of the second monitor.\n");
+ refcount = IDirect3DDevice8_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+ goto done;
+ }
+
+ device_desc.flags = 0;
+ hr = reset_device(device, &device_desc);
+ ok(hr == D3D_OK, "Failed to reset device, hr %#x.\n", hr);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ hr = IDirect3D8_GetAdapterDisplayMode(d3d8, 1, &d3ddm);
+ ok(hr == S_OK, "GetAdapterDisplayMode failed, hr %#x.\n", hr);
+ todo_wine ok(d3ddm.Width == old_devmode.dmPelsWidth, "Expected width %u, got %u.\n",
+ old_devmode.dmPelsWidth, d3ddm.Width);
+ todo_wine ok(d3ddm.Height == old_devmode.dmPelsHeight, "Expected height %u, got %u.\n",
+ old_devmode.dmPelsHeight, d3ddm.Height);
+
+ refcount = IDirect3DDevice8_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations happen for non-primary monitors on device releases */
+ device_desc.adapter_ordinal = D3DADAPTER_DEFAULT;
+ device_desc.device_window = device_window;
+ device_desc.width = registry_mode.dmPelsWidth;
+ device_desc.height = registry_mode.dmPelsHeight;
+ device_desc.flags = CREATE_DEVICE_FULLSCREEN;
+ device = create_device(d3d8, device_window, &device_desc);
+ ok(!!device, "Failed to create a D3D device.\n");
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ refcount = IDirect3DDevice8_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ hr = IDirect3D8_GetAdapterDisplayMode(d3d8, 1, &d3ddm);
+ ok(hr == S_OK, "GetAdapterDisplayMode failed, hr %#x.\n", hr);
+ todo_wine ok(d3ddm.Width == old_devmode.dmPelsWidth, "Expected width %u, got %u.\n",
+ old_devmode.dmPelsWidth, d3ddm.Width);
+ todo_wine ok(d3ddm.Height == old_devmode.dmPelsHeight, "Expected height %u, got %u.\n",
+ old_devmode.dmPelsHeight, d3ddm.Height);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations for non-primary monitors use display settings in the registry */
+ device = create_device(d3d8, device_window, &device_desc);
+ ok(!!device, "Failed to create a D3D device.\n");
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL,
+ CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ refcount = IDirect3DDevice8_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(devmode2.dmPelsWidth == devmode.dmPelsWidth && devmode2.dmPelsHeight == devmode.dmPelsHeight,
+ "Expected resolution %ux%u, got %ux%u.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
+ devmode2.dmPelsWidth, devmode2.dmPelsHeight);
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(devmode2.dmPelsWidth == devmode.dmPelsWidth && devmode2.dmPelsHeight == devmode.dmPelsHeight,
+ "Expected resolution %ux%u, got %ux%u.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
+ devmode2.dmPelsWidth, devmode2.dmPelsHeight);
+ hr = IDirect3D8_GetAdapterDisplayMode(d3d8, 1, &d3ddm);
+ ok(hr == S_OK, "GetAdapterDisplayMode failed, hr %#x.\n", hr);
+ todo_wine ok(d3ddm.Width == devmode.dmPelsWidth && d3ddm.Height == devmode.dmPelsHeight,
+ "Expected resolution %ux%u, got %ux%u.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
+ d3ddm.Width, d3ddm.Height);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test mode restorations when there are two fullscreen devices and one of them got reset */
+ device = create_device(d3d8, focus_window, &device_desc);
+ ok(!!device, "Failed to create a D3D device.\n");
+
+ device_desc2.adapter_ordinal = 1;
+ device_desc2.device_window = device_window;
+ device_desc2.width = d3d_width;
+ device_desc2.height = d3d_height;
+ device_desc2.flags = CREATE_DEVICE_FULLSCREEN;
+ device2 = create_device(d3d8, focus_window, &device_desc2);
+ ok(!!device2, "Failed to create a D3D device.\n");
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ device_desc.flags = 0;
+ hr = reset_device(device, &device_desc);
+ ok(hr == D3D_OK, "Failed to reset device, hr %#x.\n", hr);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ hr = IDirect3D8_GetAdapterDisplayMode(d3d8, 1, &d3ddm);
+ ok(hr == S_OK, "GetAdapterDisplayMode failed, hr %#x.\n", hr);
+ todo_wine ok(d3ddm.Width == old_devmode.dmPelsWidth && d3ddm.Height == old_devmode.dmPelsHeight,
+ "Expected resolution %ux%u, got %ux%u.\n", old_devmode.dmPelsWidth,
+ old_devmode.dmPelsHeight, d3ddm.Width, d3ddm.Height);
+
+ refcount = IDirect3DDevice8_Release(device2);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+ refcount = IDirect3DDevice8_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test mode restoration when there are two fullscreen devices and one of them got released */
+ device_desc.flags = CREATE_DEVICE_FULLSCREEN;
+ device = create_device(d3d8, focus_window, &device_desc);
+ ok(!!device, "Failed to create a D3D device.\n");
+ device2 = create_device(d3d8, focus_window, &device_desc2);
+ ok(!!device2, "Failed to create a D3D device.\n");
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ refcount = IDirect3DDevice8_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(equal_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ hr = IDirect3D8_GetAdapterDisplayMode(d3d8, 1, &d3ddm);
+ ok(hr == S_OK, "GetAdapterDisplayMode failed, hr %#x.\n", hr);
+ todo_wine ok(d3ddm.Width == old_devmode.dmPelsWidth && d3ddm.Height == old_devmode.dmPelsHeight,
+ "Expected resolution %ux%u, got %ux%u.\n", old_devmode.dmPelsWidth,
+ old_devmode.dmPelsHeight, d3ddm.Width, d3ddm.Height);
+
+ refcount = IDirect3DDevice8_Release(device2);
+ ok(!refcount, "Device has %u references left.\n", refcount);
done:
DestroyWindow(device_window);
DestroyWindow(focus_window);
IDirect3D8_Release(d3d8);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+ heap_free(original_modes);
}
static void test_device_window_reset(void)
--
2.27.0
3
2
Oct. 30, 2020
Mostly to test that when doing mode restoration, all display outputs get restored to their display
settings in the registry, not just one output gets restored.
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/ddraw/tests/ddraw1.c | 396 ++++++++++++++++++++++++++++++++++++-
dlls/ddraw/tests/ddraw2.c | 397 +++++++++++++++++++++++++++++++++++++-
dlls/ddraw/tests/ddraw4.c | 396 ++++++++++++++++++++++++++++++++++++-
dlls/ddraw/tests/ddraw7.c | 396 ++++++++++++++++++++++++++++++++++++-
4 files changed, 1581 insertions(+), 4 deletions(-)
diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c
index 63791c5b606..783c1b961a0 100644
--- a/dlls/ddraw/tests/ddraw1.c
+++ b/dlls/ddraw/tests/ddraw1.c
@@ -265,6 +265,69 @@ static IDirectDrawSurface *get_depth_stencil(IDirect3DDevice *device)
return ret;
}
+/* Free original_modes after finished using it */
+static BOOL save_display_modes(DEVMODEW **original_modes, unsigned int *display_count)
+{
+ unsigned int number, size = 2, count = 0, index = 0;
+ DISPLAY_DEVICEW display_device;
+ DEVMODEW *modes, *tmp;
+
+ if (!(modes = heap_alloc(size * sizeof(*modes))))
+ return FALSE;
+
+ display_device.cb = sizeof(display_device);
+ while (EnumDisplayDevicesW(NULL, index++, &display_device, 0))
+ {
+ /* Skip software devices */
+ if (swscanf(display_device.DeviceName, L"\\\\.\\DISPLAY%u", &number) != 1)
+ continue;
+
+ if (!(display_device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
+ continue;
+
+ if (count >= size)
+ {
+ size *= 2;
+ if (!(tmp = heap_realloc(modes, size * sizeof(*modes))))
+ {
+ heap_free(modes);
+ return FALSE;
+ }
+ modes = tmp;
+ }
+
+ memset(&modes[count], 0, sizeof(modes[count]));
+ modes[count].dmSize = sizeof(modes[count]);
+ if (!EnumDisplaySettingsW(display_device.DeviceName, ENUM_CURRENT_SETTINGS, &modes[count]))
+ {
+ heap_free(modes);
+ return FALSE;
+ }
+
+ lstrcpyW(modes[count++].dmDeviceName, display_device.DeviceName);
+ }
+
+ *original_modes = modes;
+ *display_count = count;
+ return TRUE;
+}
+
+static BOOL restore_display_modes(DEVMODEW *modes, unsigned int count)
+{
+ unsigned int index;
+ LONG ret;
+
+ for (index = 0; index < count; ++index)
+ {
+ ret = ChangeDisplaySettingsExW(modes[index].dmDeviceName, &modes[index], NULL,
+ CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
+ if (ret != DISP_CHANGE_SUCCESSFUL)
+ return FALSE;
+ }
+ ret = ChangeDisplaySettingsExW(NULL, NULL, NULL, 0, NULL);
+ return ret == DISP_CHANGE_SUCCESSFUL;
+}
+
static HRESULT set_display_mode(IDirectDraw *ddraw, DWORD width, DWORD height)
{
if (SUCCEEDED(IDirectDraw_SetDisplayMode(ddraw, width, height, 32)))
@@ -1301,6 +1364,14 @@ static void test_coop_level_threaded(void)
IDirectDraw_Release(ddraw);
}
+static BOOL compare_mode_rect(const DEVMODEW *mode1, const DEVMODEW *mode2)
+{
+ return mode1->dmPosition.x == mode2->dmPosition.x
+ && mode1->dmPosition.y == mode2->dmPosition.y
+ && mode1->dmPelsWidth == mode2->dmPelsWidth
+ && mode1->dmPelsHeight == mode2->dmPelsHeight;
+}
+
static ULONG get_refcount(IUnknown *test_iface)
{
IUnknown_AddRef(test_iface);
@@ -2630,6 +2701,8 @@ static HRESULT CALLBACK test_coop_level_mode_set_enum_cb(DDSURFACEDESC *surface_
static void test_coop_level_mode_set(void)
{
+ DEVMODEW *original_modes = NULL, devmode, devmode2;
+ unsigned int display_count = 0;
IDirectDrawSurface *primary;
RECT registry_rect, ddraw_rect, user32_rect, r;
IDirectDraw *ddraw;
@@ -2640,7 +2713,6 @@ static void test_coop_level_mode_set(void)
ULONG ref;
MSG msg;
struct test_coop_level_mode_set_enum_param param;
- DEVMODEW devmode;
BOOL ret;
LONG change_ret;
@@ -2716,6 +2788,18 @@ static void test_coop_level_mode_set(void)
{0, FALSE, 0},
};
+ memset(&devmode, 0, sizeof(devmode));
+ devmode.dmSize = sizeof(devmode);
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode, ®istry_mode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode, ®istry_mode), "Got a different mode.\n");
+
+ ret = save_display_modes(&original_modes, &display_count);
+ ok(ret, "Failed to save original display modes.\n");
+
ddraw = create_ddraw();
ok(!!ddraw, "Failed to create a ddraw object.\n");
@@ -2728,6 +2812,7 @@ static void test_coop_level_mode_set(void)
if (!param.user32_height)
{
skip("Fewer than 3 different modes supported, skipping mode restore test.\n");
+ heap_free(original_modes);
return;
}
@@ -3315,19 +3400,125 @@ static void test_coop_level_mode_set(void)
ok(EqualRect(&r, &ddraw_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&ddraw_rect),
wine_dbgstr_rect(&r));
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that no mode restorations if no mode changes happened */
+ devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
+ devmode.dmPelsWidth = param.user32_width;
+ devmode.dmPelsHeight = param.user32_height;
+ change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
+
+ ddraw = create_ddraw();
+ ok(!!ddraw, "Failed to create a ddraw object.\n");
+ ref = IDirectDraw_Release(ddraw);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ memset(&devmode2, 0, sizeof(devmode2));
+ devmode2.dmSize = sizeof(devmode2);
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, ®istry_mode), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that no mode restorations if no mode changes happened with fullscreen ddraw objects */
+ change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
+
+ ddraw = create_ddraw();
+ ok(!!ddraw, "Failed to create a ddraw object.\n");
+ hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
+ ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#x.\n", hr);
+ hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
+ ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#x.\n", hr);
+ ref = IDirectDraw_Release(ddraw);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, ®istry_mode), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations use display settings in the registry after ddraw object releases
+ * if SetDisplayMode() was called */
+ ddraw = create_ddraw();
+ ok(!!ddraw, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw, registry_mode.dmPelsWidth, registry_mode.dmPelsHeight);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
+
+ ref = IDirectDraw_Release(ddraw);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations use display settings in the registry after RestoreDisplayMode() */
+ ddraw = create_ddraw();
+ ok(!!ddraw, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw, param.ddraw_width, param.ddraw_height);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
+
+ hr = IDirectDraw_RestoreDisplayMode(ddraw);
+ ok(hr == DD_OK, "RestoreDisplayMode failed, hr %#x.\n", hr);
+
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+
+ ref = IDirectDraw_Release(ddraw);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
done:
expect_messages = NULL;
DestroyWindow(window);
UnregisterClassA("ddraw_test_wndproc_wc", GetModuleHandleA(NULL));
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+ heap_free(original_modes);
}
static void test_coop_level_mode_set_multi(void)
{
+ DEVMODEW old_devmode, devmode, devmode2, devmode3, *original_modes = NULL;
+ unsigned int mode_idx = 0, display_idx, display_count = 0;
+ WCHAR second_monitor_name[CCHDEVICENAME];
IDirectDraw *ddraw1, *ddraw2;
+ LONG change_ret;
UINT w, h;
HWND window;
HRESULT hr;
ULONG ref;
+ BOOL ret;
+
+ memset(&devmode, 0, sizeof(devmode));
+ devmode.dmSize = sizeof(devmode);
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode, ®istry_mode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode, ®istry_mode), "Got a different mode.\n");
+
+ ret = save_display_modes(&original_modes, &display_count);
+ ok(ret, "Failed to save original display modes.\n");
window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
0, 0, 100, 100, 0, 0, 0, 0);
@@ -3509,7 +3700,210 @@ static void test_coop_level_mode_set_multi(void)
h = GetSystemMetrics(SM_CYSCREEN);
ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
+ if (display_count < 2)
+ {
+ skip("Following tests require two monitors.\n");
+ goto done;
+ }
+
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ second_monitor_name[0] = '\0';
+ for (display_idx = 0; display_idx < display_count; ++display_idx)
+ {
+ if (original_modes[display_idx].dmPosition.x || original_modes[display_idx].dmPosition.y)
+ {
+ lstrcpyW(second_monitor_name, original_modes[display_idx].dmDeviceName);
+ break;
+ }
+ }
+ ok(lstrlenW(second_monitor_name), "Got an empty second monitor name.\n");
+ memset(&old_devmode, 0, sizeof(old_devmode));
+ old_devmode.dmSize = sizeof(old_devmode);
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &old_devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+
+ devmode = old_devmode;
+ while (EnumDisplaySettingsW(second_monitor_name, mode_idx++, &devmode))
+ {
+ if (devmode.dmPelsWidth != old_devmode.dmPelsWidth
+ || devmode.dmPelsHeight != old_devmode.dmPelsHeight)
+ break;
+ }
+ ok(devmode.dmPelsWidth != old_devmode.dmPelsWidth
+ || devmode.dmPelsHeight != old_devmode.dmPelsHeight,
+ "Failed to find a different mode for the second monitor.\n");
+
+ /* Test that no mode restorations for non-primary monitors if SetDisplayMode() was not called */
+ ddraw1 = create_ddraw();
+ ok(!!ddraw1, "Failed to create a ddraw object.\n");
+ hr = IDirectDraw_SetCooperativeLevel(ddraw1, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
+ ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ memset(&devmode2, 0, sizeof(devmode2));
+ devmode2.dmSize = sizeof(devmode2);
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ if (compare_mode_rect(&devmode2, &old_devmode))
+ {
+ skip("Failed to change display settings of the second monitor.\n");
+ ref = IDirectDraw_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+ goto done;
+ }
+
+ hr = IDirectDraw_SetCooperativeLevel(ddraw1, window, DDSCL_NORMAL);
+ ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#x.\n", hr);
+ ref = IDirectDraw_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ memset(&devmode3, 0, sizeof(devmode3));
+ devmode3.dmSize = sizeof(devmode3);
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode3);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode3, &devmode2), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations happen for non-primary monitors on ddraw releases if
+ * SetDisplayMode() was called */
+ ddraw1 = create_ddraw();
+ ok(!!ddraw1, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw1, 800, 600);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ ref = IDirectDraw_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations happen for non-primary monitors as well */
+ ddraw1 = create_ddraw();
+ ok(!!ddraw1, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw1, 800, 600);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ hr = IDirectDraw_RestoreDisplayMode(ddraw1);
+ ok(hr == DD_OK, "RestoreDisplayMode failed, hr %#x.\n", hr);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+
+ ref = IDirectDraw_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations for non-primary monitors use display settings in the registry */
+ ddraw1 = create_ddraw();
+ ok(!!ddraw1, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw1, 800, 600);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL,
+ CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ ref = IDirectDraw_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(devmode2.dmPelsWidth == devmode.dmPelsWidth && devmode2.dmPelsHeight == devmode.dmPelsHeight,
+ "Expected resolution %ux%u, got %ux%u.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
+ devmode2.dmPelsWidth, devmode2.dmPelsHeight);
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(devmode2.dmPelsWidth == devmode.dmPelsWidth && devmode2.dmPelsHeight == devmode.dmPelsHeight,
+ "Expected resolution %ux%u, got %ux%u.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
+ devmode2.dmPelsWidth, devmode2.dmPelsHeight);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test mode restorations for non-primary monitors when there are multiple fullscreen ddraw
+ * objects and one of them restores display mode */
+ ddraw1 = create_ddraw();
+ ok(!!ddraw1, "Failed to create a ddraw object.\n");
+ ddraw2 = create_ddraw();
+ ok(!!ddraw2, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw1, 800, 600);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+ hr = set_display_mode(ddraw2, 640, 480);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ hr = IDirectDraw_RestoreDisplayMode(ddraw2);
+ ok(hr == DD_OK, "RestoreDisplayMode failed, hr %#x.\n", hr);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+
+ ref = IDirectDraw_Release(ddraw2);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+ ref = IDirectDraw_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test mode restorations for non-primary monitors when there are multiple fullscreen ddraw
+ * objects and one of them got released */
+ ddraw1 = create_ddraw();
+ ok(!!ddraw1, "Failed to create a ddraw object.\n");
+ ddraw2 = create_ddraw();
+ ok(!!ddraw2, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw1, 800, 600);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+ hr = set_display_mode(ddraw2, 640, 480);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ ref = IDirectDraw_Release(ddraw2);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+
+ ref = IDirectDraw_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+done:
DestroyWindow(window);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+ heap_free(original_modes);
}
static void test_initialize(void)
diff --git a/dlls/ddraw/tests/ddraw2.c b/dlls/ddraw/tests/ddraw2.c
index 4b83230de1f..23d3e0c1f02 100644
--- a/dlls/ddraw/tests/ddraw2.c
+++ b/dlls/ddraw/tests/ddraw2.c
@@ -22,6 +22,7 @@
#define COBJMACROS
#include "wine/test.h"
+#include "wine/heap.h"
#include <limits.h>
#include <math.h>
#include "ddrawi.h"
@@ -261,6 +262,69 @@ static IDirectDrawSurface *get_depth_stencil(IDirect3DDevice2 *device)
return ret;
}
+/* Free original_modes after finished using it */
+static BOOL save_display_modes(DEVMODEW **original_modes, unsigned int *display_count)
+{
+ unsigned int number, size = 2, count = 0, index = 0;
+ DISPLAY_DEVICEW display_device;
+ DEVMODEW *modes, *tmp;
+
+ if (!(modes = heap_alloc(size * sizeof(*modes))))
+ return FALSE;
+
+ display_device.cb = sizeof(display_device);
+ while (EnumDisplayDevicesW(NULL, index++, &display_device, 0))
+ {
+ /* Skip software devices */
+ if (swscanf(display_device.DeviceName, L"\\\\.\\DISPLAY%u", &number) != 1)
+ continue;
+
+ if (!(display_device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
+ continue;
+
+ if (count >= size)
+ {
+ size *= 2;
+ if (!(tmp = heap_realloc(modes, size * sizeof(*modes))))
+ {
+ heap_free(modes);
+ return FALSE;
+ }
+ modes = tmp;
+ }
+
+ memset(&modes[count], 0, sizeof(modes[count]));
+ modes[count].dmSize = sizeof(modes[count]);
+ if (!EnumDisplaySettingsW(display_device.DeviceName, ENUM_CURRENT_SETTINGS, &modes[count]))
+ {
+ heap_free(modes);
+ return FALSE;
+ }
+
+ lstrcpyW(modes[count++].dmDeviceName, display_device.DeviceName);
+ }
+
+ *original_modes = modes;
+ *display_count = count;
+ return TRUE;
+}
+
+static BOOL restore_display_modes(DEVMODEW *modes, unsigned int count)
+{
+ unsigned int index;
+ LONG ret;
+
+ for (index = 0; index < count; ++index)
+ {
+ ret = ChangeDisplaySettingsExW(modes[index].dmDeviceName, &modes[index], NULL,
+ CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
+ if (ret != DISP_CHANGE_SUCCESSFUL)
+ return FALSE;
+ }
+ ret = ChangeDisplaySettingsExW(NULL, NULL, NULL, 0, NULL);
+ return ret == DISP_CHANGE_SUCCESSFUL;
+}
+
static HRESULT set_display_mode(IDirectDraw2 *ddraw, DWORD width, DWORD height)
{
if (SUCCEEDED(IDirectDraw2_SetDisplayMode(ddraw, width, height, 32, 0, 0)))
@@ -1458,6 +1522,14 @@ done:
if (ddraw) IDirectDraw2_Release(ddraw);
}
+static BOOL compare_mode_rect(const DEVMODEW *mode1, const DEVMODEW *mode2)
+{
+ return mode1->dmPosition.x == mode2->dmPosition.x
+ && mode1->dmPosition.y == mode2->dmPosition.y
+ && mode1->dmPelsWidth == mode2->dmPelsWidth
+ && mode1->dmPelsHeight == mode2->dmPelsHeight;
+}
+
static ULONG get_refcount(IUnknown *test_iface)
{
IUnknown_AddRef(test_iface);
@@ -2694,6 +2766,8 @@ static HRESULT CALLBACK test_coop_level_mode_set_enum_cb(DDSURFACEDESC *surface_
static void test_coop_level_mode_set(void)
{
+ DEVMODEW *original_modes = NULL, devmode, devmode2;
+ unsigned int display_count = 0;
IDirectDrawSurface *primary;
RECT registry_rect, ddraw_rect, user32_rect, r;
IDirectDraw2 *ddraw;
@@ -2704,7 +2778,6 @@ static void test_coop_level_mode_set(void)
ULONG ref;
MSG msg;
struct test_coop_level_mode_set_enum_param param;
- DEVMODEW devmode;
BOOL ret;
LONG change_ret;
@@ -2780,6 +2853,18 @@ static void test_coop_level_mode_set(void)
{0, FALSE, 0},
};
+ memset(&devmode, 0, sizeof(devmode));
+ devmode.dmSize = sizeof(devmode);
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode, ®istry_mode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode, ®istry_mode), "Got a different mode.\n");
+
+ ret = save_display_modes(&original_modes, &display_count);
+ ok(ret, "Failed to save original display modes.\n");
+
ddraw = create_ddraw();
ok(!!ddraw, "Failed to create a ddraw object.\n");
@@ -2792,6 +2877,7 @@ static void test_coop_level_mode_set(void)
if (!param.user32_height)
{
skip("Fewer than 3 different modes supported, skipping mode restore test.\n");
+ heap_free(original_modes);
return;
}
@@ -3472,21 +3558,127 @@ static void test_coop_level_mode_set(void)
ok(EqualRect(&r, &ddraw_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&ddraw_rect),
wine_dbgstr_rect(&r));
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that no mode restorations if no mode changes happened */
+ devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
+ devmode.dmPelsWidth = param.user32_width;
+ devmode.dmPelsHeight = param.user32_height;
+ change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
+
+ ddraw = create_ddraw();
+ ok(!!ddraw, "Failed to create a ddraw object.\n");
+ ref = IDirectDraw2_Release(ddraw);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ memset(&devmode2, 0, sizeof(devmode2));
+ devmode2.dmSize = sizeof(devmode2);
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, ®istry_mode), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that no mode restorations if no mode changes happened with fullscreen ddraw objects */
+ change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
+
+ ddraw = create_ddraw();
+ ok(!!ddraw, "Failed to create a ddraw object.\n");
+ hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
+ ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#x.\n", hr);
+ hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
+ ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#x.\n", hr);
+ ref = IDirectDraw2_Release(ddraw);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, ®istry_mode), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations use display settings in the registry after ddraw object releases
+ * if SetDisplayMode() was called */
+ ddraw = create_ddraw();
+ ok(!!ddraw, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw, registry_mode.dmPelsWidth, registry_mode.dmPelsHeight);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
+
+ ref = IDirectDraw2_Release(ddraw);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations use display settings in the registry after RestoreDisplayMode() */
+ ddraw = create_ddraw();
+ ok(!!ddraw, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw, param.ddraw_width, param.ddraw_height);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
+
+ hr = IDirectDraw2_RestoreDisplayMode(ddraw);
+ ok(hr == DD_OK, "RestoreDisplayMode failed, hr %#x.\n", hr);
+
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+
+ ref = IDirectDraw2_Release(ddraw);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
done:
expect_messages = NULL;
DestroyWindow(window);
DestroyWindow(window2);
UnregisterClassA("ddraw_test_wndproc_wc", GetModuleHandleA(NULL));
UnregisterClassA("ddraw_test_wndproc_wc2", GetModuleHandleA(NULL));
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+ heap_free(original_modes);
}
static void test_coop_level_mode_set_multi(void)
{
+ DEVMODEW old_devmode, devmode, devmode2, devmode3, *original_modes = NULL;
+ unsigned int mode_idx = 0, display_idx, display_count = 0;
+ WCHAR second_monitor_name[CCHDEVICENAME];
IDirectDraw2 *ddraw1, *ddraw2;
+ LONG change_ret;
UINT w, h;
HWND window;
HRESULT hr;
ULONG ref;
+ BOOL ret;
+
+ memset(&devmode, 0, sizeof(devmode));
+ devmode.dmSize = sizeof(devmode);
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode, ®istry_mode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode, ®istry_mode), "Got a different mode.\n");
+
+ ret = save_display_modes(&original_modes, &display_count);
+ ok(ret, "Failed to save original display modes.\n");
window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
0, 0, 100, 100, 0, 0, 0, 0);
@@ -3668,7 +3860,210 @@ static void test_coop_level_mode_set_multi(void)
h = GetSystemMetrics(SM_CYSCREEN);
ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
+ if (display_count < 2)
+ {
+ skip("Following tests require two monitors.\n");
+ goto done;
+ }
+
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ second_monitor_name[0] = '\0';
+ for (display_idx = 0; display_idx < display_count; ++display_idx)
+ {
+ if (original_modes[display_idx].dmPosition.x || original_modes[display_idx].dmPosition.y)
+ {
+ lstrcpyW(second_monitor_name, original_modes[display_idx].dmDeviceName);
+ break;
+ }
+ }
+ ok(lstrlenW(second_monitor_name), "Got an empty second monitor name.\n");
+ memset(&old_devmode, 0, sizeof(old_devmode));
+ old_devmode.dmSize = sizeof(old_devmode);
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &old_devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+
+ devmode = old_devmode;
+ while (EnumDisplaySettingsW(second_monitor_name, mode_idx++, &devmode))
+ {
+ if (devmode.dmPelsWidth != old_devmode.dmPelsWidth
+ || devmode.dmPelsHeight != old_devmode.dmPelsHeight)
+ break;
+ }
+ ok(devmode.dmPelsWidth != old_devmode.dmPelsWidth
+ || devmode.dmPelsHeight != old_devmode.dmPelsHeight,
+ "Failed to find a different mode for the second monitor.\n");
+
+ /* Test that no mode restorations for non-primary monitors if SetDisplayMode() was not called */
+ ddraw1 = create_ddraw();
+ ok(!!ddraw1, "Failed to create a ddraw object.\n");
+ hr = IDirectDraw2_SetCooperativeLevel(ddraw1, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
+ ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ memset(&devmode2, 0, sizeof(devmode2));
+ devmode2.dmSize = sizeof(devmode2);
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ if (compare_mode_rect(&devmode2, &old_devmode))
+ {
+ skip("Failed to change display settings of the second monitor.\n");
+ ref = IDirectDraw2_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+ goto done;
+ }
+
+ hr = IDirectDraw2_SetCooperativeLevel(ddraw1, window, DDSCL_NORMAL);
+ ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#x.\n", hr);
+ ref = IDirectDraw2_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ memset(&devmode3, 0, sizeof(devmode3));
+ devmode3.dmSize = sizeof(devmode3);
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode3);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode3, &devmode2), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations happen for non-primary monitors on ddraw releases if
+ * SetDisplayMode() was called */
+ ddraw1 = create_ddraw();
+ ok(!!ddraw1, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw1, 800, 600);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ ref = IDirectDraw2_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations happen for non-primary monitors as well */
+ ddraw1 = create_ddraw();
+ ok(!!ddraw1, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw1, 800, 600);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ hr = IDirectDraw2_RestoreDisplayMode(ddraw1);
+ ok(hr == DD_OK, "RestoreDisplayMode failed, hr %#x.\n", hr);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+
+ ref = IDirectDraw2_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations for non-primary monitors use display settings in the registry */
+ ddraw1 = create_ddraw();
+ ok(!!ddraw1, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw1, 800, 600);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL,
+ CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ ref = IDirectDraw2_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(devmode2.dmPelsWidth == devmode.dmPelsWidth && devmode2.dmPelsHeight == devmode.dmPelsHeight,
+ "Expected resolution %ux%u, got %ux%u.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
+ devmode2.dmPelsWidth, devmode2.dmPelsHeight);
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(devmode2.dmPelsWidth == devmode.dmPelsWidth && devmode2.dmPelsHeight == devmode.dmPelsHeight,
+ "Expected resolution %ux%u, got %ux%u.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
+ devmode2.dmPelsWidth, devmode2.dmPelsHeight);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test mode restorations for non-primary monitors when there are multiple fullscreen ddraw
+ * objects and one of them restores display mode */
+ ddraw1 = create_ddraw();
+ ok(!!ddraw1, "Failed to create a ddraw object.\n");
+ ddraw2 = create_ddraw();
+ ok(!!ddraw2, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw1, 800, 600);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+ hr = set_display_mode(ddraw2, 640, 480);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ hr = IDirectDraw2_RestoreDisplayMode(ddraw2);
+ ok(hr == DD_OK, "RestoreDisplayMode failed, hr %#x.\n", hr);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+
+ ref = IDirectDraw2_Release(ddraw2);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+ ref = IDirectDraw2_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test mode restorations for non-primary monitors when there are multiple fullscreen ddraw
+ * objects and one of them got released */
+ ddraw1 = create_ddraw();
+ ok(!!ddraw1, "Failed to create a ddraw object.\n");
+ ddraw2 = create_ddraw();
+ ok(!!ddraw2, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw1, 800, 600);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+ hr = set_display_mode(ddraw2, 640, 480);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ ref = IDirectDraw2_Release(ddraw2);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+
+ ref = IDirectDraw2_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+done:
DestroyWindow(window);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+ heap_free(original_modes);
}
static void test_initialize(void)
diff --git a/dlls/ddraw/tests/ddraw4.c b/dlls/ddraw/tests/ddraw4.c
index 72aad35b1e1..12cfbc3784f 100644
--- a/dlls/ddraw/tests/ddraw4.c
+++ b/dlls/ddraw/tests/ddraw4.c
@@ -263,6 +263,69 @@ static IDirectDrawSurface4 *get_depth_stencil(IDirect3DDevice3 *device)
return ret;
}
+/* Free original_modes after finished using it */
+static BOOL save_display_modes(DEVMODEW **original_modes, unsigned int *display_count)
+{
+ unsigned int number, size = 2, count = 0, index = 0;
+ DISPLAY_DEVICEW display_device;
+ DEVMODEW *modes, *tmp;
+
+ if (!(modes = heap_alloc(size * sizeof(*modes))))
+ return FALSE;
+
+ display_device.cb = sizeof(display_device);
+ while (EnumDisplayDevicesW(NULL, index++, &display_device, 0))
+ {
+ /* Skip software devices */
+ if (swscanf(display_device.DeviceName, L"\\\\.\\DISPLAY%u", &number) != 1)
+ continue;
+
+ if (!(display_device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
+ continue;
+
+ if (count >= size)
+ {
+ size *= 2;
+ if (!(tmp = heap_realloc(modes, size * sizeof(*modes))))
+ {
+ heap_free(modes);
+ return FALSE;
+ }
+ modes = tmp;
+ }
+
+ memset(&modes[count], 0, sizeof(modes[count]));
+ modes[count].dmSize = sizeof(modes[count]);
+ if (!EnumDisplaySettingsW(display_device.DeviceName, ENUM_CURRENT_SETTINGS, &modes[count]))
+ {
+ heap_free(modes);
+ return FALSE;
+ }
+
+ lstrcpyW(modes[count++].dmDeviceName, display_device.DeviceName);
+ }
+
+ *original_modes = modes;
+ *display_count = count;
+ return TRUE;
+}
+
+static BOOL restore_display_modes(DEVMODEW *modes, unsigned int count)
+{
+ unsigned int index;
+ LONG ret;
+
+ for (index = 0; index < count; ++index)
+ {
+ ret = ChangeDisplaySettingsExW(modes[index].dmDeviceName, &modes[index], NULL,
+ CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
+ if (ret != DISP_CHANGE_SUCCESSFUL)
+ return FALSE;
+ }
+ ret = ChangeDisplaySettingsExW(NULL, NULL, NULL, 0, NULL);
+ return ret == DISP_CHANGE_SUCCESSFUL;
+}
+
static HRESULT set_display_mode(IDirectDraw4 *ddraw, DWORD width, DWORD height)
{
if (SUCCEEDED(IDirectDraw4_SetDisplayMode(ddraw, width, height, 32, 0, 0)))
@@ -1628,6 +1691,14 @@ static void test_texture_load_ckey(void)
IDirectDraw4_Release(ddraw);
}
+static BOOL compare_mode_rect(const DEVMODEW *mode1, const DEVMODEW *mode2)
+{
+ return mode1->dmPosition.x == mode2->dmPosition.x
+ && mode1->dmPosition.y == mode2->dmPosition.y
+ && mode1->dmPelsWidth == mode2->dmPelsWidth
+ && mode1->dmPelsHeight == mode2->dmPelsHeight;
+}
+
static ULONG get_refcount(IUnknown *test_iface)
{
IUnknown_AddRef(test_iface);
@@ -2935,6 +3006,8 @@ static HRESULT CALLBACK test_coop_level_mode_set_enum_cb(DDSURFACEDESC2 *surface
static void test_coop_level_mode_set(void)
{
+ DEVMODEW *original_modes = NULL, devmode, devmode2;
+ unsigned int display_count = 0;
IDirectDrawSurface4 *primary;
RECT registry_rect, ddraw_rect, user32_rect, r;
IDirectDraw4 *ddraw;
@@ -2945,7 +3018,6 @@ static void test_coop_level_mode_set(void)
ULONG ref;
MSG msg;
struct test_coop_level_mode_set_enum_param param;
- DEVMODEW devmode;
BOOL ret;
LONG change_ret;
@@ -3021,6 +3093,18 @@ static void test_coop_level_mode_set(void)
{0, FALSE, 0},
};
+ memset(&devmode, 0, sizeof(devmode));
+ devmode.dmSize = sizeof(devmode);
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode, ®istry_mode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode, ®istry_mode), "Got a different mode.\n");
+
+ ret = save_display_modes(&original_modes, &display_count);
+ ok(ret, "Failed to save original display modes.\n");
+
ddraw = create_ddraw();
ok(!!ddraw, "Failed to create a ddraw object.\n");
@@ -3033,6 +3117,7 @@ static void test_coop_level_mode_set(void)
if (!param.user32_height)
{
skip("Fewer than 3 different modes supported, skipping mode restore test.\n");
+ heap_free(original_modes);
return;
}
@@ -3709,20 +3794,126 @@ static void test_coop_level_mode_set(void)
ok(EqualRect(&r, &ddraw_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&ddraw_rect),
wine_dbgstr_rect(&r));
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that no mode restorations if no mode changes happened */
+ devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
+ devmode.dmPelsWidth = param.user32_width;
+ devmode.dmPelsHeight = param.user32_height;
+ change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
+
+ ddraw = create_ddraw();
+ ok(!!ddraw, "Failed to create a ddraw object.\n");
+ ref = IDirectDraw4_Release(ddraw);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ memset(&devmode2, 0, sizeof(devmode2));
+ devmode2.dmSize = sizeof(devmode2);
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, ®istry_mode), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that no mode restorations if no mode changes happened with fullscreen ddraw objects */
+ change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
+
+ ddraw = create_ddraw();
+ ok(!!ddraw, "Failed to create a ddraw object.\n");
+ hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
+ ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#x.\n", hr);
+ hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
+ ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#x.\n", hr);
+ ref = IDirectDraw4_Release(ddraw);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, ®istry_mode), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations use display settings in the registry after ddraw object releases
+ * if SetDisplayMode() was called */
+ ddraw = create_ddraw();
+ ok(!!ddraw, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw, registry_mode.dmPelsWidth, registry_mode.dmPelsHeight);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
+
+ ref = IDirectDraw4_Release(ddraw);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations use display settings in the registry after RestoreDisplayMode() */
+ ddraw = create_ddraw();
+ ok(!!ddraw, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw, param.ddraw_width, param.ddraw_height);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
+
+ hr = IDirectDraw4_RestoreDisplayMode(ddraw);
+ ok(hr == DD_OK, "RestoreDisplayMode failed, hr %#x.\n", hr);
+
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+
+ ref = IDirectDraw4_Release(ddraw);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
expect_messages = NULL;
DestroyWindow(window);
DestroyWindow(window2);
UnregisterClassA("ddraw_test_wndproc_wc", GetModuleHandleA(NULL));
UnregisterClassA("ddraw_test_wndproc_wc2", GetModuleHandleA(NULL));
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+ heap_free(original_modes);
}
static void test_coop_level_mode_set_multi(void)
{
+ DEVMODEW old_devmode, devmode, devmode2, devmode3, *original_modes = NULL;
+ unsigned int mode_idx = 0, display_idx, display_count = 0;
+ WCHAR second_monitor_name[CCHDEVICENAME];
IDirectDraw4 *ddraw1, *ddraw2;
+ LONG change_ret;
UINT w, h;
HWND window;
HRESULT hr;
ULONG ref;
+ BOOL ret;
+
+ memset(&devmode, 0, sizeof(devmode));
+ devmode.dmSize = sizeof(devmode);
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode, ®istry_mode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode, ®istry_mode), "Got a different mode.\n");
+
+ ret = save_display_modes(&original_modes, &display_count);
+ ok(ret, "Failed to save original display modes.\n");
window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
0, 0, 100, 100, 0, 0, 0, 0);
@@ -3897,7 +4088,210 @@ static void test_coop_level_mode_set_multi(void)
h = GetSystemMetrics(SM_CYSCREEN);
ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
+ if (display_count < 2)
+ {
+ skip("Following tests require two monitors.\n");
+ goto done;
+ }
+
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ second_monitor_name[0] = '\0';
+ for (display_idx = 0; display_idx < display_count; ++display_idx)
+ {
+ if (original_modes[display_idx].dmPosition.x || original_modes[display_idx].dmPosition.y)
+ {
+ lstrcpyW(second_monitor_name, original_modes[display_idx].dmDeviceName);
+ break;
+ }
+ }
+ ok(lstrlenW(second_monitor_name), "Got an empty second monitor name.\n");
+ memset(&old_devmode, 0, sizeof(old_devmode));
+ old_devmode.dmSize = sizeof(old_devmode);
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &old_devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+
+ devmode = old_devmode;
+ while (EnumDisplaySettingsW(second_monitor_name, mode_idx++, &devmode))
+ {
+ if (devmode.dmPelsWidth != old_devmode.dmPelsWidth
+ || devmode.dmPelsHeight != old_devmode.dmPelsHeight)
+ break;
+ }
+ ok(devmode.dmPelsWidth != old_devmode.dmPelsWidth
+ || devmode.dmPelsHeight != old_devmode.dmPelsHeight,
+ "Failed to find a different mode for the second monitor.\n");
+
+ /* Test that no mode restorations for non-primary monitors if SetDisplayMode() was not called */
+ ddraw1 = create_ddraw();
+ ok(!!ddraw1, "Failed to create a ddraw object.\n");
+ hr = IDirectDraw4_SetCooperativeLevel(ddraw1, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
+ ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ memset(&devmode2, 0, sizeof(devmode2));
+ devmode2.dmSize = sizeof(devmode2);
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ if (compare_mode_rect(&devmode2, &old_devmode))
+ {
+ skip("Failed to change display settings of the second monitor.\n");
+ ref = IDirectDraw4_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+ goto done;
+ }
+
+ hr = IDirectDraw4_SetCooperativeLevel(ddraw1, window, DDSCL_NORMAL);
+ ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#x.\n", hr);
+ ref = IDirectDraw4_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ memset(&devmode3, 0, sizeof(devmode3));
+ devmode3.dmSize = sizeof(devmode3);
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode3);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode3, &devmode2), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations happen for non-primary monitors on ddraw releases if
+ * SetDisplayMode() was called */
+ ddraw1 = create_ddraw();
+ ok(!!ddraw1, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw1, 800, 600);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ ref = IDirectDraw4_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations happen for non-primary monitors as well */
+ ddraw1 = create_ddraw();
+ ok(!!ddraw1, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw1, 800, 600);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ hr = IDirectDraw4_RestoreDisplayMode(ddraw1);
+ ok(hr == DD_OK, "RestoreDisplayMode failed, hr %#x.\n", hr);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+
+ ref = IDirectDraw4_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations for non-primary monitors use display settings in the registry */
+ ddraw1 = create_ddraw();
+ ok(!!ddraw1, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw1, 800, 600);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL,
+ CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ ref = IDirectDraw4_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(devmode2.dmPelsWidth == devmode.dmPelsWidth && devmode2.dmPelsHeight == devmode.dmPelsHeight,
+ "Expected resolution %ux%u, got %ux%u.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
+ devmode2.dmPelsWidth, devmode2.dmPelsHeight);
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(devmode2.dmPelsWidth == devmode.dmPelsWidth && devmode2.dmPelsHeight == devmode.dmPelsHeight,
+ "Expected resolution %ux%u, got %ux%u.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
+ devmode2.dmPelsWidth, devmode2.dmPelsHeight);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test mode restorations for non-primary monitors when there are multiple fullscreen ddraw
+ * objects and one of them restores display mode */
+ ddraw1 = create_ddraw();
+ ok(!!ddraw1, "Failed to create a ddraw object.\n");
+ ddraw2 = create_ddraw();
+ ok(!!ddraw2, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw1, 800, 600);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+ hr = set_display_mode(ddraw2, 640, 480);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ hr = IDirectDraw4_RestoreDisplayMode(ddraw2);
+ ok(hr == DD_OK, "RestoreDisplayMode failed, hr %#x.\n", hr);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+
+ ref = IDirectDraw4_Release(ddraw2);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+ ref = IDirectDraw4_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test mode restorations for non-primary monitors when there are multiple fullscreen ddraw
+ * objects and one of them got released */
+ ddraw1 = create_ddraw();
+ ok(!!ddraw1, "Failed to create a ddraw object.\n");
+ ddraw2 = create_ddraw();
+ ok(!!ddraw2, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw1, 800, 600);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+ hr = set_display_mode(ddraw2, 640, 480);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ ref = IDirectDraw4_Release(ddraw2);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+
+ ref = IDirectDraw4_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+done:
DestroyWindow(window);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+ heap_free(original_modes);
}
static void test_initialize(void)
diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c
index e85b7d76369..c214cbc221e 100644
--- a/dlls/ddraw/tests/ddraw7.c
+++ b/dlls/ddraw/tests/ddraw7.c
@@ -102,6 +102,14 @@ static BOOL compare_color(D3DCOLOR c1, D3DCOLOR c2, BYTE max_diff)
&& compare_uint((c1 >> 24) & 0xff, (c2 >> 24) & 0xff, max_diff);
}
+static BOOL compare_mode_rect(const DEVMODEW *mode1, const DEVMODEW *mode2)
+{
+ return mode1->dmPosition.x == mode2->dmPosition.x
+ && mode1->dmPosition.y == mode2->dmPosition.y
+ && mode1->dmPelsWidth == mode2->dmPelsWidth
+ && mode1->dmPelsHeight == mode2->dmPelsHeight;
+}
+
static ULONG get_refcount(IUnknown *iface)
{
IUnknown_AddRef(iface);
@@ -281,6 +289,69 @@ static IDirectDrawSurface7 *get_depth_stencil(IDirect3DDevice7 *device)
return ret;
}
+/* Free original_modes after finished using it */
+static BOOL save_display_modes(DEVMODEW **original_modes, unsigned int *display_count)
+{
+ unsigned int number, size = 2, count = 0, index = 0;
+ DISPLAY_DEVICEW display_device;
+ DEVMODEW *modes, *tmp;
+
+ if (!(modes = heap_alloc(size * sizeof(*modes))))
+ return FALSE;
+
+ display_device.cb = sizeof(display_device);
+ while (EnumDisplayDevicesW(NULL, index++, &display_device, 0))
+ {
+ /* Skip software devices */
+ if (swscanf(display_device.DeviceName, L"\\\\.\\DISPLAY%u", &number) != 1)
+ continue;
+
+ if (!(display_device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
+ continue;
+
+ if (count >= size)
+ {
+ size *= 2;
+ if (!(tmp = heap_realloc(modes, size * sizeof(*modes))))
+ {
+ heap_free(modes);
+ return FALSE;
+ }
+ modes = tmp;
+ }
+
+ memset(&modes[count], 0, sizeof(modes[count]));
+ modes[count].dmSize = sizeof(modes[count]);
+ if (!EnumDisplaySettingsW(display_device.DeviceName, ENUM_CURRENT_SETTINGS, &modes[count]))
+ {
+ heap_free(modes);
+ return FALSE;
+ }
+
+ lstrcpyW(modes[count++].dmDeviceName, display_device.DeviceName);
+ }
+
+ *original_modes = modes;
+ *display_count = count;
+ return TRUE;
+}
+
+static BOOL restore_display_modes(DEVMODEW *modes, unsigned int count)
+{
+ unsigned int index;
+ LONG ret;
+
+ for (index = 0; index < count; ++index)
+ {
+ ret = ChangeDisplaySettingsExW(modes[index].dmDeviceName, &modes[index], NULL,
+ CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
+ if (ret != DISP_CHANGE_SUCCESSFUL)
+ return FALSE;
+ }
+ ret = ChangeDisplaySettingsExW(NULL, NULL, NULL, 0, NULL);
+ return ret == DISP_CHANGE_SUCCESSFUL;
+}
+
static HRESULT set_display_mode(IDirectDraw7 *ddraw, DWORD width, DWORD height)
{
if (SUCCEEDED(IDirectDraw7_SetDisplayMode(ddraw, width, height, 32, 0, 0)))
@@ -2582,6 +2653,8 @@ static HRESULT CALLBACK test_coop_level_mode_set_enum_cb(DDSURFACEDESC2 *surface
static void test_coop_level_mode_set(void)
{
+ DEVMODEW *original_modes = NULL, devmode, devmode2;
+ unsigned int display_count = 0;
IDirectDrawSurface7 *primary;
RECT registry_rect, ddraw_rect, user32_rect, r;
IDirectDraw7 *ddraw;
@@ -2592,7 +2665,6 @@ static void test_coop_level_mode_set(void)
ULONG ref;
MSG msg;
struct test_coop_level_mode_set_enum_param param;
- DEVMODEW devmode;
BOOL ret;
LONG change_ret;
@@ -2668,6 +2740,18 @@ static void test_coop_level_mode_set(void)
{0, FALSE, 0},
};
+ memset(&devmode, 0, sizeof(devmode));
+ devmode.dmSize = sizeof(devmode);
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode, ®istry_mode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode, ®istry_mode), "Got a different mode.\n");
+
+ ret = save_display_modes(&original_modes, &display_count);
+ ok(ret, "Failed to save original display modes.\n");
+
ddraw = create_ddraw();
ok(!!ddraw, "Failed to create a ddraw object.\n");
@@ -2680,6 +2764,7 @@ static void test_coop_level_mode_set(void)
if (!param.user32_height)
{
skip("Fewer than 3 different modes supported, skipping mode restore test.\n");
+ heap_free(original_modes);
return;
}
@@ -3356,20 +3441,126 @@ static void test_coop_level_mode_set(void)
ok(EqualRect(&r, &ddraw_rect), "Expected %s, got %s.\n", wine_dbgstr_rect(&ddraw_rect),
wine_dbgstr_rect(&r));
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that no mode restorations if no mode changes happened */
+ devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
+ devmode.dmPelsWidth = param.user32_width;
+ devmode.dmPelsHeight = param.user32_height;
+ change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
+
+ ddraw = create_ddraw();
+ ok(!!ddraw, "Failed to create a ddraw object.\n");
+ ref = IDirectDraw7_Release(ddraw);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ memset(&devmode2, 0, sizeof(devmode2));
+ devmode2.dmSize = sizeof(devmode2);
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, ®istry_mode), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that no mode restorations if no mode changes happened with fullscreen ddraw objects */
+ change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
+
+ ddraw = create_ddraw();
+ ok(!!ddraw, "Failed to create a ddraw object.\n");
+ hr = IDirectDraw7_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
+ ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#x.\n", hr);
+ hr = IDirectDraw7_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
+ ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#x.\n", hr);
+ ref = IDirectDraw7_Release(ddraw);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, ®istry_mode), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations use display settings in the registry after ddraw object releases
+ * if SetDisplayMode() was called */
+ ddraw = create_ddraw();
+ ok(!!ddraw, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw, registry_mode.dmPelsWidth, registry_mode.dmPelsHeight);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
+
+ ref = IDirectDraw7_Release(ddraw);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations use display settings in the registry after RestoreDisplayMode() */
+ ddraw = create_ddraw();
+ ok(!!ddraw, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw, param.ddraw_width, param.ddraw_height);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsW(&devmode, CDS_UPDATEREGISTRY | CDS_NORESET);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsW failed with %d.\n", change_ret);
+
+ hr = IDirectDraw7_RestoreDisplayMode(ddraw);
+ ok(hr == DD_OK, "RestoreDisplayMode failed, hr %#x.\n", hr);
+
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &devmode), "Got a different mode.\n");
+
+ ref = IDirectDraw7_Release(ddraw);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
expect_messages = NULL;
DestroyWindow(window);
DestroyWindow(window2);
UnregisterClassA("ddraw_test_wndproc_wc", GetModuleHandleA(NULL));
UnregisterClassA("ddraw_test_wndproc_wc2", GetModuleHandleA(NULL));
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+ heap_free(original_modes);
}
static void test_coop_level_mode_set_multi(void)
{
+ DEVMODEW old_devmode, devmode, devmode2, devmode3, *original_modes = NULL;
+ unsigned int mode_idx = 0, display_idx, display_count = 0;
+ WCHAR second_monitor_name[CCHDEVICENAME];
IDirectDraw7 *ddraw1, *ddraw2;
+ LONG change_ret;
UINT w, h;
HWND window;
HRESULT hr;
ULONG ref;
+ BOOL ret;
+
+ memset(&devmode, 0, sizeof(devmode));
+ devmode.dmSize = sizeof(devmode);
+ ret = EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode, ®istry_mode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(NULL, ENUM_REGISTRY_SETTINGS, &devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode, ®istry_mode), "Got a different mode.\n");
+
+ ret = save_display_modes(&original_modes, &display_count);
+ ok(ret, "Failed to save original display modes.\n");
window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
0, 0, 100, 100, 0, 0, 0, 0);
@@ -3544,7 +3735,210 @@ static void test_coop_level_mode_set_multi(void)
h = GetSystemMetrics(SM_CYSCREEN);
ok(h == registry_mode.dmPelsHeight, "Got unexpected screen height %u.\n", h);
+ if (display_count < 2)
+ {
+ skip("Following tests require two monitors.\n");
+ goto done;
+ }
+
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ second_monitor_name[0] = '\0';
+ for (display_idx = 0; display_idx < display_count; ++display_idx)
+ {
+ if (original_modes[display_idx].dmPosition.x || original_modes[display_idx].dmPosition.y)
+ {
+ lstrcpyW(second_monitor_name, original_modes[display_idx].dmDeviceName);
+ break;
+ }
+ }
+ ok(lstrlenW(second_monitor_name), "Got an empty second monitor name.\n");
+ memset(&old_devmode, 0, sizeof(old_devmode));
+ old_devmode.dmSize = sizeof(old_devmode);
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &old_devmode);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+
+ devmode = old_devmode;
+ while (EnumDisplaySettingsW(second_monitor_name, mode_idx++, &devmode))
+ {
+ if (devmode.dmPelsWidth != old_devmode.dmPelsWidth
+ || devmode.dmPelsHeight != old_devmode.dmPelsHeight)
+ break;
+ }
+ ok(devmode.dmPelsWidth != old_devmode.dmPelsWidth
+ || devmode.dmPelsHeight != old_devmode.dmPelsHeight,
+ "Failed to find a different mode for the second monitor.\n");
+
+ /* Test that no mode restorations for non-primary monitors if SetDisplayMode() was not called */
+ ddraw1 = create_ddraw();
+ ok(!!ddraw1, "Failed to create a ddraw object.\n");
+ hr = IDirectDraw7_SetCooperativeLevel(ddraw1, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
+ ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ memset(&devmode2, 0, sizeof(devmode2));
+ devmode2.dmSize = sizeof(devmode2);
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ if (compare_mode_rect(&devmode2, &old_devmode))
+ {
+ skip("Failed to change display settings of the second monitor.\n");
+ ref = IDirectDraw7_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+ goto done;
+ }
+
+ hr = IDirectDraw7_SetCooperativeLevel(ddraw1, window, DDSCL_NORMAL);
+ ok(hr == DD_OK, "SetCooperativeLevel failed, hr %#x.\n", hr);
+ ref = IDirectDraw7_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ memset(&devmode3, 0, sizeof(devmode3));
+ devmode3.dmSize = sizeof(devmode3);
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode3);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode3, &devmode2), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations happen for non-primary monitors on ddraw releases if
+ * SetDisplayMode() was called */
+ ddraw1 = create_ddraw();
+ ok(!!ddraw1, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw1, 800, 600);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ ref = IDirectDraw7_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations happen for non-primary monitors as well */
+ ddraw1 = create_ddraw();
+ ok(!!ddraw1, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw1, 800, 600);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ hr = IDirectDraw7_RestoreDisplayMode(ddraw1);
+ ok(hr == DD_OK, "RestoreDisplayMode failed, hr %#x.\n", hr);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+
+ ref = IDirectDraw7_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test that mode restorations for non-primary monitors use display settings in the registry */
+ ddraw1 = create_ddraw();
+ ok(!!ddraw1, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw1, 800, 600);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL,
+ CDS_UPDATEREGISTRY | CDS_NORESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ ref = IDirectDraw7_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(devmode2.dmPelsWidth == devmode.dmPelsWidth && devmode2.dmPelsHeight == devmode.dmPelsHeight,
+ "Expected resolution %ux%u, got %ux%u.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
+ devmode2.dmPelsWidth, devmode2.dmPelsHeight);
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(devmode2.dmPelsWidth == devmode.dmPelsWidth && devmode2.dmPelsHeight == devmode.dmPelsHeight,
+ "Expected resolution %ux%u, got %ux%u.\n", devmode.dmPelsWidth, devmode.dmPelsHeight,
+ devmode2.dmPelsWidth, devmode2.dmPelsHeight);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test mode restorations for non-primary monitors when there are multiple fullscreen ddraw
+ * objects and one of them restores display mode */
+ ddraw1 = create_ddraw();
+ ok(!!ddraw1, "Failed to create a ddraw object.\n");
+ ddraw2 = create_ddraw();
+ ok(!!ddraw2, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw1, 800, 600);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+ hr = set_display_mode(ddraw2, 640, 480);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ hr = IDirectDraw7_RestoreDisplayMode(ddraw2);
+ ok(hr == DD_OK, "RestoreDisplayMode failed, hr %#x.\n", hr);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+
+ ref = IDirectDraw7_Release(ddraw2);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+ ref = IDirectDraw7_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+
+ /* Test mode restorations for non-primary monitors when there are multiple fullscreen ddraw
+ * objects and one of them got released */
+ ddraw1 = create_ddraw();
+ ok(!!ddraw1, "Failed to create a ddraw object.\n");
+ ddraw2 = create_ddraw();
+ ok(!!ddraw2, "Failed to create a ddraw object.\n");
+ hr = set_display_mode(ddraw1, 800, 600);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+ hr = set_display_mode(ddraw2, 640, 480);
+ ok(hr == DD_OK, "Failed to set display mode, hr %#x.\n", hr);
+
+ change_ret = ChangeDisplaySettingsExW(second_monitor_name, &devmode, NULL, CDS_RESET, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
+
+ ref = IDirectDraw7_Release(ddraw2);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_CURRENT_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ todo_wine ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+ ret = EnumDisplaySettingsW(second_monitor_name, ENUM_REGISTRY_SETTINGS, &devmode2);
+ ok(ret, "EnumDisplaySettingsW failed, error %#x.\n", GetLastError());
+ ok(compare_mode_rect(&devmode2, &old_devmode), "Got a different mode.\n");
+
+ ref = IDirectDraw7_Release(ddraw1);
+ ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
+
+done:
DestroyWindow(window);
+ ret = restore_display_modes(original_modes, display_count);
+ ok(ret, "Failed to restore display modes.\n");
+ heap_free(original_modes);
}
static void test_initialize(void)
--
2.27.0
3
2
[PATCH v2 2/7] d3d9/tests: Restore display modes at the end of test_wndproc().
by Zhiyi Zhang Oct. 30, 2020
by Zhiyi Zhang Oct. 30, 2020
Oct. 30, 2020
test_wndproc() makes a series of ChangeDisplaySettings() calls that could make the current display
mode no longer match the registry display mode. Restore display modes at the end of test_wndproc()
so that other tests are not affected.
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/d3d9/tests/device.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/dlls/d3d9/tests/device.c b/dlls/d3d9/tests/device.c
index 53a83ad887b..2efb6ddc2e5 100644
--- a/dlls/d3d9/tests/device.c
+++ b/dlls/d3d9/tests/device.c
@@ -4435,6 +4435,8 @@ done:
CloseHandle(thread_params.test_finished);
CloseHandle(thread_params.window_created);
UnregisterClassA("d3d9_test_wndproc_wc", GetModuleHandleA(NULL));
+ change_ret = ChangeDisplaySettingsExW(NULL, NULL, NULL, 0, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
}
static void test_wndproc_windowed(void)
--
2.27.0
2
1
[PATCH v2 1/7] d3d8/tests: Restore display modes at the end of test_wndproc().
by Zhiyi Zhang Oct. 30, 2020
by Zhiyi Zhang Oct. 30, 2020
Oct. 30, 2020
test_wndproc() makes a series of ChangeDisplaySettings() calls that could make the current display
mode no longer match the registry display mode. Restore display modes at the end of test_wndproc()
so that other tests are not affected.
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/d3d8/tests/device.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/dlls/d3d8/tests/device.c b/dlls/d3d8/tests/device.c
index 4c567a47603..3e933143332 100644
--- a/dlls/d3d8/tests/device.c
+++ b/dlls/d3d8/tests/device.c
@@ -3361,6 +3361,8 @@ done:
DestroyWindow(device_window);
DestroyWindow(focus_window);
UnregisterClassA("d3d8_test_wndproc_wc", GetModuleHandleA(NULL));
+ change_ret = ChangeDisplaySettingsExW(NULL, NULL, NULL, 0, NULL);
+ ok(change_ret == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExW failed with %d.\n", change_ret);
}
static void test_wndproc_windowed(void)
--
2.27.0
3
2
Oct. 30, 2020
Signed-off-by: Derek Lesho <dlesho(a)codeweavers.com>
---
v8: Fix setting of frame-rate cap on 32-bit.
---
dlls/mfplat/tests/mfplat.c | 8 +-
dlls/winegstreamer/gst_private.h | 1 +
dlls/winegstreamer/media_source.c | 307 +++++++++++++++++++++++++++++-
dlls/winegstreamer/mfplat.c | 130 +++++++++++++
4 files changed, 438 insertions(+), 8 deletions(-)
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
index 6a1a5bafc1a..a080035e477 100644
--- a/dlls/mfplat/tests/mfplat.c
+++ b/dlls/mfplat/tests/mfplat.c
@@ -603,10 +603,7 @@ todo_wine
var.vt = VT_EMPTY;
hr = IMFMediaSource_Start(mediasource, descriptor, &GUID_NULL, &var);
-todo_wine
ok(hr == S_OK, "Failed to start media source, hr %#x.\n", hr);
- if (FAILED(hr))
- goto skip_source_tests;
get_event((IMFMediaEventGenerator *)mediasource, MENewStream, &var);
ok(var.vt == VT_UNKNOWN, "Unexpected value type %u from MENewStream event.\n", var.vt);
@@ -624,10 +621,13 @@ todo_wine
hr = IMFMediaStream_RequestSample(video_stream, NULL);
if (i == sample_count)
break;
+todo_wine
ok(hr == S_OK, "Failed to request sample %u, hr %#x.\n", i + 1, hr);
if (hr != S_OK)
break;
}
+ if (FAILED(hr))
+ goto skip_source_tests;
for (i = 0; i < sample_count; ++i)
{
@@ -665,11 +665,11 @@ todo_wine
hr = IMFMediaStream_RequestSample(video_stream, NULL);
ok(hr == MF_E_END_OF_STREAM, "Unexpected hr %#x.\n", hr);
- IMFMediaStream_Release(video_stream);
get_event((IMFMediaEventGenerator *)mediasource, MEEndOfPresentation, NULL);
skip_source_tests:
+ IMFMediaStream_Release(video_stream);
IMFMediaTypeHandler_Release(handler);
IMFPresentationDescriptor_Release(descriptor);
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index 57d40d19a89..3a8020b6760 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -79,6 +79,7 @@ extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj)
HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN;
IMFMediaType *mf_media_type_from_caps(const GstCaps *caps) DECLSPEC_HIDDEN;
+GstCaps *caps_from_mf_media_type(IMFMediaType *type) DECLSPEC_HIDDEN;
HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN;
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index 9b2c2174318..9c6e7bfd539 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -55,14 +55,38 @@ struct media_stream
{
STREAM_INACTIVE,
STREAM_SHUTDOWN,
+ STREAM_RUNNING,
} state;
DWORD stream_id;
};
+enum source_async_op
+{
+ SOURCE_ASYNC_START,
+};
+
+struct source_async_command
+{
+ IUnknown IUnknown_iface;
+ LONG refcount;
+ enum source_async_op op;
+ union
+ {
+ struct
+ {
+ IMFPresentationDescriptor *descriptor;
+ GUID format;
+ PROPVARIANT position;
+ } start;
+ } u;
+};
+
struct media_source
{
IMFMediaSource IMFMediaSource_iface;
+ IMFAsyncCallback async_commands_callback;
LONG ref;
+ DWORD async_commands_queue;
IMFMediaEventQueue *event_queue;
IMFByteStream *byte_stream;
struct media_stream **streams;
@@ -76,6 +100,7 @@ struct media_source
{
SOURCE_OPENING,
SOURCE_STOPPED,
+ SOURCE_RUNNING,
SOURCE_SHUTDOWN,
} state;
HANDLE no_more_pads_event;
@@ -91,7 +116,260 @@ static inline struct media_source *impl_from_IMFMediaSource(IMFMediaSource *ifac
return CONTAINING_RECORD(iface, struct media_source, IMFMediaSource_iface);
}
-static GstFlowReturn bytestream_wrapper_pull(GstPad *pad, GstObject *parent, guint64 ofs, guint len,
+static inline struct media_source *impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
+{
+ return CONTAINING_RECORD(iface, struct media_source, async_commands_callback);
+}
+
+static inline struct source_async_command *impl_from_async_command_IUnknown(IUnknown *iface)
+{
+ return CONTAINING_RECORD(iface, struct source_async_command, IUnknown_iface);
+}
+
+static HRESULT WINAPI source_async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
+{
+ if (IsEqualIID(riid, &IID_IUnknown))
+ {
+ *obj = iface;
+ IUnknown_AddRef(iface);
+ return S_OK;
+ }
+
+ WARN("Unsupported interface %s.\n", debugstr_guid(riid));
+ *obj = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI source_async_command_AddRef(IUnknown *iface)
+{
+ struct source_async_command *command = impl_from_async_command_IUnknown(iface);
+ return InterlockedIncrement(&command->refcount);
+}
+
+static ULONG WINAPI source_async_command_Release(IUnknown *iface)
+{
+ struct source_async_command *command = impl_from_async_command_IUnknown(iface);
+ ULONG refcount = InterlockedDecrement(&command->refcount);
+
+ if (!refcount)
+ {
+ if (command->op == SOURCE_ASYNC_START)
+ PropVariantClear(&command->u.start.position);
+ heap_free(command);
+ }
+
+ return refcount;
+}
+
+static const IUnknownVtbl source_async_command_vtbl =
+{
+ source_async_command_QueryInterface,
+ source_async_command_AddRef,
+ source_async_command_Release,
+};
+
+static HRESULT source_create_async_op(enum source_async_op op, struct source_async_command **ret)
+{
+ struct source_async_command *command;
+
+ if (!(command = heap_alloc_zero(sizeof(*command))))
+ return E_OUTOFMEMORY;
+
+ command->IUnknown_iface.lpVtbl = &source_async_command_vtbl;
+ command->op = op;
+
+ *ret = command;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
+{
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
+
+ if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *obj = iface;
+ IMFAsyncCallback_AddRef(iface);
+ return S_OK;
+ }
+
+ WARN("Unsupported %s.\n", debugstr_guid(riid));
+ *obj = NULL;
+ return E_NOINTERFACE;
+}
+
+static HRESULT WINAPI callback_GetParameters(IMFAsyncCallback *iface,
+ DWORD *flags, DWORD *queue)
+{
+ return E_NOTIMPL;
+}
+
+static ULONG WINAPI source_async_commands_callback_AddRef(IMFAsyncCallback *iface)
+{
+ struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
+ return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
+}
+
+static ULONG WINAPI source_async_commands_callback_Release(IMFAsyncCallback *iface)
+{
+ struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
+ return IMFMediaSource_Release(&source->IMFMediaSource_iface);
+}
+
+static IMFStreamDescriptor *stream_descriptor_from_id(IMFPresentationDescriptor *pres_desc, DWORD id, BOOL *selected)
+{
+ ULONG sd_count;
+ IMFStreamDescriptor *ret;
+ unsigned int i;
+
+ if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(pres_desc, &sd_count)))
+ return NULL;
+
+ for (i = 0; i < sd_count; i++)
+ {
+ DWORD stream_id;
+
+ if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(pres_desc, i, selected, &ret)))
+ return NULL;
+
+ if (SUCCEEDED(IMFStreamDescriptor_GetStreamIdentifier(ret, &stream_id)) && stream_id == id)
+ return ret;
+
+ IMFStreamDescriptor_Release(ret);
+ }
+ return NULL;
+}
+
+static void start_pipeline(struct media_source *source, struct source_async_command *command)
+{
+ PROPVARIANT *position = &command->u.start.position;
+ BOOL seek_message = source->state != SOURCE_STOPPED && position->vt != VT_EMPTY;
+ GstStateChangeReturn ret;
+ unsigned int i;
+
+ gst_element_set_state(source->container, GST_STATE_PAUSED);
+ ret = gst_element_get_state(source->container, NULL, NULL, -1);
+ assert(ret == GST_STATE_CHANGE_SUCCESS);
+
+ /* seek to beginning on stop->play */
+ if (source->state == SOURCE_STOPPED && position->vt == VT_EMPTY)
+ {
+ position->vt = VT_I8;
+ position->u.hVal.QuadPart = 0;
+ }
+
+ for (i = 0; i < source->stream_count; i++)
+ {
+ struct media_stream *stream;
+ IMFStreamDescriptor *sd;
+ IMFMediaTypeHandler *mth;
+ IMFMediaType *current_mt;
+ GstCaps *current_caps;
+ GstCaps *prev_caps;
+ DWORD stream_id;
+ BOOL was_active;
+ BOOL selected;
+
+ stream = source->streams[i];
+
+ IMFStreamDescriptor_GetStreamIdentifier(stream->descriptor, &stream_id);
+
+ sd = stream_descriptor_from_id(command->u.start.descriptor, stream_id, &selected);
+ IMFStreamDescriptor_Release(sd);
+
+ was_active = stream->state != STREAM_INACTIVE;
+
+ stream->state = selected ? STREAM_RUNNING : STREAM_INACTIVE;
+
+ if (selected)
+ {
+ IMFStreamDescriptor_GetMediaTypeHandler(stream->descriptor, &mth);
+ IMFMediaTypeHandler_GetCurrentMediaType(mth, ¤t_mt);
+ current_caps = caps_from_mf_media_type(current_mt);
+ g_object_get(stream->appsink, "caps", &prev_caps, NULL);
+ if (!prev_caps || !gst_caps_is_equal(prev_caps, current_caps))
+ {
+ GstEvent *reconfigure_event = gst_event_new_reconfigure();
+ g_object_set(stream->appsink, "caps", current_caps, NULL);
+ gst_pad_push_event(gst_element_get_static_pad(stream->appsink, "sink"), reconfigure_event);
+ }
+
+ gst_caps_unref(current_caps);
+ if (prev_caps)
+ gst_caps_unref(prev_caps);
+ IMFMediaType_Release(current_mt);
+ IMFMediaTypeHandler_Release(mth);
+ }
+
+ g_object_set(stream->appsink, "drop", !selected, NULL);
+
+ if (position->vt != VT_EMPTY)
+ {
+ GstEvent *seek_event = gst_event_new_seek(1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
+ GST_SEEK_TYPE_SET, position->u.hVal.QuadPart / 100, GST_SEEK_TYPE_NONE, 0);
+
+ gst_pad_push_event(stream->my_sink, seek_event);
+ }
+
+ if (selected)
+ {
+ TRACE("Stream %u (%p) selected\n", i, stream);
+ IMFMediaEventQueue_QueueEventParamUnk(source->event_queue,
+ was_active ? MEUpdatedStream : MENewStream, &GUID_NULL,
+ S_OK, (IUnknown*) &stream->IMFMediaStream_iface);
+
+ IMFMediaEventQueue_QueueEventParamVar(stream->event_queue,
+ seek_message ? MEStreamSeeked : MEStreamStarted, &GUID_NULL, S_OK, position);
+ }
+ }
+
+ IMFMediaEventQueue_QueueEventParamVar(source->event_queue,
+ seek_message ? MESourceSeeked : MESourceStarted,
+ &GUID_NULL, S_OK, position);
+
+ source->state = SOURCE_RUNNING;
+
+ gst_element_set_state(source->container, GST_STATE_PLAYING);
+}
+
+static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
+{
+ struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
+ struct source_async_command *command;
+ IUnknown *state;
+ HRESULT hr;
+
+ if (source->state == SOURCE_SHUTDOWN)
+ return S_OK;
+
+ if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
+ return hr;
+
+ command = impl_from_async_command_IUnknown(state);
+ switch (command->op)
+ {
+ case SOURCE_ASYNC_START:
+ start_pipeline(source, command);
+ break;
+ }
+
+ IUnknown_Release(state);
+
+ return S_OK;
+}
+
+static const IMFAsyncCallbackVtbl source_async_commands_callback_vtbl =
+{
+ callback_QueryInterface,
+ source_async_commands_callback_AddRef,
+ source_async_commands_callback_Release,
+ callback_GetParameters,
+ source_async_commands_Invoke,
+};
+
+GstFlowReturn bytestream_wrapper_pull(GstPad *pad, GstObject *parent, guint64 ofs, guint len,
GstBuffer **buf)
{
struct media_source *source = gst_pad_get_element_private(pad);
@@ -683,16 +961,30 @@ static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *
}
static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor,
- const GUID *time_format, const PROPVARIANT *start_position)
+ const GUID *time_format, const PROPVARIANT *position)
{
struct media_source *source = impl_from_IMFMediaSource(iface);
+ struct source_async_command *command;
+ HRESULT hr;
- FIXME("(%p)->(%p, %p, %p): stub\n", source, descriptor, time_format, start_position);
+ TRACE("(%p)->(%p, %p, %p)\n", source, descriptor, time_format, position);
if (source->state == SOURCE_SHUTDOWN)
return MF_E_SHUTDOWN;
- return E_NOTIMPL;
+ if (!(IsEqualIID(time_format, &GUID_NULL)))
+ return MF_E_UNSUPPORTED_TIME_FORMAT;
+
+ if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_START, &command)))
+ {
+ command->u.start.descriptor = descriptor;
+ command->u.start.format = *time_format;
+ PropVariantCopy(&command->u.start.position, position);
+
+ hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface);
+ }
+
+ return hr;
}
static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface)
@@ -773,6 +1065,9 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface)
if (source->no_more_pads_event)
CloseHandle(source->no_more_pads_event);
+ if (source->async_commands_queue)
+ MFUnlockWorkQueue(source->async_commands_queue);
+
return S_OK;
}
@@ -853,6 +1148,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_
return E_OUTOFMEMORY;
object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl;
+ object->async_commands_callback.lpVtbl = &source_async_commands_callback_vtbl;
object->ref = 1;
object->byte_stream = bytestream;
IMFByteStream_AddRef(bytestream);
@@ -861,6 +1157,9 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_
if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
goto fail;
+ if (FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue)))
+ goto fail;
+
object->container = gst_bin_new(NULL);
object->bus = gst_bus_new();
gst_bus_set_sync_handler(object->bus, mf_src_bus_watch_wrapper, object, NULL);
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
index 2e8b0978648..d0071cae438 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -601,3 +601,133 @@ IMFMediaType *mf_media_type_from_caps(const GstCaps *caps)
return media_type;
}
+
+GstCaps *caps_from_mf_media_type(IMFMediaType *type)
+{
+ GUID major_type;
+ GUID subtype;
+ GstCaps *output = NULL;
+
+ if (FAILED(IMFMediaType_GetMajorType(type, &major_type)))
+ return NULL;
+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
+ return NULL;
+
+ if (IsEqualGUID(&major_type, &MFMediaType_Video))
+ {
+ UINT64 frame_rate = 0, frame_size = 0;
+ DWORD width, height;
+ GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
+ GUID subtype_base;
+ GstVideoInfo info;
+ unsigned int i;
+
+ if (FAILED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size)))
+ return NULL;
+ width = frame_size >> 32;
+ height = frame_size;
+
+ output = gst_caps_new_empty_simple("video/x-raw");
+
+ for (i = 0; i < ARRAY_SIZE(uncompressed_video_formats); i++)
+ {
+ if (IsEqualGUID(uncompressed_video_formats[i].subtype, &subtype))
+ {
+ format = uncompressed_video_formats[i].format;
+ break;
+ }
+ }
+
+ subtype_base = subtype;
+ subtype_base.Data1 = 0;
+ if (format == GST_VIDEO_FORMAT_UNKNOWN && IsEqualGUID(&MFVideoFormat_Base, &subtype_base))
+ format = gst_video_format_from_fourcc(subtype.Data1);
+
+ if (format == GST_VIDEO_FORMAT_UNKNOWN)
+ {
+ FIXME("Unrecognized format %s\n", debugstr_guid(&subtype));
+ return NULL;
+ }
+
+ gst_video_info_set_format(&info, format, width, height);
+ output = gst_video_info_to_caps(&info);
+
+ if (frame_size)
+ {
+ gst_caps_set_simple(output, "width", G_TYPE_INT, width, NULL);
+ gst_caps_set_simple(output, "height", G_TYPE_INT, height, NULL);
+ }
+ if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)))
+ {
+ /* Darksiders: Warmastered Edition uses a MF_MT_FRAME_RATE of 0,
+ and gstreamer won't accept an undefined number as the framerate. */
+ if (!(DWORD32)frame_rate)
+ frame_rate = 1;
+ gst_caps_set_simple(output, "framerate", GST_TYPE_FRACTION, (DWORD32)(frame_rate >> 32), (DWORD32) frame_rate, NULL);
+ }
+ return output;
+ }
+ else if (IsEqualGUID(&major_type, &MFMediaType_Audio))
+ {
+ DWORD rate, channels, channel_mask, bitrate;
+
+ if (IsEqualGUID(&subtype, &MFAudioFormat_Float))
+ {
+ output = gst_caps_new_empty_simple("audio/x-raw");
+
+ gst_caps_set_simple(output, "format", G_TYPE_STRING, "F32LE", NULL);
+ gst_caps_set_simple(output, "layout", G_TYPE_STRING, "interleaved", NULL);
+ }
+ else if (IsEqualGUID(&subtype, &MFAudioFormat_PCM))
+ {
+ DWORD bits_per_sample;
+
+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &bits_per_sample)))
+ {
+ char format[6];
+ char type;
+
+ type = bits_per_sample > 8 ? 'S' : 'U';
+
+ output = gst_caps_new_empty_simple("audio/x-raw");
+
+ sprintf(format, "%c%u%s", type, bits_per_sample, bits_per_sample > 8 ? "LE" : "");
+
+ gst_caps_set_simple(output, "format", G_TYPE_STRING, format, NULL);
+ }
+ else
+ {
+ ERR("Bits per sample not set.\n");
+ return NULL;
+ }
+ }
+ else
+ {
+ FIXME("Unrecognized subtype %s\n", debugstr_guid(&subtype));
+ return NULL;
+ }
+
+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate)))
+ {
+ gst_caps_set_simple(output, "rate", G_TYPE_INT, rate, NULL);
+ }
+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &channels)))
+ {
+ gst_caps_set_simple(output, "channels", G_TYPE_INT, channels, NULL);
+ }
+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_CHANNEL_MASK, &channel_mask)))
+ {
+ gst_caps_set_simple(output, "channel-mask", GST_TYPE_BITMASK, (guint64) channel_mask, NULL);
+ }
+
+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_AVG_BITRATE, &bitrate)))
+ {
+ gst_caps_set_simple(output, "bitrate", G_TYPE_INT, bitrate, NULL);
+ }
+
+ return output;
+ }
+
+ FIXME("Unrecognized major type %s\n", debugstr_guid(&major_type));
+ return NULL;
+}
--
2.28.0
2
1
[PATCH] crypt32: Add support for CRYPT_STRING_HEX to CryptBinaryToStringW.
by Dmitry Timoshkov Oct. 30, 2020
by Dmitry Timoshkov Oct. 30, 2020
Oct. 30, 2020
Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
---
dlls/crypt32/base64.c | 79 ++++++++++++++++++++++++-
dlls/crypt32/tests/base64.c | 113 +++++++++++++++++++++++++++++++++++-
2 files changed, 189 insertions(+), 3 deletions(-)
diff --git a/dlls/crypt32/base64.c b/dlls/crypt32/base64.c
index 73619421ab..28cf0eee0e 100644
--- a/dlls/crypt32/base64.c
+++ b/dlls/crypt32/base64.c
@@ -477,7 +477,7 @@ static BOOL BinaryToBase64W(const BYTE *pbBinary,
return ret;
}
-static BOOL BinaryToHexW(const BYTE *bin, DWORD nbin, DWORD flags, LPWSTR str, DWORD *nstr)
+static BOOL BinaryToHexRawW(const BYTE *bin, DWORD nbin, DWORD flags, LPWSTR str, DWORD *nstr)
{
static const WCHAR hex[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
DWORD needed;
@@ -523,6 +523,79 @@ static BOOL BinaryToHexW(const BYTE *bin, DWORD nbin, DWORD flags, LPWSTR str, D
return TRUE;
}
+static BOOL binary_to_hexW(const BYTE *bin, DWORD nbin, DWORD flags, LPWSTR str, DWORD *nstr)
+{
+ static const WCHAR hex[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
+ DWORD needed, i;
+
+ needed = nbin * 3; /* spaces + terminating \0 */
+
+ if (flags & CRYPT_STRING_NOCR)
+ {
+ needed += (nbin + 7) / 16; /* space every 16 characters */
+ needed += 1; /* terminating \n */
+ }
+ else if (!(flags & CRYPT_STRING_NOCRLF))
+ {
+ needed += (nbin + 7) / 16; /* space every 16 characters */
+ needed += nbin / 16 + 1; /* LF every 16 characters + terminating \r */
+
+ if (nbin % 16)
+ needed += 1; /* terminating \n */
+ }
+
+ if (!str)
+ {
+ *nstr = needed;
+ return TRUE;
+ }
+
+ if (needed > *nstr)
+ {
+ SetLastError(ERROR_MORE_DATA);
+ return FALSE;
+ }
+
+ for (i = 0; i < nbin; i++)
+ {
+ *str++ = hex[(bin[i] >> 4) & 0xf];
+ *str++ = hex[bin[i] & 0xf];
+
+ if (i >= nbin - 1) break;
+
+ if (i && !(flags & CRYPT_STRING_NOCRLF))
+ {
+ if (i >= 15 && !((i + 1) % 16))
+ {
+ if (flags & CRYPT_STRING_NOCR)
+ *str++ = '\n';
+ else
+ {
+ *str++ = '\r';
+ *str++ = '\n';
+ }
+ continue;
+ }
+ else if (i >= 7 && !((i + 1) % 8))
+ *str++ = ' ';
+ }
+
+ *str++ = ' ';
+ }
+
+ if (flags & CRYPT_STRING_NOCR)
+ *str++ = '\n';
+ else if (!(flags & CRYPT_STRING_NOCRLF))
+ {
+ *str++ = '\r';
+ *str++ = '\n';
+ }
+
+ *str = 0;
+ *nstr = needed - 1;
+ return TRUE;
+}
+
BOOL WINAPI CryptBinaryToStringW(const BYTE *pbBinary,
DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
{
@@ -554,9 +627,11 @@ BOOL WINAPI CryptBinaryToStringW(const BYTE *pbBinary,
encoder = BinaryToBase64W;
break;
case CRYPT_STRING_HEXRAW:
- encoder = BinaryToHexW;
+ encoder = BinaryToHexRawW;
break;
case CRYPT_STRING_HEX:
+ encoder = binary_to_hexW;
+ break;
case CRYPT_STRING_HEXASCII:
case CRYPT_STRING_HEXADDR:
case CRYPT_STRING_HEXASCIIADDR:
diff --git a/dlls/crypt32/tests/base64.c b/dlls/crypt32/tests/base64.c
index a48f0a5c44..a17267c702 100644
--- a/dlls/crypt32/tests/base64.c
+++ b/dlls/crypt32/tests/base64.c
@@ -236,12 +236,36 @@ static void encode_compare_base64_W(const BYTE *toEncode, DWORD toEncodeLen, DWO
heap_free(trailerW);
}
+static DWORD binary_to_hex_len(DWORD binary_len, DWORD flags)
+{
+ DWORD strLen2;
+
+ strLen2 = binary_len * 3; /* spaces + terminating \0 */
+
+ if (flags & CRYPT_STRING_NOCR)
+ {
+ strLen2 += (binary_len + 7) / 16; /* space every 16 characters */
+ strLen2 += 1; /* terminating \n */
+ }
+ else if (!(flags & CRYPT_STRING_NOCRLF))
+ {
+ strLen2 += (binary_len + 7) / 16; /* space every 16 characters */
+ strLen2 += binary_len / 16 + 1; /* LF every 16 characters + terminating \r */
+
+ if (binary_len % 16)
+ strLen2 += 1; /* terminating \n */
+ }
+
+ return strLen2;
+}
+
static void test_CryptBinaryToString(void)
{
static const DWORD flags[] = { 0, CRYPT_STRING_NOCR, CRYPT_STRING_NOCRLF };
+ static const DWORD sizes[] = { 3, 4, 7, 8, 12, 15, 16, 17, 256 };
static const WCHAR hexdig[] = L"0123456789abcdef";
BYTE input[256 * sizeof(WCHAR)];
- DWORD strLen, strLen2, i, j;
+ DWORD strLen, strLen2, i, j, k;
WCHAR *hex, *cmp, *ptr;
BOOL ret;
@@ -444,6 +468,93 @@ static void test_CryptBinaryToString(void)
heap_free(hex);
heap_free(cmp);
}
+
+ for (k = 0; k < ARRAY_SIZE(sizes); k++)
+ for (i = 0; i < ARRAY_SIZE(flags); i++)
+ {
+ strLen = 0;
+ ret = CryptBinaryToStringW(input, sizes[k], CRYPT_STRING_HEX | flags[i], NULL, &strLen);
+ ok(ret, "CryptBinaryToStringW failed: %d\n", GetLastError());
+ ok(strLen > 0, "Unexpected string length.\n");
+
+ strLen = ~0;
+ ret = CryptBinaryToStringW(input, sizes[k], CRYPT_STRING_HEX | flags[i], NULL, &strLen);
+ ok(ret, "CryptBinaryToStringW failed: %d\n", GetLastError());
+ strLen2 = binary_to_hex_len(sizes[k], CRYPT_STRING_HEX | flags[i]);
+ ok(strLen == strLen2, "%u: Expected length %d, got %d\n", i, strLen2, strLen);
+
+ hex = heap_alloc(strLen * sizeof(WCHAR) + 256);
+ memset(hex, 0xcc, strLen * sizeof(WCHAR));
+
+ ptr = cmp = heap_alloc(strLen * sizeof(WCHAR) + 256);
+ for (j = 0; j < sizes[k]; j++)
+ {
+ *ptr++ = hexdig[(input[j] >> 4) & 0xf];
+ *ptr++ = hexdig[input[j] & 0xf];
+
+ if (j >= sizes[k] - 1) break;
+
+ if (j && !(flags[i] & CRYPT_STRING_NOCRLF))
+ {
+
+ if (j >= 15 && !((j + 1) % 16))
+ {
+ if (flags[i] & CRYPT_STRING_NOCR)
+ {
+ *ptr++ = '\n';
+ }
+ else
+ {
+ *ptr++ = '\r';
+ *ptr++ = '\n';
+ }
+ continue;
+ }
+ else if (j >= 7 && !((j + 1) % 8))
+ *ptr++ = ' ';
+ }
+
+ *ptr++ = ' ';
+ }
+
+ if (flags[i] & CRYPT_STRING_NOCR)
+ {
+ *ptr++ = '\n';
+ }
+ else if (!(flags[i] & CRYPT_STRING_NOCRLF))
+ {
+ *ptr++ = '\r';
+ *ptr++ = '\n';
+ }
+ *ptr++ = 0;
+
+ ret = CryptBinaryToStringW(input, sizes[k], CRYPT_STRING_HEX | flags[i], hex, &strLen);
+ ok(ret, "CryptBinaryToStringW failed: %d\n", GetLastError());
+ strLen2--;
+ ok(strLen == strLen2, "%u: Expected length %d, got %d\n", i, strLen, strLen2);
+ ok(!memcmp(hex, cmp, strLen * sizeof(WCHAR)), "%u: got %s\n", i, wine_dbgstr_wn(hex, strLen));
+
+ /* adjusts size if buffer too big */
+ strLen *= 2;
+ ret = CryptBinaryToStringW(input, sizes[k], CRYPT_STRING_HEX | flags[i], hex, &strLen);
+ ok(ret, "CryptBinaryToStringW failed: %d\n", GetLastError());
+ ok(strLen == strLen2, "%u: Expected length %d, got %d\n", i, strLen, strLen2);
+
+ /* no writes if buffer too small */
+ strLen /= 2;
+ strLen2 /= 2;
+ memset(hex, 0xcc, strLen * sizeof(WCHAR));
+ memset(cmp, 0xcc, strLen * sizeof(WCHAR));
+ SetLastError(0xdeadbeef);
+ ret = CryptBinaryToStringW(input, sizes[k], CRYPT_STRING_HEX | flags[i], hex, &strLen);
+ ok(!ret && GetLastError() == ERROR_MORE_DATA,"Expected ERROR_MORE_DATA, got ret=%d le=%u\n",
+ ret, GetLastError());
+ ok(strLen == strLen2, "%u: Expected length %d, got %d\n", i, strLen, strLen2);
+ ok(!memcmp(hex, cmp, strLen * sizeof(WCHAR)), "%u: got %s\n", i, wine_dbgstr_wn(hex, strLen));
+
+ heap_free(hex);
+ heap_free(cmp);
+ }
}
static void decodeAndCompareBase64_A(LPCSTR toDecode, LPCSTR header,
--
2.29.1
1
0
[PATCH 1/5] winegstreamer: Replace gst_pad_get_current_caps with gst_pad_query_caps.
by Derek Lesho Oct. 30, 2020
by Derek Lesho Oct. 30, 2020
Oct. 30, 2020
Signed-off-by: Derek Lesho <dlesho(a)codeweavers.com>
---
v1: v5 of 528e687 was meant to revert the change from gst_pad_query_caps to gst_pad_get_current_caps at zebediah's suggestion, however, I somehow managed to resend a duplicate of v4 instead. This resolves that.
---
dlls/winegstreamer/media_source.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index 0991710755c..d6c7837e544 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -388,7 +388,7 @@ static const IMFMediaStreamVtbl media_stream_vtbl =
the user throws at us through gstreamer's caps negotiation. */
static HRESULT media_stream_connect_to_sink(struct media_stream *stream)
{
- GstCaps *source_caps = gst_pad_get_current_caps(stream->their_src);
+ GstCaps *source_caps = gst_pad_query_caps(stream->their_src, NULL);
const gchar *stream_type;
if (!source_caps)
--
2.28.0
4
13
[v3 PATCH 3/5] mfreadwrite: Abort ReadSample when unable to request any samples.
by Nikolay Sivov Oct. 30, 2020
by Nikolay Sivov Oct. 30, 2020
Oct. 30, 2020
From: Derek Lesho <dlesho(a)codeweavers.com>
Signed-off-by: Derek Lesho <dlesho(a)codeweavers.com>
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
v3: removed reset of actual index, will send some tests later for that
(currently blocked by mfplat fix preventing first stream detection).
dlls/mfreadwrite/reader.c | 13 ++++++++++---
dlls/mfreadwrite/tests/mfplat.c | 26 ++++++++++++++++++++++++++
2 files changed, 36 insertions(+), 3 deletions(-)
diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c
index 96a82b798ab..cc1b29a2b6a 100644
--- a/dlls/mfreadwrite/reader.c
+++ b/dlls/mfreadwrite/reader.c
@@ -439,7 +439,8 @@ static HRESULT source_reader_new_stream_handler(struct source_reader *reader, IM
}
if (reader->streams[i].requests)
- source_reader_request_sample(reader, &reader->streams[i]);
+ if (FAILED(source_reader_request_sample(reader, &reader->streams[i])))
+ WakeAllConditionVariable(&reader->sample_event);
}
break;
}
@@ -1780,10 +1781,16 @@ static HRESULT source_reader_read_sample(struct source_reader *reader, DWORD ind
stream->requests++;
if (FAILED(hr = source_reader_request_sample(reader, stream)))
WARN("Failed to request a sample, hr %#x.\n", hr);
+ if (stream->stream && !(stream->flags & STREAM_FLAG_SAMPLE_REQUESTED))
+ {
+ *stream_flags = MF_SOURCE_READERF_ERROR;
+ *timestamp = 0;
+ break;
+ }
SleepConditionVariableCS(&reader->sample_event, &reader->cs, INFINITE);
}
-
- source_reader_get_read_result(reader, stream, flags, &hr, actual_index, stream_flags,
+ if (SUCCEEDED(hr))
+ source_reader_get_read_result(reader, stream, flags, &hr, actual_index, stream_flags,
timestamp, sample);
}
}
diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c
index cfe68cb6736..0e5053f905f 100644
--- a/dlls/mfreadwrite/tests/mfplat.c
+++ b/dlls/mfreadwrite/tests/mfplat.c
@@ -158,6 +158,8 @@ static HRESULT WINAPI test_media_stream_GetStreamDescriptor(IMFMediaStream *ifac
return S_OK;
}
+static BOOL fail_request_sample;
+
static HRESULT WINAPI test_media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token)
{
struct test_media_stream *stream = impl_from_IMFMediaStream(iface);
@@ -165,6 +167,9 @@ static HRESULT WINAPI test_media_stream_RequestSample(IMFMediaStream *iface, IUn
IMFSample *sample;
HRESULT hr;
+ if (fail_request_sample)
+ return E_NOTIMPL;
+
hr = MFCreateSample(&sample);
ok(hr == S_OK, "Failed to create a sample, hr %#x.\n", hr);
hr = IMFSample_SetSampleTime(sample, 123);
@@ -977,6 +982,27 @@ static void test_source_reader_from_media_source(void)
ok(hr == MF_E_NOTACCEPTING, "Unexpected hr %#x.\n", hr);
IMFSourceReader_Release(reader);
+ IMFMediaSource_Release(source);
+
+ /* RequestSample failure. */
+ source = create_test_source();
+ ok(!!source, "Failed to create test source.\n");
+
+ fail_request_sample = TRUE;
+
+ hr = MFCreateSourceReaderFromMediaSource(source, NULL, &reader);
+ ok(hr == S_OK, "Failed to create source reader, hr %#x.\n", hr);
+
+ hr = IMFSourceReader_SetStreamSelection(reader, 0, TRUE);
+ ok(hr == S_OK, "Failed to select a stream, hr %#x.\n", hr);
+
+ hr = IMFSourceReader_ReadSample(reader, 0, 0, &actual_index, &stream_flags, ×tamp, &sample);
+ ok(hr == E_NOTIMPL, "Unexpected ReadSample result, hr %#x.\n", hr);
+
+ IMFSourceReader_Release(reader);
+ IMFMediaSource_Release(source);
+
+ fail_request_sample = FALSE;
}
START_TEST(mfplat)
--
2.28.0
1
0