1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * PURPOSE: pMonitor support 5 * FILE: subsys/win32k/ntuser/monitor.c 6 * PROGRAMERS: Anich Gregor (blight@blight.eu.org) 7 * Rafal Harabien (rafalh@reactos.org) 8 */ 9 10 #include <win32k.h> 11 DBG_DEFAULT_CHANNEL(UserMonitor); 12 13 #define NDEBUG 14 #include <debug.h> 15 16 /* GLOBALS *******************************************************************/ 17 18 /* List of monitors */ 19 static PMONITOR gMonitorList = NULL; 20 21 /* PRIVATE FUNCTIONS **********************************************************/ 22 23 /* IntCreateMonitorObject 24 * 25 * Creates a MONITOR 26 * 27 * Return value 28 * If the function succeeds a pointer to a MONITOR is returned. On failure 29 * NULL is returned. 30 */ 31 static 32 PMONITOR 33 IntCreateMonitorObject(VOID) 34 { 35 return UserCreateObject(gHandleTable, NULL, NULL, NULL, TYPE_MONITOR, sizeof(MONITOR)); 36 } 37 38 /* IntDestroyMonitorObject 39 * 40 * Destroys a MONITOR 41 * You have to be the owner of the monitors lock to safely destroy it. 42 * 43 * Arguments 44 * 45 * pMonitor 46 * Pointer to the MONITOR which shall be deleted 47 */ 48 static 49 void 50 IntDestroyMonitorObject(IN PMONITOR pMonitor) 51 { 52 /* Remove monitor region */ 53 if (pMonitor->hrgnMonitor) 54 { 55 GreSetObjectOwner(pMonitor->hrgnMonitor, GDI_OBJ_HMGR_POWNED); 56 GreDeleteObject(pMonitor->hrgnMonitor); 57 } 58 59 /* Destroy monitor object */ 60 UserDereferenceObject(pMonitor); 61 UserDeleteObject(UserHMGetHandle(pMonitor), TYPE_MONITOR); 62 } 63 64 /* UserGetMonitorObject 65 * 66 * Returns monitor object from handle or sets last error if handle is invalid 67 * 68 * Arguments 69 * 70 * hMonitor 71 * Handle of MONITOR object 72 */ 73 PMONITOR NTAPI 74 UserGetMonitorObject(IN HMONITOR hMonitor) 75 { 76 PMONITOR pMonitor; 77 78 if (!hMonitor) 79 { 80 EngSetLastError(ERROR_INVALID_MONITOR_HANDLE); 81 return NULL; 82 } 83 84 pMonitor = (PMONITOR)UserGetObject(gHandleTable, hMonitor, TYPE_MONITOR); 85 if (!pMonitor) 86 { 87 EngSetLastError(ERROR_INVALID_MONITOR_HANDLE); 88 return NULL; 89 } 90 91 return pMonitor; 92 } 93 94 /* UserGetPrimaryMonitor 95 * 96 * Returns a PMONITOR for the primary monitor 97 * 98 * Return value 99 * PMONITOR 100 */ 101 PMONITOR NTAPI 102 UserGetPrimaryMonitor(VOID) 103 { 104 PMONITOR pMonitor; 105 106 /* Find primary monitor */ 107 for (pMonitor = gMonitorList; pMonitor != NULL; pMonitor = pMonitor->pMonitorNext) 108 { 109 if (pMonitor->IsPrimary) 110 break; 111 } 112 113 return pMonitor; 114 } 115 116 /* UserAttachMonitor 117 * 118 * Creates a new MONITOR and appends it to the list of monitors. 119 * 120 * Arguments 121 * 122 * pGdiDevice Pointer to the PDEVOBJ onto which the monitor was attached 123 * DisplayNumber Display Number (starting with 0) 124 * 125 * Return value 126 * Returns a NTSTATUS 127 */ 128 NTSTATUS NTAPI 129 UserAttachMonitor(IN HDEV hDev) 130 { 131 PMONITOR pMonitor; 132 133 TRACE("Attaching monitor...\n"); 134 135 /* Create new monitor object */ 136 pMonitor = IntCreateMonitorObject(); 137 if (pMonitor == NULL) 138 { 139 TRACE("Couldnt create monitor object\n"); 140 return STATUS_INSUFFICIENT_RESOURCES; 141 } 142 143 pMonitor->hDev = hDev; 144 pMonitor->cWndStack = 0; 145 146 if (gMonitorList == NULL) 147 { 148 TRACE("Primary monitor is beeing attached\n"); 149 pMonitor->IsPrimary = TRUE; 150 gMonitorList = pMonitor; 151 } 152 else 153 { 154 PMONITOR pmonLast = gMonitorList; 155 TRACE("Additional monitor is beeing attached\n"); 156 while (pmonLast->pMonitorNext != NULL) 157 pmonLast = pmonLast->pMonitorNext; 158 159 pmonLast->pMonitorNext = pMonitor; 160 } 161 162 UserUpdateMonitorSize(hDev); 163 164 return STATUS_SUCCESS; 165 } 166 167 /* UserDetachMonitor 168 * 169 * Deletes a MONITOR and removes it from the list of monitors. 170 * 171 * Arguments 172 * 173 * pGdiDevice Pointer to the PDEVOBJ from which the monitor was detached 174 * 175 * Return value 176 * Returns a NTSTATUS 177 */ 178 NTSTATUS NTAPI 179 UserDetachMonitor(IN HDEV hDev) 180 { 181 PMONITOR pMonitor = gMonitorList, *pLink = &gMonitorList; 182 183 /* Find monitor attached to given device */ 184 while (pMonitor != NULL) 185 { 186 if (pMonitor->hDev == hDev) 187 break; 188 189 pLink = &pMonitor->pMonitorNext; 190 pMonitor = pMonitor->pMonitorNext; 191 } 192 193 if (pMonitor == NULL) 194 { 195 /* No monitor has been found */ 196 return STATUS_INVALID_PARAMETER; 197 } 198 199 /* We destroy primary monitor - set next as primary */ 200 if (pMonitor->IsPrimary && pMonitor->pMonitorNext != NULL) 201 pMonitor->pMonitorNext->IsPrimary = TRUE; 202 203 /* Update Next ptr in previous monitor */ 204 *pLink = pMonitor->pMonitorNext; 205 206 /* Finally destroy monitor */ 207 IntDestroyMonitorObject(pMonitor); 208 209 return STATUS_SUCCESS; 210 } 211 212 /* UserUpdateMonitorSize 213 * 214 * Reset size of the monitor using atached device 215 * 216 * Arguments 217 * 218 * PMONITOR 219 * pGdiDevice Pointer to the PDEVOBJ, which size has changed 220 * 221 * Return value 222 * Returns a NTSTATUS 223 */ 224 NTSTATUS NTAPI 225 UserUpdateMonitorSize(IN HDEV hDev) 226 { 227 PMONITOR pMonitor; 228 SIZEL DeviceSize; 229 230 /* Find monitor attached to given device */ 231 for (pMonitor = gMonitorList; pMonitor != NULL; pMonitor = pMonitor->pMonitorNext) 232 { 233 if (pMonitor->hDev == hDev) 234 break; 235 } 236 237 if (pMonitor == NULL) 238 { 239 /* No monitor has been found */ 240 return STATUS_INVALID_PARAMETER; 241 } 242 243 /* Get the size of the hdev */ 244 PDEVOBJ_sizl((PPDEVOBJ)hDev, &DeviceSize); 245 246 /* Update monitor size */ 247 pMonitor->rcMonitor.left = 0; 248 pMonitor->rcMonitor.top = 0; 249 pMonitor->rcMonitor.right = pMonitor->rcMonitor.left + DeviceSize.cx; 250 pMonitor->rcMonitor.bottom = pMonitor->rcMonitor.top + DeviceSize.cy; 251 pMonitor->rcWork = pMonitor->rcMonitor; 252 253 /* Destroy monitor region... */ 254 if (pMonitor->hrgnMonitor) 255 { 256 GreSetObjectOwner(pMonitor->hrgnMonitor, GDI_OBJ_HMGR_POWNED); 257 GreDeleteObject(pMonitor->hrgnMonitor); 258 } 259 260 /* ...and create new one */ 261 pMonitor->hrgnMonitor = NtGdiCreateRectRgn( 262 pMonitor->rcMonitor.left, 263 pMonitor->rcMonitor.top, 264 pMonitor->rcMonitor.right, 265 pMonitor->rcMonitor.bottom); 266 if (pMonitor->hrgnMonitor) 267 IntGdiSetRegionOwner(pMonitor->hrgnMonitor, GDI_OBJ_HMGR_PUBLIC); 268 269 // 270 // Should be Virtual accumulation of all the available monitors. 271 // 272 gpsi->rcScreenReal = pMonitor->rcMonitor; 273 274 return STATUS_SUCCESS; 275 } 276 277 /* IntGetMonitorsFromRect 278 * 279 * Returns a list of monitor handles/rectangles. The rectangles in the list are 280 * the areas of intersection with the monitors. 281 * 282 * Arguments 283 * 284 * pRect 285 * Rectangle in desktop coordinates. If this is NULL all monitors are 286 * returned and the rect list is filled with the sizes of the monitors. 287 * 288 * phMonitorList 289 * Pointer to an array of HMONITOR which is filled with monitor handles. 290 * Can be NULL 291 * 292 * prcMonitorList 293 * Pointer to an array of RECT which is filled with intersection rects in 294 * desktop coordinates. 295 * Can be NULL, will be ignored if no intersecting monitor is found and 296 * flags is MONITOR_DEFAULTTONEAREST 297 * 298 * dwListSize 299 * Size of the phMonitorList and prcMonitorList arguments. If this is zero 300 * phMonitorList and prcMonitorList are ignored. 301 * 302 * dwFlags 303 * Either 0 or MONITOR_DEFAULTTONEAREST (ignored if rect is NULL) 304 * 305 * Returns 306 * The number of monitors which intersect the specified region. 307 */ 308 static 309 UINT 310 IntGetMonitorsFromRect(OPTIONAL IN LPCRECTL pRect, 311 OPTIONAL OUT HMONITOR *phMonitorList, 312 OPTIONAL OUT PRECTL prcMonitorList, 313 OPTIONAL IN DWORD dwListSize, 314 OPTIONAL IN DWORD dwFlags) 315 { 316 PMONITOR pMonitor, pNearestMonitor = NULL, pPrimaryMonitor = NULL; 317 UINT cMonitors = 0; 318 ULONG iNearestDistance = 0xffffffff; 319 320 /* Find monitors which intersects the rectangle */ 321 for (pMonitor = gMonitorList; pMonitor != NULL; pMonitor = pMonitor->pMonitorNext) 322 { 323 RECTL MonitorRect, IntersectionRect; 324 325 MonitorRect = pMonitor->rcMonitor; 326 327 TRACE("MonitorRect: left = %d, top = %d, right = %d, bottom = %d\n", 328 MonitorRect.left, MonitorRect.top, MonitorRect.right, MonitorRect.bottom); 329 330 /* Save primary monitor for later usage */ 331 if (dwFlags == MONITOR_DEFAULTTOPRIMARY && pMonitor->IsPrimary) 332 pPrimaryMonitor = pMonitor; 333 334 /* Check if a rect is given */ 335 if (pRect == NULL) 336 { 337 /* No rect given, so use the full monitor rect */ 338 IntersectionRect = MonitorRect; 339 } 340 /* We have a rect, calculate intersection */ 341 else if (!RECTL_bIntersectRect(&IntersectionRect, &MonitorRect, pRect)) 342 { 343 /* Rects did not intersect */ 344 if (dwFlags == MONITOR_DEFAULTTONEAREST) 345 { 346 ULONG cx, cy, iDistance; 347 348 /* Get x and y distance */ 349 cx = min(abs(MonitorRect.left - pRect->right), 350 abs(pRect->left - MonitorRect.right)); 351 cy = min(abs(MonitorRect.top - pRect->bottom), 352 abs(pRect->top - MonitorRect.bottom)); 353 354 /* Calculate distance square */ 355 iDistance = cx * cx + cy * cy; 356 357 /* Check if this is the new nearest monitor */ 358 if (iDistance < iNearestDistance) 359 { 360 iNearestDistance = iDistance; 361 pNearestMonitor = pMonitor; 362 } 363 } 364 365 continue; 366 } 367 368 /* Check if there's space in the buffer */ 369 if (cMonitors < dwListSize) 370 { 371 /* Save monitor data */ 372 if (phMonitorList != NULL) 373 phMonitorList[cMonitors] = UserHMGetHandle(pMonitor); 374 if (prcMonitorList != NULL) 375 prcMonitorList[cMonitors] = IntersectionRect; 376 } 377 378 /* Increase count of found monitors */ 379 cMonitors++; 380 } 381 382 /* Nothing has been found? */ 383 if (cMonitors == 0) 384 { 385 /* Check if we shall default to the nearest monitor */ 386 if (dwFlags == MONITOR_DEFAULTTONEAREST && pNearestMonitor) 387 { 388 if (phMonitorList && dwListSize > 0) 389 phMonitorList[cMonitors] = UserHMGetHandle(pNearestMonitor); 390 cMonitors++; 391 } 392 /* Check if we shall default to the primary monitor */ 393 else if (dwFlags == MONITOR_DEFAULTTOPRIMARY && pPrimaryMonitor) 394 { 395 if (phMonitorList != NULL && dwListSize > 0) 396 phMonitorList[cMonitors] = UserHMGetHandle(pPrimaryMonitor); 397 cMonitors++; 398 } 399 } 400 401 return cMonitors; 402 } 403 404 PMONITOR NTAPI 405 UserMonitorFromRect( 406 PRECTL pRect, 407 DWORD dwFlags) 408 { 409 ULONG cMonitors, LargestArea = 0, i; 410 PRECTL prcMonitorList = NULL; 411 HMONITOR *phMonitorList = NULL; 412 HMONITOR hMonitor = NULL; 413 414 /* Check if flags are valid */ 415 if (dwFlags != MONITOR_DEFAULTTONULL && 416 dwFlags != MONITOR_DEFAULTTOPRIMARY && 417 dwFlags != MONITOR_DEFAULTTONEAREST) 418 { 419 EngSetLastError(ERROR_INVALID_FLAGS); 420 return NULL; 421 } 422 423 /* Find intersecting monitors */ 424 cMonitors = IntGetMonitorsFromRect(pRect, &hMonitor, NULL, 1, dwFlags); 425 if (cMonitors <= 1) 426 { 427 /* No or one monitor found. Just return handle. */ 428 goto cleanup; 429 } 430 431 /* There is more than one monitor. Find monitor with largest intersection. 432 Temporary reset hMonitor */ 433 hMonitor = NULL; 434 435 /* Allocate helper buffers */ 436 phMonitorList = ExAllocatePoolWithTag(PagedPool, 437 sizeof(HMONITOR) * cMonitors, 438 USERTAG_MONITORRECTS); 439 if (phMonitorList == NULL) 440 { 441 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 442 goto cleanup; 443 } 444 445 prcMonitorList = ExAllocatePoolWithTag(PagedPool, 446 sizeof(RECT) * cMonitors, 447 USERTAG_MONITORRECTS); 448 if (prcMonitorList == NULL) 449 { 450 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 451 goto cleanup; 452 } 453 454 /* Get intersecting monitors again but now with rectangle list */ 455 cMonitors = IntGetMonitorsFromRect(pRect, phMonitorList, prcMonitorList, 456 cMonitors, 0); 457 458 /* Find largest intersection */ 459 for (i = 0; i < cMonitors; i++) 460 { 461 ULONG Area = (prcMonitorList[i].right - prcMonitorList[i].left) * 462 (prcMonitorList[i].bottom - prcMonitorList[i].top); 463 if (Area >= LargestArea) 464 { 465 hMonitor = phMonitorList[i]; 466 LargestArea = Area; 467 } 468 } 469 470 cleanup: 471 if (phMonitorList) 472 ExFreePoolWithTag(phMonitorList, USERTAG_MONITORRECTS); 473 if (prcMonitorList) 474 ExFreePoolWithTag(prcMonitorList, USERTAG_MONITORRECTS); 475 476 return UserGetMonitorObject(hMonitor); 477 } 478 479 PMONITOR 480 FASTCALL 481 UserMonitorFromPoint( 482 IN POINT pt, 483 IN DWORD dwFlags) 484 { 485 RECTL rc; 486 HMONITOR hMonitor = NULL; 487 488 /* Check if flags are valid */ 489 if (dwFlags != MONITOR_DEFAULTTONULL && 490 dwFlags != MONITOR_DEFAULTTOPRIMARY && 491 dwFlags != MONITOR_DEFAULTTONEAREST) 492 { 493 EngSetLastError(ERROR_INVALID_FLAGS); 494 return NULL; 495 } 496 497 /* Fill rect (bottom-right exclusive) */ 498 rc.left = pt.x; 499 rc.right = pt.x + 1; 500 rc.top = pt.y; 501 rc.bottom = pt.y + 1; 502 503 /* Find intersecting monitor */ 504 IntGetMonitorsFromRect(&rc, &hMonitor, NULL, 1, dwFlags); 505 506 return UserGetMonitorObject(hMonitor); 507 } 508 509 /* PUBLIC FUNCTIONS ***********************************************************/ 510 511 /* NtUserEnumDisplayMonitors 512 * 513 * Enumerates display monitors which intersect the given HDC/cliprect 514 * 515 * Arguments 516 * 517 * hdc 518 * Handle to a DC for which to enum intersecting monitors. If this is NULL 519 * it returns all monitors which are part of the current virtual screen. 520 * 521 * pUnsafeRect 522 * Clipping rectangle with coordinate system origin at the DCs origin if the 523 * given HDC is not NULL or in virtual screen coordinated if it is NULL. 524 * Can be NULL 525 * 526 * phUnsafeMonitorList 527 * Pointer to an array of HMONITOR which is filled with monitor handles. 528 * Can be NULL 529 * 530 * prcUnsafeMonitorList 531 * Pointer to an array of RECT which is filled with intersection rectangles. 532 * Can be NULL 533 * 534 * dwListSize 535 * Size of the hMonitorList and monitorRectList arguments. If this is zero 536 * hMonitorList and monitorRectList are ignored. 537 * 538 * Returns 539 * The number of monitors which intersect the specified region or -1 on failure. 540 */ 541 INT 542 APIENTRY 543 NtUserEnumDisplayMonitors( 544 OPTIONAL IN HDC hdc, 545 OPTIONAL IN LPCRECTL pUnsafeRect, 546 OPTIONAL OUT HMONITOR *phUnsafeMonitorList, 547 OPTIONAL OUT PRECTL prcUnsafeMonitorList, 548 OPTIONAL IN DWORD dwListSize) 549 { 550 UINT cMonitors, i; 551 INT iRet = -1; 552 HMONITOR *phMonitorList = NULL; 553 PRECTL prcMonitorList = NULL; 554 RECTL rc, *pRect; 555 RECTL DcRect = {0}; 556 NTSTATUS Status; 557 558 /* Get rectangle */ 559 if (pUnsafeRect != NULL) 560 { 561 Status = MmCopyFromCaller(&rc, pUnsafeRect, sizeof(RECT)); 562 if (!NT_SUCCESS(Status)) 563 { 564 TRACE("MmCopyFromCaller() failed!\n"); 565 SetLastNtError(Status); 566 return -1; 567 } 568 } 569 570 if (hdc != NULL) 571 { 572 PDC pDc; 573 INT iRgnType; 574 575 /* Get visible region bounding rect */ 576 pDc = DC_LockDc(hdc); 577 if (pDc == NULL) 578 { 579 TRACE("DC_LockDc() failed!\n"); 580 /* FIXME: setlasterror? */ 581 return -1; 582 } 583 iRgnType = REGION_GetRgnBox(pDc->prgnVis, &DcRect); 584 DC_UnlockDc(pDc); 585 586 if (iRgnType == 0) 587 { 588 TRACE("NtGdiGetRgnBox() failed!\n"); 589 return -1; 590 } 591 if (iRgnType == NULLREGION) 592 return 0; 593 if (iRgnType == COMPLEXREGION) 594 { 595 /* TODO: Warning */ 596 } 597 598 /* If hdc and pRect are given the area of interest is pRect with 599 coordinate origin at the DC position */ 600 if (pUnsafeRect != NULL) 601 { 602 rc.left += DcRect.left; 603 rc.right += DcRect.left; 604 rc.top += DcRect.top; 605 rc.bottom += DcRect.top; 606 } 607 /* If hdc is given and pRect is not the area of interest is the 608 bounding rect of hdc */ 609 else 610 { 611 rc = DcRect; 612 } 613 } 614 615 if (hdc == NULL && pUnsafeRect == NULL) 616 pRect = NULL; 617 else 618 pRect = &rc; 619 620 UserEnterShared(); 621 622 /* Find intersecting monitors */ 623 cMonitors = IntGetMonitorsFromRect(pRect, NULL, NULL, 0, MONITOR_DEFAULTTONULL); 624 if (cMonitors == 0 || dwListSize == 0 || 625 (phUnsafeMonitorList == NULL && prcUnsafeMonitorList == NULL)) 626 { 627 /* Simple case - just return monitors count */ 628 TRACE("cMonitors = %u\n", cMonitors); 629 iRet = cMonitors; 630 goto cleanup; 631 } 632 633 /* Allocate safe buffers */ 634 if (phUnsafeMonitorList != NULL && dwListSize != 0) 635 { 636 phMonitorList = ExAllocatePoolWithTag(PagedPool, sizeof (HMONITOR) * dwListSize, USERTAG_MONITORRECTS); 637 if (phMonitorList == NULL) 638 { 639 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 640 goto cleanup; 641 } 642 } 643 if (prcUnsafeMonitorList != NULL && dwListSize != 0) 644 { 645 prcMonitorList = ExAllocatePoolWithTag(PagedPool, sizeof(RECT) * dwListSize,USERTAG_MONITORRECTS); 646 if (prcMonitorList == NULL) 647 { 648 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 649 goto cleanup; 650 } 651 } 652 653 /* Get intersecting monitors */ 654 cMonitors = IntGetMonitorsFromRect(pRect, phMonitorList, prcMonitorList, 655 dwListSize, MONITOR_DEFAULTTONULL); 656 657 if (hdc != NULL && pRect != NULL && prcMonitorList != NULL) 658 { 659 for (i = 0; i < min(cMonitors, dwListSize); i++) 660 { 661 _Analysis_assume_(i < dwListSize); 662 prcMonitorList[i].left -= DcRect.left; 663 prcMonitorList[i].right -= DcRect.left; 664 prcMonitorList[i].top -= DcRect.top; 665 prcMonitorList[i].bottom -= DcRect.top; 666 } 667 } 668 669 /* Output result */ 670 if (phUnsafeMonitorList != NULL && dwListSize != 0) 671 { 672 Status = MmCopyToCaller(phUnsafeMonitorList, phMonitorList, sizeof(HMONITOR) * dwListSize); 673 if (!NT_SUCCESS(Status)) 674 { 675 SetLastNtError(Status); 676 goto cleanup; 677 } 678 } 679 if (prcUnsafeMonitorList != NULL && dwListSize != 0) 680 { 681 Status = MmCopyToCaller(prcUnsafeMonitorList, prcMonitorList, sizeof(RECT) * dwListSize); 682 if (!NT_SUCCESS(Status)) 683 { 684 SetLastNtError(Status); 685 goto cleanup; 686 } 687 } 688 689 /* Return monitors count on success */ 690 iRet = cMonitors; 691 692 cleanup: 693 if (phMonitorList) 694 ExFreePoolWithTag(phMonitorList, USERTAG_MONITORRECTS); 695 if (prcMonitorList) 696 ExFreePoolWithTag(prcMonitorList, USERTAG_MONITORRECTS); 697 698 UserLeave(); 699 return iRet; 700 } 701 702 /* NtUserGetMonitorInfo 703 * 704 * Retrieves information about a given monitor 705 * 706 * Arguments 707 * 708 * hMonitor 709 * Handle to a monitor for which to get information 710 * 711 * pMonitorInfoUnsafe 712 * Pointer to a MONITORINFO struct which is filled with the information. 713 * The cbSize member must be set to sizeof(MONITORINFO) or 714 * sizeof(MONITORINFOEX). Even if set to sizeof(MONITORINFOEX) only parts 715 * from MONITORINFO will be filled. 716 * 717 * pDevice 718 * Pointer to a UNICODE_STRING which will receive the device's name. The 719 * length should be CCHDEVICENAME 720 * Can be NULL 721 * 722 * Return value 723 * TRUE on success; FALSE on failure (calls SetLastNtError()) 724 * 725 */ 726 BOOL 727 APIENTRY 728 NtUserGetMonitorInfo( 729 IN HMONITOR hMonitor, 730 OUT LPMONITORINFO pMonitorInfoUnsafe) 731 { 732 PMONITOR pMonitor; 733 MONITORINFOEXW MonitorInfo; 734 NTSTATUS Status; 735 BOOL bRet = FALSE; 736 PWCHAR pwstrDeviceName; 737 738 TRACE("Enter NtUserGetMonitorInfo\n"); 739 UserEnterShared(); 740 741 /* Get monitor object */ 742 pMonitor = UserGetMonitorObject(hMonitor); 743 if (!pMonitor) 744 { 745 TRACE("Couldnt find monitor %p\n", hMonitor); 746 goto cleanup; 747 } 748 749 /* Check if pMonitorInfoUnsafe is valid */ 750 if(pMonitorInfoUnsafe == NULL) 751 { 752 SetLastNtError(STATUS_INVALID_PARAMETER); 753 goto cleanup; 754 } 755 756 pwstrDeviceName = ((PPDEVOBJ)(pMonitor->hDev))->pGraphicsDevice->szWinDeviceName; 757 758 /* Get size of pMonitorInfoUnsafe */ 759 Status = MmCopyFromCaller(&MonitorInfo.cbSize, &pMonitorInfoUnsafe->cbSize, sizeof(MonitorInfo.cbSize)); 760 if (!NT_SUCCESS(Status)) 761 { 762 SetLastNtError(Status); 763 goto cleanup; 764 } 765 766 /* Check if size of struct is valid */ 767 if (MonitorInfo.cbSize != sizeof(MONITORINFO) && 768 MonitorInfo.cbSize != sizeof(MONITORINFOEXW)) 769 { 770 SetLastNtError(STATUS_INVALID_PARAMETER); 771 goto cleanup; 772 } 773 774 /* Fill monitor info */ 775 MonitorInfo.rcMonitor = pMonitor->rcMonitor; 776 MonitorInfo.rcWork = pMonitor->rcWork; 777 MonitorInfo.dwFlags = 0; 778 if (pMonitor->IsPrimary) 779 MonitorInfo.dwFlags |= MONITORINFOF_PRIMARY; 780 781 /* Fill device name */ 782 if (MonitorInfo.cbSize == sizeof(MONITORINFOEXW)) 783 { 784 RtlStringCbCopyNExW(MonitorInfo.szDevice, 785 sizeof(MonitorInfo.szDevice), 786 pwstrDeviceName, 787 (wcslen(pwstrDeviceName)+1) * sizeof(WCHAR), 788 NULL, NULL, STRSAFE_FILL_BEHIND_NULL); 789 } 790 791 /* Output data */ 792 Status = MmCopyToCaller(pMonitorInfoUnsafe, &MonitorInfo, MonitorInfo.cbSize); 793 if (!NT_SUCCESS(Status)) 794 { 795 TRACE("GetMonitorInfo: MmCopyToCaller failed\n"); 796 SetLastNtError(Status); 797 goto cleanup; 798 } 799 800 TRACE("GetMonitorInfo: success\n"); 801 bRet = TRUE; 802 803 cleanup: 804 TRACE("Leave NtUserGetMonitorInfo, ret=%i\n", bRet); 805 UserLeave(); 806 return bRet; 807 } 808 809 /* NtUserMonitorFromPoint 810 * 811 * Returns a handle to the monitor containing the given point. 812 * 813 * Arguments 814 * 815 * pt 816 * Point for which to find monitor 817 * 818 * dwFlags 819 * Specifies the behaviour if the point isn't on any of the monitors. 820 * 821 * Return value 822 * If the point is found a handle to the monitor is returned; if not the 823 * return value depends on dwFlags 824 */ 825 HMONITOR 826 APIENTRY 827 NtUserMonitorFromPoint( 828 IN POINT pt, 829 IN DWORD dwFlags) 830 { 831 RECTL rc; 832 HMONITOR hMonitor = NULL; 833 834 /* Check if flags are valid */ 835 if (dwFlags != MONITOR_DEFAULTTONULL && 836 dwFlags != MONITOR_DEFAULTTOPRIMARY && 837 dwFlags != MONITOR_DEFAULTTONEAREST) 838 { 839 EngSetLastError(ERROR_INVALID_FLAGS); 840 return NULL; 841 } 842 843 /* Fill rect (bottom-right exclusive) */ 844 rc.left = pt.x; 845 rc.right = pt.x + 1; 846 rc.top = pt.y; 847 rc.bottom = pt.y + 1; 848 849 UserEnterShared(); 850 851 /* Find intersecting monitor */ 852 IntGetMonitorsFromRect(&rc, &hMonitor, NULL, 1, dwFlags); 853 854 UserLeave(); 855 return hMonitor; 856 } 857 858 /* NtUserMonitorFromRect 859 * 860 * Returns a handle to the monitor having the largest intersection with a 861 * given rectangle 862 * 863 * Arguments 864 * 865 * pRectUnsafe 866 * Pointer to a RECT for which to find monitor 867 * 868 * dwFlags 869 * Specifies the behaviour if no monitor intersects the given rect 870 * 871 * Return value 872 * If a monitor intersects the rect a handle to it is returned; if not the 873 * return value depends on dwFlags 874 */ 875 HMONITOR 876 APIENTRY 877 NtUserMonitorFromRect( 878 IN LPCRECTL pRectUnsafe, 879 IN DWORD dwFlags) 880 { 881 ULONG cMonitors, LargestArea = 0, i; 882 PRECTL prcMonitorList = NULL; 883 HMONITOR *phMonitorList = NULL; 884 HMONITOR hMonitor = NULL; 885 RECTL Rect; 886 NTSTATUS Status; 887 888 /* Check if flags are valid */ 889 if (dwFlags != MONITOR_DEFAULTTONULL && 890 dwFlags != MONITOR_DEFAULTTOPRIMARY && 891 dwFlags != MONITOR_DEFAULTTONEAREST) 892 { 893 EngSetLastError(ERROR_INVALID_FLAGS); 894 return NULL; 895 } 896 897 /* Copy rectangle to safe buffer */ 898 Status = MmCopyFromCaller(&Rect, pRectUnsafe, sizeof (RECT)); 899 if (!NT_SUCCESS(Status)) 900 { 901 SetLastNtError(Status); 902 return NULL; 903 } 904 905 UserEnterShared(); 906 907 /* Find intersecting monitors */ 908 cMonitors = IntGetMonitorsFromRect(&Rect, &hMonitor, NULL, 1, dwFlags); 909 if (cMonitors <= 1) 910 { 911 /* No or one monitor found. Just return handle. */ 912 goto cleanup; 913 } 914 915 /* There is more than one monitor. Find monitor with largest intersection. 916 Temporary reset hMonitor */ 917 hMonitor = NULL; 918 919 /* Allocate helper buffers */ 920 phMonitorList = ExAllocatePoolWithTag(PagedPool, 921 sizeof(HMONITOR) * cMonitors, 922 USERTAG_MONITORRECTS); 923 if (phMonitorList == NULL) 924 { 925 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 926 goto cleanup; 927 } 928 929 prcMonitorList = ExAllocatePoolWithTag(PagedPool, 930 sizeof(RECT) * cMonitors, 931 USERTAG_MONITORRECTS); 932 if (prcMonitorList == NULL) 933 { 934 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 935 goto cleanup; 936 } 937 938 /* Get intersecting monitors again but now with rectangle list */ 939 cMonitors = IntGetMonitorsFromRect(&Rect, phMonitorList, prcMonitorList, 940 cMonitors, 0); 941 942 /* Find largest intersection */ 943 for (i = 0; i < cMonitors; i++) 944 { 945 ULONG Area = (prcMonitorList[i].right - prcMonitorList[i].left) * 946 (prcMonitorList[i].bottom - prcMonitorList[i].top); 947 if (Area >= LargestArea) 948 { 949 hMonitor = phMonitorList[i]; 950 LargestArea = Area; 951 } 952 } 953 954 cleanup: 955 if (phMonitorList) 956 ExFreePoolWithTag(phMonitorList, USERTAG_MONITORRECTS); 957 if (prcMonitorList) 958 ExFreePoolWithTag(prcMonitorList, USERTAG_MONITORRECTS); 959 UserLeave(); 960 961 return hMonitor; 962 } 963 964 965 HMONITOR 966 APIENTRY 967 NtUserMonitorFromWindow( 968 IN HWND hWnd, 969 IN DWORD dwFlags) 970 { 971 PWND pWnd; 972 HMONITOR hMonitor = NULL; 973 RECTL Rect = {0, 0, 0, 0}; 974 975 TRACE("Enter NtUserMonitorFromWindow\n"); 976 977 /* Check if flags are valid */ 978 if (dwFlags != MONITOR_DEFAULTTONULL && 979 dwFlags != MONITOR_DEFAULTTOPRIMARY && 980 dwFlags != MONITOR_DEFAULTTONEAREST) 981 { 982 EngSetLastError(ERROR_INVALID_FLAGS); 983 return NULL; 984 } 985 986 UserEnterShared(); 987 988 /* If window is given, use it first */ 989 if (hWnd) 990 { 991 /* Get window object */ 992 pWnd = UserGetWindowObject(hWnd); 993 if (!pWnd) 994 goto cleanup; 995 996 /* Find only monitors which have intersection with given window */ 997 Rect.left = Rect.right = pWnd->rcWindow.left; 998 Rect.top = Rect.bottom = pWnd->rcWindow.bottom; 999 } 1000 1001 /* Find monitors now */ 1002 IntGetMonitorsFromRect(&Rect, &hMonitor, NULL, 1, dwFlags); 1003 1004 cleanup: 1005 TRACE("Leave NtUserMonitorFromWindow, ret=%p\n", hMonitor); 1006 UserLeave(); 1007 return hMonitor; 1008 } 1009