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)
11 DBG_DEFAULT_CHANNEL(UserMonitor
);
16 /* GLOBALS *******************************************************************/
18 /* List of monitors */
19 static PMONITOR gMonitorList
= NULL
;
21 /* PRIVATE FUNCTIONS **********************************************************/
23 /* IntCreateMonitorObject
28 * If the function succeeds a pointer to a MONITOR is returned. On failure
33 IntCreateMonitorObject(VOID
)
35 return UserCreateObject(gHandleTable
, NULL
, NULL
, NULL
, TYPE_MONITOR
, sizeof(MONITOR
));
38 /* IntDestroyMonitorObject
41 * You have to be the owner of the monitors lock to safely destroy it.
46 * Pointer to the MONITOR which shall be deleted
50 IntDestroyMonitorObject(IN PMONITOR pMonitor
)
52 /* Remove monitor region */
53 if (pMonitor
->hrgnMonitor
)
55 GreSetObjectOwner(pMonitor
->hrgnMonitor
, GDI_OBJ_HMGR_POWNED
);
56 GreDeleteObject(pMonitor
->hrgnMonitor
);
59 /* Destroy monitor object */
60 UserDereferenceObject(pMonitor
);
61 UserDeleteObject(UserHMGetHandle(pMonitor
), TYPE_MONITOR
);
64 /* UserGetMonitorObject
66 * Returns monitor object from handle or sets last error if handle is invalid
71 * Handle of MONITOR object
74 UserGetMonitorObject(IN HMONITOR hMonitor
)
80 EngSetLastError(ERROR_INVALID_MONITOR_HANDLE
);
84 pMonitor
= (PMONITOR
)UserGetObject(gHandleTable
, hMonitor
, TYPE_MONITOR
);
87 EngSetLastError(ERROR_INVALID_MONITOR_HANDLE
);
94 /* UserGetPrimaryMonitor
96 * Returns a PMONITOR for the primary monitor
102 UserGetPrimaryMonitor(VOID
)
106 /* Find primary monitor */
107 for (pMonitor
= gMonitorList
; pMonitor
!= NULL
; pMonitor
= pMonitor
->pMonitorNext
)
109 if (pMonitor
->IsPrimary
)
118 * Creates a new MONITOR and appends it to the list of monitors.
122 * pGdiDevice Pointer to the PDEVOBJ onto which the monitor was attached
123 * DisplayNumber Display Number (starting with 0)
129 UserAttachMonitor(IN HDEV hDev
)
133 TRACE("Attaching monitor...\n");
135 /* Create new monitor object */
136 pMonitor
= IntCreateMonitorObject();
137 if (pMonitor
== NULL
)
139 TRACE("Couldnt create monitor object\n");
140 return STATUS_INSUFFICIENT_RESOURCES
;
143 pMonitor
->hDev
= hDev
;
144 pMonitor
->cWndStack
= 0;
146 if (gMonitorList
== NULL
)
148 TRACE("Primary monitor is beeing attached\n");
149 pMonitor
->IsPrimary
= TRUE
;
150 gMonitorList
= pMonitor
;
154 PMONITOR pmonLast
= gMonitorList
;
155 TRACE("Additional monitor is beeing attached\n");
156 while (pmonLast
->pMonitorNext
!= NULL
)
157 pmonLast
= pmonLast
->pMonitorNext
;
159 pmonLast
->pMonitorNext
= pMonitor
;
162 UserUpdateMonitorSize(hDev
);
164 return STATUS_SUCCESS
;
169 * Deletes a MONITOR and removes it from the list of monitors.
173 * pGdiDevice Pointer to the PDEVOBJ from which the monitor was detached
179 UserDetachMonitor(IN HDEV hDev
)
181 PMONITOR pMonitor
= gMonitorList
, *pLink
= &gMonitorList
;
183 /* Find monitor attached to given device */
184 while (pMonitor
!= NULL
)
186 if (pMonitor
->hDev
== hDev
)
189 pLink
= &pMonitor
->pMonitorNext
;
190 pMonitor
= pMonitor
->pMonitorNext
;
193 if (pMonitor
== NULL
)
195 /* No monitor has been found */
196 return STATUS_INVALID_PARAMETER
;
199 /* We destroy primary monitor - set next as primary */
200 if (pMonitor
->IsPrimary
&& pMonitor
->pMonitorNext
!= NULL
)
201 pMonitor
->pMonitorNext
->IsPrimary
= TRUE
;
203 /* Update Next ptr in previous monitor */
204 *pLink
= pMonitor
->pMonitorNext
;
206 /* Finally destroy monitor */
207 IntDestroyMonitorObject(pMonitor
);
209 return STATUS_SUCCESS
;
212 /* UserUpdateMonitorSize
214 * Reset size of the monitor using atached device
219 * pGdiDevice Pointer to the PDEVOBJ, which size has changed
225 UserUpdateMonitorSize(IN HDEV hDev
)
230 /* Find monitor attached to given device */
231 for (pMonitor
= gMonitorList
; pMonitor
!= NULL
; pMonitor
= pMonitor
->pMonitorNext
)
233 if (pMonitor
->hDev
== hDev
)
237 if (pMonitor
== NULL
)
239 /* No monitor has been found */
240 return STATUS_INVALID_PARAMETER
;
243 /* Get the size of the hdev */
244 PDEVOBJ_sizl((PPDEVOBJ
)hDev
, &DeviceSize
);
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
;
253 /* Destroy monitor region... */
254 if (pMonitor
->hrgnMonitor
)
256 GreSetObjectOwner(pMonitor
->hrgnMonitor
, GDI_OBJ_HMGR_POWNED
);
257 GreDeleteObject(pMonitor
->hrgnMonitor
);
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
);
270 // Should be Virtual accumulation of all the available monitors.
272 gpsi
->rcScreenReal
= pMonitor
->rcMonitor
;
274 return STATUS_SUCCESS
;
277 /* IntGetMonitorsFromRect
279 * Returns a list of monitor handles/rectangles. The rectangles in the list are
280 * the areas of intersection with the monitors.
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.
289 * Pointer to an array of HMONITOR which is filled with monitor handles.
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
299 * Size of the phMonitorList and prcMonitorList arguments. If this is zero
300 * phMonitorList and prcMonitorList are ignored.
303 * Either 0 or MONITOR_DEFAULTTONEAREST (ignored if rect is NULL)
306 * The number of monitors which intersect the specified region.
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
)
316 PMONITOR pMonitor
, pNearestMonitor
= NULL
, pPrimaryMonitor
= NULL
;
318 ULONG iNearestDistance
= 0xffffffff;
320 /* Find monitors which intersects the rectangle */
321 for (pMonitor
= gMonitorList
; pMonitor
!= NULL
; pMonitor
= pMonitor
->pMonitorNext
)
323 RECTL MonitorRect
, IntersectionRect
;
325 MonitorRect
= pMonitor
->rcMonitor
;
327 TRACE("MonitorRect: left = %d, top = %d, right = %d, bottom = %d\n",
328 MonitorRect
.left
, MonitorRect
.top
, MonitorRect
.right
, MonitorRect
.bottom
);
330 /* Save primary monitor for later usage */
331 if (dwFlags
== MONITOR_DEFAULTTOPRIMARY
&& pMonitor
->IsPrimary
)
332 pPrimaryMonitor
= pMonitor
;
334 /* Check if a rect is given */
337 /* No rect given, so use the full monitor rect */
338 IntersectionRect
= MonitorRect
;
340 /* We have a rect, calculate intersection */
341 else if (!RECTL_bIntersectRect(&IntersectionRect
, &MonitorRect
, pRect
))
343 /* Rects did not intersect */
344 if (dwFlags
== MONITOR_DEFAULTTONEAREST
)
346 ULONG cx
, cy
, iDistance
;
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
));
354 /* Calculate distance square */
355 iDistance
= cx
* cx
+ cy
* cy
;
357 /* Check if this is the new nearest monitor */
358 if (iDistance
< iNearestDistance
)
360 iNearestDistance
= iDistance
;
361 pNearestMonitor
= pMonitor
;
368 /* Check if there's space in the buffer */
369 if (cMonitors
< dwListSize
)
371 /* Save monitor data */
372 if (phMonitorList
!= NULL
)
373 phMonitorList
[cMonitors
] = UserHMGetHandle(pMonitor
);
374 if (prcMonitorList
!= NULL
)
375 prcMonitorList
[cMonitors
] = IntersectionRect
;
378 /* Increase count of found monitors */
382 /* Nothing has been found? */
385 /* Check if we shall default to the nearest monitor */
386 if (dwFlags
== MONITOR_DEFAULTTONEAREST
&& pNearestMonitor
)
388 if (phMonitorList
&& dwListSize
> 0)
389 phMonitorList
[cMonitors
] = UserHMGetHandle(pNearestMonitor
);
392 /* Check if we shall default to the primary monitor */
393 else if (dwFlags
== MONITOR_DEFAULTTOPRIMARY
&& pPrimaryMonitor
)
395 if (phMonitorList
!= NULL
&& dwListSize
> 0)
396 phMonitorList
[cMonitors
] = UserHMGetHandle(pPrimaryMonitor
);
409 ULONG cMonitors
, LargestArea
= 0, i
;
410 PRECTL prcMonitorList
= NULL
;
411 HMONITOR
*phMonitorList
= NULL
;
412 HMONITOR hMonitor
= NULL
;
414 /* Check if flags are valid */
415 if (dwFlags
!= MONITOR_DEFAULTTONULL
&&
416 dwFlags
!= MONITOR_DEFAULTTOPRIMARY
&&
417 dwFlags
!= MONITOR_DEFAULTTONEAREST
)
419 EngSetLastError(ERROR_INVALID_FLAGS
);
423 /* Find intersecting monitors */
424 cMonitors
= IntGetMonitorsFromRect(pRect
, &hMonitor
, NULL
, 1, dwFlags
);
427 /* No or one monitor found. Just return handle. */
431 /* There is more than one monitor. Find monitor with largest intersection.
432 Temporary reset hMonitor */
435 /* Allocate helper buffers */
436 phMonitorList
= ExAllocatePoolWithTag(PagedPool
,
437 sizeof(HMONITOR
) * cMonitors
,
438 USERTAG_MONITORRECTS
);
439 if (phMonitorList
== NULL
)
441 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
445 prcMonitorList
= ExAllocatePoolWithTag(PagedPool
,
446 sizeof(RECT
) * cMonitors
,
447 USERTAG_MONITORRECTS
);
448 if (prcMonitorList
== NULL
)
450 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
454 /* Get intersecting monitors again but now with rectangle list */
455 cMonitors
= IntGetMonitorsFromRect(pRect
, phMonitorList
, prcMonitorList
,
458 /* Find largest intersection */
459 for (i
= 0; i
< cMonitors
; i
++)
461 ULONG Area
= (prcMonitorList
[i
].right
- prcMonitorList
[i
].left
) *
462 (prcMonitorList
[i
].bottom
- prcMonitorList
[i
].top
);
463 if (Area
>= LargestArea
)
465 hMonitor
= phMonitorList
[i
];
472 ExFreePoolWithTag(phMonitorList
, USERTAG_MONITORRECTS
);
474 ExFreePoolWithTag(prcMonitorList
, USERTAG_MONITORRECTS
);
476 return UserGetMonitorObject(hMonitor
);
481 UserMonitorFromPoint(
486 HMONITOR hMonitor
= NULL
;
488 /* Check if flags are valid */
489 if (dwFlags
!= MONITOR_DEFAULTTONULL
&&
490 dwFlags
!= MONITOR_DEFAULTTOPRIMARY
&&
491 dwFlags
!= MONITOR_DEFAULTTONEAREST
)
493 EngSetLastError(ERROR_INVALID_FLAGS
);
497 /* Fill rect (bottom-right exclusive) */
501 rc
.bottom
= pt
.y
+ 1;
503 /* Find intersecting monitor */
504 IntGetMonitorsFromRect(&rc
, &hMonitor
, NULL
, 1, dwFlags
);
506 return UserGetMonitorObject(hMonitor
);
509 /* PUBLIC FUNCTIONS ***********************************************************/
511 /* NtUserEnumDisplayMonitors
513 * Enumerates display monitors which intersect the given HDC/cliprect
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.
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.
526 * phUnsafeMonitorList
527 * Pointer to an array of HMONITOR which is filled with monitor handles.
530 * prcUnsafeMonitorList
531 * Pointer to an array of RECT which is filled with intersection rectangles.
535 * Size of the hMonitorList and monitorRectList arguments. If this is zero
536 * hMonitorList and monitorRectList are ignored.
539 * The number of monitors which intersect the specified region or -1 on failure.
543 NtUserEnumDisplayMonitors(
545 OPTIONAL IN LPCRECTL pUnsafeRect
,
546 OPTIONAL OUT HMONITOR
*phUnsafeMonitorList
,
547 OPTIONAL OUT PRECTL prcUnsafeMonitorList
,
548 OPTIONAL IN DWORD dwListSize
)
552 HMONITOR
*phMonitorList
= NULL
;
553 PRECTL prcMonitorList
= NULL
;
559 if (pUnsafeRect
!= NULL
)
561 Status
= MmCopyFromCaller(&rc
, pUnsafeRect
, sizeof(RECT
));
562 if (!NT_SUCCESS(Status
))
564 TRACE("MmCopyFromCaller() failed!\n");
565 SetLastNtError(Status
);
575 /* Get visible region bounding rect */
576 pDc
= DC_LockDc(hdc
);
579 TRACE("DC_LockDc() failed!\n");
580 /* FIXME: setlasterror? */
583 iRgnType
= REGION_GetRgnBox(pDc
->prgnVis
, &DcRect
);
588 TRACE("NtGdiGetRgnBox() failed!\n");
591 if (iRgnType
== NULLREGION
)
593 if (iRgnType
== COMPLEXREGION
)
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
)
602 rc
.left
+= DcRect
.left
;
603 rc
.right
+= DcRect
.left
;
604 rc
.top
+= DcRect
.top
;
605 rc
.bottom
+= DcRect
.top
;
607 /* If hdc is given and pRect is not the area of interest is the
608 bounding rect of hdc */
615 if (hdc
== NULL
&& pUnsafeRect
== NULL
)
622 /* Find intersecting monitors */
623 cMonitors
= IntGetMonitorsFromRect(pRect
, NULL
, NULL
, 0, MONITOR_DEFAULTTONULL
);
624 if (cMonitors
== 0 || dwListSize
== 0 ||
625 (phUnsafeMonitorList
== NULL
&& prcUnsafeMonitorList
== NULL
))
627 /* Simple case - just return monitors count */
628 TRACE("cMonitors = %u\n", cMonitors
);
633 /* Allocate safe buffers */
634 if (phUnsafeMonitorList
!= NULL
&& dwListSize
!= 0)
636 phMonitorList
= ExAllocatePoolWithTag(PagedPool
, sizeof (HMONITOR
) * dwListSize
, USERTAG_MONITORRECTS
);
637 if (phMonitorList
== NULL
)
639 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
643 if (prcUnsafeMonitorList
!= NULL
&& dwListSize
!= 0)
645 prcMonitorList
= ExAllocatePoolWithTag(PagedPool
, sizeof(RECT
) * dwListSize
,USERTAG_MONITORRECTS
);
646 if (prcMonitorList
== NULL
)
648 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
653 /* Get intersecting monitors */
654 cMonitors
= IntGetMonitorsFromRect(pRect
, phMonitorList
, prcMonitorList
,
655 dwListSize
, MONITOR_DEFAULTTONULL
);
657 if (hdc
!= NULL
&& pRect
!= NULL
&& prcMonitorList
!= NULL
)
659 for (i
= 0; i
< min(cMonitors
, dwListSize
); i
++)
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
;
670 if (phUnsafeMonitorList
!= NULL
&& dwListSize
!= 0)
672 Status
= MmCopyToCaller(phUnsafeMonitorList
, phMonitorList
, sizeof(HMONITOR
) * dwListSize
);
673 if (!NT_SUCCESS(Status
))
675 SetLastNtError(Status
);
679 if (prcUnsafeMonitorList
!= NULL
&& dwListSize
!= 0)
681 Status
= MmCopyToCaller(prcUnsafeMonitorList
, prcMonitorList
, sizeof(RECT
) * dwListSize
);
682 if (!NT_SUCCESS(Status
))
684 SetLastNtError(Status
);
689 /* Return monitors count on success */
694 ExFreePoolWithTag(phMonitorList
, USERTAG_MONITORRECTS
);
696 ExFreePoolWithTag(prcMonitorList
, USERTAG_MONITORRECTS
);
702 /* NtUserGetMonitorInfo
704 * Retrieves information about a given monitor
709 * Handle to a monitor for which to get information
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.
718 * Pointer to a UNICODE_STRING which will receive the device's name. The
719 * length should be CCHDEVICENAME
723 * TRUE on success; FALSE on failure (calls SetLastNtError())
728 NtUserGetMonitorInfo(
729 IN HMONITOR hMonitor
,
730 OUT LPMONITORINFO pMonitorInfoUnsafe
)
733 MONITORINFOEXW MonitorInfo
;
736 PWCHAR pwstrDeviceName
;
738 TRACE("Enter NtUserGetMonitorInfo\n");
741 /* Get monitor object */
742 pMonitor
= UserGetMonitorObject(hMonitor
);
745 TRACE("Couldnt find monitor %p\n", hMonitor
);
749 /* Check if pMonitorInfoUnsafe is valid */
750 if(pMonitorInfoUnsafe
== NULL
)
752 SetLastNtError(STATUS_INVALID_PARAMETER
);
756 pwstrDeviceName
= ((PPDEVOBJ
)(pMonitor
->hDev
))->pGraphicsDevice
->szWinDeviceName
;
758 /* Get size of pMonitorInfoUnsafe */
759 Status
= MmCopyFromCaller(&MonitorInfo
.cbSize
, &pMonitorInfoUnsafe
->cbSize
, sizeof(MonitorInfo
.cbSize
));
760 if (!NT_SUCCESS(Status
))
762 SetLastNtError(Status
);
766 /* Check if size of struct is valid */
767 if (MonitorInfo
.cbSize
!= sizeof(MONITORINFO
) &&
768 MonitorInfo
.cbSize
!= sizeof(MONITORINFOEXW
))
770 SetLastNtError(STATUS_INVALID_PARAMETER
);
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
;
781 /* Fill device name */
782 if (MonitorInfo
.cbSize
== sizeof(MONITORINFOEXW
))
784 RtlStringCbCopyNExW(MonitorInfo
.szDevice
,
785 sizeof(MonitorInfo
.szDevice
),
787 (wcslen(pwstrDeviceName
)+1) * sizeof(WCHAR
),
788 NULL
, NULL
, STRSAFE_FILL_BEHIND_NULL
);
792 Status
= MmCopyToCaller(pMonitorInfoUnsafe
, &MonitorInfo
, MonitorInfo
.cbSize
);
793 if (!NT_SUCCESS(Status
))
795 TRACE("GetMonitorInfo: MmCopyToCaller failed\n");
796 SetLastNtError(Status
);
800 TRACE("GetMonitorInfo: success\n");
804 TRACE("Leave NtUserGetMonitorInfo, ret=%i\n", bRet
);
809 /* NtUserMonitorFromPoint
811 * Returns a handle to the monitor containing the given point.
816 * Point for which to find monitor
819 * Specifies the behaviour if the point isn't on any of the monitors.
822 * If the point is found a handle to the monitor is returned; if not the
823 * return value depends on dwFlags
827 NtUserMonitorFromPoint(
832 HMONITOR hMonitor
= NULL
;
834 /* Check if flags are valid */
835 if (dwFlags
!= MONITOR_DEFAULTTONULL
&&
836 dwFlags
!= MONITOR_DEFAULTTOPRIMARY
&&
837 dwFlags
!= MONITOR_DEFAULTTONEAREST
)
839 EngSetLastError(ERROR_INVALID_FLAGS
);
843 /* Fill rect (bottom-right exclusive) */
847 rc
.bottom
= pt
.y
+ 1;
851 /* Find intersecting monitor */
852 IntGetMonitorsFromRect(&rc
, &hMonitor
, NULL
, 1, dwFlags
);
858 /* NtUserMonitorFromRect
860 * Returns a handle to the monitor having the largest intersection with a
866 * Pointer to a RECT for which to find monitor
869 * Specifies the behaviour if no monitor intersects the given rect
872 * If a monitor intersects the rect a handle to it is returned; if not the
873 * return value depends on dwFlags
877 NtUserMonitorFromRect(
878 IN LPCRECTL pRectUnsafe
,
881 ULONG cMonitors
, LargestArea
= 0, i
;
882 PRECTL prcMonitorList
= NULL
;
883 HMONITOR
*phMonitorList
= NULL
;
884 HMONITOR hMonitor
= NULL
;
888 /* Check if flags are valid */
889 if (dwFlags
!= MONITOR_DEFAULTTONULL
&&
890 dwFlags
!= MONITOR_DEFAULTTOPRIMARY
&&
891 dwFlags
!= MONITOR_DEFAULTTONEAREST
)
893 EngSetLastError(ERROR_INVALID_FLAGS
);
897 /* Copy rectangle to safe buffer */
898 Status
= MmCopyFromCaller(&Rect
, pRectUnsafe
, sizeof (RECT
));
899 if (!NT_SUCCESS(Status
))
901 SetLastNtError(Status
);
907 /* Find intersecting monitors */
908 cMonitors
= IntGetMonitorsFromRect(&Rect
, &hMonitor
, NULL
, 1, dwFlags
);
911 /* No or one monitor found. Just return handle. */
915 /* There is more than one monitor. Find monitor with largest intersection.
916 Temporary reset hMonitor */
919 /* Allocate helper buffers */
920 phMonitorList
= ExAllocatePoolWithTag(PagedPool
,
921 sizeof(HMONITOR
) * cMonitors
,
922 USERTAG_MONITORRECTS
);
923 if (phMonitorList
== NULL
)
925 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
929 prcMonitorList
= ExAllocatePoolWithTag(PagedPool
,
930 sizeof(RECT
) * cMonitors
,
931 USERTAG_MONITORRECTS
);
932 if (prcMonitorList
== NULL
)
934 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
938 /* Get intersecting monitors again but now with rectangle list */
939 cMonitors
= IntGetMonitorsFromRect(&Rect
, phMonitorList
, prcMonitorList
,
942 /* Find largest intersection */
943 for (i
= 0; i
< cMonitors
; i
++)
945 ULONG Area
= (prcMonitorList
[i
].right
- prcMonitorList
[i
].left
) *
946 (prcMonitorList
[i
].bottom
- prcMonitorList
[i
].top
);
947 if (Area
>= LargestArea
)
949 hMonitor
= phMonitorList
[i
];
956 ExFreePoolWithTag(phMonitorList
, USERTAG_MONITORRECTS
);
958 ExFreePoolWithTag(prcMonitorList
, USERTAG_MONITORRECTS
);
967 NtUserMonitorFromWindow(
972 HMONITOR hMonitor
= NULL
;
973 RECTL Rect
= {0, 0, 0, 0};
975 TRACE("Enter NtUserMonitorFromWindow\n");
977 /* Check if flags are valid */
978 if (dwFlags
!= MONITOR_DEFAULTTONULL
&&
979 dwFlags
!= MONITOR_DEFAULTTOPRIMARY
&&
980 dwFlags
!= MONITOR_DEFAULTTONEAREST
)
982 EngSetLastError(ERROR_INVALID_FLAGS
);
988 /* If window is given, use it first */
991 /* Get window object */
992 pWnd
= UserGetWindowObject(hWnd
);
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
;
1001 /* Find monitors now */
1002 IntGetMonitorsFromRect(&Rect
, &hMonitor
, NULL
, 1, dwFlags
);
1005 TRACE("Leave NtUserMonitorFromWindow, ret=%p\n", hMonitor
);