1 /* 2 * Unit tests for monitor APIs 3 * 4 * Copyright 2005 Huw Davies 5 * Copyright 2008 Dmitry Timoshkov 6 * 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. 11 * 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. 16 * 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 20 */ 21 22 #include "precomp.h" 23 24 static HMODULE hdll; 25 static LONG (WINAPI *pChangeDisplaySettingsExA)(LPCSTR, LPDEVMODEA, HWND, DWORD, LPVOID); 26 static LONG (WINAPI *pChangeDisplaySettingsExW)(LPCWSTR, LPDEVMODEW, HWND, DWORD, LPVOID); 27 static BOOL (WINAPI *pEnumDisplayDevicesA)(LPCSTR,DWORD,LPDISPLAY_DEVICEA,DWORD); 28 static BOOL (WINAPI *pEnumDisplayMonitors)(HDC,LPRECT,MONITORENUMPROC,LPARAM); 29 static BOOL (WINAPI *pGetMonitorInfoA)(HMONITOR,LPMONITORINFO); 30 static BOOL (WINAPI *pGetMonitorInfoW)(HMONITOR,LPMONITORINFO); 31 static HMONITOR (WINAPI *pMonitorFromPoint)(POINT,DWORD); 32 static HMONITOR (WINAPI *pMonitorFromRect)(LPCRECT,DWORD); 33 static HMONITOR (WINAPI *pMonitorFromWindow)(HWND,DWORD); 34 static LONG (WINAPI *pGetDisplayConfigBufferSizes)(UINT32,UINT32*,UINT32*); 35 36 static void init_function_pointers(void) 37 { 38 hdll = GetModuleHandleA("user32.dll"); 39 40 #define GET_PROC(func) \ 41 p ## func = (void*)GetProcAddress(hdll, #func); \ 42 if(!p ## func) \ 43 trace("GetProcAddress(%s) failed\n", #func); 44 45 GET_PROC(ChangeDisplaySettingsExA) 46 GET_PROC(ChangeDisplaySettingsExW) 47 GET_PROC(EnumDisplayDevicesA) 48 GET_PROC(EnumDisplayMonitors) 49 GET_PROC(GetDisplayConfigBufferSizes) 50 GET_PROC(GetMonitorInfoA) 51 GET_PROC(GetMonitorInfoW) 52 GET_PROC(MonitorFromPoint) 53 GET_PROC(MonitorFromRect) 54 GET_PROC(MonitorFromWindow) 55 56 #undef GET_PROC 57 } 58 59 static BOOL CALLBACK monitor_enum_proc(HMONITOR hmon, HDC hdc, LPRECT lprc, 60 LPARAM lparam) 61 { 62 MONITORINFOEXA mi; 63 char *primary = (char *)lparam; 64 65 mi.cbSize = sizeof(mi); 66 67 ok(pGetMonitorInfoA(hmon, (MONITORINFO*)&mi), "GetMonitorInfo failed\n"); 68 if (mi.dwFlags & MONITORINFOF_PRIMARY) 69 strcpy(primary, mi.szDevice); 70 71 return TRUE; 72 } 73 74 static void test_enumdisplaydevices(void) 75 { 76 DISPLAY_DEVICEA dd; 77 char primary_device_name[32]; 78 char primary_monitor_device_name[32]; 79 DWORD primary_num = -1, num = 0; 80 BOOL ret; 81 82 if (!pEnumDisplayDevicesA) 83 { 84 win_skip("EnumDisplayDevicesA is not available\n"); 85 return; 86 } 87 88 dd.cb = sizeof(dd); 89 for (num = 0;; num++) 90 { 91 HDC dc; 92 ret = pEnumDisplayDevicesA(NULL, num, &dd, 0); 93 if(!ret) break; 94 95 if(dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) 96 { 97 strcpy(primary_device_name, dd.DeviceName); 98 primary_num = num; 99 } 100 if(dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) 101 { 102 /* test creating DC */ 103 dc = CreateDCA(dd.DeviceName, NULL, NULL, NULL); 104 ok(dc != NULL, "Failed to CreateDC(\"%s\") err=%d\n", dd.DeviceName, GetLastError()); 105 DeleteDC(dc); 106 } 107 } 108 109 if (primary_num == -1 || !pEnumDisplayMonitors || !pGetMonitorInfoA) 110 { 111 win_skip("EnumDisplayMonitors or GetMonitorInfoA are not available\n"); 112 return; 113 } 114 115 primary_monitor_device_name[0] = 0; 116 ret = pEnumDisplayMonitors(NULL, NULL, monitor_enum_proc, (LPARAM)primary_monitor_device_name); 117 ok(ret, "EnumDisplayMonitors failed\n"); 118 ok(!strcmp(primary_monitor_device_name, primary_device_name), 119 "monitor device name %s, device name %s\n", primary_monitor_device_name, 120 primary_device_name); 121 122 dd.cb = sizeof(dd); 123 for (num = 0;; num++) 124 { 125 ret = pEnumDisplayDevicesA(primary_device_name, num, &dd, 0); 126 if (!ret) break; 127 128 dd.DeviceID[63] = 0; 129 ok(!strcasecmp(dd.DeviceID, "Monitor\\Default_Monitor\\{4D36E96E-E325-11CE-BFC1-08002BE10318}\\"), 130 "DeviceID \"%s\" does not start with \"Monitor\\Default_Monitor\\...\" prefix\n", dd.DeviceID); 131 } 132 } 133 134 struct vid_mode 135 { 136 DWORD w, h, bpp, freq, fields; 137 BOOL must_succeed; 138 }; 139 140 static const struct vid_mode vid_modes_test[] = { 141 {640, 480, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY, 0}, 142 {640, 480, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY, 1}, 143 {640, 480, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL , 0}, 144 {640, 480, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT , 1}, 145 {640, 480, 0, 0, DM_BITSPERPEL , 0}, 146 {640, 480, 0, 0, DM_DISPLAYFREQUENCY, 0}, 147 148 {0, 0, 0, 0, DM_PELSWIDTH, 0}, 149 {0, 0, 0, 0, DM_PELSHEIGHT, 0}, 150 151 {640, 480, 0, 0, DM_PELSWIDTH, 0}, 152 {640, 480, 0, 0, DM_PELSHEIGHT, 0}, 153 { 0, 480, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT, 0}, 154 {640, 0, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT, 0}, 155 156 /* the following test succeeds under XP SP3 157 {0, 0, 0, 0, DM_DISPLAYFREQUENCY, 0} 158 */ 159 }; 160 #define vid_modes_cnt (sizeof(vid_modes_test) / sizeof(vid_modes_test[0])) 161 162 static void test_ChangeDisplaySettingsEx(void) 163 { 164 DEVMODEA dm; 165 DEVMODEW dmW; 166 DWORD width; 167 LONG res; 168 int i; 169 170 if (!pChangeDisplaySettingsExA) 171 { 172 win_skip("ChangeDisplaySettingsExA is not available\n"); 173 return; 174 } 175 176 SetLastError(0xdeadbeef); 177 res = EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &dm); 178 ok(res, "EnumDisplaySettings error %u\n", GetLastError()); 179 180 width = dm.dmPelsWidth; 181 182 dm.dmDriverExtra = 1; 183 res = ChangeDisplaySettingsA(&dm, CDS_TEST); 184 ok(res == DISP_CHANGE_SUCCESSFUL, 185 "ChangeDisplaySettingsA returned %d, expected DISP_CHANGE_SUCCESSFUL\n", res); 186 ok(dm.dmDriverExtra == 0 || broken(dm.dmDriverExtra == 1) /* win9x */, 187 "ChangeDisplaySettingsA didn't reset dmDriverExtra to 0\n"); 188 189 /* crashes under XP SP3 for large dmDriverExtra values */ 190 dm.dmDriverExtra = 1; 191 res = pChangeDisplaySettingsExA(NULL, &dm, NULL, CDS_TEST, NULL); 192 ok(res == DISP_CHANGE_SUCCESSFUL, 193 "ChangeDisplaySettingsExW returned %d, expected DISP_CHANGE_SUCCESSFUL\n", res); 194 ok(dm.dmDriverExtra == 1, "ChangeDisplaySettingsExA shouldn't reset dmDriverExtra to 0\n"); 195 196 memset(&dmW, 0, sizeof(dmW)); 197 dmW.dmSize = sizeof(dmW); 198 dmW.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; 199 dmW.dmPelsWidth = dm.dmPelsWidth; 200 dmW.dmPelsHeight = dm.dmPelsHeight; 201 dmW.dmDriverExtra = 1; 202 SetLastError(0xdeadbeef); 203 res = ChangeDisplaySettingsW(&dmW, CDS_TEST); 204 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) 205 { 206 ok(res == DISP_CHANGE_SUCCESSFUL, 207 "ChangeDisplaySettingsW returned %d, expected DISP_CHANGE_SUCCESSFUL\n", res); 208 ok(dmW.dmDriverExtra == 0, "ChangeDisplaySettingsW didn't reset dmDriverExtra to 0\n"); 209 } 210 211 /* Apparently XP treats dmDriverExtra being != 0 as an error */ 212 dmW.dmDriverExtra = 1; 213 res = pChangeDisplaySettingsExW(NULL, &dmW, NULL, CDS_TEST, NULL); 214 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) 215 { 216 ok(res == DISP_CHANGE_SUCCESSFUL, 217 "ChangeDisplaySettingsExW returned %d, expected DISP_CHANGE_SUCCESSFUL\n", res); 218 ok(dmW.dmDriverExtra == 1, "ChangeDisplaySettingsExW shouldn't reset dmDriverExtra to 0\n"); 219 } 220 221 /* the following 2 tests show that dm.dmSize being 0 is invalid, but 222 * ChangeDisplaySettingsExA still reports success. 223 */ 224 memset(&dm, 0, sizeof(dm)); 225 dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; 226 dm.dmPelsWidth = width; 227 res = pChangeDisplaySettingsExA(NULL, &dm, NULL, CDS_TEST, NULL); 228 ok(res == DISP_CHANGE_SUCCESSFUL || 229 res == DISP_CHANGE_BADMODE || /* Win98, WinMe */ 230 res == DISP_CHANGE_FAILED, /* NT4 */ 231 "ChangeDisplaySettingsExA returned unexpected %d\n", res); 232 233 memset(&dmW, 0, sizeof(dmW)); 234 dmW.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; 235 dmW.dmPelsWidth = width; 236 SetLastError(0xdeadbeef); 237 res = pChangeDisplaySettingsExW(NULL, &dmW, NULL, CDS_TEST, NULL); 238 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) 239 ok(res == DISP_CHANGE_FAILED || 240 res == DISP_CHANGE_BADPARAM || /* NT4 */ 241 res == DISP_CHANGE_BADMODE /* XP SP3 */, 242 "ChangeDisplaySettingsExW returned %d\n", res); 243 244 memset(&dm, 0, sizeof(dm)); 245 dm.dmSize = sizeof(dm); 246 247 for (i = 0; i < vid_modes_cnt; i++) 248 { 249 dm.dmPelsWidth = vid_modes_test[i].w; 250 dm.dmPelsHeight = vid_modes_test[i].h; 251 dm.dmBitsPerPel = vid_modes_test[i].bpp; 252 dm.dmDisplayFrequency = vid_modes_test[i].freq; 253 dm.dmFields = vid_modes_test[i].fields; 254 res = pChangeDisplaySettingsExA(NULL, &dm, NULL, CDS_TEST, NULL); 255 ok(vid_modes_test[i].must_succeed ? 256 (res == DISP_CHANGE_SUCCESSFUL || res == DISP_CHANGE_RESTART) : 257 (res == DISP_CHANGE_SUCCESSFUL || res == DISP_CHANGE_RESTART || 258 res == DISP_CHANGE_BADMODE || res == DISP_CHANGE_BADPARAM), 259 "Unexpected ChangeDisplaySettingsEx() return code for resolution[%d]: %d\n", i, res); 260 261 if (res == DISP_CHANGE_SUCCESSFUL) 262 { 263 RECT r, r1, virt; 264 265 SetRect(&virt, 0, 0, GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN)); 266 if (IsRectEmpty(&virt)) /* NT4 doesn't have SM_CX/YVIRTUALSCREEN */ 267 SetRect(&virt, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); 268 OffsetRect(&virt, GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN)); 269 270 /* Resolution change resets clip rect */ 271 ok(GetClipCursor(&r), "GetClipCursor() failed\n"); 272 ok(EqualRect(&r, &virt), "Invalid clip rect: %s\n", wine_dbgstr_rect(&r)); 273 274 if (!ClipCursor(NULL)) continue; 275 ok(GetClipCursor(&r), "GetClipCursor() failed\n"); 276 ok(EqualRect(&r, &virt), "Invalid clip rect: %s\n", wine_dbgstr_rect(&r)); 277 278 /* This should always work. Primary monitor is at (0,0) */ 279 SetRect(&r1, 10, 10, 20, 20); 280 ok(ClipCursor(&r1), "ClipCursor() failed\n"); 281 ok(GetClipCursor(&r), "GetClipCursor() failed\n"); 282 ok(EqualRect(&r, &r1), "Invalid clip rect: %s\n", wine_dbgstr_rect(&r)); 283 SetRect(&r1, 10, 10, 10, 10); 284 ok(ClipCursor(&r1), "ClipCursor() failed\n"); 285 ok(GetClipCursor(&r), "GetClipCursor() failed\n"); 286 ok(EqualRect(&r, &r1), "Invalid clip rect: %s\n", wine_dbgstr_rect(&r)); 287 SetRect(&r1, 10, 10, 10, 9); 288 ok(!ClipCursor(&r1), "ClipCursor() succeeded\n"); 289 /* Windows bug: further clipping fails once an empty rect is set, so we have to reset it */ 290 ClipCursor(NULL); 291 292 SetRect(&r1, virt.left - 10, virt.top - 10, virt.right + 20, virt.bottom + 20); 293 ok(ClipCursor(&r1), "ClipCursor() failed\n"); 294 ok(GetClipCursor(&r), "GetClipCursor() failed\n"); 295 ok(EqualRect(&r, &virt) || broken(EqualRect(&r, &r1)) /* win9x */, 296 "Invalid clip rect: %s\n", wine_dbgstr_rect(&r)); 297 ClipCursor(&virt); 298 } 299 } 300 res = pChangeDisplaySettingsExA(NULL, NULL, NULL, CDS_RESET, NULL); 301 ok(res == DISP_CHANGE_SUCCESSFUL, "Failed to reset default resolution: %d\n", res); 302 } 303 304 static void test_monitors(void) 305 { 306 HMONITOR monitor, primary, nearest; 307 POINT pt; 308 RECT rc; 309 MONITORINFO mi; 310 MONITORINFOEXA miexa; 311 MONITORINFOEXW miexw; 312 BOOL ret; 313 DWORD i; 314 315 static const struct 316 { 317 DWORD cbSize; 318 BOOL ret; 319 } testdatami[] = { 320 {0, FALSE}, 321 {sizeof(MONITORINFO)+1, FALSE}, 322 {sizeof(MONITORINFO)-1, FALSE}, 323 {sizeof(MONITORINFO), TRUE}, 324 {-1, FALSE}, 325 {0xdeadbeef, FALSE}, 326 }, 327 testdatamiexa[] = { 328 {0, FALSE}, 329 {sizeof(MONITORINFOEXA)+1, FALSE}, 330 {sizeof(MONITORINFOEXA)-1, FALSE}, 331 {sizeof(MONITORINFOEXA), TRUE}, 332 {-1, FALSE}, 333 {0xdeadbeef, FALSE}, 334 }, 335 testdatamiexw[] = { 336 {0, FALSE}, 337 {sizeof(MONITORINFOEXW)+1, FALSE}, 338 {sizeof(MONITORINFOEXW)-1, FALSE}, 339 {sizeof(MONITORINFOEXW), TRUE}, 340 {-1, FALSE}, 341 {0xdeadbeef, FALSE}, 342 }; 343 344 if (!pMonitorFromPoint || !pMonitorFromWindow || !pMonitorFromRect) 345 { 346 win_skip("MonitorFromPoint, MonitorFromWindow, or MonitorFromRect is not available\n"); 347 return; 348 } 349 350 pt.x = pt.y = 0; 351 primary = pMonitorFromPoint( pt, MONITOR_DEFAULTTOPRIMARY ); 352 ok( primary != 0, "couldn't get primary monitor\n" ); 353 354 monitor = pMonitorFromWindow( 0, MONITOR_DEFAULTTONULL ); 355 ok( !monitor, "got %p, should not get a monitor for an invalid window\n", monitor ); 356 monitor = pMonitorFromWindow( 0, MONITOR_DEFAULTTOPRIMARY ); 357 ok( monitor == primary, "got %p, should get primary %p for MONITOR_DEFAULTTOPRIMARY\n", monitor, primary ); 358 monitor = pMonitorFromWindow( 0, MONITOR_DEFAULTTONEAREST ); 359 ok( monitor == primary, "got %p, should get primary %p for MONITOR_DEFAULTTONEAREST\n", monitor, primary ); 360 361 SetRect( &rc, 0, 0, 1, 1 ); 362 monitor = pMonitorFromRect( &rc, MONITOR_DEFAULTTONULL ); 363 ok( monitor == primary, "got %p, should get primary %p\n", monitor, primary ); 364 365 monitor = pMonitorFromRect( &rc, MONITOR_DEFAULTTOPRIMARY ); 366 ok( monitor == primary, "got %p, should get primary %p\n", monitor, primary ); 367 368 monitor = pMonitorFromRect( &rc, MONITOR_DEFAULTTONEAREST ); 369 ok( monitor == primary, "got %p, should get primary %p\n", monitor, primary ); 370 371 /* Empty rect at 0,0 is considered inside the primary monitor */ 372 SetRect( &rc, 0, 0, -1, -1 ); 373 monitor = pMonitorFromRect( &rc, MONITOR_DEFAULTTONULL ); 374 ok( monitor == primary, "got %p, should get primary %p\n", monitor, primary ); 375 376 /* Even if there is a monitor left of the primary, the primary will have the most overlapping area */ 377 SetRect( &rc, -1, 0, 2, 1 ); 378 monitor = pMonitorFromRect( &rc, MONITOR_DEFAULTTONULL ); 379 ok( monitor == primary, "got %p, should get primary %p\n", monitor, primary ); 380 381 /* But the width of the rect doesn't matter if it's empty. */ 382 SetRect( &rc, -1, 0, 2, -1 ); 383 monitor = pMonitorFromRect( &rc, MONITOR_DEFAULTTONULL ); 384 ok( monitor != primary, "got primary %p\n", monitor ); 385 386 if (!pGetMonitorInfoA) 387 { 388 win_skip("GetMonitorInfoA is not available\n"); 389 return; 390 } 391 392 /* Search for a monitor that has no others equally near to (left, top-1) */ 393 SetRect( &rc, -1, -2, 2, 0 ); 394 monitor = pMonitorFromRect( &rc, MONITOR_DEFAULTTONULL ); 395 nearest = primary; 396 while (monitor != NULL) 397 { 398 ok( monitor != primary, "got primary %p\n", monitor ); 399 nearest = monitor; 400 mi.cbSize = sizeof(mi); 401 ret = pGetMonitorInfoA( monitor, &mi ); 402 ok( ret, "GetMonitorInfo failed\n" ); 403 SetRect( &rc, mi.rcMonitor.left-1, mi.rcMonitor.top-2, mi.rcMonitor.left+2, mi.rcMonitor.top ); 404 monitor = pMonitorFromRect( &rc, MONITOR_DEFAULTTONULL ); 405 } 406 407 /* tests for cbSize in MONITORINFO */ 408 monitor = pMonitorFromWindow( 0, MONITOR_DEFAULTTOPRIMARY ); 409 for (i = 0; i < (sizeof(testdatami) / sizeof(testdatami[0])); i++) 410 { 411 memset( &mi, 0, sizeof(mi) ); 412 mi.cbSize = testdatami[i].cbSize; 413 ret = pGetMonitorInfoA( monitor, &mi ); 414 ok( ret == testdatami[i].ret, "GetMonitorInfo returned wrong value\n" ); 415 if (ret) 416 ok( (mi.dwFlags & MONITORINFOF_PRIMARY), "MONITORINFOF_PRIMARY flag isn't set\n" ); 417 else 418 ok( !(mi.dwFlags & MONITORINFOF_PRIMARY), "MONITORINFOF_PRIMARY flag is set\n" ); 419 420 memset( &miexw, 0, sizeof(miexw) ); 421 miexw.cbSize = testdatamiexw[i].cbSize; 422 ret = pGetMonitorInfoW( monitor, (LPMONITORINFO)&miexw ); 423 ok( ret == testdatamiexw[i].ret, "GetMonitorInfo returned wrong value\n" ); 424 if (ret) 425 ok( (miexw.dwFlags & MONITORINFOF_PRIMARY), "MONITORINFOF_PRIMARY flag isn't set\n" ); 426 else 427 ok( !(miexw.dwFlags & MONITORINFOF_PRIMARY), "MONITORINFOF_PRIMARY flag is set\n" ); 428 } 429 430 /* tests for cbSize in MONITORINFOEXA */ 431 for (i = 0; i < (sizeof(testdatamiexa) / sizeof(testdatamiexa[0])); i++) 432 { 433 memset( &miexa, 0, sizeof(miexa) ); 434 miexa.cbSize = testdatamiexa[i].cbSize; 435 ret = pGetMonitorInfoA( monitor, (LPMONITORINFO)&miexa ); 436 ok( ret == testdatamiexa[i].ret, "GetMonitorInfo returned wrong value\n" ); 437 if (ret) 438 ok( (miexa.dwFlags & MONITORINFOF_PRIMARY), "MONITORINFOF_PRIMARY flag isn't set\n" ); 439 else 440 ok( !(miexa.dwFlags & MONITORINFOF_PRIMARY), "MONITORINFOF_PRIMARY flag is set\n" ); 441 } 442 443 /* tests for cbSize in MONITORINFOEXW */ 444 for (i = 0; i < (sizeof(testdatamiexw) / sizeof(testdatamiexw[0])); i++) 445 { 446 memset( &miexw, 0, sizeof(miexw) ); 447 miexw.cbSize = testdatamiexw[i].cbSize; 448 ret = pGetMonitorInfoW( monitor, (LPMONITORINFO)&miexw ); 449 ok( ret == testdatamiexw[i].ret, "GetMonitorInfo returned wrong value\n" ); 450 if (ret) 451 ok( (miexw.dwFlags & MONITORINFOF_PRIMARY), "MONITORINFOF_PRIMARY flag isn't set\n" ); 452 else 453 ok( !(miexw.dwFlags & MONITORINFOF_PRIMARY), "MONITORINFOF_PRIMARY flag is set\n" ); 454 } 455 456 SetRect( &rc, rc.left+1, rc.top+1, rc.left+2, rc.top+2 ); 457 458 monitor = pMonitorFromRect( &rc, MONITOR_DEFAULTTONULL ); 459 ok( monitor == NULL, "got %p\n", monitor ); 460 461 monitor = pMonitorFromRect( &rc, MONITOR_DEFAULTTOPRIMARY ); 462 ok( monitor == primary, "got %p, should get primary %p\n", monitor, primary ); 463 464 monitor = pMonitorFromRect( &rc, MONITOR_DEFAULTTONEAREST ); 465 ok( monitor == nearest, "got %p, should get nearest %p\n", monitor, nearest ); 466 } 467 468 static BOOL CALLBACK find_primary_mon(HMONITOR hmon, HDC hdc, LPRECT rc, LPARAM lp) 469 { 470 MONITORINFO mi; 471 BOOL ret; 472 473 mi.cbSize = sizeof(mi); 474 ret = pGetMonitorInfoA(hmon, &mi); 475 ok(ret, "GetMonitorInfo failed\n"); 476 if (mi.dwFlags & MONITORINFOF_PRIMARY) 477 { 478 *(HMONITOR *)lp = hmon; 479 return FALSE; 480 } 481 return TRUE; 482 } 483 484 static void test_work_area(void) 485 { 486 HMONITOR hmon; 487 MONITORINFO mi; 488 RECT rc_work, rc_normal; 489 HWND hwnd; 490 WINDOWPLACEMENT wp; 491 BOOL ret; 492 493 if (!pEnumDisplayMonitors || !pGetMonitorInfoA) 494 { 495 win_skip("EnumDisplayMonitors or GetMonitorInfoA are not available\n"); 496 return; 497 } 498 499 hmon = 0; 500 ret = pEnumDisplayMonitors(NULL, NULL, find_primary_mon, (LPARAM)&hmon); 501 ok(!ret && hmon != 0, "Failed to find primary monitor\n"); 502 503 mi.cbSize = sizeof(mi); 504 SetLastError(0xdeadbeef); 505 ret = pGetMonitorInfoA(hmon, &mi); 506 ok(ret, "GetMonitorInfo error %u\n", GetLastError()); 507 ok(mi.dwFlags & MONITORINFOF_PRIMARY, "not a primary monitor\n"); 508 trace("primary monitor %s\n", wine_dbgstr_rect(&mi.rcMonitor)); 509 510 SetLastError(0xdeadbeef); 511 ret = SystemParametersInfoA(SPI_GETWORKAREA, 0, &rc_work, 0); 512 ok(ret, "SystemParametersInfo error %u\n", GetLastError()); 513 trace("work area %s\n", wine_dbgstr_rect(&rc_work)); 514 ok(EqualRect(&rc_work, &mi.rcWork), "work area is different\n"); 515 516 hwnd = CreateWindowExA(0, "static", NULL, WS_OVERLAPPEDWINDOW|WS_VISIBLE,100,100,10,10,0,0,0,NULL); 517 ok(hwnd != 0, "CreateWindowEx failed\n"); 518 519 ret = GetWindowRect(hwnd, &rc_normal); 520 ok(ret, "GetWindowRect failed\n"); 521 trace("normal %s\n", wine_dbgstr_rect(&rc_normal)); 522 523 wp.length = sizeof(wp); 524 ret = GetWindowPlacement(hwnd, &wp); 525 ok(ret, "GetWindowPlacement failed\n"); 526 trace("min: %d,%d max %d,%d normal %s\n", wp.ptMinPosition.x, wp.ptMinPosition.y, 527 wp.ptMaxPosition.x, wp.ptMaxPosition.y, wine_dbgstr_rect(&wp.rcNormalPosition)); 528 OffsetRect(&wp.rcNormalPosition, rc_work.left, rc_work.top); 529 todo_wine_if (mi.rcMonitor.left != mi.rcWork.left || 530 mi.rcMonitor.top != mi.rcWork.top) /* FIXME: remove once Wine is fixed */ 531 { 532 ok(EqualRect(&rc_normal, &wp.rcNormalPosition), "normal pos is different\n"); 533 } 534 535 SetWindowLongA(hwnd, GWL_EXSTYLE, WS_EX_TOOLWINDOW); 536 537 wp.length = sizeof(wp); 538 ret = GetWindowPlacement(hwnd, &wp); 539 ok(ret, "GetWindowPlacement failed\n"); 540 trace("min: %d,%d max %d,%d normal %s\n", wp.ptMinPosition.x, wp.ptMinPosition.y, 541 wp.ptMaxPosition.x, wp.ptMaxPosition.y, wine_dbgstr_rect(&wp.rcNormalPosition)); 542 ok(EqualRect(&rc_normal, &wp.rcNormalPosition), "normal pos is different\n"); 543 544 DestroyWindow(hwnd); 545 } 546 547 static void test_display_config(void) 548 { 549 UINT32 paths, modes; 550 LONG ret; 551 552 if (!pGetDisplayConfigBufferSizes) 553 { 554 win_skip("GetDisplayConfigBufferSizes is not supported\n"); 555 return; 556 } 557 558 ret = pGetDisplayConfigBufferSizes(QDC_ALL_PATHS, NULL, NULL); 559 ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret); 560 561 paths = 100; 562 ret = pGetDisplayConfigBufferSizes(QDC_ALL_PATHS, &paths, NULL); 563 ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret); 564 ok(paths == 100, "got %u\n", paths); 565 566 modes = 100; 567 ret = pGetDisplayConfigBufferSizes(QDC_ALL_PATHS, NULL, &modes); 568 ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret); 569 ok(modes == 100, "got %u\n", modes); 570 571 paths = modes = 0; 572 ret = pGetDisplayConfigBufferSizes(QDC_ALL_PATHS, &paths, &modes); 573 if (!ret) 574 ok(paths > 0 && modes > 0, "got %u, %u\n", paths, modes); 575 else 576 ok(ret == ERROR_NOT_SUPPORTED, "got %d\n", ret); 577 578 /* Invalid flags, non-zero invalid flags validation is version (or driver?) dependent, 579 it's unreliable to use in tests. */ 580 ret = pGetDisplayConfigBufferSizes(0, NULL, NULL); 581 ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret); 582 583 paths = 100; 584 ret = pGetDisplayConfigBufferSizes(0, &paths, NULL); 585 ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret); 586 ok(paths == 100, "got %u\n", paths); 587 588 modes = 100; 589 ret = pGetDisplayConfigBufferSizes(0, NULL, &modes); 590 ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret); 591 ok(modes == 100, "got %u\n", modes); 592 593 paths = modes = 100; 594 ret = pGetDisplayConfigBufferSizes(0, &paths, &modes); 595 ok(ret == ERROR_INVALID_PARAMETER || ret == ERROR_NOT_SUPPORTED, "got %d\n", ret); 596 ok(modes == 0 && paths == 0, "got %u, %u\n", modes, paths); 597 } 598 599 START_TEST(monitor) 600 { 601 init_function_pointers(); 602 test_enumdisplaydevices(); 603 test_ChangeDisplaySettingsEx(); 604 test_monitors(); 605 test_work_area(); 606 test_display_config(); 607 } 608