ReactOS  0.4.13-dev-79-gcd489d8
monitor.c
Go to the documentation of this file.
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 */
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
34 {
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
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);
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  */
75 {
76  PMONITOR pMonitor;
77 
78  if (!hMonitor)
79  {
81  return NULL;
82  }
83 
84  pMonitor = (PMONITOR)UserGetObject(gHandleTable, hMonitor, TYPE_MONITOR);
85  if (!pMonitor)
86  {
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  */
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  */
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");
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  */
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 */
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  */
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 */
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  {
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)
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
311  OPTIONAL OUT HMONITOR *phMonitorList,
312  OPTIONAL OUT PRECTL prcMonitorList,
313  OPTIONAL IN DWORD dwListSize,
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 
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  {
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,
439  if (phMonitorList == NULL)
440  {
442  goto cleanup;
443  }
444 
445  prcMonitorList = ExAllocatePoolWithTag(PagedPool,
446  sizeof(RECT) * cMonitors,
448  if (prcMonitorList == NULL)
449  {
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
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  {
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
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};
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");
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  {
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  {
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  {
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  {
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
729  IN HMONITOR hMonitor,
730  OUT LPMONITORINFO pMonitorInfoUnsafe)
731 {
732  PMONITOR pMonitor;
733  MONITORINFOEXW MonitorInfo;
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  {
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  {
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  {
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),
789  }
790 
791  /* Output data */
792  Status = MmCopyToCaller(pMonitorInfoUnsafe, &MonitorInfo, MonitorInfo.cbSize);
793  if (!NT_SUCCESS(Status))
794  {
795  TRACE("GetMonitorInfo: MmCopyToCaller failed\n");
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
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  {
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
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;
887 
888  /* Check if flags are valid */
889  if (dwFlags != MONITOR_DEFAULTTONULL &&
890  dwFlags != MONITOR_DEFAULTTOPRIMARY &&
891  dwFlags != MONITOR_DEFAULTTONEAREST)
892  {
894  return NULL;
895  }
896 
897  /* Copy rectangle to safe buffer */
898  Status = MmCopyFromCaller(&Rect, pRectUnsafe, sizeof (RECT));
899  if (!NT_SUCCESS(Status))
900  {
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,
923  if (phMonitorList == NULL)
924  {
926  goto cleanup;
927  }
928 
929  prcMonitorList = ExAllocatePoolWithTag(PagedPool,
930  sizeof(RECT) * cMonitors,
932  if (prcMonitorList == NULL)
933  {
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
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  {
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 }
__kernel_entry W32KAPI HRGN APIENTRY NtGdiCreateRectRgn(_In_ INT xLeft, _In_ INT yTop, _In_ INT xRight, _In_ INT yBottom)
#define abs(i)
Definition: fconv.c:206
VOID FASTCALL UserEnterShared(VOID)
Definition: ntuser.c:241
#define IN
Definition: typedefs.h:38
BOOL NTAPI GreSetObjectOwner(HGDIOBJ hobj, ULONG ulOwner)
Definition: gdiobj.c:1250
BOOL FASTCALL UserDeleteObject(HANDLE h, HANDLE_TYPE type)
Definition: object.c:683
BOOL NTAPI GreDeleteObject(HGDIOBJ hobj)
Definition: gdiobj.c:1153
#define TRUE
Definition: types.h:120
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
FORCEINLINE PDC DC_LockDc(HDC hdc)
Definition: dc.h:219
NTSTATUS NTAPI UserUpdateMonitorSize(IN HDEV hDev)
Definition: monitor.c:225
PMONITOR FASTCALL UserMonitorFromPoint(IN POINT pt, IN DWORD dwFlags)
Definition: monitor.c:481
static UINT IntGetMonitorsFromRect(OPTIONAL IN LPCRECTL pRect, OPTIONAL OUT HMONITOR *phMonitorList, OPTIONAL OUT PRECTL prcMonitorList, OPTIONAL IN DWORD dwListSize, OPTIONAL IN DWORD dwFlags)
Definition: monitor.c:310
#define pt(x, y)
Definition: drawing.c:79
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
LONG NTSTATUS
Definition: precomp.h:26
HDEV hDev
Definition: monitor.h:23
static HDC
Definition: imagelist.c:92
HWND hWnd
Definition: settings.c:17
#define COMPLEXREGION
Definition: wingdi.h:362
#define NULLREGION
Definition: wingdi.h:360
LONG top
Definition: windef.h:292
long bottom
Definition: polytest.cpp:53
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define MmCopyFromCaller
Definition: polytest.cpp:29
BOOL FASTCALL UserDereferenceObject(PVOID Object)
Definition: object.c:610
#define MmCopyToCaller(x, y, z)
Definition: mmcopy.h:19
uint16_t * PWCHAR
Definition: typedefs.h:54
LONG left
Definition: windef.h:291
LONG right
Definition: windef.h:293
#define FASTCALL
Definition: nt_native.h:50
int32_t INT
Definition: typedefs.h:56
PSERVERINFO gpsi
Definition: main.c:27
SHORT cWndStack
Definition: monitor.h:22
RECT rcWork
Definition: monitor.h:19
NTSTATUS NTAPI UserAttachMonitor(IN HDEV hDev)
Definition: monitor.c:129
PVOID FASTCALL UserCreateObject(PUSER_HANDLE_TABLE ht, PDESKTOP pDesktop, PTHREADINFO pti, HANDLE *h, HANDLE_TYPE type, ULONG size)
Definition: object.c:535
PMONITOR NTAPI UserMonitorFromRect(PRECTL pRect, DWORD dwFlags)
Definition: monitor.c:405
struct _PDEVOBJ * PPDEVOBJ
long right
Definition: polytest.cpp:53
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
unsigned int BOOL
Definition: ntddk_ex.h:94
#define ERROR_INVALID_MONITOR_HANDLE
Definition: winerror.h:942
long top
Definition: polytest.cpp:53
HMONITOR APIENTRY NtUserMonitorFromWindow(IN HWND hWnd, IN DWORD dwFlags)
Definition: monitor.c:967
_Out_opt_ int _Out_opt_ int * cy
Definition: commctrl.h:570
smooth NULL
Definition: ftsmooth.c:416
struct _MONITOR * PMONITOR
LONG cx
Definition: windef.h:319
GLint GLint bottom
Definition: glext.h:7726
long left
Definition: polytest.cpp:53
PWND FASTCALL UserGetWindowObject(HWND hWnd)
Definition: window.c:103
NTSTATUS NTAPI UserDetachMonitor(IN HDEV hDev)
Definition: monitor.c:179
BOOL APIENTRY NtUserGetMonitorInfo(IN HMONITOR hMonitor, OUT LPMONITORINFO pMonitorInfoUnsafe)
Definition: monitor.c:728
#define USERTAG_MONITORRECTS
Definition: tags.h:253
#define UserHMGetHandle(obj)
Definition: ntuser.h:208
PMONITOR NTAPI UserGetMonitorObject(IN HMONITOR hMonitor)
Definition: monitor.c:74
#define TRACE(s)
Definition: solgame.cpp:4
Definition: polytest.cpp:40
DWORD IsPrimary
Definition: monitor.h:15
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
BOOL FASTCALL IntGdiSetRegionOwner(HRGN hRgn, DWORD OwnerMask)
Definition: region.c:2481
WCHAR szDevice[CCHDEVICENAME]
Definition: winuser.h:3746
BOOL FASTCALL RECTL_bIntersectRect(_Out_ RECTL *prclDst, _In_ const RECTL *prcl1, _In_ const RECTL *prcl2)
Definition: rect.c:55
unsigned long DWORD
Definition: ntddk_ex.h:95
static PMONITOR gMonitorList
Definition: monitor.c:19
PSIZEL FASTCALL PDEVOBJ_sizl(PPDEVOBJ ppdev, PSIZEL psizl)
Definition: pdevobj.c:973
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
DBG_DEFAULT_CHANNEL(UserMonitor)
HDC hdc
Definition: main.c:9
_In_ PCCERT_CONTEXT _In_ DWORD dwFlags
Definition: wincrypt.h:1175
RECT rcWindow
Definition: ntuser.h:680
HMONITOR APIENTRY NtUserMonitorFromPoint(IN POINT pt, IN DWORD dwFlags)
Definition: monitor.c:827
#define GDI_OBJ_HMGR_POWNED
Definition: ntgdihdl.h:117
NTSTRSAFEAPI RtlStringCbCopyNExW(_Out_writes_bytes_(cbDest) NTSTRSAFE_PWSTR pszDest, _In_ size_t cbDest, _In_reads_bytes_(cbToCopy) STRSAFE_LPCWSTR pszSrc, _In_ size_t cbToCopy, _Outptr_opt_result_bytebuffer_(*pcbRemaining) NTSTRSAFE_PWSTR *ppszDestEnd, _Out_opt_ size_t *pcbRemaining, _In_ STRSAFE_DWORD dwFlags)
Definition: ntstrsafe.h:537
INT APIENTRY NtUserEnumDisplayMonitors(OPTIONAL IN HDC hdc, OPTIONAL IN LPCRECTL pUnsafeRect, OPTIONAL OUT HMONITOR *phUnsafeMonitorList, OPTIONAL OUT PRECTL prcUnsafeMonitorList, OPTIONAL IN DWORD dwListSize)
Definition: monitor.c:543
VOID FASTCALL SetLastNtError(NTSTATUS Status)
Definition: error.c:36
struct _MONITOR * pMonitorNext
Definition: monitor.h:7
Status
Definition: gdiplustypes.h:24
static void IntDestroyMonitorObject(IN PMONITOR pMonitor)
Definition: monitor.c:50
Definition: ntuser.h:657
VOID FASTCALL UserLeave(VOID)
Definition: ntuser.c:255
FORCEINLINE VOID DC_UnlockDc(PDC pdc)
Definition: dc.h:237
PVOID UserGetObject(PUSER_HANDLE_TABLE ht, HANDLE handle, HANDLE_TYPE type)
Definition: object.c:462
static PMONITOR IntCreateMonitorObject(VOID)
Definition: monitor.c:33
#define GDI_OBJ_HMGR_PUBLIC
Definition: ntgdihdl.h:116
#define min(a, b)
Definition: monoChain.cc:55
unsigned int UINT
Definition: ndis.h:50
_Out_opt_ int * cx
Definition: commctrl.h:570
PMONITOR NTAPI UserGetPrimaryMonitor(VOID)
Definition: monitor.c:102
#define OUT
Definition: typedefs.h:39
RECT rcMonitor
Definition: monitor.h:18
unsigned int ULONG
Definition: retypes.h:1
LONG bottom
Definition: windef.h:294
char * cleanup(char *str)
Definition: wpickclick.c:99
HMONITOR APIENTRY NtUserMonitorFromRect(IN LPCRECTL pRectUnsafe, IN DWORD dwFlags)
Definition: monitor.c:877
#define STRSAFE_FILL_BEHIND_NULL
Definition: ntstrsafe.h:45
GLdouble GLdouble GLdouble GLdouble top
Definition: glext.h:10859
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
INT FASTCALL REGION_GetRgnBox(PREGION Rgn, PRECTL pRect)
Definition: region.c:2565
return STATUS_SUCCESS
Definition: btrfs.c:2725
PUSER_HANDLE_TABLE gHandleTable
Definition: object.c:13
LONG cy
Definition: windef.h:320
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define ERROR_INVALID_FLAGS
Definition: winerror.h:583
ENGAPI VOID APIENTRY EngSetLastError(_In_ ULONG iError)
Definition: error.c:27
HRGN hrgnMonitor
Definition: monitor.h:20
#define APIENTRY
Definition: api.h:79
struct Rect Rect
#define _Analysis_assume_(expr)
Definition: no_sal2.h:10
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68