2 * Unit tests for monitor APIs
4 * Copyright 2005 Huw Davies
5 * Copyright 2008 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/test.h"
27 #include "wine/heap.h"
31 static LONG (WINAPI
*pGetDisplayConfigBufferSizes
)(UINT32
,UINT32
*,UINT32
*);
32 static LONG (WINAPI
*pQueryDisplayConfig
)(UINT32
,UINT32
*,DISPLAYCONFIG_PATH_INFO
*,UINT32
*,
33 DISPLAYCONFIG_MODE_INFO
*,DISPLAYCONFIG_TOPOLOGY_ID
*);
34 static LONG (WINAPI
*pDisplayConfigGetDeviceInfo
)(DISPLAYCONFIG_DEVICE_INFO_HEADER
*);
35 static DPI_AWARENESS_CONTEXT (WINAPI
*pSetThreadDpiAwarenessContext
)(DPI_AWARENESS_CONTEXT
);
37 static void init_function_pointers(void)
39 hdll
= GetModuleHandleA("user32.dll");
41 #define GET_PROC(func) \
42 p ## func = (void*)GetProcAddress(hdll, #func); \
44 trace("GetProcAddress(%s) failed\n", #func);
46 GET_PROC(GetDisplayConfigBufferSizes
)
47 GET_PROC(QueryDisplayConfig
)
48 GET_PROC(DisplayConfigGetDeviceInfo
)
49 GET_PROC(SetThreadDpiAwarenessContext
)
54 static void flush_events(void)
60 time
= GetTickCount() + diff
;
63 if (MsgWaitForMultipleObjects(0, NULL
, FALSE
, 200, QS_ALLINPUT
) == WAIT_TIMEOUT
)
65 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
))
66 DispatchMessageA(&msg
);
67 diff
= time
- GetTickCount();
71 static BOOL CALLBACK
monitor_enum_proc(HMONITOR hmon
, HDC hdc
, LPRECT lprc
,
75 char *primary
= (char *)lparam
;
77 mi
.cbSize
= sizeof(mi
);
79 ok(GetMonitorInfoA(hmon
, (MONITORINFO
*)&mi
), "GetMonitorInfo failed\n");
80 if (mi
.dwFlags
& MONITORINFOF_PRIMARY
)
81 strcpy(primary
, mi
.szDevice
);
86 static int adapter_count
= 0;
87 static int monitor_count
= 0;
89 static void test_enumdisplaydevices_adapter(int index
, const DISPLAY_DEVICEA
*device
, DWORD flags
)
102 ok(sscanf(device
->DeviceName
, "\\\\.\\DISPLAY%d", &number
) == 1, "#%d: wrong DeviceName %s\n", index
,
106 /* \Device\Video? value in HLKM\HARDWARE\DEVICEMAP\VIDEO are not necessarily in order with adapter index.
107 * Check format only */
108 ok(sscanf(device
->DeviceKey
, "\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Video\\%[^\\]\\%04d", buffer
, &number
) == 2,
109 "#%d: wrong DeviceKey %s\n", index
, device
->DeviceKey
);
112 ok(broken(!*device
->DeviceString
) || /* XP on Testbot will return an empty string, whereas XP on real machine doesn't. Probably a bug in virtual adapter driver */
113 *device
->DeviceString
, "#%d: expect DeviceString not empty\n", index
);
117 ok(device
->StateFlags
& DISPLAY_DEVICE_PRIMARY_DEVICE
, "#%d: adapter should be primary\n", index
);
119 ok(!(device
->StateFlags
& DISPLAY_DEVICE_PRIMARY_DEVICE
), "#%d: adapter should not be primary\n", index
);
121 if (device
->StateFlags
& DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
)
123 /* Test creating DC */
124 hdc
= CreateDCA(device
->DeviceName
, NULL
, NULL
, NULL
);
125 ok(hdc
!= NULL
, "#%d: failed to CreateDC(\"%s\") err=%d\n", index
, device
->DeviceName
, GetLastError());
130 /* DeviceID should equal to the first string of HardwareID value data in PCI GPU instance. You can verify this
131 * by changing the data and rerun EnumDisplayDevices. But it's difficult to find corresponding PCI device on
132 * userland. So here we check the expected format instead. */
133 if (flags
& EDD_GET_DEVICE_INTERFACE_NAME
)
134 ok(strlen(device
->DeviceID
) == 0 || /* vista+ */
135 sscanf(device
->DeviceID
, "PCI\\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X",
136 &vendor_id
, &device_id
, &subsys_id
, &revision_id
) == 4, /* XP/2003 ignores EDD_GET_DEVICE_INTERFACE_NAME */
137 "#%d: got %s\n", index
, device
->DeviceID
);
140 ok(broken(strlen(device
->DeviceID
) == 0) || /* XP on Testbot returns an empty string, whereas real machine doesn't */
141 sscanf(device
->DeviceID
, "PCI\\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X", &vendor_id
, &device_id
, &subsys_id
,
142 &revision_id
) == 4, "#%d: wrong DeviceID %s\n", index
, device
->DeviceID
);
146 static void test_enumdisplaydevices_monitor(int adapter_index
, int monitor_index
, const char *adapter_name
,
147 DISPLAY_DEVICEA
*device
, DWORD flags
)
149 static const char device_key_prefix
[] = "\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class"
150 "\\{4d36e96e-e325-11ce-bfc1-08002be10318}\\";
151 char monitor_name
[32];
158 lstrcpyA(monitor_name
, adapter_name
);
159 sprintf(monitor_name
+ strlen(monitor_name
), "\\Monitor%d", monitor_index
);
160 ok(!strcmp(monitor_name
, device
->DeviceName
), "#%d: expect %s, got %s\n", monitor_index
, monitor_name
, device
->DeviceName
);
163 ok(*device
->DeviceString
, "#%d: expect DeviceString not empty\n", monitor_index
);
166 if (adapter_index
== 0 && monitor_index
== 0)
167 ok(device
->StateFlags
& DISPLAY_DEVICE_ATTACHED
, "#%d expect to have a primary monitor attached\n", monitor_index
);
169 ok(device
->StateFlags
<= (DISPLAY_DEVICE_ATTACHED
| DISPLAY_DEVICE_ACTIVE
), "#%d wrong state %#x\n", monitor_index
,
173 CharLowerA(device
->DeviceID
);
174 if (flags
& EDD_GET_DEVICE_INTERFACE_NAME
)
175 { /* HKLM\SYSTEM\CurrentControlSet\Enum\DISPLAY\[monitor name]\[instance id] GUID_DEVINTERFACE_MONITOR
177 * Expect format \\?\DISPLAY#[monitor name]#[instance id]#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7} */
178 ok(strlen(device
->DeviceID
) == 0 || /* vista ~ win7 */
179 sscanf(device
->DeviceID
, "\\\\?\\display#%[^#]#%[^#]#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}", buffer
, buffer
) == 2 || /* win8+ */
180 sscanf(device
->DeviceID
, "monitor\\%[^\\]\\{4d36e96e-e325-11ce-bfc1-08002be10318}\\%04d", buffer
, &number
) == 2, /* XP/2003 ignores EDD_GET_DEVICE_INTERFACE_NAME */
181 "#%d: wrong DeviceID : %s\n", monitor_index
, device
->DeviceID
);
185 /* Expect HarewareID value data + Driver value data in HKLM\SYSTEM\CurrentControlSet\Enum\DISPLAY\[monitor name]\{instance} */
186 /* But we don't know which monitor instance this belongs to, so check format instead */
187 ok(sscanf(device
->DeviceID
, "monitor\\%[^\\]\\{4d36e96e-e325-11ce-bfc1-08002be10318}\\%04d", buffer
, &number
) == 2,
188 "#%d: wrong DeviceID : %s\n", monitor_index
, device
->DeviceID
);
192 lstrcpynA(buffer
, device
->DeviceKey
, sizeof(device_key_prefix
));
193 ok(!lstrcmpiA(buffer
, device_key_prefix
), "#%d: wrong DeviceKey : %s\n", monitor_index
, device
->DeviceKey
);
194 ok(sscanf(device
->DeviceKey
+ sizeof(device_key_prefix
) - 1, "%04d", &number
) == 1,
195 "#%d wrong DeviceKey : %s\n", monitor_index
, device
->DeviceKey
);
198 static void test_enumdisplaydevices(void)
200 static const DWORD flags
[] = {0, EDD_GET_DEVICE_INTERFACE_NAME
};
202 char primary_device_name
[32];
203 char primary_monitor_device_name
[32];
204 char adapter_name
[32];
211 /* Doesn't accept \\.\DISPLAY */
213 ret
= EnumDisplayDevicesA("\\\\.\\DISPLAY", 0, &dd
, 0);
214 ok(!ret
, "Expect failure\n");
217 for (flag_index
= 0; flag_index
< ARRAY_SIZE(flags
); flag_index
++)
218 for (adapter_index
= 0; EnumDisplayDevicesA(NULL
, adapter_index
, &dd
, flags
[flag_index
]); adapter_index
++)
220 lstrcpyA(adapter_name
, dd
.DeviceName
);
222 if (sscanf(adapter_name
, "\\\\.\\DISPLAYV%d", &number
) == 1)
224 skip("Skipping software devices %s:%s\n", adapter_name
, dd
.DeviceString
);
228 test_enumdisplaydevices_adapter(adapter_index
, &dd
, flags
[flag_index
]);
230 for (monitor_index
= 0; EnumDisplayDevicesA(adapter_name
, monitor_index
, &dd
, flags
[flag_index
]);
232 test_enumdisplaydevices_monitor(adapter_index
, monitor_index
, adapter_name
, &dd
, flags
[flag_index
]);
235 ok(adapter_count
> 0, "Expect at least one adapter found\n");
236 /* XP on Testbot doesn't report a monitor, whereas XP on real machine does */
237 ok(broken(monitor_count
== 0) || monitor_count
> 0, "Expect at least one monitor found\n");
239 ret
= EnumDisplayDevicesA(NULL
, 0, &dd
, 0);
240 ok(ret
, "Expect success\n");
241 lstrcpyA(primary_device_name
, dd
.DeviceName
);
243 primary_monitor_device_name
[0] = 0;
244 ret
= EnumDisplayMonitors(NULL
, NULL
, monitor_enum_proc
, (LPARAM
)primary_monitor_device_name
);
245 ok(ret
, "EnumDisplayMonitors failed\n");
246 ok(!strcmp(primary_monitor_device_name
, primary_device_name
),
247 "monitor device name %s, device name %s\n", primary_monitor_device_name
,
248 primary_device_name
);
253 DWORD w
, h
, bpp
, freq
, fields
;
257 static const struct vid_mode vid_modes_test
[] = {
258 {1024, 768, 0, 0, DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_BITSPERPEL
| DM_DISPLAYFREQUENCY
, 0},
259 {1024, 768, 0, 0, DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_DISPLAYFREQUENCY
, 1},
260 {1024, 768, 0, 1, DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_DISPLAYFREQUENCY
, 0},
261 {1024, 768, 0, 0, DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_BITSPERPEL
, 0},
262 {1024, 768, 0, 0, DM_PELSWIDTH
| DM_PELSHEIGHT
, 1},
263 {1024, 768, 0, 0, DM_BITSPERPEL
, 0},
264 {1024, 768, 0, 0, DM_DISPLAYFREQUENCY
, 0},
266 {0, 0, 0, 0, DM_PELSWIDTH
, 0},
267 {0, 0, 0, 0, DM_PELSHEIGHT
, 0},
269 {1024, 768, 0, 0, DM_PELSWIDTH
, 0},
270 {1024, 768, 0, 0, DM_PELSHEIGHT
, 0},
271 { 0, 768, 0, 0, DM_PELSWIDTH
| DM_PELSHEIGHT
, 0},
272 {1024, 0, 0, 0, DM_PELSWIDTH
| DM_PELSHEIGHT
, 0},
274 /* the following test succeeds under XP SP3
275 {0, 0, 0, 0, DM_DISPLAYFREQUENCY, 0}
282 CHAR name
[CCHDEVICENAME
];
283 DEVMODEA original_mode
;
286 #define expect_dm(a, b, c) _expect_dm(__LINE__, a, b, c)
287 static void _expect_dm(INT line
, const DEVMODEA
*expected
, const CHAR
*device
, DWORD test
)
292 memset(&dm
, 0, sizeof(dm
));
293 dm
.dmSize
= sizeof(dm
);
294 SetLastError(0xdeadbeef);
295 ret
= EnumDisplaySettingsA(device
, ENUM_CURRENT_SETTINGS
, &dm
);
296 ok_(__FILE__
, line
)(ret
, "Device %s test %d EnumDisplaySettingsA failed, error %#x\n", device
, test
, GetLastError());
298 ok_(__FILE__
, line
)((dm
.dmFields
& expected
->dmFields
) == expected
->dmFields
,
299 "Device %s test %d expect dmFields to contain %#x, got %#x\n", device
, test
, expected
->dmFields
, dm
.dmFields
);
300 /* Wine doesn't support changing color depth yet */
301 todo_wine_if(expected
->dmFields
& DM_BITSPERPEL
&& expected
->dmBitsPerPel
!= 32 && expected
->dmBitsPerPel
!= 24)
302 ok_(__FILE__
, line
)(!(expected
->dmFields
& DM_BITSPERPEL
) || dm
.dmBitsPerPel
== expected
->dmBitsPerPel
,
303 "Device %s test %d expect dmBitsPerPel %u, got %u\n", device
, test
, expected
->dmBitsPerPel
, dm
.dmBitsPerPel
);
304 ok_(__FILE__
, line
)(!(expected
->dmFields
& DM_PELSWIDTH
) || dm
.dmPelsWidth
== expected
->dmPelsWidth
,
305 "Device %s test %d expect dmPelsWidth %u, got %u\n", device
, test
, expected
->dmPelsWidth
, dm
.dmPelsWidth
);
306 ok_(__FILE__
, line
)(!(expected
->dmFields
& DM_PELSHEIGHT
) || dm
.dmPelsHeight
== expected
->dmPelsHeight
,
307 "Device %s test %d expect dmPelsHeight %u, got %u\n", device
, test
, expected
->dmPelsHeight
, dm
.dmPelsHeight
);
308 ok_(__FILE__
, line
)(!(expected
->dmFields
& DM_POSITION
) || dm
.dmPosition
.x
== expected
->dmPosition
.x
,
309 "Device %s test %d expect dmPosition.x %d, got %d\n", device
, test
, expected
->dmPosition
.x
, dm
.dmPosition
.x
);
310 ok_(__FILE__
, line
)(!(expected
->dmFields
& DM_POSITION
) || dm
.dmPosition
.y
== expected
->dmPosition
.y
,
311 "Device %s test %d expect dmPosition.y %d, got %d\n", device
, test
, expected
->dmPosition
.y
, dm
.dmPosition
.y
);
312 ok_(__FILE__
, line
)(!(expected
->dmFields
& DM_DISPLAYFREQUENCY
) ||
313 dm
.dmDisplayFrequency
== expected
->dmDisplayFrequency
,
314 "Device %s test %d expect dmDisplayFrequency %u, got %u\n", device
, test
, expected
->dmDisplayFrequency
,
315 dm
.dmDisplayFrequency
);
316 ok_(__FILE__
, line
)(!(expected
->dmFields
& DM_DISPLAYORIENTATION
) ||
317 dm
.dmDisplayOrientation
== expected
->dmDisplayOrientation
,
318 "Device %s test %d expect dmDisplayOrientation %d, got %d\n", device
, test
, expected
->dmDisplayOrientation
,
319 dm
.dmDisplayOrientation
);
322 static void test_ChangeDisplaySettingsEx(void)
324 static const DWORD registry_fields
= DM_DISPLAYORIENTATION
| DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
|
325 DM_DISPLAYFLAGS
| DM_DISPLAYFREQUENCY
| DM_POSITION
;
326 static const DWORD depths
[] = {8, 16, 32};
327 DPI_AWARENESS_CONTEXT context
= NULL
;
328 UINT primary
, device
, test
, mode
;
329 UINT device_size
, device_count
;
330 struct device_info
*devices
;
331 DEVMODEA dm
, dm2
, dm3
;
332 INT count
, old_count
;
339 /* Test invalid device names */
340 memset(&dm
, 0, sizeof(dm
));
341 dm
.dmSize
= sizeof(dm
);
342 res
= EnumDisplaySettingsA(NULL
, ENUM_CURRENT_SETTINGS
, &dm
);
343 ok(res
, "EnumDisplaySettingsA failed, error %#x\n", GetLastError());
345 res
= ChangeDisplaySettingsExA("invalid", &dm
, NULL
, CDS_TEST
, NULL
);
346 ok(res
== DISP_CHANGE_BADPARAM
, "ChangeDisplaySettingsA returned unexpected %d\n", res
);
348 res
= ChangeDisplaySettingsExA("\\\\.\\DISPLAY0", &dm
, NULL
, CDS_TEST
, NULL
);
349 ok(res
== DISP_CHANGE_BADPARAM
, "ChangeDisplaySettingsA returned unexpected %d\n", res
);
351 res
= ChangeDisplaySettingsExA("\\\\.\\DISPLAY1\\Monitor0", &dm
, NULL
, CDS_TEST
, NULL
);
352 ok(res
== DISP_CHANGE_BADPARAM
, "ChangeDisplaySettingsA returned unexpected %d\n", res
);
354 /* Test dmDriverExtra */
355 memset(&dm
, 0, sizeof(dm
));
356 dm
.dmSize
= sizeof(dm
);
357 res
= EnumDisplaySettingsA(NULL
, ENUM_CURRENT_SETTINGS
, &dm
);
358 ok(res
, "EnumDisplaySettingsA failed, error %#x\n", GetLastError());
360 memset(&dmW
, 0, sizeof(dmW
));
361 dmW
.dmSize
= sizeof(dmW
);
362 res
= EnumDisplaySettingsW(NULL
, ENUM_CURRENT_SETTINGS
, &dmW
);
363 ok(res
, "EnumDisplaySettingsW failed, error %#x\n", GetLastError());
365 /* ChangeDisplaySettingsA/W reset dmDriverExtra to 0 */
366 dm
.dmDriverExtra
= 1;
367 res
= ChangeDisplaySettingsA(&dm
, CDS_TEST
);
368 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsA returned unexpected %d\n", res
);
369 ok(dm
.dmDriverExtra
== 0, "ChangeDisplaySettingsA didn't reset dmDriverExtra to 0\n");
371 dmW
.dmDriverExtra
= 1;
372 res
= ChangeDisplaySettingsW(&dmW
, CDS_TEST
);
373 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsW returned unexpected %d\n", res
);
374 ok(dmW
.dmDriverExtra
== 0, "ChangeDisplaySettingsW didn't reset dmDriverExtra to 0\n");
376 /* ChangeDisplaySettingsExA/W do not modify dmDriverExtra */
377 dm
.dmDriverExtra
= 1;
378 res
= ChangeDisplaySettingsExA(NULL
, &dm
, NULL
, CDS_TEST
, NULL
);
379 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA returned unexpected %d\n", res
);
380 ok(dm
.dmDriverExtra
== 1, "ChangeDisplaySettingsExA shouldn't change dmDriverExtra\n");
382 dmW
.dmDriverExtra
= 1;
383 res
= ChangeDisplaySettingsExW(NULL
, &dmW
, NULL
, CDS_TEST
, NULL
);
384 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExW returned unexpected %d\n", res
);
385 ok(dmW
.dmDriverExtra
== 1, "ChangeDisplaySettingsExW shouldn't change dmDriverExtra\n");
388 /* ChangeDisplaySettingsA/ExA report success even if dmSize is 0 */
389 memset(&dm
, 0, sizeof(dm
));
390 dm
.dmSize
= sizeof(dm
);
391 res
= EnumDisplaySettingsA(NULL
, ENUM_CURRENT_SETTINGS
, &dm
);
392 ok(res
, "EnumDisplaySettingsA failed, error %#x\n", GetLastError());
395 res
= ChangeDisplaySettingsA(&dm
, CDS_TEST
);
396 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsA returned unexpected %d\n", res
);
399 res
= ChangeDisplaySettingsExA(NULL
, &dm
, NULL
, CDS_TEST
, NULL
);
400 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA returned unexpected %d\n", res
);
402 /* dmSize for ChangeDisplaySettingsW/ExW needs to be at least FIELD_OFFSET(DEVMODEW, dmICMMethod) */
403 memset(&dmW
, 0, sizeof(dmW
));
404 dmW
.dmSize
= sizeof(dmW
);
405 res
= EnumDisplaySettingsW(NULL
, ENUM_CURRENT_SETTINGS
, &dmW
);
406 ok(res
, "EnumDisplaySettingsW failed, error %#x\n", GetLastError());
408 dmW
.dmSize
= FIELD_OFFSET(DEVMODEW
, dmICMMethod
) - 1;
409 res
= ChangeDisplaySettingsW(&dmW
, CDS_TEST
);
410 ok(res
== DISP_CHANGE_BADMODE
, "ChangeDisplaySettingsW returned %d, expect DISP_CHANGE_BADMODE\n", res
);
412 dmW
.dmSize
= FIELD_OFFSET(DEVMODEW
, dmICMMethod
) - 1;
413 res
= ChangeDisplaySettingsExW(NULL
, &dmW
, NULL
, CDS_TEST
, NULL
);
414 ok(res
== DISP_CHANGE_BADMODE
, "ChangeDisplaySettingsExW returned %d, expect DISP_CHANGE_BADMODE\n", res
);
416 dmW
.dmSize
= FIELD_OFFSET(DEVMODEW
, dmICMMethod
);
417 res
= ChangeDisplaySettingsW(&dmW
, CDS_TEST
);
418 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsW returned unexpected %d\n", res
);
420 dmW
.dmSize
= FIELD_OFFSET(DEVMODEW
, dmICMMethod
);
421 res
= ChangeDisplaySettingsExW(NULL
, &dmW
, NULL
, CDS_TEST
, NULL
);
422 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExW returned unexpected %d\n", res
);
424 /* Test clip rectangle after resolution changes */
425 /* GetClipCursor always returns result in physical pixels but GetSystemMetrics(SM_CX/CYVIRTUALSCREEN) are not.
426 * Set per-monitor aware context so that virtual screen rectangles are in physical pixels */
427 if (pSetThreadDpiAwarenessContext
)
428 context
= pSetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
);
429 memset(&dm
, 0, sizeof(dm
));
430 dm
.dmSize
= sizeof(dm
);
432 for (i
= 0; i
< ARRAY_SIZE(vid_modes_test
); i
++)
434 dm
.dmPelsWidth
= vid_modes_test
[i
].w
;
435 dm
.dmPelsHeight
= vid_modes_test
[i
].h
;
436 dm
.dmBitsPerPel
= vid_modes_test
[i
].bpp
;
437 dm
.dmDisplayFrequency
= vid_modes_test
[i
].freq
;
438 dm
.dmFields
= vid_modes_test
[i
].fields
;
439 res
= ChangeDisplaySettingsExA(NULL
, &dm
, NULL
, CDS_TEST
, NULL
);
440 ok(vid_modes_test
[i
].must_succeed
?
441 (res
== DISP_CHANGE_SUCCESSFUL
|| res
== DISP_CHANGE_RESTART
) :
442 (res
== DISP_CHANGE_SUCCESSFUL
|| res
== DISP_CHANGE_RESTART
||
443 res
== DISP_CHANGE_BADMODE
|| res
== DISP_CHANGE_BADPARAM
),
444 "Unexpected ChangeDisplaySettingsExA() return code for vid_modes_test[%d]: %d\n", i
, res
);
446 if (res
== DISP_CHANGE_SUCCESSFUL
)
450 SetRect(&virt
, 0, 0, GetSystemMetrics(SM_CXVIRTUALSCREEN
), GetSystemMetrics(SM_CYVIRTUALSCREEN
));
451 if (IsRectEmpty(&virt
)) /* NT4 doesn't have SM_CX/YVIRTUALSCREEN */
452 SetRect(&virt
, 0, 0, GetSystemMetrics(SM_CXSCREEN
), GetSystemMetrics(SM_CYSCREEN
));
453 OffsetRect(&virt
, GetSystemMetrics(SM_XVIRTUALSCREEN
), GetSystemMetrics(SM_YVIRTUALSCREEN
));
455 /* Resolution change resets clip rect */
456 ok(GetClipCursor(&r
), "GetClipCursor() failed\n");
457 ok(EqualRect(&r
, &virt
), "Invalid clip rect: %s\n", wine_dbgstr_rect(&r
));
459 if (!ClipCursor(NULL
)) continue;
460 ok(GetClipCursor(&r
), "GetClipCursor() failed\n");
461 ok(EqualRect(&r
, &virt
), "Invalid clip rect: %s\n", wine_dbgstr_rect(&r
));
463 /* This should always work. Primary monitor is at (0,0) */
464 SetRect(&r1
, 10, 10, 20, 20);
465 ok(ClipCursor(&r1
), "ClipCursor() failed\n");
466 ok(GetClipCursor(&r
), "GetClipCursor() failed\n");
467 ok(EqualRect(&r
, &r1
), "Invalid clip rect: %s\n", wine_dbgstr_rect(&r
));
468 SetRect(&r1
, 10, 10, 10, 10);
469 ok(ClipCursor(&r1
), "ClipCursor() failed\n");
470 ok(GetClipCursor(&r
), "GetClipCursor() failed\n");
471 ok(EqualRect(&r
, &r1
), "Invalid clip rect: %s\n", wine_dbgstr_rect(&r
));
472 SetRect(&r1
, 10, 10, 10, 9);
473 ok(!ClipCursor(&r1
), "ClipCursor() succeeded\n");
474 /* Windows bug: further clipping fails once an empty rect is set, so we have to reset it */
477 SetRect(&r1
, virt
.left
- 10, virt
.top
- 10, virt
.right
+ 20, virt
.bottom
+ 20);
478 ok(ClipCursor(&r1
), "ClipCursor() failed\n");
479 ok(GetClipCursor(&r
), "GetClipCursor() failed\n");
480 ok(EqualRect(&r
, &virt
) || broken(EqualRect(&r
, &r1
)) /* win9x */,
481 "Invalid clip rect: %s\n", wine_dbgstr_rect(&r
));
485 if (pSetThreadDpiAwarenessContext
&& context
)
486 pSetThreadDpiAwarenessContext(context
);
487 res
= ChangeDisplaySettingsExA(NULL
, NULL
, NULL
, CDS_RESET
, NULL
);
488 ok(res
== DISP_CHANGE_SUCCESSFUL
, "Failed to reset default resolution: %d\n", res
);
490 /* Save the original mode for all devices so that they can be restored at the end of tests */
493 devices
= heap_calloc(device_size
, sizeof(*devices
));
494 ok(devices
!= NULL
, "Failed to allocate memory.\n");
497 memset(&dd
, 0, sizeof(dd
));
499 for (device
= 0; EnumDisplayDevicesA(NULL
, device
, &dd
, 0); ++device
)
503 /* Skip software devices */
504 if (sscanf(dd
.DeviceName
, "\\\\.\\DISPLAY%d", &number
) != 1)
507 if (!(dd
.StateFlags
& DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
))
510 if (dd
.StateFlags
& DISPLAY_DEVICE_PRIMARY_DEVICE
)
511 primary
= device_count
;
513 if (device_count
>= device_size
)
516 devices
= heap_realloc(devices
, device_size
* sizeof(*devices
));
517 ok(devices
!= NULL
, "Failed to reallocate memory.\n");
520 devices
[device_count
].index
= device
;
521 lstrcpyA(devices
[device_count
].name
, dd
.DeviceName
);
522 memset(&devices
[device_count
].original_mode
, 0, sizeof(devices
[device_count
].original_mode
));
523 devices
[device_count
].original_mode
.dmSize
= sizeof(devices
[device_count
].original_mode
);
524 res
= EnumDisplaySettingsA(dd
.DeviceName
, ENUM_CURRENT_SETTINGS
, &devices
[device_count
].original_mode
);
525 ok(res
, "EnumDisplaySettingsA %s failed, error %#x\n", dd
.DeviceName
, GetLastError());
529 /* Make the primary adapter first */
532 struct device_info tmp
;
534 devices
[0] = devices
[primary
];
535 devices
[primary
] = tmp
;
538 /* Test detaching adapters */
539 /* Test that when there is only one adapter, it can't be detached */
540 if (device_count
== 1)
542 old_count
= GetSystemMetrics(SM_CMONITORS
);
544 memset(&dm
, 0, sizeof(dm
));
545 dm
.dmSize
= sizeof(dm
);
546 dm
.dmFields
= DM_POSITION
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
547 dm
.dmPosition
= devices
[0].original_mode
.dmPosition
;
548 res
= ChangeDisplaySettingsExA(devices
[0].name
, &dm
, NULL
, CDS_UPDATEREGISTRY
| CDS_NORESET
, NULL
);
549 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA %s returned unexpected %d\n", devices
[0].name
, res
);
550 res
= ChangeDisplaySettingsExA(NULL
, NULL
, NULL
, 0, NULL
);
551 ok(res
== DISP_CHANGE_SUCCESSFUL
||
552 broken(res
== DISP_CHANGE_FAILED
), /* win8 TestBot */
553 "ChangeDisplaySettingsExA %s returned unexpected %d\n", devices
[0].name
, res
);
555 /* Check that the adapter is still attached */
557 res
= EnumDisplayDevicesA(NULL
, devices
[0].index
, &dd
, 0);
558 ok(res
, "EnumDisplayDevicesA %s failed, error %#x\n", devices
[0].name
, GetLastError());
559 ok(dd
.StateFlags
& DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
, "Expect device %s still attached.\n", devices
[0].name
);
561 count
= GetSystemMetrics(SM_CMONITORS
);
562 ok(count
== old_count
, "Expect monitor count %d, got %d\n", old_count
, count
);
564 /* Restore registry settings */
565 res
= ChangeDisplaySettingsExA(devices
[0].name
, &devices
[0].original_mode
, NULL
,
566 CDS_UPDATEREGISTRY
| CDS_NORESET
, NULL
);
567 ok(res
== DISP_CHANGE_SUCCESSFUL
||
568 broken(res
== DISP_CHANGE_BADPARAM
) || /* win10 */
569 broken(res
== DISP_CHANGE_FAILED
), /* win8 TestBot */
570 "ChangeDisplaySettingsExA %s returned unexpected %d\n", devices
[0].name
, res
);
571 res
= ChangeDisplaySettingsExA(NULL
, NULL
, NULL
, 0, NULL
);
572 ok(res
== DISP_CHANGE_SUCCESSFUL
||
573 broken(res
== DISP_CHANGE_FAILED
), /* win8 TestBot */
574 "ChangeDisplaySettingsExA %s returned unexpected %d\n", devices
[0].name
, res
);
577 /* Test that only specifying DM_POSITION in dmFields is not enough to detach an adapter */
578 if (device_count
>= 2)
580 old_count
= GetSystemMetrics(SM_CMONITORS
);
582 /* MSDN says set dmFields to DM_POSITION to detach, but DM_PELSWIDTH and DM_PELSHEIGHT are needed actually.
583 * To successfully detach adapters, settings have to be saved to the registry first, and then call
584 * ChangeDisplaySettingsExA(device, NULL, NULL, 0, NULL) to update settings. Otherwise on some older versions
585 * of Windows, e.g., XP and Win7, the adapter doesn't get detached */
586 memset(&dm
, 0, sizeof(dm
));
587 dm
.dmSize
= sizeof(dm
);
588 dm
.dmFields
= DM_POSITION
;
589 dm
.dmPosition
= devices
[1].original_mode
.dmPosition
;
590 res
= ChangeDisplaySettingsExA(devices
[1].name
, &dm
, NULL
, CDS_UPDATEREGISTRY
| CDS_NORESET
, NULL
);
591 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA %s returned unexpected %d\n", devices
[1].name
, res
);
592 res
= ChangeDisplaySettingsExA(devices
[1].name
, NULL
, NULL
, 0, NULL
);
593 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA %s returned unexpected %d\n", devices
[1].name
, res
);
596 res
= EnumDisplayDevicesA(NULL
, devices
[1].index
, &dd
, 0);
597 ok(res
, "EnumDisplayDevicesA %s failed, error %#x\n", devices
[1].name
, GetLastError());
598 ok(dd
.StateFlags
& DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
, "Expect device %s still attached.\n", devices
[1].name
);
600 count
= GetSystemMetrics(SM_CMONITORS
);
601 ok(count
== old_count
, "Expect monitor count %d, got %d\n", old_count
, count
);
604 /* Test changing to a mode with depth set but with zero width and height */
605 for (device
= 0; device
< device_count
; ++device
)
607 for (test
= 0; test
< ARRAY_SIZE(depths
); ++test
)
609 /* Find the native resolution */
610 memset(&dm
, 0, sizeof(dm
));
611 memset(&dm2
, 0, sizeof(dm2
));
612 dm2
.dmSize
= sizeof(dm2
);
613 for (mode
= 0; EnumDisplaySettingsExA(devices
[device
].name
, mode
, &dm2
, 0); ++mode
)
615 if (dm2
.dmBitsPerPel
== depths
[test
]
616 && dm2
.dmPelsWidth
> dm
.dmPelsWidth
&& dm2
.dmPelsHeight
> dm
.dmPelsHeight
)
619 if (dm
.dmBitsPerPel
!= depths
[test
])
621 skip("Depth %u is unsupported for %s.\n", depths
[test
], devices
[device
].name
);
625 /* Find the second resolution */
626 memset(&dm2
, 0, sizeof(dm2
));
627 dm2
.dmSize
= sizeof(dm2
);
628 for (mode
= 0; EnumDisplaySettingsExA(devices
[device
].name
, mode
, &dm2
, 0); ++mode
)
630 if (dm2
.dmBitsPerPel
== depths
[test
]
631 && dm2
.dmPelsWidth
!= dm
.dmPelsWidth
&& dm2
.dmPelsHeight
!= dm
.dmPelsHeight
)
634 if (dm2
.dmBitsPerPel
!= depths
[test
]
635 || dm2
.dmPelsWidth
== dm
.dmPelsWidth
|| dm2
.dmPelsHeight
== dm
.dmPelsHeight
)
637 skip("Failed to find the second mode for %s.\n", devices
[device
].name
);
641 /* Find the third resolution */
642 memset(&dm3
, 0, sizeof(dm3
));
643 dm3
.dmSize
= sizeof(dm3
);
644 for (mode
= 0; EnumDisplaySettingsExA(devices
[device
].name
, mode
, &dm3
, 0); ++mode
)
646 if (dm3
.dmBitsPerPel
== depths
[test
]
647 && dm3
.dmPelsWidth
!= dm
.dmPelsWidth
&& dm3
.dmPelsHeight
!= dm
.dmPelsHeight
648 && dm3
.dmPelsWidth
!= dm2
.dmPelsWidth
&& dm3
.dmPelsHeight
!= dm2
.dmPelsHeight
)
651 if (dm3
.dmBitsPerPel
!= depths
[test
]
652 || dm3
.dmPelsWidth
== dm
.dmPelsWidth
|| dm3
.dmPelsHeight
== dm
.dmPelsHeight
653 || dm3
.dmPelsWidth
== dm2
.dmPelsWidth
|| dm3
.dmPelsHeight
== dm2
.dmPelsHeight
)
655 skip("Failed to find the third mode for %s.\n", devices
[device
].name
);
659 /* Change the current mode to the third mode first */
660 res
= ChangeDisplaySettingsExA(devices
[device
].name
, &dm3
, NULL
, CDS_RESET
, NULL
);
661 ok(res
== DISP_CHANGE_SUCCESSFUL
662 || broken(res
== DISP_CHANGE_FAILED
), /* Win8 TestBots */
663 "ChangeDisplaySettingsExA %s returned unexpected %d.\n", devices
[device
].name
, res
);
664 if (res
!= DISP_CHANGE_SUCCESSFUL
)
666 win_skip("Failed to change display mode for %s.\n", devices
[device
].name
);
670 expect_dm(&dm3
, devices
[device
].name
, test
);
672 /* Change the registry mode to the second mode */
673 res
= ChangeDisplaySettingsExA(devices
[device
].name
, &dm2
, NULL
, CDS_UPDATEREGISTRY
| CDS_NORESET
, NULL
);
674 ok(res
== DISP_CHANGE_SUCCESSFUL
675 || broken(res
== DISP_CHANGE_BADFLAGS
), /* Win10 32bit */
676 "ChangeDisplaySettingsExA %s returned unexpected %d.\n", devices
[device
].name
, res
);
678 /* Change to a mode with depth set but with zero width and height */
679 memset(&dm
, 0, sizeof(dm
));
680 dm
.dmSize
= sizeof(dm
);
681 dm
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
682 dm
.dmBitsPerPel
= depths
[test
];
683 res
= ChangeDisplaySettingsExA(devices
[device
].name
, &dm
, NULL
, CDS_RESET
, NULL
);
684 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA %s returned unexpected %d.\n",
685 devices
[device
].name
, res
);
689 res
= EnumDisplayDevicesA(NULL
, devices
[device
].index
, &dd
, 0);
690 ok(res
, "EnumDisplayDevicesA %s failed, error %#x.\n", devices
[device
].name
, GetLastError());
691 ok(dd
.StateFlags
& DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
, "Expect %s attached.\n",
692 devices
[device
].name
);
694 memset(&dm
, 0, sizeof(dm
));
695 dm
.dmSize
= sizeof(dm
);
696 res
= EnumDisplaySettingsA(devices
[device
].name
, ENUM_CURRENT_SETTINGS
, &dm
);
697 ok(res
, "Device %s EnumDisplaySettingsA failed, error %#x.\n", devices
[device
].name
, GetLastError());
698 todo_wine_if(depths
[test
] != 32)
699 ok(dm
.dmBitsPerPel
== depths
[test
], "Device %s expect dmBitsPerPel %u, got %u.\n",
700 devices
[device
].name
, depths
[test
], dm
.dmBitsPerPel
);
701 /* 2008 resets to the resolution in the registry. Newer versions of Windows doesn't
702 * change the current resolution */
703 ok(dm
.dmPelsWidth
== dm3
.dmPelsWidth
|| broken(dm
.dmPelsWidth
== dm2
.dmPelsWidth
),
704 "Device %s expect dmPelsWidth %u, got %u.\n",
705 devices
[device
].name
, dm3
.dmPelsWidth
, dm
.dmPelsWidth
);
706 ok(dm
.dmPelsHeight
== dm3
.dmPelsHeight
|| broken(dm
.dmPelsHeight
== dm2
.dmPelsHeight
),
707 "Device %s expect dmPelsHeight %u, got %u.\n",
708 devices
[device
].name
, dm3
.dmPelsHeight
, dm
.dmPelsHeight
);
712 /* Detach all non-primary adapters to avoid position conflicts */
713 for (device
= 1; device
< device_count
; ++device
)
715 old_count
= GetSystemMetrics(SM_CMONITORS
);
717 memset(&dm
, 0, sizeof(dm
));
718 dm
.dmSize
= sizeof(dm
);
719 dm
.dmFields
= DM_POSITION
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
720 dm
.dmPosition
= devices
[device
].original_mode
.dmPosition
;
721 res
= ChangeDisplaySettingsExA(devices
[device
].name
, &dm
, NULL
, CDS_UPDATEREGISTRY
| CDS_NORESET
, NULL
);
722 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA %s returned unexpected %d\n", devices
[device
].name
, res
);
723 res
= ChangeDisplaySettingsExA(devices
[device
].name
, NULL
, NULL
, 0, NULL
);
724 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA %s returned unexpected %d\n", devices
[device
].name
, res
);
727 res
= EnumDisplayDevicesA(NULL
, devices
[device
].index
, &dd
, 0);
728 ok(res
, "EnumDisplayDevicesA %s failed, error %#x\n", devices
[device
].name
, GetLastError());
729 ok(!(dd
.StateFlags
& DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
), "Expect device %s detached.\n", devices
[device
].name
);
731 count
= GetSystemMetrics(SM_CMONITORS
);
732 ok(count
== old_count
- 1, "Expect monitor count %d, got %d\n", old_count
- 1, count
);
735 /* Test changing each adapter to every available mode */
738 for (device
= 0; device
< device_count
; ++device
)
740 memset(&dm
, 0, sizeof(dm
));
741 dm
.dmSize
= sizeof(dm
);
742 for (mode
= 0; EnumDisplaySettingsExA(devices
[device
].name
, mode
, &dm
, 0); ++mode
)
744 dm
.dmPosition
= position
;
745 dm
.dmFields
|= DM_POSITION
;
746 /* Reattach detached non-primary adapters, otherwise ChangeDisplaySettingsExA with only CDS_RESET fails */
747 if (mode
== 0 && device
)
749 res
= ChangeDisplaySettingsExA(devices
[device
].name
, &dm
, NULL
, CDS_UPDATEREGISTRY
| CDS_NORESET
, NULL
);
750 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA %s mode %d returned unexpected %d\n",
751 devices
[device
].name
, mode
, res
);
752 res
= ChangeDisplaySettingsExA(NULL
, NULL
, NULL
, 0, NULL
);
756 res
= ChangeDisplaySettingsExA(devices
[device
].name
, &dm
, NULL
, CDS_RESET
, NULL
);
759 ok(res
== DISP_CHANGE_SUCCESSFUL
||
760 broken(res
== DISP_CHANGE_FAILED
), /* TestBots using VGA driver can't change to some modes */
761 "ChangeDisplaySettingsExA %s mode %d returned unexpected %d\n", devices
[device
].name
, mode
, res
);
762 if (res
!= DISP_CHANGE_SUCCESSFUL
)
764 win_skip("Failed to change %s to mode %d.\n", devices
[device
].name
, mode
);
769 expect_dm(&dm
, devices
[device
].name
, mode
);
772 /* Restore settings */
773 res
= ChangeDisplaySettingsExA(devices
[device
].name
, NULL
, NULL
, 0, NULL
);
774 ok(res
== DISP_CHANGE_SUCCESSFUL
||
775 broken(res
== DISP_CHANGE_FAILED
), /* win8 TestBot */
776 "ChangeDisplaySettingsExA %s returned unexpected %d\n", devices
[device
].name
, res
);
778 /* Place the next adapter to the right so that there is no position conflict */
779 memset(&dm
, 0, sizeof(dm
));
780 dm
.dmSize
= sizeof(dm
);
781 res
= EnumDisplaySettingsA(devices
[device
].name
, ENUM_CURRENT_SETTINGS
, &dm
);
782 ok(res
, "EnumDisplaySettingsA %s failed, error %#x\n", devices
[device
].name
, GetLastError());
783 position
.x
= dm
.dmPosition
.x
+ dm
.dmPelsWidth
;
786 /* Test changing modes by saving settings to the registry first */
787 for (device
= 0; device
< device_count
; ++device
)
789 /* Place adapter to the right */
797 memset(&dm
, 0, sizeof(dm
));
798 dm
.dmSize
= sizeof(dm
);
799 res
= EnumDisplaySettingsA(devices
[device
- 1].name
, ENUM_CURRENT_SETTINGS
, &dm
);
800 ok(res
, "EnumDisplaySettingsA %s failed, error %#x.\n", devices
[device
- 1].name
, GetLastError());
801 position
.x
= dm
.dmPosition
.x
+ dm
.dmPelsWidth
;
804 memset(&dm
, 0, sizeof(dm
));
805 dm
.dmSize
= sizeof(dm
);
806 res
= EnumDisplaySettingsA(devices
[device
].name
, ENUM_CURRENT_SETTINGS
, &dm
);
807 ok(res
, "EnumDisplaySettingsA %s failed, error %#x\n", devices
[device
].name
, GetLastError());
810 /* Find a mode that's different from the current mode */
811 memset(&dm2
, 0, sizeof(dm2
));
812 dm2
.dmSize
= sizeof(dm2
);
813 for (mode
= 0; EnumDisplaySettingsA(devices
[device
].name
, mode
, &dm2
); ++mode
)
815 /* Use the same color depth because the win2008 TestBots are unable to change it */
816 if (dm2
.dmPelsWidth
!= dm
.dmPelsWidth
&& dm2
.dmPelsHeight
!= dm
.dmPelsHeight
&&
817 dm2
.dmBitsPerPel
== dm
.dmBitsPerPel
)
820 ok(dm2
.dmPelsWidth
!= dm
.dmPelsWidth
&& dm2
.dmPelsHeight
!= dm
.dmPelsHeight
&&
821 dm2
.dmBitsPerPel
== dm
.dmBitsPerPel
, "Failed to find a different mode.\n");
823 /* Test normal operation */
825 dm
.dmFields
|= DM_POSITION
;
826 dm
.dmPosition
= position
;
827 res
= ChangeDisplaySettingsExA(devices
[device
].name
, &dm
, NULL
, CDS_UPDATEREGISTRY
| CDS_NORESET
, NULL
);
828 ok(res
== DISP_CHANGE_SUCCESSFUL
||
829 broken(res
== DISP_CHANGE_FAILED
), /* win8 TestBot */
830 "ChangeDisplaySettingsExA %s returned unexpected %d\n", devices
[device
].name
, res
);
831 res
= ChangeDisplaySettingsExA(devices
[device
].name
, NULL
, NULL
, 0, NULL
);
832 ok(res
== DISP_CHANGE_SUCCESSFUL
||
833 broken(res
== DISP_CHANGE_FAILED
), /* win8 TestBot */
834 "ChangeDisplaySettingsExA %s returned unexpected %d\n", devices
[device
].name
, res
);
835 if (res
!= DISP_CHANGE_SUCCESSFUL
)
837 win_skip("Failed to change mode for %s.\n", devices
[device
].name
);
842 expect_dm(&dm
, devices
[device
].name
, 0);
844 /* Test specifying only position, width and height */
845 memset(&dm
, 0, sizeof(dm
));
846 dm
.dmSize
= sizeof(dm
);
847 dm
.dmFields
= DM_POSITION
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
848 dm
.dmPosition
= position
;
849 dm
.dmPelsWidth
= dm3
.dmPelsWidth
;
850 dm
.dmPelsHeight
= dm3
.dmPelsHeight
;
851 res
= ChangeDisplaySettingsExA(devices
[device
].name
, &dm
, NULL
, CDS_UPDATEREGISTRY
| CDS_NORESET
, NULL
);
852 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA %s returned %d.\n", devices
[device
].name
, res
);
853 res
= EnumDisplaySettingsA(devices
[device
].name
, ENUM_REGISTRY_SETTINGS
, &dm
);
854 /* Win10 either returns failure here or retrieves outdated display settings until they're applied */
857 ok((dm
.dmFields
& registry_fields
) == registry_fields
, "Got unexpected dmFields %#x.\n", dm
.dmFields
);
858 ok(dm
.dmPosition
.x
== position
.x
, "Expected dmPosition.x %d, got %d.\n", position
.x
, dm
.dmPosition
.x
);
859 ok(dm
.dmPosition
.y
== position
.y
, "Expected dmPosition.y %d, got %d.\n", position
.y
, dm
.dmPosition
.y
);
860 ok(dm
.dmPelsWidth
== dm3
.dmPelsWidth
|| broken(dm
.dmPelsWidth
== dm2
.dmPelsWidth
), /* Win10 */
861 "Expected dmPelsWidth %u, got %u.\n", dm3
.dmPelsWidth
, dm
.dmPelsWidth
);
862 ok(dm
.dmPelsHeight
== dm3
.dmPelsHeight
|| broken(dm
.dmPelsHeight
== dm2
.dmPelsHeight
), /* Win10 */
863 "Expected dmPelsHeight %u, got %u.\n", dm3
.dmPelsHeight
, dm
.dmPelsHeight
);
864 ok(dm
.dmBitsPerPel
, "Expected dmBitsPerPel not zero.\n");
865 ok(dm
.dmDisplayFrequency
, "Expected dmDisplayFrequency not zero.\n");
869 win_skip("EnumDisplaySettingsA %s failed, error %#x.\n", devices
[device
].name
, GetLastError());
872 res
= ChangeDisplaySettingsExA(devices
[device
].name
, NULL
, NULL
, 0, NULL
);
873 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA %s returned %d.\n", devices
[device
].name
, res
);
876 res
= EnumDisplaySettingsA(devices
[device
].name
, ENUM_REGISTRY_SETTINGS
, &dm
);
877 ok(res
, "EnumDisplaySettingsA %s failed, error %#x.\n", devices
[device
].name
, GetLastError());
878 ok((dm
.dmFields
& registry_fields
) == registry_fields
, "Got unexpected dmFields %#x.\n", dm
.dmFields
);
879 ok(dm
.dmPosition
.x
== position
.x
, "Expected dmPosition.x %d, got %d.\n", position
.x
, dm
.dmPosition
.x
);
880 ok(dm
.dmPosition
.y
== position
.y
, "Expected dmPosition.y %d, got %d.\n", position
.y
, dm
.dmPosition
.y
);
881 ok(dm
.dmPelsWidth
== dm3
.dmPelsWidth
, "Expected dmPelsWidth %u, got %u.\n", dm3
.dmPelsWidth
, dm
.dmPelsWidth
);
882 ok(dm
.dmPelsHeight
== dm3
.dmPelsHeight
, "Expected dmPelsHeight %u, got %u.\n", dm3
.dmPelsHeight
,
884 ok(dm
.dmBitsPerPel
, "Expected dmBitsPerPel not zero.\n");
885 ok(dm
.dmDisplayFrequency
, "Expected dmDisplayFrequency not zero.\n");
887 expect_dm(&dm
, devices
[device
].name
, 0);
890 /* Test dmPosition */
891 /* First detach all adapters except for the primary and secondary adapters to avoid position conflicts */
892 if (device_count
>= 3)
894 for (device
= 2; device
< device_count
; ++device
)
896 memset(&dm
, 0, sizeof(dm
));
897 dm
.dmSize
= sizeof(dm
);
898 res
= EnumDisplaySettingsA(devices
[device
].name
, ENUM_CURRENT_SETTINGS
, &dm
);
899 ok(res
, "EnumDisplaySettingsA %s failed, error %#x\n", devices
[device
].name
, GetLastError());
903 dm
.dmFields
= DM_POSITION
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
904 res
= ChangeDisplaySettingsExA(devices
[device
].name
, &dm
, NULL
, CDS_UPDATEREGISTRY
| CDS_NORESET
, NULL
);
905 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA %s returned unexpected %d\n", devices
[device
].name
, res
);
907 res
= ChangeDisplaySettingsExA(NULL
, NULL
, NULL
, 0, NULL
);
908 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA returned unexpected %d\n", res
);
911 if (device_count
>= 2)
913 /* Query the primary adapter settings */
914 memset(&dm
, 0, sizeof(dm
));
915 dm
.dmSize
= sizeof(dm
);
916 res
= EnumDisplaySettingsA(devices
[0].name
, ENUM_CURRENT_SETTINGS
, &dm
);
917 ok(res
, "EnumDisplaySettingsA %s failed, error %#x\n", devices
[0].name
, GetLastError());
921 /* Query the secondary adapter settings */
922 memset(&dm2
, 0, sizeof(dm2
));
923 dm2
.dmSize
= sizeof(dm2
);
924 res
= EnumDisplaySettingsA(devices
[1].name
, ENUM_CURRENT_SETTINGS
, &dm2
);
925 ok(res
, "EnumDisplaySettingsA %s failed, error %#x\n", devices
[1].name
, GetLastError());
930 /* The secondary adapter should be to the right of the primary adapter */
931 ok(dm2
.dmPosition
.x
== dm
.dmPosition
.x
+ dm
.dmPelsWidth
,
932 "Expected dm2.dmPosition.x %d, got %d.\n", dm
.dmPosition
.x
+ dm
.dmPelsWidth
,
934 ok(dm2
.dmPosition
.y
== dm
.dmPosition
.y
, "Expected dm2.dmPosition.y %d, got %d.\n",
935 dm
.dmPosition
.y
, dm2
.dmPosition
.y
);
937 /* Test position conflict */
938 dm2
.dmPosition
.x
= dm
.dmPosition
.x
- dm2
.dmPelsWidth
+ 1;
939 dm2
.dmPosition
.y
= dm
.dmPosition
.y
;
940 res
= ChangeDisplaySettingsExA(devices
[1].name
, &dm2
, NULL
, CDS_RESET
, NULL
);
941 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA %s returned unexpected %d\n", devices
[1].name
, res
);
943 /* Position is changed and automatically moved */
944 memset(&dm2
, 0, sizeof(dm2
));
945 dm2
.dmSize
= sizeof(dm2
);
946 res
= EnumDisplaySettingsA(devices
[1].name
, ENUM_CURRENT_SETTINGS
, &dm2
);
947 ok(res
, "EnumDisplaySettingsA %s failed, error %#x\n", devices
[1].name
, GetLastError());
948 ok(dm2
.dmPosition
.x
== dm
.dmPosition
.x
- dm2
.dmPelsWidth
,
949 "Expected dmPosition.x %d, got %d.\n", dm
.dmPosition
.x
- dm2
.dmPelsWidth
,
952 /* Test position with extra space. The extra space will be removed */
953 dm2
.dmPosition
.x
= dm
.dmPosition
.x
+ dm
.dmPelsWidth
+ 1;
954 dm2
.dmPosition
.y
= dm
.dmPosition
.y
;
955 res
= ChangeDisplaySettingsExA(devices
[1].name
, &dm2
, NULL
, CDS_RESET
, NULL
);
956 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA %s returned unexpected %d\n", devices
[1].name
, res
);
958 dm2
.dmPosition
.x
= dm
.dmPosition
.x
+ dm
.dmPelsWidth
;
959 expect_dm(&dm2
, devices
[1].name
, 0);
961 /* Test placing the secondary adapter to all sides of the primary adapter */
962 for (test
= 0; test
< 8; ++test
)
966 /* Bottom side with x offset */
968 dm2
.dmPosition
.x
= dm
.dmPosition
.x
+ dm
.dmPelsWidth
/ 2;
969 dm2
.dmPosition
.y
= dm
.dmPosition
.y
+ dm
.dmPelsHeight
;
971 /* Left side with y offset */
973 dm2
.dmPosition
.x
= dm
.dmPosition
.x
- dm2
.dmPelsWidth
;
974 dm2
.dmPosition
.y
= dm
.dmPosition
.y
+ dm
.dmPelsHeight
/ 2;
976 /* Top side with x offset */
978 dm2
.dmPosition
.x
= dm
.dmPosition
.x
+ dm
.dmPelsWidth
/ 2;
979 dm2
.dmPosition
.y
= dm
.dmPosition
.y
- dm2
.dmPelsHeight
;
981 /* Right side with y offset */
983 dm2
.dmPosition
.x
= dm
.dmPosition
.x
+ dm
.dmPelsWidth
;
984 dm2
.dmPosition
.y
= dm
.dmPosition
.y
+ dm
.dmPelsHeight
/ 2;
986 /* Bottom side with the same x */
988 dm2
.dmPosition
.x
= dm
.dmPosition
.x
;
989 dm2
.dmPosition
.y
= dm
.dmPosition
.y
+ dm
.dmPelsHeight
;
991 /* Left side with the same y */
993 dm2
.dmPosition
.x
= dm
.dmPosition
.x
- dm2
.dmPelsWidth
;
994 dm2
.dmPosition
.y
= dm
.dmPosition
.y
;
996 /* Top side with the same x */
998 dm2
.dmPosition
.x
= dm
.dmPosition
.x
;
999 dm2
.dmPosition
.y
= dm
.dmPosition
.y
- dm2
.dmPelsHeight
;
1001 /* Right side with the same y */
1003 dm2
.dmPosition
.x
= dm
.dmPosition
.x
+ dm
.dmPelsWidth
;
1004 dm2
.dmPosition
.y
= dm
.dmPosition
.y
;
1008 res
= ChangeDisplaySettingsExA(devices
[1].name
, &dm2
, NULL
, CDS_RESET
, NULL
);
1009 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA %s test %d returned unexpected %d\n",
1010 devices
[1].name
, test
, res
);
1011 if (res
!= DISP_CHANGE_SUCCESSFUL
)
1013 win_skip("ChangeDisplaySettingsExA %s test %d returned unexpected %d.\n", devices
[1].name
, test
, res
);
1018 expect_dm(&dm2
, devices
[1].name
, test
);
1021 /* Test automatic position update when other adapters change resolution */
1022 /* Find a mode that's different from the current mode */
1023 memset(&dm2
, 0, sizeof(dm2
));
1024 dm2
.dmSize
= sizeof(dm2
);
1025 for (mode
= 0; EnumDisplaySettingsA(devices
[0].name
, mode
, &dm2
); ++mode
)
1027 if (dm2
.dmPelsWidth
!= dm
.dmPelsWidth
&& dm2
.dmPelsHeight
!= dm
.dmPelsHeight
)
1030 ok(dm2
.dmPelsWidth
!= dm
.dmPelsWidth
&& dm2
.dmPelsHeight
!= dm
.dmPelsHeight
, "Failed to find a different mode.\n");
1032 /* Change the primary adapter to a different mode */
1034 res
= ChangeDisplaySettingsExA(devices
[0].name
, &dm
, NULL
, CDS_RESET
, NULL
);
1035 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA %s returned unexpected %d\n", devices
[0].name
, res
);
1037 /* Now the position of the second adapter should be changed */
1038 memset(&dm2
, 0, sizeof(dm2
));
1039 dm2
.dmSize
= sizeof(dm2
);
1040 res
= EnumDisplaySettingsA(devices
[1].name
, ENUM_CURRENT_SETTINGS
, &dm2
);
1041 ok(res
, "EnumDisplaySettingsA %s failed, error %#x\n", devices
[1].name
, GetLastError());
1042 ok(dm2
.dmPosition
.x
== dm
.dmPelsWidth
, "Expect dmPosition.x %d, got %d\n",
1043 dm
.dmPelsWidth
, dm2
.dmPosition
.x
);
1047 win_skip("EnumDisplaySettingsA failed\n");
1051 /* Test changing each adapter to every supported display orientation */
1052 for (device
= 0; device
< device_count
; ++device
)
1054 memset(&dm
, 0, sizeof(dm
));
1055 dm
.dmSize
= sizeof(dm
);
1056 res
= EnumDisplaySettingsA(devices
[device
].name
, ENUM_CURRENT_SETTINGS
, &dm
);
1057 ok(res
, "EnumDisplaySettingsA %s failed, error %#x.\n", devices
[device
].name
, GetLastError());
1059 memset(&dm2
, 0, sizeof(dm2
));
1060 dm2
.dmSize
= sizeof(dm2
);
1061 for (mode
= 0; EnumDisplaySettingsExA(devices
[device
].name
, mode
, &dm2
, EDS_ROTATEDMODE
); ++mode
)
1063 if (dm2
.dmBitsPerPel
!= dm
.dmBitsPerPel
|| dm2
.dmDisplayFrequency
!= dm
.dmDisplayFrequency
)
1066 if ((dm2
.dmDisplayOrientation
== DMDO_DEFAULT
|| dm2
.dmDisplayOrientation
== DMDO_180
)
1067 && (dm2
.dmPelsWidth
!= dm
.dmPelsWidth
|| dm2
.dmPelsHeight
!= dm
.dmPelsHeight
))
1070 if ((dm2
.dmDisplayOrientation
== DMDO_90
|| dm2
.dmDisplayOrientation
== DMDO_270
)
1071 && (dm2
.dmPelsWidth
!= dm
.dmPelsHeight
|| dm2
.dmPelsHeight
!= dm
.dmPelsWidth
))
1074 res
= ChangeDisplaySettingsExA(devices
[device
].name
, &dm2
, NULL
, CDS_RESET
, NULL
);
1075 if (res
!= DISP_CHANGE_SUCCESSFUL
)
1077 win_skip("Failed to change %s to mode %d.\n", devices
[device
].name
, mode
);
1080 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA %s mode %d returned unexpected %d.\n",
1081 devices
[device
].name
, mode
, res
);
1083 expect_dm(&dm2
, devices
[device
].name
, mode
);
1085 /* EnumDisplaySettingsEx without EDS_ROTATEDMODE reports modes with current orientation */
1086 memset(&dm3
, 0, sizeof(dm3
));
1087 dm3
.dmSize
= sizeof(dm3
);
1088 for (i
= 0; EnumDisplaySettingsExA(devices
[device
].name
, i
, &dm3
, 0); ++i
)
1090 ok(dm3
.dmDisplayOrientation
== dm2
.dmDisplayOrientation
,
1091 "Expected %s display mode %d orientation %d, got %d.\n",
1092 devices
[device
].name
, i
, dm2
.dmDisplayOrientation
, dm3
.dmDisplayOrientation
);
1094 ok(i
> 0, "Expected at least one display mode found.\n");
1098 ok(GetSystemMetrics(SM_CXSCREEN
) == dm2
.dmPelsWidth
, "Expected %d, got %d.\n",
1099 dm2
.dmPelsWidth
, GetSystemMetrics(SM_CXSCREEN
));
1100 ok(GetSystemMetrics(SM_CYSCREEN
) == dm2
.dmPelsHeight
, "Expected %d, got %d.\n",
1101 dm2
.dmPelsHeight
, GetSystemMetrics(SM_CYSCREEN
));
1104 if (device_count
== 1)
1106 ok(GetSystemMetrics(SM_CXVIRTUALSCREEN
) == dm2
.dmPelsWidth
, "Expected %d, got %d.\n",
1107 dm2
.dmPelsWidth
, GetSystemMetrics(SM_CXVIRTUALSCREEN
));
1108 ok(GetSystemMetrics(SM_CYVIRTUALSCREEN
) == dm2
.dmPelsHeight
, "Expected %d, got %d.\n",
1109 dm2
.dmPelsHeight
, GetSystemMetrics(SM_CYVIRTUALSCREEN
));
1112 ok(mode
> 0, "Expected at least one display mode found.\n");
1115 /* Restore all adapters to their original settings */
1116 for (device
= 0; device
< device_count
; ++device
)
1118 res
= ChangeDisplaySettingsExA(devices
[device
].name
, &devices
[device
].original_mode
, NULL
,
1119 CDS_UPDATEREGISTRY
| CDS_NORESET
, NULL
);
1120 ok(res
== DISP_CHANGE_SUCCESSFUL
||
1121 broken(res
== DISP_CHANGE_FAILED
), /* win8 TestBot */
1122 "ChangeDisplaySettingsExA %s returned unexpected %d\n", devices
[device
].name
, res
);
1124 res
= ChangeDisplaySettingsExA(NULL
, NULL
, NULL
, 0, NULL
);
1125 ok(res
== DISP_CHANGE_SUCCESSFUL
||
1126 broken(res
== DISP_CHANGE_FAILED
), /* win8 TestBot */
1127 "ChangeDisplaySettingsExA returned unexpected %d\n", res
);
1128 for (device
= 0; device
< device_count
; ++device
)
1129 expect_dm(&devices
[device
].original_mode
, devices
[device
].name
, 0);
1134 static void test_monitors(void)
1136 HMONITOR monitor
, primary
, nearest
;
1140 MONITORINFOEXA miexa
;
1141 MONITORINFOEXW miexw
;
1151 {sizeof(MONITORINFO
)+1, FALSE
},
1152 {sizeof(MONITORINFO
)-1, FALSE
},
1153 {sizeof(MONITORINFO
), TRUE
},
1155 {0xdeadbeef, FALSE
},
1159 {sizeof(MONITORINFOEXA
)+1, FALSE
},
1160 {sizeof(MONITORINFOEXA
)-1, FALSE
},
1161 {sizeof(MONITORINFOEXA
), TRUE
},
1163 {0xdeadbeef, FALSE
},
1167 {sizeof(MONITORINFOEXW
)+1, FALSE
},
1168 {sizeof(MONITORINFOEXW
)-1, FALSE
},
1169 {sizeof(MONITORINFOEXW
), TRUE
},
1171 {0xdeadbeef, FALSE
},
1175 primary
= MonitorFromPoint( pt
, MONITOR_DEFAULTTOPRIMARY
);
1176 ok( primary
!= 0, "couldn't get primary monitor\n" );
1178 monitor
= MonitorFromWindow( 0, MONITOR_DEFAULTTONULL
);
1179 ok( !monitor
, "got %p, should not get a monitor for an invalid window\n", monitor
);
1180 monitor
= MonitorFromWindow( 0, MONITOR_DEFAULTTOPRIMARY
);
1181 ok( monitor
== primary
, "got %p, should get primary %p for MONITOR_DEFAULTTOPRIMARY\n", monitor
, primary
);
1182 monitor
= MonitorFromWindow( 0, MONITOR_DEFAULTTONEAREST
);
1183 ok( monitor
== primary
, "got %p, should get primary %p for MONITOR_DEFAULTTONEAREST\n", monitor
, primary
);
1185 SetRect( &rc
, 0, 0, 1, 1 );
1186 monitor
= MonitorFromRect( &rc
, MONITOR_DEFAULTTONULL
);
1187 ok( monitor
== primary
, "got %p, should get primary %p\n", monitor
, primary
);
1189 monitor
= MonitorFromRect( &rc
, MONITOR_DEFAULTTOPRIMARY
);
1190 ok( monitor
== primary
, "got %p, should get primary %p\n", monitor
, primary
);
1192 monitor
= MonitorFromRect( &rc
, MONITOR_DEFAULTTONEAREST
);
1193 ok( monitor
== primary
, "got %p, should get primary %p\n", monitor
, primary
);
1195 /* Empty rect at 0,0 is considered inside the primary monitor */
1196 SetRect( &rc
, 0, 0, -1, -1 );
1197 monitor
= MonitorFromRect( &rc
, MONITOR_DEFAULTTONULL
);
1198 ok( monitor
== primary
, "got %p, should get primary %p\n", monitor
, primary
);
1200 /* Even if there is a monitor left of the primary, the primary will have the most overlapping area */
1201 SetRect( &rc
, -1, 0, 2, 1 );
1202 monitor
= MonitorFromRect( &rc
, MONITOR_DEFAULTTONULL
);
1203 ok( monitor
== primary
, "got %p, should get primary %p\n", monitor
, primary
);
1205 /* But the width of the rect doesn't matter if it's empty. */
1206 SetRect( &rc
, -1, 0, 2, -1 );
1207 monitor
= MonitorFromRect( &rc
, MONITOR_DEFAULTTONULL
);
1208 ok( monitor
!= primary
, "got primary %p\n", monitor
);
1210 /* Search for a monitor that has no others equally near to (left, top-1) */
1211 SetRect( &rc
, -1, -2, 2, 0 );
1212 monitor
= MonitorFromRect( &rc
, MONITOR_DEFAULTTONULL
);
1214 while (monitor
!= NULL
)
1216 ok( monitor
!= primary
, "got primary %p\n", monitor
);
1218 mi
.cbSize
= sizeof(mi
);
1219 ret
= GetMonitorInfoA( monitor
, &mi
);
1220 ok( ret
, "GetMonitorInfo failed\n" );
1221 SetRect( &rc
, mi
.rcMonitor
.left
-1, mi
.rcMonitor
.top
-2, mi
.rcMonitor
.left
+2, mi
.rcMonitor
.top
);
1222 monitor
= MonitorFromRect( &rc
, MONITOR_DEFAULTTONULL
);
1225 /* tests for cbSize in MONITORINFO */
1226 monitor
= MonitorFromWindow( 0, MONITOR_DEFAULTTOPRIMARY
);
1227 for (i
= 0; i
< ARRAY_SIZE(testdatami
); i
++)
1229 memset( &mi
, 0, sizeof(mi
) );
1230 mi
.cbSize
= testdatami
[i
].cbSize
;
1231 ret
= GetMonitorInfoA( monitor
, &mi
);
1232 ok( ret
== testdatami
[i
].ret
, "GetMonitorInfo returned wrong value\n" );
1234 ok( (mi
.dwFlags
& MONITORINFOF_PRIMARY
), "MONITORINFOF_PRIMARY flag isn't set\n" );
1236 ok( !(mi
.dwFlags
& MONITORINFOF_PRIMARY
), "MONITORINFOF_PRIMARY flag is set\n" );
1238 memset( &miexw
, 0, sizeof(miexw
) );
1239 miexw
.cbSize
= testdatamiexw
[i
].cbSize
;
1240 ret
= GetMonitorInfoW( monitor
, (LPMONITORINFO
)&miexw
);
1241 ok( ret
== testdatamiexw
[i
].ret
, "GetMonitorInfo returned wrong value\n" );
1243 ok( (miexw
.dwFlags
& MONITORINFOF_PRIMARY
), "MONITORINFOF_PRIMARY flag isn't set\n" );
1245 ok( !(miexw
.dwFlags
& MONITORINFOF_PRIMARY
), "MONITORINFOF_PRIMARY flag is set\n" );
1248 /* tests for cbSize in MONITORINFOEXA */
1249 for (i
= 0; i
< ARRAY_SIZE(testdatamiexa
); i
++)
1251 memset( &miexa
, 0, sizeof(miexa
) );
1252 miexa
.cbSize
= testdatamiexa
[i
].cbSize
;
1253 ret
= GetMonitorInfoA( monitor
, (LPMONITORINFO
)&miexa
);
1254 ok( ret
== testdatamiexa
[i
].ret
, "GetMonitorInfo returned wrong value\n" );
1256 ok( (miexa
.dwFlags
& MONITORINFOF_PRIMARY
), "MONITORINFOF_PRIMARY flag isn't set\n" );
1258 ok( !(miexa
.dwFlags
& MONITORINFOF_PRIMARY
), "MONITORINFOF_PRIMARY flag is set\n" );
1261 /* tests for cbSize in MONITORINFOEXW */
1262 for (i
= 0; i
< ARRAY_SIZE(testdatamiexw
); i
++)
1264 memset( &miexw
, 0, sizeof(miexw
) );
1265 miexw
.cbSize
= testdatamiexw
[i
].cbSize
;
1266 ret
= GetMonitorInfoW( monitor
, (LPMONITORINFO
)&miexw
);
1267 ok( ret
== testdatamiexw
[i
].ret
, "GetMonitorInfo returned wrong value\n" );
1269 ok( (miexw
.dwFlags
& MONITORINFOF_PRIMARY
), "MONITORINFOF_PRIMARY flag isn't set\n" );
1271 ok( !(miexw
.dwFlags
& MONITORINFOF_PRIMARY
), "MONITORINFOF_PRIMARY flag is set\n" );
1274 SetRect( &rc
, rc
.left
+1, rc
.top
+1, rc
.left
+2, rc
.top
+2 );
1276 monitor
= MonitorFromRect( &rc
, MONITOR_DEFAULTTONULL
);
1277 ok( monitor
== NULL
, "got %p\n", monitor
);
1279 monitor
= MonitorFromRect( &rc
, MONITOR_DEFAULTTOPRIMARY
);
1280 ok( monitor
== primary
, "got %p, should get primary %p\n", monitor
, primary
);
1282 monitor
= MonitorFromRect( &rc
, MONITOR_DEFAULTTONEAREST
);
1283 ok( monitor
== nearest
, "got %p, should get nearest %p\n", monitor
, nearest
);
1286 static BOOL CALLBACK
find_primary_mon(HMONITOR hmon
, HDC hdc
, LPRECT rc
, LPARAM lp
)
1291 mi
.cbSize
= sizeof(mi
);
1292 ret
= GetMonitorInfoA(hmon
, &mi
);
1293 ok(ret
, "GetMonitorInfo failed\n");
1294 if (mi
.dwFlags
& MONITORINFOF_PRIMARY
)
1296 *(HMONITOR
*)lp
= hmon
;
1302 static void test_work_area(void)
1306 RECT rc_work
, rc_normal
;
1312 ret
= EnumDisplayMonitors(NULL
, NULL
, find_primary_mon
, (LPARAM
)&hmon
);
1313 ok(!ret
&& hmon
!= 0, "Failed to find primary monitor\n");
1315 mi
.cbSize
= sizeof(mi
);
1316 SetLastError(0xdeadbeef);
1317 ret
= GetMonitorInfoA(hmon
, &mi
);
1318 ok(ret
, "GetMonitorInfo error %u\n", GetLastError());
1319 ok(mi
.dwFlags
& MONITORINFOF_PRIMARY
, "not a primary monitor\n");
1320 trace("primary monitor %s\n", wine_dbgstr_rect(&mi
.rcMonitor
));
1322 SetLastError(0xdeadbeef);
1323 ret
= SystemParametersInfoA(SPI_GETWORKAREA
, 0, &rc_work
, 0);
1324 ok(ret
, "SystemParametersInfo error %u\n", GetLastError());
1325 trace("work area %s\n", wine_dbgstr_rect(&rc_work
));
1326 ok(EqualRect(&rc_work
, &mi
.rcWork
), "work area is different\n");
1328 hwnd
= CreateWindowExA(0, "static", NULL
, WS_OVERLAPPEDWINDOW
|WS_VISIBLE
,100,100,10,10,0,0,0,NULL
);
1329 ok(hwnd
!= 0, "CreateWindowEx failed\n");
1331 ret
= GetWindowRect(hwnd
, &rc_normal
);
1332 ok(ret
, "GetWindowRect failed\n");
1333 trace("normal %s\n", wine_dbgstr_rect(&rc_normal
));
1335 wp
.length
= sizeof(wp
);
1336 ret
= GetWindowPlacement(hwnd
, &wp
);
1337 ok(ret
, "GetWindowPlacement failed\n");
1338 trace("min: %d,%d max %d,%d normal %s\n", wp
.ptMinPosition
.x
, wp
.ptMinPosition
.y
,
1339 wp
.ptMaxPosition
.x
, wp
.ptMaxPosition
.y
, wine_dbgstr_rect(&wp
.rcNormalPosition
));
1340 OffsetRect(&wp
.rcNormalPosition
, rc_work
.left
, rc_work
.top
);
1341 todo_wine_if (mi
.rcMonitor
.left
!= mi
.rcWork
.left
||
1342 mi
.rcMonitor
.top
!= mi
.rcWork
.top
) /* FIXME: remove once Wine is fixed */
1344 ok(EqualRect(&rc_normal
, &wp
.rcNormalPosition
), "normal pos is different\n");
1347 SetWindowLongA(hwnd
, GWL_EXSTYLE
, WS_EX_TOOLWINDOW
);
1349 wp
.length
= sizeof(wp
);
1350 ret
= GetWindowPlacement(hwnd
, &wp
);
1351 ok(ret
, "GetWindowPlacement failed\n");
1352 trace("min: %d,%d max %d,%d normal %s\n", wp
.ptMinPosition
.x
, wp
.ptMinPosition
.y
,
1353 wp
.ptMaxPosition
.x
, wp
.ptMaxPosition
.y
, wine_dbgstr_rect(&wp
.rcNormalPosition
));
1354 ok(EqualRect(&rc_normal
, &wp
.rcNormalPosition
), "normal pos is different\n");
1356 DestroyWindow(hwnd
);
1359 static void test_GetDisplayConfigBufferSizes(void)
1361 UINT32 paths
, modes
;
1364 ret
= pGetDisplayConfigBufferSizes(QDC_ALL_PATHS
, NULL
, NULL
);
1365 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
1368 ret
= pGetDisplayConfigBufferSizes(QDC_ALL_PATHS
, &paths
, NULL
);
1369 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
1370 ok(paths
== 100, "got %u\n", paths
);
1373 ret
= pGetDisplayConfigBufferSizes(QDC_ALL_PATHS
, NULL
, &modes
);
1374 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
1375 ok(modes
== 100, "got %u\n", modes
);
1377 ret
= pGetDisplayConfigBufferSizes(0, NULL
, NULL
);
1378 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
1381 ret
= pGetDisplayConfigBufferSizes(0, &paths
, NULL
);
1382 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
1383 ok(paths
== 100, "got %u\n", paths
);
1386 ret
= pGetDisplayConfigBufferSizes(0, NULL
, &modes
);
1387 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
1388 ok(modes
== 100, "got %u\n", modes
);
1390 /* Flag validation on Windows is driver-dependent */
1391 paths
= modes
= 100;
1392 ret
= pGetDisplayConfigBufferSizes(0, &paths
, &modes
);
1393 ok(ret
== ERROR_INVALID_PARAMETER
|| ret
== ERROR_NOT_SUPPORTED
, "got %d\n", ret
);
1394 ok((modes
== 0 || modes
== 100) && paths
== 0, "got %u, %u\n", modes
, paths
);
1396 paths
= modes
= 100;
1397 ret
= pGetDisplayConfigBufferSizes(0xFF, &paths
, &modes
);
1398 ok(ret
== ERROR_INVALID_PARAMETER
|| ret
== ERROR_NOT_SUPPORTED
, "got %d\n", ret
);
1399 ok((modes
== 0 || modes
== 100) && paths
== 0, "got %u, %u\n", modes
, paths
);
1403 ret
= pGetDisplayConfigBufferSizes(QDC_ALL_PATHS
, &paths
, &modes
);
1405 ok(paths
> 0 && modes
> 0, "got %u, %u\n", paths
, modes
);
1407 ok(ret
== ERROR_NOT_SUPPORTED
, "got %d\n", ret
);
1410 ret
= pGetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS
, &paths
, &modes
);
1412 ok(paths
> 0 && modes
> 0, "got %u, %u\n", paths
, modes
);
1414 ok(ret
== ERROR_NOT_SUPPORTED
, "got %d\n", ret
);
1417 ret
= pGetDisplayConfigBufferSizes(QDC_DATABASE_CURRENT
, &paths
, &modes
);
1419 ok(paths
> 0 && modes
> 0, "got %u, %u\n", paths
, modes
);
1421 ok(ret
== ERROR_NOT_SUPPORTED
, "got %d\n", ret
);
1424 static BOOL CALLBACK
test_EnumDisplayMonitors_normal_cb(HMONITOR monitor
, HDC hdc
, LPRECT rect
,
1430 mi
.cbSize
= sizeof(mi
);
1431 ret
= GetMonitorInfoA(monitor
, &mi
);
1432 ok(ret
, "GetMonitorInfoA failed, error %#x.\n", GetLastError());
1433 ok(EqualRect(rect
, &mi
.rcMonitor
), "Expected rect %s, got %s.\n",
1434 wine_dbgstr_rect(&mi
.rcMonitor
), wine_dbgstr_rect(rect
));
1439 static BOOL CALLBACK
test_EnumDisplayMonitors_return_false_cb(HMONITOR monitor
, HDC hdc
,
1440 LPRECT rect
, LPARAM lparam
)
1445 static BOOL CALLBACK
test_EnumDisplayMonitors_invalid_handle_cb(HMONITOR monitor
, HDC hdc
,
1446 LPRECT rect
, LPARAM lparam
)
1448 MONITORINFOEXA mi
, mi2
;
1449 DEVMODEA old_dm
, dm
;
1454 mi
.cbSize
= sizeof(mi
);
1455 ret
= GetMonitorInfoA(monitor
, (MONITORINFO
*)&mi
);
1456 ok(ret
, "GetMonitorInfoA failed, error %#x.\n", GetLastError());
1458 /* Test that monitor handle is invalid after the monitor is detached */
1459 if (!(mi
.dwFlags
& MONITORINFOF_PRIMARY
))
1461 count
= GetSystemMetrics(SM_CMONITORS
);
1463 /* Save current display settings */
1464 memset(&old_dm
, 0, sizeof(old_dm
));
1465 old_dm
.dmSize
= sizeof(old_dm
);
1466 ret
= EnumDisplaySettingsA(mi
.szDevice
, ENUM_CURRENT_SETTINGS
, &old_dm
);
1467 ok(ret
, "EnumDisplaySettingsA %s failed, error %#x.\n", mi
.szDevice
, GetLastError());
1469 /* Detach monitor */
1470 memset(&dm
, 0, sizeof(dm
));
1471 dm
.dmSize
= sizeof(dm
);
1472 dm
.dmFields
= DM_POSITION
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
1473 dm
.dmPosition
.x
= mi
.rcMonitor
.left
;
1474 dm
.dmPosition
.y
= mi
.rcMonitor
.top
;
1475 ret
= ChangeDisplaySettingsExA(mi
.szDevice
, &dm
, NULL
, CDS_UPDATEREGISTRY
| CDS_NORESET
,
1477 ok(ret
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA %s returned unexpected %d.\n",
1479 ret
= ChangeDisplaySettingsExA(mi
.szDevice
, NULL
, NULL
, 0, NULL
);
1480 ok(ret
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA %s returned unexpected %d.\n",
1483 /* Check if it's really detached */
1484 if (GetSystemMetrics(SM_CMONITORS
) != count
- 1)
1486 skip("Failed to detach %s.\n", mi
.szDevice
);
1487 SetLastError(0xdeadbeef);
1491 /* The monitor handle should be invalid now */
1492 mi2
.cbSize
= sizeof(mi2
);
1493 SetLastError(0xdeadbeef);
1494 ret
= GetMonitorInfoA(monitor
, (MONITORINFO
*)&mi2
);
1495 ok(!ret
, "GetMonitorInfoA succeeded.\n");
1496 error
= GetLastError();
1497 ok(error
== ERROR_INVALID_MONITOR_HANDLE
|| error
== ERROR_INVALID_HANDLE
,
1498 "Expected error %#x, got %#x.\n", ERROR_INVALID_MONITOR_HANDLE
, error
);
1500 /* Restore the original display settings */
1501 ret
= ChangeDisplaySettingsExA(mi
.szDevice
, &old_dm
, NULL
, CDS_UPDATEREGISTRY
| CDS_NORESET
,
1503 ok(ret
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA %s returned unexpected %d.\n",
1505 ret
= ChangeDisplaySettingsExA(mi
.szDevice
, NULL
, NULL
, 0, NULL
);
1506 ok(ret
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA %s returned unexpected %d.\n",
1510 SetLastError(0xdeadbeef);
1514 static BOOL CALLBACK
test_EnumDisplayMonitors_count(HMONITOR monitor
, HDC hdc
, LPRECT rect
,
1517 INT
*count
= (INT
*)lparam
;
1522 static void test_EnumDisplayMonitors(void)
1524 static const DWORD DESKTOP_ALL_ACCESS
= 0x01ff;
1525 HWINSTA winstation
, old_winstation
;
1526 HDESK desktop
, old_desktop
;
1527 INT count
, old_count
;
1531 ret
= EnumDisplayMonitors(NULL
, NULL
, test_EnumDisplayMonitors_normal_cb
, 0);
1532 ok(ret
, "EnumDisplayMonitors failed, error %#x.\n", GetLastError());
1534 SetLastError(0xdeadbeef);
1535 ret
= EnumDisplayMonitors(NULL
, NULL
, test_EnumDisplayMonitors_return_false_cb
, 0);
1536 error
= GetLastError();
1537 ok(!ret
, "EnumDisplayMonitors succeeded.\n");
1538 ok(error
== 0xdeadbeef, "Expected error %#x, got %#x.\n", 0xdeadbeef, error
);
1540 count
= GetSystemMetrics(SM_CMONITORS
);
1541 SetLastError(0xdeadbeef);
1542 ret
= EnumDisplayMonitors(NULL
, NULL
, test_EnumDisplayMonitors_invalid_handle_cb
, 0);
1543 error
= GetLastError();
1545 todo_wine
ok(!ret
, "EnumDisplayMonitors succeeded.\n");
1547 ok(ret
, "EnumDisplayMonitors failed.\n");
1548 ok(error
== 0xdeadbeef, "Expected error %#x, got %#x.\n", 0xdeadbeef, error
);
1550 /* Test that monitor enumeration is not affected by window stations and desktops */
1551 old_winstation
= GetProcessWindowStation();
1552 old_desktop
= GetThreadDesktop(GetCurrentThreadId());
1553 old_count
= GetSystemMetrics(SM_CMONITORS
);
1556 ret
= EnumDisplayMonitors(NULL
, NULL
, test_EnumDisplayMonitors_count
, (LPARAM
)&count
);
1557 ok(ret
, "EnumDisplayMonitors failed, error %#x.\n", GetLastError());
1558 ok(count
== old_count
, "Expected %d, got %d.\n", old_count
, count
);
1560 winstation
= CreateWindowStationW(NULL
, 0, WINSTA_ALL_ACCESS
, NULL
);
1561 ok(!!winstation
&& winstation
!= old_winstation
, "CreateWindowStationW failed, error %#x.\n", GetLastError());
1562 ret
= SetProcessWindowStation(winstation
);
1563 ok(ret
, "SetProcessWindowStation failed, error %#x.\n", GetLastError());
1564 ok(winstation
== GetProcessWindowStation(), "Expected %p, got %p.\n", GetProcessWindowStation(), winstation
);
1566 desktop
= CreateDesktopW(L
"test_desktop", NULL
, NULL
, 0, DESKTOP_ALL_ACCESS
, NULL
);
1567 ok(!!desktop
&& desktop
!= old_desktop
, "CreateDesktopW failed, error %#x.\n", GetLastError());
1568 ret
= SetThreadDesktop(desktop
);
1569 ok(ret
, "SetThreadDesktop failed, error %#x.\n", GetLastError());
1570 ok(desktop
== GetThreadDesktop(GetCurrentThreadId()), "Expected %p, got %p.\n",
1571 GetThreadDesktop(GetCurrentThreadId()), desktop
);
1573 count
= GetSystemMetrics(SM_CMONITORS
);
1574 ok(count
== old_count
, "Expected %d, got %d.\n", old_count
, count
);
1576 ret
= EnumDisplayMonitors(NULL
, NULL
, test_EnumDisplayMonitors_count
, (LPARAM
)&count
);
1577 ok(ret
, "EnumDisplayMonitors failed, error %#x.\n", GetLastError());
1578 ok(count
== old_count
, "Expected %d, got %d.\n", old_count
, count
);
1580 ret
= SetProcessWindowStation(old_winstation
);
1581 ok(ret
, "SetProcessWindowStation failed, error %#x.\n", GetLastError());
1582 ret
= SetThreadDesktop(old_desktop
);
1583 ok(ret
, "SetThreadDesktop failed, error %#x.\n", GetLastError());
1584 ret
= CloseDesktop(desktop
);
1585 ok(ret
, "CloseDesktop failed, error %#x.\n", GetLastError());
1586 ret
= CloseWindowStation(winstation
);
1587 ok(ret
, "CloseWindowStation failed, error %#x.\n", GetLastError());
1590 static void test_QueryDisplayConfig_result(UINT32 flags
,
1591 UINT32 paths
, const DISPLAYCONFIG_PATH_INFO
*pi
, UINT32 modes
, const DISPLAYCONFIG_MODE_INFO
*mi
)
1595 DISPLAYCONFIG_SOURCE_DEVICE_NAME source_name
;
1596 DISPLAYCONFIG_TARGET_DEVICE_NAME target_name
;
1597 DISPLAYCONFIG_TARGET_PREFERRED_MODE preferred_mode
;
1598 DISPLAYCONFIG_ADAPTER_NAME adapter_name
;
1600 for (i
= 0; i
< paths
; i
++)
1602 source_name
.header
.type
= DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME
;
1603 source_name
.header
.size
= sizeof(source_name
);
1604 source_name
.header
.adapterId
= pi
[i
].sourceInfo
.adapterId
;
1605 source_name
.header
.id
= pi
[i
].sourceInfo
.id
;
1606 source_name
.viewGdiDeviceName
[0] = '\0';
1607 ret
= pDisplayConfigGetDeviceInfo(&source_name
.header
);
1608 ok(!ret
, "Expected 0, got %d\n", ret
);
1609 ok(source_name
.viewGdiDeviceName
[0] != '\0', "Expected GDI device name, got empty string\n");
1611 /* Test with an invalid adapter LUID */
1612 source_name
.header
.type
= DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME
;
1613 source_name
.header
.size
= sizeof(source_name
);
1614 source_name
.header
.adapterId
.LowPart
= 0xFFFF;
1615 source_name
.header
.adapterId
.HighPart
= 0xFFFF;
1616 source_name
.header
.id
= pi
[i
].sourceInfo
.id
;
1617 ret
= pDisplayConfigGetDeviceInfo(&source_name
.header
);
1618 ok(ret
== ERROR_GEN_FAILURE
, "Expected GEN_FAILURE, got %d\n", ret
);
1621 target_name
.header
.type
= DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME
;
1622 target_name
.header
.size
= sizeof(target_name
);
1623 target_name
.header
.adapterId
= pi
[i
].targetInfo
.adapterId
;
1624 target_name
.header
.id
= pi
[i
].targetInfo
.id
;
1625 target_name
.monitorDevicePath
[0] = '\0';
1626 ret
= pDisplayConfigGetDeviceInfo(&target_name
.header
);
1627 ok(!ret
, "Expected 0, got %d\n", ret
);
1628 ok(target_name
.monitorDevicePath
[0] != '\0', "Expected monitor device path, got empty string\n");
1632 preferred_mode
.header
.type
= DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE
;
1633 preferred_mode
.header
.size
= sizeof(preferred_mode
);
1634 preferred_mode
.header
.adapterId
= pi
[i
].targetInfo
.adapterId
;
1635 preferred_mode
.header
.id
= pi
[i
].targetInfo
.id
;
1636 preferred_mode
.width
= preferred_mode
.height
= 0;
1637 ret
= pDisplayConfigGetDeviceInfo(&preferred_mode
.header
);
1638 ok(!ret
, "Expected 0, got %d\n", ret
);
1639 ok(preferred_mode
.width
> 0 && preferred_mode
.height
> 0, "Expected non-zero height/width, got %ux%u\n",
1640 preferred_mode
.width
, preferred_mode
.height
);
1644 adapter_name
.header
.type
= DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME
;
1645 adapter_name
.header
.size
= sizeof(adapter_name
);
1646 adapter_name
.header
.adapterId
= pi
[i
].sourceInfo
.adapterId
;
1647 adapter_name
.adapterDevicePath
[0] = '\0';
1648 ret
= pDisplayConfigGetDeviceInfo(&adapter_name
.header
);
1649 ok(!ret
, "Expected 0, got %d\n", ret
);
1650 ok(adapter_name
.adapterDevicePath
[0] != '\0', "Expected adapter device path, got empty string\n");
1653 /* Check corresponding modes */
1654 if (pi
[i
].sourceInfo
.modeInfoIdx
== DISPLAYCONFIG_PATH_MODE_IDX_INVALID
)
1656 skip("Path doesn't contain source modeInfoIdx");
1659 ok(pi
[i
].sourceInfo
.modeInfoIdx
< modes
, "Expected index <%d, got %d\n", modes
, pi
[i
].sourceInfo
.modeInfoIdx
);
1660 if (pi
[i
].sourceInfo
.modeInfoIdx
>= modes
)
1663 ok(mi
[pi
[i
].sourceInfo
.modeInfoIdx
].infoType
== DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE
, "Expected infoType %d, got %d\n",
1664 DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE
, mi
[pi
[i
].sourceInfo
.modeInfoIdx
].infoType
);
1665 ok(pi
[i
].sourceInfo
.id
== mi
[pi
[i
].sourceInfo
.modeInfoIdx
].id
, "Expected id %u, got %u\n",
1666 pi
[i
].sourceInfo
.id
, mi
[pi
[i
].sourceInfo
.modeInfoIdx
].id
);
1667 ok(pi
[i
].sourceInfo
.adapterId
.HighPart
== mi
[pi
[i
].sourceInfo
.modeInfoIdx
].adapterId
.HighPart
&&
1668 pi
[i
].sourceInfo
.adapterId
.LowPart
== mi
[pi
[i
].sourceInfo
.modeInfoIdx
].adapterId
.LowPart
,
1669 "Expected LUID %08x:%08x, got %08x:%08x\n",
1670 pi
[i
].sourceInfo
.adapterId
.HighPart
, pi
[i
].sourceInfo
.adapterId
.LowPart
,
1671 mi
[pi
[i
].sourceInfo
.modeInfoIdx
].adapterId
.HighPart
, mi
[pi
[i
].sourceInfo
.modeInfoIdx
].adapterId
.LowPart
);
1672 ok(mi
[pi
[i
].sourceInfo
.modeInfoIdx
].sourceMode
.width
> 0 && mi
[pi
[i
].sourceInfo
.modeInfoIdx
].sourceMode
.height
> 0,
1673 "Expected non-zero height/width, got %ux%u\n",
1674 mi
[pi
[i
].sourceInfo
.modeInfoIdx
].sourceMode
.width
, mi
[pi
[i
].sourceInfo
.modeInfoIdx
].sourceMode
.height
);
1677 if (pi
[i
].targetInfo
.modeInfoIdx
== DISPLAYCONFIG_PATH_MODE_IDX_INVALID
)
1679 skip("Path doesn't contain target modeInfoIdx");
1682 ok(pi
[i
].targetInfo
.modeInfoIdx
< modes
, "Expected index <%d, got %d\n", modes
, pi
[i
].targetInfo
.modeInfoIdx
);
1683 if (pi
[i
].targetInfo
.modeInfoIdx
>= modes
)
1686 ok(mi
[pi
[i
].targetInfo
.modeInfoIdx
].infoType
== DISPLAYCONFIG_MODE_INFO_TYPE_TARGET
, "Expected infoType %d, got %d\n",
1687 DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE
, mi
[pi
[i
].targetInfo
.modeInfoIdx
].infoType
);
1688 ok(pi
[i
].targetInfo
.id
== mi
[pi
[i
].targetInfo
.modeInfoIdx
].id
, "Expected id %u, got %u\n",
1689 pi
[i
].targetInfo
.id
, mi
[pi
[i
].targetInfo
.modeInfoIdx
].id
);
1690 ok(pi
[i
].targetInfo
.adapterId
.HighPart
== mi
[pi
[i
].targetInfo
.modeInfoIdx
].adapterId
.HighPart
&&
1691 pi
[i
].targetInfo
.adapterId
.LowPart
== mi
[pi
[i
].targetInfo
.modeInfoIdx
].adapterId
.LowPart
,
1692 "Expected LUID %08x:%08x, got %08x:%08x\n",
1693 pi
[i
].targetInfo
.adapterId
.HighPart
, pi
[i
].targetInfo
.adapterId
.LowPart
,
1694 mi
[pi
[i
].targetInfo
.modeInfoIdx
].adapterId
.HighPart
, mi
[pi
[i
].targetInfo
.modeInfoIdx
].adapterId
.LowPart
);
1695 ok(mi
[pi
[i
].targetInfo
.modeInfoIdx
].targetMode
.targetVideoSignalInfo
.activeSize
.cx
> 0 &&
1696 mi
[pi
[i
].targetInfo
.modeInfoIdx
].targetMode
.targetVideoSignalInfo
.activeSize
.cy
> 0,
1697 "Expected non-zero height/width, got %ux%u\n",
1698 mi
[pi
[i
].targetInfo
.modeInfoIdx
].targetMode
.targetVideoSignalInfo
.activeSize
.cx
,
1699 mi
[pi
[i
].targetInfo
.modeInfoIdx
].targetMode
.targetVideoSignalInfo
.activeSize
.cy
);
1701 if (flags
== QDC_DATABASE_CURRENT
)
1702 ok(mi
[pi
[i
].targetInfo
.modeInfoIdx
].targetMode
.targetVideoSignalInfo
.totalSize
.cx
== 0 &&
1703 mi
[pi
[i
].targetInfo
.modeInfoIdx
].targetMode
.targetVideoSignalInfo
.totalSize
.cy
== 0,
1704 "Expected zero height/width, got %ux%u\n",
1705 mi
[pi
[i
].targetInfo
.modeInfoIdx
].targetMode
.targetVideoSignalInfo
.totalSize
.cx
,
1706 mi
[pi
[i
].targetInfo
.modeInfoIdx
].targetMode
.targetVideoSignalInfo
.totalSize
.cy
);
1708 ok(mi
[pi
[i
].targetInfo
.modeInfoIdx
].targetMode
.targetVideoSignalInfo
.totalSize
.cx
> 0 &&
1709 mi
[pi
[i
].targetInfo
.modeInfoIdx
].targetMode
.targetVideoSignalInfo
.totalSize
.cy
> 0,
1710 "Expected non-zero height/width, got %ux%u\n",
1711 mi
[pi
[i
].targetInfo
.modeInfoIdx
].targetMode
.targetVideoSignalInfo
.totalSize
.cx
,
1712 mi
[pi
[i
].targetInfo
.modeInfoIdx
].targetMode
.targetVideoSignalInfo
.totalSize
.cy
);
1716 static void test_QueryDisplayConfig(void)
1718 UINT32 paths
, modes
;
1719 DISPLAYCONFIG_PATH_INFO pi
[10];
1720 DISPLAYCONFIG_MODE_INFO mi
[20];
1721 DISPLAYCONFIG_TOPOLOGY_ID topologyid
;
1724 ret
= pQueryDisplayConfig(QDC_ALL_PATHS
, NULL
, NULL
, NULL
, NULL
, NULL
);
1725 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
1728 ret
= pQueryDisplayConfig(QDC_ALL_PATHS
, &paths
, NULL
, &modes
, NULL
, NULL
);
1729 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
1732 ret
= pQueryDisplayConfig(QDC_ALL_PATHS
, &paths
, pi
, &modes
, NULL
, NULL
);
1733 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
1736 ret
= pQueryDisplayConfig(QDC_ALL_PATHS
, &paths
, NULL
, &modes
, mi
, NULL
);
1737 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
1740 ret
= pQueryDisplayConfig(QDC_ALL_PATHS
, &paths
, pi
, &modes
, mi
, NULL
);
1741 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
1745 ret
= pQueryDisplayConfig(QDC_ALL_PATHS
, &paths
, pi
, &modes
, mi
, NULL
);
1746 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
1747 ok (paths
== 0, "got %u\n", paths
);
1748 ok (modes
== 1, "got %u\n", modes
);
1750 /* Crashes on Windows 10 */
1753 ret
= pQueryDisplayConfig(QDC_ALL_PATHS
, NULL
, pi
, NULL
, mi
, NULL
);
1754 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
1756 ret
= pQueryDisplayConfig(QDC_ALL_PATHS
, NULL
, pi
, &modes
, mi
, NULL
);
1757 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
1761 ret
= pQueryDisplayConfig(0, &paths
, pi
, &modes
, mi
, NULL
);
1762 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
1765 ret
= pQueryDisplayConfig(0xFF, &paths
, pi
, &modes
, mi
, NULL
);
1766 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
1769 ret
= pQueryDisplayConfig(QDC_DATABASE_CURRENT
, &paths
, pi
, &modes
, mi
, NULL
);
1770 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
1773 ret
= pQueryDisplayConfig(QDC_ALL_PATHS
, &paths
, pi
, &modes
, mi
, &topologyid
);
1774 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
1776 /* Below this point, test functionality that requires a WDDM driver on Windows */
1778 memset(pi
, 0xFF, sizeof(pi
[0]));
1779 memset(mi
, 0xFF, sizeof(mi
[0]));
1780 ret
= pQueryDisplayConfig(QDC_ALL_PATHS
, &paths
, pi
, &modes
, mi
, NULL
);
1781 if (ret
== ERROR_NOT_SUPPORTED
)
1784 win_skip("QueryDisplayConfig() functionality is unsupported\n");
1787 ok(ret
== ERROR_INSUFFICIENT_BUFFER
, "got %d\n", ret
);
1788 ok (paths
== 1, "got %u\n", paths
);
1789 ok (modes
== 1, "got %u\n", modes
);
1791 paths
= ARRAY_SIZE(pi
);
1792 modes
= ARRAY_SIZE(mi
);
1793 memset(pi
, 0xFF, sizeof(pi
));
1794 memset(mi
, 0xFF, sizeof(mi
));
1795 ret
= pQueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS
, &paths
, pi
, &modes
, mi
, NULL
);
1796 ok(!ret
, "got %d\n", ret
);
1797 ok(paths
> 0 && modes
> 0, "got %u, %u\n", paths
, modes
);
1798 if (!ret
&& paths
> 0 && modes
> 0)
1799 test_QueryDisplayConfig_result(QDC_ONLY_ACTIVE_PATHS
, paths
, pi
, modes
, mi
);
1801 paths
= ARRAY_SIZE(pi
);
1802 modes
= ARRAY_SIZE(mi
);
1803 memset(pi
, 0xFF, sizeof(pi
));
1804 memset(mi
, 0xFF, sizeof(mi
));
1806 ret
= pQueryDisplayConfig(QDC_DATABASE_CURRENT
, &paths
, pi
, &modes
, mi
, &topologyid
);
1807 ok(!ret
, "got %d\n", ret
);
1808 ok(topologyid
!= 0xFF, "expected topologyid to be set, got %d\n", topologyid
);
1809 if (!ret
&& paths
> 0 && modes
> 0)
1810 test_QueryDisplayConfig_result(QDC_DATABASE_CURRENT
, paths
, pi
, modes
, mi
);
1813 static void test_DisplayConfigGetDeviceInfo(void)
1816 DISPLAYCONFIG_SOURCE_DEVICE_NAME source_name
;
1817 DISPLAYCONFIG_TARGET_DEVICE_NAME target_name
;
1818 DISPLAYCONFIG_TARGET_PREFERRED_MODE preferred_mode
;
1819 DISPLAYCONFIG_ADAPTER_NAME adapter_name
;
1821 ret
= pDisplayConfigGetDeviceInfo(NULL
);
1822 ok(ret
== ERROR_GEN_FAILURE
, "got %d\n", ret
);
1824 source_name
.header
.type
= 0xFFFF;
1825 source_name
.header
.size
= 0;
1826 ret
= pDisplayConfigGetDeviceInfo(&source_name
.header
);
1827 ok(ret
== ERROR_GEN_FAILURE
, "got %d\n", ret
);
1829 source_name
.header
.type
= DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME
;
1830 source_name
.header
.size
= 0;
1831 ret
= pDisplayConfigGetDeviceInfo(&source_name
.header
);
1832 ok(ret
== ERROR_GEN_FAILURE
, "got %d\n", ret
);
1834 source_name
.header
.type
= 0xFFFF;
1835 source_name
.header
.size
= sizeof(source_name
.header
);
1836 ret
= pDisplayConfigGetDeviceInfo(&source_name
.header
);
1837 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
1839 source_name
.header
.type
= DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME
;
1840 source_name
.header
.size
= sizeof(source_name
.header
);
1841 ret
= pDisplayConfigGetDeviceInfo(&source_name
.header
);
1842 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
1844 source_name
.header
.type
= 0xFFFF;
1845 source_name
.header
.size
= sizeof(source_name
);
1846 ret
= pDisplayConfigGetDeviceInfo(&source_name
.header
);
1847 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
1849 source_name
.header
.type
= DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME
;
1850 source_name
.header
.size
= sizeof(source_name
) - 1;
1851 ret
= pDisplayConfigGetDeviceInfo(&source_name
.header
);
1852 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
1854 source_name
.header
.type
= DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME
;
1855 source_name
.header
.size
= sizeof(source_name
);
1856 source_name
.header
.adapterId
.LowPart
= 0xFFFF;
1857 source_name
.header
.adapterId
.HighPart
= 0xFFFF;
1858 source_name
.header
.id
= 0;
1859 ret
= pDisplayConfigGetDeviceInfo(&source_name
.header
);
1860 ok(ret
== ERROR_GEN_FAILURE
|| ret
== ERROR_NOT_SUPPORTED
, "got %d\n", ret
);
1862 target_name
.header
.type
= DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME
;
1863 target_name
.header
.size
= sizeof(target_name
) - 1;
1864 ret
= pDisplayConfigGetDeviceInfo(&target_name
.header
);
1865 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
1867 target_name
.header
.type
= DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME
;
1868 target_name
.header
.size
= sizeof(target_name
);
1869 target_name
.header
.adapterId
.LowPart
= 0xFFFF;
1870 target_name
.header
.adapterId
.HighPart
= 0xFFFF;
1871 target_name
.header
.id
= 0;
1872 ret
= pDisplayConfigGetDeviceInfo(&target_name
.header
);
1873 ok(ret
== ERROR_GEN_FAILURE
|| ret
== ERROR_NOT_SUPPORTED
, "got %d\n", ret
);
1875 preferred_mode
.header
.type
= DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE
;
1876 preferred_mode
.header
.size
= sizeof(preferred_mode
) - 1;
1877 ret
= pDisplayConfigGetDeviceInfo(&preferred_mode
.header
);
1878 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
1880 preferred_mode
.header
.type
= DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE
;
1881 preferred_mode
.header
.size
= sizeof(preferred_mode
);
1882 preferred_mode
.header
.adapterId
.LowPart
= 0xFFFF;
1883 preferred_mode
.header
.adapterId
.HighPart
= 0xFFFF;
1884 preferred_mode
.header
.id
= 0;
1885 ret
= pDisplayConfigGetDeviceInfo(&preferred_mode
.header
);
1886 ok(ret
== ERROR_GEN_FAILURE
|| ret
== ERROR_INVALID_PARAMETER
|| ret
== ERROR_NOT_SUPPORTED
, "got %d\n", ret
);
1888 adapter_name
.header
.type
= DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME
;
1889 adapter_name
.header
.size
= sizeof(adapter_name
) - 1;
1890 ret
= pDisplayConfigGetDeviceInfo(&adapter_name
.header
);
1891 ok(ret
== ERROR_INVALID_PARAMETER
, "got %d\n", ret
);
1893 adapter_name
.header
.type
= DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME
;
1894 adapter_name
.header
.size
= sizeof(adapter_name
);
1895 adapter_name
.header
.adapterId
.LowPart
= 0xFFFF;
1896 adapter_name
.header
.adapterId
.HighPart
= 0xFFFF;
1897 ret
= pDisplayConfigGetDeviceInfo(&adapter_name
.header
);
1898 ok(ret
== ERROR_GEN_FAILURE
|| ret
== ERROR_INVALID_PARAMETER
|| ret
== ERROR_NOT_SUPPORTED
, "got %d\n", ret
);
1901 static void test_display_config(void)
1903 if (!pGetDisplayConfigBufferSizes
||
1904 !pQueryDisplayConfig
||
1905 !pDisplayConfigGetDeviceInfo
)
1907 win_skip("DisplayConfig APIs are not supported\n");
1911 test_GetDisplayConfigBufferSizes();
1912 test_QueryDisplayConfig();
1913 test_DisplayConfigGetDeviceInfo();
1916 static BOOL CALLBACK
test_handle_proc(HMONITOR full_monitor
, HDC hdc
, LPRECT rect
, LPARAM lparam
)
1918 MONITORINFO monitor_info
= {sizeof(monitor_info
)};
1923 if ((ULONG_PTR
)full_monitor
>> 32)
1924 monitor
= full_monitor
;
1926 monitor
= (HMONITOR
)((ULONG_PTR
)full_monitor
| ((ULONG_PTR
)~0u << 32));
1927 SetLastError(0xdeadbeef);
1928 ret
= GetMonitorInfoW(monitor
, &monitor_info
);
1929 ok(ret
, "GetMonitorInfoW failed, error %#x.\n", GetLastError());
1931 monitor
= (HMONITOR
)((ULONG_PTR
)full_monitor
& 0xffffffff);
1932 SetLastError(0xdeadbeef);
1933 ret
= GetMonitorInfoW(monitor
, &monitor_info
);
1934 ok(ret
, "GetMonitorInfoW failed, error %#x.\n", GetLastError());
1936 monitor
= (HMONITOR
)(((ULONG_PTR
)full_monitor
& 0xffffffff) | ((ULONG_PTR
)0x1234 << 32));
1937 SetLastError(0xdeadbeef);
1938 ret
= GetMonitorInfoW(monitor
, &monitor_info
);
1939 ok(ret
, "GetMonitorInfoW failed, error %#x.\n", GetLastError());
1941 monitor
= (HMONITOR
)((ULONG_PTR
)full_monitor
& 0xffff);
1942 SetLastError(0xdeadbeef);
1943 ret
= GetMonitorInfoW(monitor
, &monitor_info
);
1944 todo_wine
ok(!ret
, "GetMonitorInfoW succeeded.\n");
1945 todo_wine
ok(GetLastError() == ERROR_INVALID_MONITOR_HANDLE
, "Expected error code %#x, got %#x.\n",
1946 ERROR_INVALID_MONITOR_HANDLE
, GetLastError());
1948 monitor
= (HMONITOR
)(((ULONG_PTR
)full_monitor
& 0xffff) | ((ULONG_PTR
)0x9876 << 16));
1949 SetLastError(0xdeadbeef);
1950 ret
= GetMonitorInfoW(monitor
, &monitor_info
);
1951 ok(!ret
, "GetMonitorInfoW succeeded.\n");
1952 ok(GetLastError() == ERROR_INVALID_MONITOR_HANDLE
, "Expected error code %#x, got %#x.\n",
1953 ERROR_INVALID_MONITOR_HANDLE
, GetLastError());
1955 monitor
= (HMONITOR
)(((ULONG_PTR
)full_monitor
& 0xffff) | ((ULONG_PTR
)0x12345678 << 16));
1956 SetLastError(0xdeadbeef);
1957 ret
= GetMonitorInfoW(monitor
, &monitor_info
);
1958 ok(!ret
, "GetMonitorInfoW succeeded.\n");
1959 ok(GetLastError() == ERROR_INVALID_MONITOR_HANDLE
, "Expected error code %#x, got %#x.\n",
1960 ERROR_INVALID_MONITOR_HANDLE
, GetLastError());
1962 if ((ULONG_PTR
)full_monitor
>> 16)
1963 monitor
= full_monitor
;
1965 monitor
= (HMONITOR
)((ULONG_PTR
)full_monitor
| ((ULONG_PTR
)~0u << 16));
1966 SetLastError(0xdeadbeef);
1967 ret
= GetMonitorInfoW(monitor
, &monitor_info
);
1968 todo_wine_if(((ULONG_PTR
)full_monitor
>> 16) == 0)
1969 ok(ret
, "GetMonitorInfoW failed, error %#x.\n", GetLastError());
1971 monitor
= (HMONITOR
)((ULONG_PTR
)full_monitor
& 0xffff);
1972 SetLastError(0xdeadbeef);
1973 ret
= GetMonitorInfoW(monitor
, &monitor_info
);
1974 ok(ret
, "GetMonitorInfoW failed, error %#x.\n", GetLastError());
1976 monitor
= (HMONITOR
)(((ULONG_PTR
)full_monitor
& 0xffff) | ((ULONG_PTR
)0x1234 << 16));
1977 SetLastError(0xdeadbeef);
1978 ret
= GetMonitorInfoW(monitor
, &monitor_info
);
1979 ok(!ret
, "GetMonitorInfoW succeeded.\n");
1980 ok(GetLastError() == ERROR_INVALID_MONITOR_HANDLE
, "Expected error code %#x, got %#x.\n",
1981 ERROR_INVALID_MONITOR_HANDLE
, GetLastError());
1987 static void test_handles(void)
1991 /* Test that monitor handles are user32 handles */
1992 ret
= EnumDisplayMonitors(NULL
, NULL
, test_handle_proc
, 0);
1993 ok(ret
, "EnumDisplayMonitors failed, error %#x.\n", GetLastError());
1996 #define check_display_dc(a, b, c) _check_display_dc(__LINE__, a, b, c)
1997 static void _check_display_dc(INT line
, HDC hdc
, const DEVMODEA
*dm
, BOOL allow_todo
)
2001 value
= GetDeviceCaps(hdc
, HORZRES
);
2002 todo_wine_if(allow_todo
&& dm
->dmPelsWidth
!= GetSystemMetrics(SM_CXSCREEN
))
2003 ok_(__FILE__
, line
)(value
== dm
->dmPelsWidth
, "Expected HORZRES %d, got %d.\n",
2004 dm
->dmPelsWidth
, value
);
2006 value
= GetDeviceCaps(hdc
, VERTRES
);
2007 todo_wine_if(allow_todo
&& dm
->dmPelsHeight
!= GetSystemMetrics(SM_CYSCREEN
))
2008 ok_(__FILE__
, line
)(value
== dm
->dmPelsHeight
, "Expected VERTRES %d, got %d.\n",
2009 dm
->dmPelsHeight
, value
);
2011 value
= GetDeviceCaps(hdc
, DESKTOPHORZRES
);
2012 todo_wine_if(dm
->dmPelsWidth
!= GetSystemMetrics(SM_CXVIRTUALSCREEN
)
2013 && value
== GetSystemMetrics(SM_CXVIRTUALSCREEN
))
2014 ok_(__FILE__
, line
)(value
== dm
->dmPelsWidth
, "Expected DESKTOPHORZRES %d, got %d.\n",
2015 dm
->dmPelsWidth
, value
);
2017 value
= GetDeviceCaps(hdc
, DESKTOPVERTRES
);
2018 todo_wine_if(dm
->dmPelsHeight
!= GetSystemMetrics(SM_CYVIRTUALSCREEN
)
2019 && value
== GetSystemMetrics(SM_CYVIRTUALSCREEN
))
2020 ok_(__FILE__
, line
)(value
== dm
->dmPelsHeight
, "Expected DESKTOPVERTRES %d, got %d.\n",
2021 dm
->dmPelsHeight
, value
);
2023 value
= GetDeviceCaps(hdc
, VREFRESH
);
2024 todo_wine_if(allow_todo
)
2025 ok_(__FILE__
, line
)(value
== dm
->dmDisplayFrequency
, "Expected VREFRESH %d, got %d.\n",
2026 dm
->dmDisplayFrequency
, value
);
2029 static void test_display_dc(void)
2031 DWORD device_idx
, mode_idx
;
2032 DEVMODEA dm
, dm2
, dm3
;
2033 INT count
, old_count
;
2039 /* Test DCs covering the entire virtual screen */
2040 hdc
= CreateDCA("DISPLAY", NULL
, NULL
, NULL
);
2041 ok(!!hdc
, "CreateDCA failed.\n");
2043 memset(&dm
, 0, sizeof(dm
));
2044 dm
.dmSize
= sizeof(dm
);
2045 ret
= EnumDisplaySettingsA(NULL
, ENUM_CURRENT_SETTINGS
, &dm
);
2046 ok(ret
, "EnumDisplaySettingsA failed.\n");
2048 check_display_dc(hdc
, &dm
, FALSE
);
2050 /* Tests after mode changes */
2051 memset(&dm2
, 0, sizeof(dm2
));
2052 dm2
.dmSize
= sizeof(dm2
);
2053 for (mode_idx
= 0; EnumDisplaySettingsA(NULL
, mode_idx
, &dm2
); ++mode_idx
)
2055 if (dm2
.dmPelsWidth
!= dm
.dmPelsWidth
&& dm2
.dmPelsHeight
!= dm
.dmPelsHeight
)
2058 ok(dm2
.dmPelsWidth
&& dm2
.dmPelsWidth
!= dm
.dmPelsWidth
&& dm2
.dmPelsHeight
!= dm
.dmPelsHeight
,
2059 "Failed to find a different resolution.\n");
2061 res
= ChangeDisplaySettingsExA(NULL
, &dm2
, NULL
, CDS_RESET
, NULL
);
2062 ok(res
== DISP_CHANGE_SUCCESSFUL
|| broken(res
== DISP_CHANGE_FAILED
), /* Win8 TestBots */
2063 "ChangeDisplaySettingsExA returned unexpected %d.\n", res
);
2064 if (res
== DISP_CHANGE_SUCCESSFUL
)
2066 check_display_dc(hdc
, &dm2
, FALSE
);
2068 res
= ChangeDisplaySettingsExA(NULL
, NULL
, NULL
, 0, NULL
);
2069 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA returned unexpected %d.\n", res
);
2074 /* Test DCs covering a specific monitor */
2076 for (device_idx
= 0; EnumDisplayDevicesA(NULL
, device_idx
, &dd
, 0); ++device_idx
)
2078 if (!(dd
.StateFlags
& DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
))
2081 memset(&dm
, 0, sizeof(dm
));
2082 dm
.dmSize
= sizeof(dm
);
2083 ret
= EnumDisplaySettingsA(dd
.DeviceName
, ENUM_CURRENT_SETTINGS
, &dm
);
2084 ok(ret
, "EnumDisplaySettingsA %s failed.\n", dd
.DeviceName
);
2086 hdc
= CreateDCA(dd
.DeviceName
, NULL
, NULL
, NULL
);
2087 ok(!!hdc
, "CreateDCA %s failed.\n", dd
.DeviceName
);
2089 check_display_dc(hdc
, &dm
, FALSE
);
2091 /* Tests after mode changes */
2092 memset(&dm2
, 0, sizeof(dm2
));
2093 dm2
.dmSize
= sizeof(dm2
);
2094 for (mode_idx
= 0; EnumDisplaySettingsA(dd
.DeviceName
, mode_idx
, &dm2
); ++mode_idx
)
2096 if (dm2
.dmPelsWidth
!= dm
.dmPelsWidth
&& dm2
.dmPelsHeight
!= dm
.dmPelsHeight
)
2099 ok(dm2
.dmPelsWidth
&& dm2
.dmPelsWidth
!= dm
.dmPelsWidth
&& dm2
.dmPelsHeight
!= dm
.dmPelsHeight
,
2100 "Failed to find a different resolution for %s.\n", dd
.DeviceName
);
2102 res
= ChangeDisplaySettingsExA(dd
.DeviceName
, &dm2
, NULL
, CDS_RESET
, NULL
);
2103 ok(res
== DISP_CHANGE_SUCCESSFUL
|| broken(res
== DISP_CHANGE_FAILED
), /* Win8 TestBots */
2104 "ChangeDisplaySettingsExA %s returned unexpected %d.\n", dd
.DeviceName
, res
);
2105 if (res
!= DISP_CHANGE_SUCCESSFUL
)
2107 win_skip("Failed to change display mode for %s.\n", dd
.DeviceName
);
2112 check_display_dc(hdc
, &dm2
, FALSE
);
2114 /* Tests after monitor detach */
2115 if (!(dd
.StateFlags
& DISPLAY_DEVICE_PRIMARY_DEVICE
))
2117 old_count
= GetSystemMetrics(SM_CMONITORS
);
2119 memset(&dm3
, 0, sizeof(dm3
));
2120 dm3
.dmSize
= sizeof(dm3
);
2121 ret
= EnumDisplaySettingsA(dd
.DeviceName
, ENUM_CURRENT_SETTINGS
, &dm3
);
2122 ok(ret
, "EnumDisplaySettingsA %s failed.\n", dd
.DeviceName
);
2124 dm3
.dmFields
= DM_POSITION
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
2125 dm3
.dmPelsWidth
= 0;
2126 dm3
.dmPelsHeight
= 0;
2127 res
= ChangeDisplaySettingsExA(dd
.DeviceName
, &dm3
, NULL
, CDS_UPDATEREGISTRY
| CDS_NORESET
, NULL
);
2128 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA %s returned unexpected %d.\n",
2129 dd
.DeviceName
, res
);
2130 res
= ChangeDisplaySettingsExA(dd
.DeviceName
, NULL
, NULL
, 0, NULL
);
2131 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA %s returned unexpected %d.\n",
2132 dd
.DeviceName
, res
);
2134 count
= GetSystemMetrics(SM_CMONITORS
);
2135 ok(count
== old_count
- 1, "Expected monitor count %d, got %d.\n", old_count
- 1, count
);
2137 /* Should report the same values before detach */
2138 check_display_dc(hdc
, &dm2
, TRUE
);
2141 res
= ChangeDisplaySettingsExA(dd
.DeviceName
, &dm
, NULL
, CDS_UPDATEREGISTRY
| CDS_NORESET
, NULL
);
2142 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA %s returned unexpected %d.\n",
2143 dd
.DeviceName
, res
);
2144 res
= ChangeDisplaySettingsExA(NULL
, NULL
, NULL
, 0, NULL
);
2145 ok(res
== DISP_CHANGE_SUCCESSFUL
, "ChangeDisplaySettingsExA %s returned unexpected %d.\n",
2146 dd
.DeviceName
, res
);
2153 init_function_pointers();
2154 test_enumdisplaydevices();
2155 test_ChangeDisplaySettingsEx();
2156 test_EnumDisplayMonitors();
2159 test_display_config();