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