2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 * COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS kernel
21 * PURPOSE: Monitor support
22 * FILE: subsys/win32k/ntuser/monitor.c
23 * PROGRAMER: Anich Gregor (blight@blight.eu.org)
28 /* INCLUDES ******************************************************************/
32 /* FIXME: find include file for these */
33 #define MONITORINFOF_PRIMARY 1
34 #define MONITOR_DEFAULTTONULL 0
35 #define MONITOR_DEFAULTTOPRIMARY 1
36 #define MONITOR_DEFAULTTONEAREST 2
41 /* GLOBALS *******************************************************************/
43 /* list of monitors */
44 static PMONITOR_OBJECT MonitorList
= NULL
;
45 static FAST_MUTEX MonitorListLock
; /* R/W lock for monitor list */
47 /* INITALIZATION FUNCTIONS ****************************************************/
52 DPRINT("Initializing monitor implementation...\n");
53 ExInitializeFastMutex(&MonitorListLock
);
55 return STATUS_SUCCESS
;
61 DPRINT("Cleaning up monitor implementation...\n");
62 /* FIXME: Destroy monitor objects? */
64 return STATUS_SUCCESS
;
67 /* PRIVATE FUNCTIONS **********************************************************/
70 # define MIN(a, b) ((a) < (b) ? (a) : (b))
73 # define MAX(a, b) ((a) > (b) ? (a) : (b))
76 # define ABS(a) ((a) < (0) ? (-(a)) : (a))
79 /* IntCreateMonitorObject
81 * Creates a MONITOR_OBJECT
84 * If the function succeeds a pointer to a MONITOR_OBJECT is returned. On failure
89 IntCreateMonitorObject()
92 PMONITOR_OBJECT Monitor
;
94 Monitor
= ObmCreateObject(PsGetWin32Thread()->Desktop
->WindowStation
->HandleTable
, &Handle
, otMonitor
, sizeof (MONITOR_OBJECT
));
100 Monitor
->Handle
= Handle
;
101 ExInitializeFastMutex(&Monitor
->Lock
);
106 /* IntDestroyMonitorObject
108 * Destroys a MONITOR_OBJECT
109 * You have to be the owner of the monitors lock to safely destroy it.
114 * Pointer to the MONITOR_OBJECT which shall be deleted
118 IntDestroyMonitorObject(IN PMONITOR_OBJECT pMonitor
)
120 RtlFreeUnicodeString(&pMonitor
->DeviceName
);
121 ObmDereferenceObject(pMonitor
);
124 /* IntGetMonitorObject
126 * Returns the MONITOR_OBJECT for the given monitor handle.
131 * Monitor handle for which to get the MONITOR_OBJECT
134 * Returns a pointer to a MONITOR_OBJECT on success and increase the
135 * refcount of the monitor object; NULL on failure
139 IntGetMonitorObject(IN HMONITOR hMonitor
)
141 PMONITOR_OBJECT Monitor
;
144 Status
= ObmReferenceObjectByHandle(PsGetWin32Thread()->Desktop
->WindowStation
->HandleTable
, hMonitor
, otMonitor
, (PVOID
*)&Monitor
);
145 if (!NT_SUCCESS(Status
) || Monitor
== NULL
)
147 /* FIXME: SetLastNtError( status ); ? */
154 /* IntReleaseMonitorObject
156 * Releases the given MONITOR_OBJECT.
161 * MONITOR_OBJECT to be released
163 #define IntReleaseMonitorObject(MonitorObj) \
164 ObmDereferenceObject(MonitorObj);
168 * Creates a new MONITOR_OBJECT and appends it to the list of monitors.
172 * pGdiDevice Pointer to the GDIDEVICE onto which the monitor was attached
173 * DisplayNumber Display Number (starting with 0)
179 IntAttachMonitor(IN GDIDEVICE
*pGdiDevice
,
180 IN ULONG DisplayNumber
)
182 PMONITOR_OBJECT Monitor
;
183 WCHAR Buffer
[CCHDEVICENAME
];
185 DPRINT("Attaching monitor...\n");
187 /* create new monitor object */
188 Monitor
= IntCreateMonitorObject();
191 DPRINT("Couldnt create monitor object\n");
192 return STATUS_INSUFFICIENT_RESOURCES
;
195 _snwprintf(Buffer
, CCHDEVICENAME
, L
"\\??\\DISPLAY%d", DisplayNumber
+ 1);
196 if (!RtlCreateUnicodeString(&Monitor
->DeviceName
, Buffer
))
198 DPRINT("Couldn't duplicate monitor name!\n");
199 return STATUS_INSUFFICIENT_RESOURCES
;
202 Monitor
->GdiDevice
= pGdiDevice
;
203 ExAcquireFastMutex(&MonitorListLock
);
204 if (MonitorList
== NULL
)
206 DPRINT("Primary monitor is beeing attached\n");
207 Monitor
->IsPrimary
= TRUE
;
208 MonitorList
= Monitor
;
213 DPRINT("Additional monitor is beeing attached\n");
214 for (p
= MonitorList
; p
->Next
!= NULL
; p
= p
->Next
);
220 ExReleaseFastMutex(&MonitorListLock
);
222 return STATUS_SUCCESS
;
227 * Deletes a MONITOR_OBJECT and removes it from the list of monitors.
231 * pGdiDevice Pointer to the GDIDEVICE from which the monitor was detached
237 IntDetachMonitor(IN GDIDEVICE
*pGdiDevice
)
239 PMONITOR_OBJECT Monitor
;
241 ExAcquireFastMutex(&MonitorListLock
);
242 for (Monitor
= MonitorList
; Monitor
!= NULL
; Monitor
= Monitor
->Next
)
244 if (Monitor
->GdiDevice
== pGdiDevice
)
250 /* no monitor for given device found */
251 ExReleaseFastMutex(&MonitorListLock
);
252 return STATUS_INVALID_PARAMETER
;
255 if (Monitor
->IsPrimary
&& (Monitor
->Next
!= NULL
|| Monitor
->Prev
!= NULL
))
257 PMONITOR_OBJECT NewPrimaryMonitor
= (Monitor
->Prev
!= NULL
) ? (Monitor
->Prev
) : (Monitor
->Next
);
259 ExAcquireFastMutex(&NewPrimaryMonitor
->Lock
);
260 NewPrimaryMonitor
->IsPrimary
= TRUE
;
261 ExReleaseFastMutex(&NewPrimaryMonitor
->Lock
);
264 if (MonitorList
== Monitor
)
266 MonitorList
= Monitor
->Next
;
267 if (Monitor
->Next
!= NULL
)
268 Monitor
->Next
->Prev
= NULL
;
272 Monitor
->Prev
->Next
= Monitor
->Next
;
273 if (Monitor
->Next
!= NULL
)
274 Monitor
->Next
->Prev
= Monitor
->Prev
;
276 ExReleaseFastMutex(&MonitorListLock
);
278 IntDestroyMonitorObject(Monitor
);
280 return STATUS_SUCCESS
;
283 /* IntGetPrimaryMonitor
285 * Returns a PMONITOR_OBJECT for the primary monitor
292 IntGetPrimaryMonitor()
294 PMONITOR_OBJECT Monitor
;
296 ExAcquireFastMutex(&MonitorListLock
);
297 for (Monitor
= MonitorList
; Monitor
!= NULL
; Monitor
= Monitor
->Next
)
299 /* FIXME: I guess locking the monitor is not neccessary to read 1 int */
300 if (Monitor
->IsPrimary
)
303 ExReleaseFastMutex(&MonitorListLock
);
308 /* IntGetMonitorsFromRect
310 * Returns a list of monitor handles/rectangles. The rectangles in the list are
311 * the areas of intersection with the monitors.
316 * Rectangle in desktop coordinates. If this is NULL all monitors are
317 * returned and the rect list is filled with the sizes of the monitors.
320 * Pointer to an array of HMONITOR which is filled with monitor handles.
324 * Pointer to an array of RECT which is filled with intersection rects in
325 * desktop coordinates.
326 * Can be NULL, will be ignored if no intersecting monitor is found and
327 * flags is MONITOR_DEFAULTTONEAREST
330 * Size of the hMonitorList and monitorRectList arguments. If this is zero
331 * hMonitorList and monitorRectList are ignored.
334 * Either 0 or MONITOR_DEFAULTTONEAREST (ignored if rect is NULL)
337 * The number of monitors which intersect the specified region.
341 IntGetMonitorsFromRect(OPTIONAL IN LPCRECT pRect
,
342 OPTIONAL OUT HMONITOR
*hMonitorList
,
343 OPTIONAL OUT LPRECT monitorRectList
,
344 OPTIONAL IN DWORD listSize
,
345 OPTIONAL IN DWORD flags
)
347 PMONITOR_OBJECT Monitor
, NearestMonitor
= NULL
;
349 LONG iNearestDistanceX
= 0x7fffffff, iNearestDistanceY
= 0x7fffffff;
351 /* find monitors which intersect the rectangle */
352 ExAcquireFastMutex(&MonitorListLock
);
353 for (Monitor
= MonitorList
; Monitor
!= NULL
; Monitor
= Monitor
->Next
)
355 RECT MonitorRect
, IntersectionRect
;
357 ExAcquireFastMutex(&Monitor
->Lock
);
358 MonitorRect
.left
= 0; /* FIXME: get origin */
359 MonitorRect
.top
= 0; /* FIXME: get origin */
360 MonitorRect
.right
= MonitorRect
.left
+ Monitor
->GdiDevice
->GDIInfo
.ulHorzRes
;
361 MonitorRect
.bottom
= MonitorRect
.top
+ Monitor
->GdiDevice
->GDIInfo
.ulVertRes
;
362 ExReleaseFastMutex(&Monitor
->Lock
);
364 DPRINT("MonitorRect: left = %d, top = %d, right = %d, bottom = %d\n",
365 MonitorRect
.left
, MonitorRect
.top
, MonitorRect
.right
, MonitorRect
.bottom
);
369 BOOL intersects
= TRUE
;
371 /* check if the rect intersects the monitor */
372 if ((pRect
->right
< MonitorRect
.left
) || (pRect
->left
> MonitorRect
.right
) ||
373 (pRect
->bottom
< MonitorRect
.top
) || (pRect
->top
> MonitorRect
.bottom
))
378 if (flags
== MONITOR_DEFAULTTONEAREST
&& !intersects
)
380 INT distanceX
, distanceY
;
382 distanceX
= MIN(ABS(MonitorRect
.left
- pRect
->right
),
383 ABS(pRect
->left
- MonitorRect
.right
));
384 distanceY
= MIN(ABS(MonitorRect
.top
- pRect
->bottom
),
385 ABS(pRect
->top
- MonitorRect
.bottom
));
387 if (((distanceX
< iNearestDistanceX
) && (distanceY
<= iNearestDistanceY
)) ||
388 ((distanceX
<= iNearestDistanceX
) && (distanceY
< iNearestDistanceY
)))
390 iNearestDistanceX
= distanceX
;
391 iNearestDistanceY
= distanceY
;
392 NearestMonitor
= Monitor
;
399 /* calculate intersection */
400 IntersectionRect
.left
= MAX(MonitorRect
.left
, pRect
->left
);
401 IntersectionRect
.top
= MAX(MonitorRect
.top
, pRect
->top
);
402 IntersectionRect
.right
= MIN(MonitorRect
.right
, pRect
->right
);
403 IntersectionRect
.bottom
= MIN(MonitorRect
.bottom
, pRect
->bottom
);
407 IntersectionRect
= MonitorRect
;
410 if (iCount
< listSize
)
412 if (hMonitorList
!= NULL
)
413 hMonitorList
[iCount
] = Monitor
->Handle
;
414 if (monitorRectList
!= NULL
)
415 monitorRectList
[iCount
] = IntersectionRect
;
419 ExReleaseFastMutex(&MonitorListLock
);
421 if (iCount
== 0 && flags
== MONITOR_DEFAULTTONEAREST
)
423 if (iCount
< listSize
)
425 if (hMonitorList
!= NULL
)
426 hMonitorList
[iCount
] = NearestMonitor
->Handle
;
434 /* PUBLIC FUNCTIONS ***********************************************************/
436 /* NtUserEnumDisplayMonitors
438 * Enumerates display monitors which intersect the given HDC/cliprect
443 * Handle to a DC for which to enum intersecting monitors. If this is NULL
444 * it returns all monitors which are part of the current virtual screen.
447 * Clipping rectangle with coordinate system origin at the DCs origin if the
448 * given HDC is not NULL or in virtual screen coordinated if it is NULL.
452 * Pointer to an array of HMONITOR which is filled with monitor handles.
456 * Pointer to an array of RECT which is filled with intersection rectangles.
460 * Size of the hMonitorList and monitorRectList arguments. If this is zero
461 * hMonitorList and monitorRectList are ignored.
464 * The number of monitors which intersect the specified region or -1 on failure.
468 NtUserEnumDisplayMonitors(
470 OPTIONAL IN LPCRECT pRect
,
471 OPTIONAL OUT HMONITOR
*hMonitorList
,
472 OPTIONAL OUT LPRECT monitorRectList
,
473 OPTIONAL IN DWORD listSize
)
476 HMONITOR
*safeHMonitorList
= NULL
;
477 LPRECT safeRectList
= NULL
;
485 status
= MmCopyFromCaller(&rect
, pRect
, sizeof (RECT
));
486 if (!NT_SUCCESS(status
))
488 DPRINT("MmCopyFromCaller() failed!\n");
489 SetLastNtError(status
);
500 /* get visible region bounding rect */
504 DPRINT("DC_LockDc() failed!\n");
505 /* FIXME: setlasterror? */
508 dcVisRgn
= dc
->w
.hVisRgn
;
511 regionType
= NtGdiGetRgnBox(dcVisRgn
, &dcRect
);
514 DPRINT("NtGdiGetRgnBox() failed!\n");
517 if (regionType
== NULLREGION
)
519 if (regionType
== COMPLEXREGION
)
520 { /* TODO: warning */ }
522 /* if hDC and pRect are given the area of interest is pRect with
523 coordinate origin at the DC position */
526 rect
.left
+= dcRect
.left
;
527 rect
.right
+= dcRect
.left
;
528 rect
.top
+= dcRect
.top
;
529 rect
.bottom
+= dcRect
.top
;
531 /* if hDC is given and pRect is not the area of interest is the
532 bounding rect of hDC */
539 if (hDC
== NULL
&& pRect
== NULL
)
544 /* find intersecting monitors */
545 numMonitors
= IntGetMonitorsFromRect(myRect
, NULL
, NULL
, 0, 0);
546 if (numMonitors
== 0 || listSize
== 0 ||
547 (hMonitorList
== NULL
&& monitorRectList
== NULL
))
549 DPRINT("numMonitors = %d\n", numMonitors
);
553 if (hMonitorList
!= NULL
&& listSize
!= 0)
555 safeHMonitorList
= ExAllocatePool(PagedPool
, sizeof (HMONITOR
) * listSize
);
556 if (safeHMonitorList
== NULL
)
558 /* FIXME: SetLastWin32Error? */
562 if (monitorRectList
!= NULL
&& listSize
!= 0)
564 safeRectList
= ExAllocatePool(PagedPool
, sizeof (RECT
) * listSize
);
565 if (safeRectList
== NULL
)
567 ExFreePool(safeHMonitorList
);
568 /* FIXME: SetLastWin32Error? */
573 /* get intersecting monitors */
574 numMonitors
= IntGetMonitorsFromRect(myRect
, safeHMonitorList
, safeRectList
,
577 if (hDC
!= NULL
&& pRect
!= NULL
&& safeRectList
!= NULL
)
578 for (i
= 0; i
< numMonitors
; i
++)
580 safeRectList
[i
].left
-= dcRect
.left
;
581 safeRectList
[i
].right
-= dcRect
.left
;
582 safeRectList
[i
].top
-= dcRect
.top
;
583 safeRectList
[i
].bottom
-= dcRect
.top
;
587 if (hMonitorList
!= NULL
&& listSize
!= 0)
589 status
= MmCopyToCaller(hMonitorList
, safeHMonitorList
, sizeof (HMONITOR
) * listSize
);
590 ExFreePool(safeHMonitorList
);
591 if (!NT_SUCCESS(status
))
593 ExFreePool(safeRectList
);
594 SetLastNtError(status
);
598 if (monitorRectList
!= NULL
&& listSize
!= 0)
600 status
= MmCopyToCaller(monitorRectList
, safeRectList
, sizeof (RECT
) * listSize
);
601 ExFreePool(safeRectList
);
602 if (!NT_SUCCESS(status
))
604 SetLastNtError(status
);
612 /* NtUserGetMonitorInfo
614 * Retrieves information about a given monitor
619 * Handle to a monitor for which to get information
622 * Pointer to a MONITORINFO struct which is filled with the information.
623 * The cbSize member must be set to sizeof(MONITORINFO) or
624 * sizeof(MONITORINFOEX). Even if set to sizeof(MONITORINFOEX) only parts
625 * from MONITORINFO will be filled.
628 * Pointer to a UNICODE_STRING which will recieve the device's name. The
629 * length should be CCHDEVICENAME
633 * TRUE on success; FALSE on failure (calls SetLastNtError())
638 NtUserGetMonitorInfo(
639 IN HMONITOR hMonitor
,
640 OUT LPMONITORINFO pMonitorInfo
)
642 PMONITOR_OBJECT Monitor
;
643 MONITORINFOEXW MonitorInfo
;
646 /* get monitor object */
647 if ((Monitor
= IntGetMonitorObject(hMonitor
)) == NULL
)
649 DPRINT("Couldnt find monitor 0x%lx\n", hMonitor
);
650 SetLastNtError(STATUS_INVALID_HANDLE
);
654 /* get size of pMonitorInfo */
655 Status
= MmCopyFromCaller(&MonitorInfo
.cbSize
, &pMonitorInfo
->cbSize
, sizeof (MonitorInfo
.cbSize
));
656 if (!NT_SUCCESS(Status
))
658 IntReleaseMonitorObject(Monitor
);
659 SetLastNtError(Status
);
662 if ((MonitorInfo
.cbSize
!= sizeof (MONITORINFO
)) &&
663 (MonitorInfo
.cbSize
!= sizeof (MONITORINFOEXW
)))
665 SetLastNtError(STATUS_INVALID_PARAMETER
);
669 ExAcquireFastMutex(&Monitor
->Lock
);
670 /* fill monitor info */
671 MonitorInfo
.rcMonitor
.left
= 0; /* FIXME: get origin */
672 MonitorInfo
.rcMonitor
.top
= 0; /* FIXME: get origin */
673 MonitorInfo
.rcMonitor
.right
= MonitorInfo
.rcMonitor
.left
+ Monitor
->GdiDevice
->GDIInfo
.ulHorzRes
;
674 MonitorInfo
.rcMonitor
.bottom
= MonitorInfo
.rcMonitor
.top
+ Monitor
->GdiDevice
->GDIInfo
.ulVertRes
;
675 MonitorInfo
.rcWork
= MonitorInfo
.rcMonitor
; /* FIXME: use DEVMODE panning to calculate work area? */
676 MonitorInfo
.dwFlags
= 0;
677 if (Monitor
->IsPrimary
)
678 MonitorInfo
.dwFlags
|= MONITORINFOF_PRIMARY
;
680 /* fill device name */
681 if (MonitorInfo
.cbSize
== sizeof (MONITORINFOEXW
))
684 INT len
= Monitor
->DeviceName
.Length
;
685 if (len
>= CCHDEVICENAME
* sizeof (WCHAR
))
686 len
= (CCHDEVICENAME
- 1) * sizeof (WCHAR
);
688 memcpy(MonitorInfo
.szDevice
, Monitor
->DeviceName
.Buffer
, len
);
689 memcpy(MonitorInfo
.szDevice
+ (len
/ sizeof (WCHAR
)), &nul
, sizeof (WCHAR
));
691 ExReleaseFastMutex(&Monitor
->Lock
);
692 IntReleaseMonitorObject(Monitor
);
695 Status
= MmCopyToCaller(pMonitorInfo
, &MonitorInfo
, MonitorInfo
.cbSize
);
696 if (!NT_SUCCESS(Status
))
698 DPRINT("GetMonitorInfo: MmCopyToCaller failed\n");
699 SetLastNtError(Status
);
703 DPRINT("GetMonitorInfo: success\n");
708 /* NtUserMonitorFromPoint
710 * Returns a handle to the monitor containing the given point.
715 * Point for which to find monitor
718 * Specifies the behaviour if the point isn't on any of the monitors.
721 * If the point is found a handle to the monitor is returned; if not the
722 * return value depends on dwFlags
726 NtUserMonitorFromPoint(
732 HMONITOR hMonitor
= NULL
;
735 InRect
.left
= InRect
.right
= point
.x
;
736 InRect
.top
= InRect
.bottom
= point
.y
;
738 /* find intersecting monitor */
739 NumMonitors
= IntGetMonitorsFromRect(&InRect
, &hMonitor
, NULL
, 1, 0);
742 return (HMONITOR
)NULL
;
745 if (hMonitor
== NULL
)
747 if (dwFlags
== MONITOR_DEFAULTTOPRIMARY
)
749 PMONITOR_OBJECT MonitorObj
= IntGetPrimaryMonitor();
751 hMonitor
= MonitorObj
->Handle
;
753 else if (dwFlags
== MONITOR_DEFAULTTONEAREST
)
755 NumMonitors
= IntGetMonitorsFromRect(&InRect
, &hMonitor
, NULL
,
756 1, MONITOR_DEFAULTTONEAREST
);
757 /*ASSERT( (numMonitors > 0) && (hMonitor != NULL) );*/
759 /* else flag is DEFAULTTONULL */
765 /* NtUserMonitorFromRect
767 * Returns a handle to the monitor having the largest intersection with a
773 * Pointer to a RECT for which to find monitor
776 * Specifies the behaviour if no monitor intersects the given rect
779 * If a monitor intersects the rect a handle to it is returned; if not the
780 * return value depends on dwFlags
784 NtUserMonitorFromRect(
788 INT numMonitors
, iLargestArea
= -1, i
;
790 HMONITOR
*hMonitorList
;
791 HMONITOR hMonitor
= NULL
;
796 status
= MmCopyFromCaller(&rect
, pRect
, sizeof (RECT
));
797 if (!NT_SUCCESS(status
))
799 SetLastNtError(status
);
800 return (HMONITOR
)NULL
;
803 /* find intersecting monitors */
804 numMonitors
= IntGetMonitorsFromRect(&rect
, NULL
, NULL
, 0, 0);
807 return (HMONITOR
)NULL
;
810 if (numMonitors
== 0)
812 if (dwFlags
== MONITOR_DEFAULTTOPRIMARY
)
814 PMONITOR_OBJECT monitorObj
= IntGetPrimaryMonitor();
816 return monitorObj
->Handle
;
818 else if (dwFlags
== MONITOR_DEFAULTTONEAREST
)
820 numMonitors
= IntGetMonitorsFromRect(&rect
, &hMonitor
, NULL
,
821 1, MONITOR_DEFAULTTONEAREST
);
822 if (numMonitors
<= 0)
825 return (HMONITOR
)NULL
;
831 /* else flag is DEFAULTTONULL */
832 return (HMONITOR
)NULL
;
835 hMonitorList
= ExAllocatePool(PagedPool
, sizeof (HMONITOR
) * numMonitors
);
836 if (hMonitorList
== NULL
)
838 /* FIXME: SetLastWin32Error? */
839 return (HMONITOR
)NULL
;
841 rectList
= ExAllocatePool(PagedPool
, sizeof (RECT
) * numMonitors
);
842 if (rectList
== NULL
)
844 ExFreePool(hMonitorList
);
845 /* FIXME: SetLastWin32Error? */
846 return (HMONITOR
)NULL
;
849 /* get intersecting monitors */
850 numMonitors
= IntGetMonitorsFromRect(&rect
, hMonitorList
, rectList
,
852 if (numMonitors
<= 0)
854 return (HMONITOR
)NULL
;
857 /* find largest intersection */
858 for (i
= 0; i
< numMonitors
; i
++)
860 INT area
= (rectList
[i
].right
- rectList
[i
].left
) *
861 (rectList
[i
].bottom
- rectList
[i
].top
);
862 if (area
> iLargestArea
)
864 hMonitor
= hMonitorList
[i
];
868 ExFreePool(hMonitorList
);
869 ExFreePool(rectList
);
877 NtUserMonitorFromWindow(
881 PWINDOW_OBJECT Window
;
882 HMONITOR hMonitor
= NULL
;
885 Window
= IntGetWindowObject(hWnd
);
888 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
889 return (HMONITOR
)NULL
;
892 Rect
.left
= Rect
.right
= Window
->WindowRect
.left
;
893 Rect
.top
= Rect
.bottom
= Window
->WindowRect
.bottom
;
895 IntGetMonitorsFromRect(&Rect
, &hMonitor
, NULL
, 1, dwFlags
);
897 IntReleaseWindowObject(Window
);