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 along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 gMonitorList
= NULL
;
46 /* INITALIZATION FUNCTIONS ****************************************************/
51 DPRINT("Initializing monitor implementation...\n");
53 return STATUS_SUCCESS
;
59 DPRINT("Cleaning up monitor implementation...\n");
60 /* FIXME: Destroy monitor objects? */
62 return STATUS_SUCCESS
;
65 /* PRIVATE FUNCTIONS **********************************************************/
68 # define MIN(a, b) ((a) < (b) ? (a) : (b))
71 # define MAX(a, b) ((a) > (b) ? (a) : (b))
74 # define ABS(a) ((a) < (0) ? (-(a)) : (a))
77 /* IntCreateMonitorObject
82 * If the function succeeds a pointer to a MONITOR is returned. On failure
87 IntCreateMonitorObject()
92 Monitor
= UserCreateObject(gHandleTable
, NULL
, &Handle
, otMonitor
, sizeof (MONITOR
));
98 ExInitializeFastMutex(&Monitor
->Lock
);
103 /* IntDestroyMonitorObject
106 * You have to be the owner of the monitors lock to safely destroy it.
111 * Pointer to the MONITOR which shall be deleted
115 IntDestroyMonitorObject(IN PMONITOR pMonitor
)
117 RtlFreeUnicodeString(&pMonitor
->DeviceName
);
118 UserDereferenceObject(pMonitor
);
123 UserGetMonitorObject(IN HMONITOR hMonitor
)
129 SetLastWin32Error(ERROR_INVALID_MONITOR_HANDLE
);
134 Monitor
= (PMONITOR
)UserGetObject(gHandleTable
, hMonitor
, otMonitor
);
137 SetLastWin32Error(ERROR_INVALID_MONITOR_HANDLE
);
141 ASSERT(Monitor
->head
.cLockObj
>= 0);
149 * Creates a new MONITOR and appends it to the list of monitors.
153 * pGdiDevice Pointer to the PDEVOBJ onto which the monitor was attached
154 * DisplayNumber Display Number (starting with 0)
160 IntAttachMonitor(IN PDEVOBJ
*pGdiDevice
,
161 IN ULONG DisplayNumber
)
164 WCHAR Buffer
[CCHDEVICENAME
];
166 DPRINT("Attaching monitor...\n");
168 /* create new monitor object */
169 Monitor
= IntCreateMonitorObject();
172 DPRINT("Couldnt create monitor object\n");
173 return STATUS_INSUFFICIENT_RESOURCES
;
176 _snwprintf(Buffer
, CCHDEVICENAME
, L
"\\\\.\\DISPLAY%d", DisplayNumber
+ 1);
177 if (!RtlCreateUnicodeString(&Monitor
->DeviceName
, Buffer
))
179 DPRINT("Couldn't duplicate monitor name!\n");
180 UserDereferenceObject(Monitor
);
181 UserDeleteObject(UserHMGetHandle(Monitor
), otMonitor
);
182 return STATUS_INSUFFICIENT_RESOURCES
;
185 Monitor
->GdiDevice
= pGdiDevice
;
186 Monitor
->rcMonitor
.left
= 0;
187 Monitor
->rcMonitor
.top
= 0;
188 Monitor
->rcMonitor
.right
= Monitor
->rcMonitor
.left
+ pGdiDevice
->gdiinfo
.ulHorzRes
;
189 Monitor
->rcMonitor
.bottom
= Monitor
->rcMonitor
.top
+ pGdiDevice
->gdiinfo
.ulVertRes
;
190 Monitor
->rcWork
= Monitor
->rcMonitor
;
191 Monitor
->cWndStack
= 0;
193 Monitor
->hrgnMonitor
= IntSysCreateRectRgnIndirect( &Monitor
->rcMonitor
);
195 IntGdiSetRegionOwner(Monitor
->hrgnMonitor
, GDI_OBJ_HMGR_PUBLIC
);
197 if (gMonitorList
== NULL
)
199 DPRINT("Primary monitor is beeing attached\n");
200 Monitor
->IsPrimary
= TRUE
;
201 gMonitorList
= Monitor
;
206 DPRINT("Additional monitor is beeing attached\n");
207 for (p
= gMonitorList
; p
->Next
!= NULL
; p
= p
->Next
)
214 return STATUS_SUCCESS
;
219 * Deletes a MONITOR and removes it from the list of monitors.
223 * pGdiDevice Pointer to the PDEVOBJ from which the monitor was detached
229 IntDetachMonitor(IN PDEVOBJ
*pGdiDevice
)
233 for (Monitor
= gMonitorList
; Monitor
!= NULL
; Monitor
= Monitor
->Next
)
235 if (Monitor
->GdiDevice
== pGdiDevice
)
241 /* no monitor for given device found */
242 return STATUS_INVALID_PARAMETER
;
245 if (Monitor
->IsPrimary
&& (Monitor
->Next
!= NULL
|| Monitor
->Prev
!= NULL
))
247 PMONITOR NewPrimaryMonitor
= (Monitor
->Prev
!= NULL
) ? (Monitor
->Prev
) : (Monitor
->Next
);
249 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&NewPrimaryMonitor
->Lock
);
250 NewPrimaryMonitor
->IsPrimary
= TRUE
;
251 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&NewPrimaryMonitor
->Lock
);
254 if (gMonitorList
== Monitor
)
256 gMonitorList
= Monitor
->Next
;
257 if (Monitor
->Next
!= NULL
)
258 Monitor
->Next
->Prev
= NULL
;
262 Monitor
->Prev
->Next
= Monitor
->Next
;
263 if (Monitor
->Next
!= NULL
)
264 Monitor
->Next
->Prev
= Monitor
->Prev
;
267 if (Monitor
->hrgnMonitor
)
268 REGION_FreeRgnByHandle(Monitor
->hrgnMonitor
);
270 IntDestroyMonitorObject(Monitor
);
272 return STATUS_SUCCESS
;
275 /* IntGetPrimaryMonitor
277 * Returns a PMONITOR for the primary monitor
284 IntGetPrimaryMonitor()
288 for (Monitor
= gMonitorList
; Monitor
!= NULL
; Monitor
= Monitor
->Next
)
290 /* FIXME: I guess locking the monitor is not neccessary to read 1 int */
291 if (Monitor
->IsPrimary
)
298 /* IntGetMonitorsFromRect
300 * Returns a list of monitor handles/rectangles. The rectangles in the list are
301 * the areas of intersection with the monitors.
306 * Rectangle in desktop coordinates. If this is NULL all monitors are
307 * returned and the rect list is filled with the sizes of the monitors.
310 * Pointer to an array of HMONITOR which is filled with monitor handles.
314 * Pointer to an array of RECT which is filled with intersection rects in
315 * desktop coordinates.
316 * Can be NULL, will be ignored if no intersecting monitor is found and
317 * flags is MONITOR_DEFAULTTONEAREST
320 * Size of the hMonitorList and monitorRectList arguments. If this is zero
321 * hMonitorList and monitorRectList are ignored.
324 * Either 0 or MONITOR_DEFAULTTONEAREST (ignored if rect is NULL)
327 * The number of monitors which intersect the specified region.
331 IntGetMonitorsFromRect(OPTIONAL IN LPCRECTL pRect
,
332 OPTIONAL OUT HMONITOR
*hMonitorList
,
333 OPTIONAL OUT PRECTL monitorRectList
,
334 OPTIONAL IN DWORD listSize
,
335 OPTIONAL IN DWORD flags
)
337 PMONITOR Monitor
, NearestMonitor
= NULL
, PrimaryMonitor
= NULL
;
339 LONG iNearestDistanceX
= 0x7fffffff, iNearestDistanceY
= 0x7fffffff;
341 /* find monitors which intersect the rectangle */
342 for (Monitor
= gMonitorList
; Monitor
!= NULL
; Monitor
= Monitor
->Next
)
344 RECTL MonitorRect
, IntersectionRect
;
346 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&Monitor
->Lock
);
347 MonitorRect
= Monitor
->rcMonitor
;
348 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&Monitor
->Lock
);
350 DPRINT("MonitorRect: left = %d, top = %d, right = %d, bottom = %d\n",
351 MonitorRect
.left
, MonitorRect
.top
, MonitorRect
.right
, MonitorRect
.bottom
);
353 if (flags
== MONITOR_DEFAULTTOPRIMARY
&& Monitor
->IsPrimary
)
355 PrimaryMonitor
= Monitor
;
360 BOOL intersects
= TRUE
;
362 /* check if the rect intersects the monitor */
363 if ((pRect
->right
< MonitorRect
.left
) || (pRect
->left
> MonitorRect
.right
) ||
364 (pRect
->bottom
< MonitorRect
.top
) || (pRect
->top
> MonitorRect
.bottom
))
369 if (flags
== MONITOR_DEFAULTTONEAREST
&& !intersects
)
371 INT distanceX
, distanceY
;
373 distanceX
= MIN(ABS(MonitorRect
.left
- pRect
->right
),
374 ABS(pRect
->left
- MonitorRect
.right
));
375 distanceY
= MIN(ABS(MonitorRect
.top
- pRect
->bottom
),
376 ABS(pRect
->top
- MonitorRect
.bottom
));
378 if (((distanceX
< iNearestDistanceX
) && (distanceY
<= iNearestDistanceY
)) ||
379 ((distanceX
<= iNearestDistanceX
) && (distanceY
< iNearestDistanceY
)))
381 iNearestDistanceX
= distanceX
;
382 iNearestDistanceY
= distanceY
;
383 NearestMonitor
= Monitor
;
390 /* calculate intersection */
391 IntersectionRect
.left
= MAX(MonitorRect
.left
, pRect
->left
);
392 IntersectionRect
.top
= MAX(MonitorRect
.top
, pRect
->top
);
393 IntersectionRect
.right
= MIN(MonitorRect
.right
, pRect
->right
);
394 IntersectionRect
.bottom
= MIN(MonitorRect
.bottom
, pRect
->bottom
);
398 IntersectionRect
= MonitorRect
;
401 if (iCount
< listSize
)
403 if (hMonitorList
!= NULL
)
404 hMonitorList
[iCount
] = UserHMGetHandle(Monitor
);
405 if (monitorRectList
!= NULL
)
406 monitorRectList
[iCount
] = IntersectionRect
;
411 if (iCount
== 0 && flags
== MONITOR_DEFAULTTONEAREST
)
413 if (iCount
< listSize
)
415 if (hMonitorList
!= NULL
)
416 hMonitorList
[iCount
] = UserHMGetHandle(NearestMonitor
);
420 else if (iCount
== 0 && flags
== MONITOR_DEFAULTTOPRIMARY
)
422 if (iCount
< listSize
)
424 if (hMonitorList
!= NULL
)
425 hMonitorList
[iCount
] = UserHMGetHandle(PrimaryMonitor
);
432 /* PUBLIC FUNCTIONS ***********************************************************/
434 /* NtUserEnumDisplayMonitors
436 * Enumerates display monitors which intersect the given HDC/cliprect
441 * Handle to a DC for which to enum intersecting monitors. If this is NULL
442 * it returns all monitors which are part of the current virtual screen.
445 * Clipping rectangle with coordinate system origin at the DCs origin if the
446 * given HDC is not NULL or in virtual screen coordinated if it is NULL.
450 * Pointer to an array of HMONITOR which is filled with monitor handles.
454 * Pointer to an array of RECT which is filled with intersection rectangles.
458 * Size of the hMonitorList and monitorRectList arguments. If this is zero
459 * hMonitorList and monitorRectList are ignored.
462 * The number of monitors which intersect the specified region or -1 on failure.
466 NtUserEnumDisplayMonitors(
468 OPTIONAL IN LPCRECTL pRect
,
469 OPTIONAL OUT HMONITOR
*hMonitorList
,
470 OPTIONAL OUT PRECTL monitorRectList
,
471 OPTIONAL IN DWORD listSize
)
474 HMONITOR
*safeHMonitorList
= NULL
;
475 PRECTL safeRectList
= NULL
;
483 status
= MmCopyFromCaller(&rect
, pRect
, sizeof (RECT
));
484 if (!NT_SUCCESS(status
))
486 DPRINT("MmCopyFromCaller() failed!\n");
487 SetLastNtError(status
);
498 /* get visible region bounding rect */
502 DPRINT("DC_LockDc() failed!\n");
503 /* FIXME: setlasterror? */
506 dcVisRgn
= dc
->prgnVis
->BaseObject
.hHmgr
;
509 regionType
= NtGdiGetRgnBox(dcVisRgn
, &dcRect
);
512 DPRINT("NtGdiGetRgnBox() failed!\n");
515 if (regionType
== NULLREGION
)
517 if (regionType
== COMPLEXREGION
)
518 { /* TODO: warning */
521 /* if hDC and pRect are given the area of interest is pRect with
522 coordinate origin at the DC position */
525 rect
.left
+= dcRect
.left
;
526 rect
.right
+= dcRect
.left
;
527 rect
.top
+= dcRect
.top
;
528 rect
.bottom
+= dcRect
.top
;
530 /* if hDC is given and pRect is not the area of interest is the
531 bounding rect of hDC */
538 if (hDC
== NULL
&& pRect
== NULL
)
543 /* find intersecting monitors */
544 numMonitors
= IntGetMonitorsFromRect(myRect
, NULL
, NULL
, 0, 0);
545 if (numMonitors
== 0 || listSize
== 0 ||
546 (hMonitorList
== NULL
&& monitorRectList
== NULL
))
548 DPRINT("numMonitors = %d\n", numMonitors
);
552 if (hMonitorList
!= NULL
&& listSize
!= 0)
554 safeHMonitorList
= ExAllocatePool(PagedPool
, sizeof (HMONITOR
) * listSize
);
555 if (safeHMonitorList
== NULL
)
557 /* FIXME: SetLastWin32Error? */
561 if (monitorRectList
!= NULL
&& listSize
!= 0)
563 safeRectList
= ExAllocatePool(PagedPool
, sizeof (RECT
) * listSize
);
564 if (safeRectList
== NULL
)
566 ExFreePool(safeHMonitorList
);
567 /* FIXME: SetLastWin32Error? */
572 /* get intersecting monitors */
573 numMonitors
= IntGetMonitorsFromRect(myRect
, safeHMonitorList
, safeRectList
,
576 if (hDC
!= NULL
&& pRect
!= NULL
&& safeRectList
!= NULL
)
577 for (i
= 0; i
< numMonitors
; i
++)
579 safeRectList
[i
].left
-= dcRect
.left
;
580 safeRectList
[i
].right
-= dcRect
.left
;
581 safeRectList
[i
].top
-= dcRect
.top
;
582 safeRectList
[i
].bottom
-= dcRect
.top
;
586 if (hMonitorList
!= NULL
&& listSize
!= 0)
588 status
= MmCopyToCaller(hMonitorList
, safeHMonitorList
, sizeof (HMONITOR
) * listSize
);
589 ExFreePool(safeHMonitorList
);
590 if (!NT_SUCCESS(status
))
592 ExFreePool(safeRectList
);
593 SetLastNtError(status
);
597 if (monitorRectList
!= NULL
&& listSize
!= 0)
599 status
= MmCopyToCaller(monitorRectList
, safeRectList
, sizeof (RECT
) * listSize
);
600 ExFreePool(safeRectList
);
601 if (!NT_SUCCESS(status
))
603 SetLastNtError(status
);
611 /* NtUserGetMonitorInfo
613 * Retrieves information about a given monitor
618 * Handle to a monitor for which to get information
621 * Pointer to a MONITORINFO struct which is filled with the information.
622 * The cbSize member must be set to sizeof(MONITORINFO) or
623 * sizeof(MONITORINFOEX). Even if set to sizeof(MONITORINFOEX) only parts
624 * from MONITORINFO will be filled.
627 * Pointer to a UNICODE_STRING which will recieve the device's name. The
628 * length should be CCHDEVICENAME
632 * TRUE on success; FALSE on failure (calls SetLastNtError())
637 NtUserGetMonitorInfo(
638 IN HMONITOR hMonitor
,
639 OUT LPMONITORINFO pMonitorInfo
)
642 MONITORINFOEXW MonitorInfo
;
644 DECLARE_RETURN(BOOL
);
646 DPRINT("Enter NtUserGetMonitorInfo\n");
649 /* get monitor object */
650 if (!(Monitor
= UserGetMonitorObject(hMonitor
)))
652 DPRINT("Couldnt find monitor 0x%lx\n", hMonitor
);
656 if(pMonitorInfo
== NULL
)
658 SetLastNtError(STATUS_INVALID_PARAMETER
);
662 /* get size of pMonitorInfo */
663 Status
= MmCopyFromCaller(&MonitorInfo
.cbSize
, &pMonitorInfo
->cbSize
, sizeof (MonitorInfo
.cbSize
));
664 if (!NT_SUCCESS(Status
))
666 SetLastNtError(Status
);
669 if ((MonitorInfo
.cbSize
!= sizeof (MONITORINFO
)) &&
670 (MonitorInfo
.cbSize
!= sizeof (MONITORINFOEXW
)))
672 SetLastNtError(STATUS_INVALID_PARAMETER
);
676 /* fill monitor info */
677 MonitorInfo
.rcMonitor
= Monitor
->rcMonitor
;
678 MonitorInfo
.rcWork
= Monitor
->rcWork
;
679 MonitorInfo
.dwFlags
= 0;
681 if (Monitor
->IsPrimary
)
682 MonitorInfo
.dwFlags
|= MONITORINFOF_PRIMARY
;
684 /* fill device name */
685 if (MonitorInfo
.cbSize
== sizeof (MONITORINFOEXW
))
688 INT len
= Monitor
->DeviceName
.Length
;
689 if (len
>= CCHDEVICENAME
* sizeof (WCHAR
))
690 len
= (CCHDEVICENAME
- 1) * sizeof (WCHAR
);
692 memcpy(MonitorInfo
.szDevice
, Monitor
->DeviceName
.Buffer
, len
);
693 memcpy(MonitorInfo
.szDevice
+ (len
/ sizeof (WCHAR
)), &nul
, sizeof (WCHAR
));
697 Status
= MmCopyToCaller(pMonitorInfo
, &MonitorInfo
, MonitorInfo
.cbSize
);
698 if (!NT_SUCCESS(Status
))
700 DPRINT("GetMonitorInfo: MmCopyToCaller failed\n");
701 SetLastNtError(Status
);
705 DPRINT("GetMonitorInfo: success\n");
710 DPRINT("Leave NtUserGetMonitorInfo, ret=%i\n",_ret_
);
715 /* NtUserMonitorFromPoint
717 * Returns a handle to the monitor containing the given point.
722 * Point for which to find monitor
725 * Specifies the behaviour if the point isn't on any of the monitors.
728 * If the point is found a handle to the monitor is returned; if not the
729 * return value depends on dwFlags
733 NtUserMonitorFromPoint(
739 HMONITOR hMonitor
= NULL
;
742 InRect
.left
= InRect
.right
= point
.x
;
743 InRect
.top
= InRect
.bottom
= point
.y
;
745 /* find intersecting monitor */
746 NumMonitors
= IntGetMonitorsFromRect(&InRect
, &hMonitor
, NULL
, 1, 0);
749 return (HMONITOR
)NULL
;
752 if (hMonitor
== NULL
)
754 if (dwFlags
== MONITOR_DEFAULTTOPRIMARY
)
756 PMONITOR MonitorObj
= IntGetPrimaryMonitor();
758 hMonitor
= UserHMGetHandle(MonitorObj
);
760 else if (dwFlags
== MONITOR_DEFAULTTONEAREST
)
762 NumMonitors
= IntGetMonitorsFromRect(&InRect
, &hMonitor
, NULL
,
763 1, MONITOR_DEFAULTTONEAREST
);
764 /*ASSERT( (numMonitors > 0) && (hMonitor != NULL) );*/
766 /* else flag is DEFAULTTONULL */
772 /* NtUserMonitorFromRect
774 * Returns a handle to the monitor having the largest intersection with a
780 * Pointer to a RECT for which to find monitor
783 * Specifies the behaviour if no monitor intersects the given rect
786 * If a monitor intersects the rect a handle to it is returned; if not the
787 * return value depends on dwFlags
791 NtUserMonitorFromRect(
795 INT numMonitors
, iLargestArea
= -1, i
;
797 HMONITOR
*hMonitorList
;
798 HMONITOR hMonitor
= NULL
;
803 status
= MmCopyFromCaller(&rect
, pRect
, sizeof (RECT
));
804 if (!NT_SUCCESS(status
))
806 SetLastNtError(status
);
807 return (HMONITOR
)NULL
;
810 /* find intersecting monitors */
811 numMonitors
= IntGetMonitorsFromRect(&rect
, NULL
, NULL
, 0, 0);
814 return (HMONITOR
)NULL
;
817 if (numMonitors
== 0)
819 if (dwFlags
== MONITOR_DEFAULTTOPRIMARY
)
821 PMONITOR monitorObj
= IntGetPrimaryMonitor();
823 return UserHMGetHandle(monitorObj
);
825 else if (dwFlags
== MONITOR_DEFAULTTONEAREST
)
827 numMonitors
= IntGetMonitorsFromRect(&rect
, &hMonitor
, NULL
,
828 1, MONITOR_DEFAULTTONEAREST
);
829 if (numMonitors
<= 0)
832 return (HMONITOR
)NULL
;
838 /* else flag is DEFAULTTONULL */
839 return (HMONITOR
)NULL
;
842 hMonitorList
= ExAllocatePool(PagedPool
, sizeof (HMONITOR
) * numMonitors
);
843 if (hMonitorList
== NULL
)
845 /* FIXME: SetLastWin32Error? */
846 return (HMONITOR
)NULL
;
848 rectList
= ExAllocatePool(PagedPool
, sizeof (RECT
) * numMonitors
);
849 if (rectList
== NULL
)
851 ExFreePool(hMonitorList
);
852 /* FIXME: SetLastWin32Error? */
853 return (HMONITOR
)NULL
;
856 /* get intersecting monitors */
857 numMonitors
= IntGetMonitorsFromRect(&rect
, hMonitorList
, rectList
,
859 if (numMonitors
<= 0)
861 ExFreePool(hMonitorList
);
862 ExFreePool(rectList
);
863 return (HMONITOR
)NULL
;
866 /* find largest intersection */
867 for (i
= 0; i
< numMonitors
; i
++)
869 INT area
= (rectList
[i
].right
- rectList
[i
].left
) *
870 (rectList
[i
].bottom
- rectList
[i
].top
);
871 if (area
> iLargestArea
)
873 hMonitor
= hMonitorList
[i
];
877 ExFreePool(hMonitorList
);
878 ExFreePool(rectList
);
886 NtUserMonitorFromWindow(
890 PWINDOW_OBJECT Window
;
891 HMONITOR hMonitor
= NULL
;
893 DECLARE_RETURN(HMONITOR
);
895 DPRINT("Enter NtUserMonitorFromWindow\n");
898 if (!(Window
= UserGetWindowObject(hWnd
)))
900 if (dwFlags
== MONITOR_DEFAULTTONULL
)
904 IntGetMonitorsFromRect(NULL
, &hMonitor
, NULL
, 1, dwFlags
);
911 Rect
.left
= Rect
.right
= Window
->Wnd
->rcWindow
.left
;
912 Rect
.top
= Rect
.bottom
= Window
->Wnd
->rcWindow
.bottom
;
914 IntGetMonitorsFromRect(&Rect
, &hMonitor
, NULL
, 1, dwFlags
);
919 DPRINT("Leave NtUserMonitorFromWindow, ret=%i\n",_ret_
);