/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * PURPOSE: pMonitor support * FILE: subsys/win32k/ntuser/monitor.c * PROGRAMERS: Anich Gregor (blight@blight.eu.org) * Rafal Harabien (rafalh@reactos.org) */ #include DBG_DEFAULT_CHANNEL(UserMonitor); #define NDEBUG #include /* GLOBALS *******************************************************************/ /* List of monitors */ static PMONITOR gMonitorList = NULL; /* PRIVATE FUNCTIONS **********************************************************/ /* IntCreateMonitorObject * * Creates a MONITOR * * Return value * If the function succeeds a pointer to a MONITOR is returned. On failure * NULL is returned. */ static PMONITOR IntCreateMonitorObject(VOID) { return UserCreateObject(gHandleTable, NULL, NULL, NULL, TYPE_MONITOR, sizeof(MONITOR)); } /* IntDestroyMonitorObject * * Destroys a MONITOR * You have to be the owner of the monitors lock to safely destroy it. * * Arguments * * pMonitor * Pointer to the MONITOR which shall be deleted */ static void IntDestroyMonitorObject(IN PMONITOR pMonitor) { /* Remove monitor region */ if (pMonitor->hrgnMonitor) { GreSetObjectOwner(pMonitor->hrgnMonitor, GDI_OBJ_HMGR_POWNED); GreDeleteObject(pMonitor->hrgnMonitor); } /* Destroy monitor object */ UserDereferenceObject(pMonitor); UserDeleteObject(UserHMGetHandle(pMonitor), TYPE_MONITOR); } /* UserGetMonitorObject * * Returns monitor object from handle or sets last error if handle is invalid * * Arguments * * hMonitor * Handle of MONITOR object */ PMONITOR NTAPI UserGetMonitorObject(IN HMONITOR hMonitor) { PMONITOR pMonitor; if (!hMonitor) { EngSetLastError(ERROR_INVALID_MONITOR_HANDLE); return NULL; } pMonitor = (PMONITOR)UserGetObject(gHandleTable, hMonitor, TYPE_MONITOR); if (!pMonitor) { EngSetLastError(ERROR_INVALID_MONITOR_HANDLE); return NULL; } return pMonitor; } /* UserGetPrimaryMonitor * * Returns a PMONITOR for the primary monitor * * Return value * PMONITOR */ PMONITOR NTAPI UserGetPrimaryMonitor(VOID) { PMONITOR pMonitor; /* Find primary monitor */ for (pMonitor = gMonitorList; pMonitor != NULL; pMonitor = pMonitor->pMonitorNext) { if (pMonitor->IsPrimary) break; } return pMonitor; } /* UserAttachMonitor * * Creates a new MONITOR and appends it to the list of monitors. * * Arguments * * pGdiDevice Pointer to the PDEVOBJ onto which the monitor was attached * DisplayNumber Display Number (starting with 0) * * Return value * Returns a NTSTATUS */ NTSTATUS NTAPI UserAttachMonitor(IN HDEV hDev) { PMONITOR pMonitor; TRACE("Attaching monitor...\n"); /* Create new monitor object */ pMonitor = IntCreateMonitorObject(); if (pMonitor == NULL) { TRACE("Couldnt create monitor object\n"); return STATUS_INSUFFICIENT_RESOURCES; } pMonitor->hDev = hDev; pMonitor->cWndStack = 0; if (gMonitorList == NULL) { TRACE("Primary monitor is beeing attached\n"); pMonitor->IsPrimary = TRUE; gMonitorList = pMonitor; } else { PMONITOR pmonLast = gMonitorList; TRACE("Additional monitor is beeing attached\n"); while (pmonLast->pMonitorNext != NULL) pmonLast = pmonLast->pMonitorNext; pmonLast->pMonitorNext = pMonitor; } UserUpdateMonitorSize(hDev); return STATUS_SUCCESS; } /* UserDetachMonitor * * Deletes a MONITOR and removes it from the list of monitors. * * Arguments * * pGdiDevice Pointer to the PDEVOBJ from which the monitor was detached * * Return value * Returns a NTSTATUS */ NTSTATUS NTAPI UserDetachMonitor(IN HDEV hDev) { PMONITOR pMonitor = gMonitorList, *pLink = &gMonitorList; /* Find monitor attached to given device */ while (pMonitor != NULL) { if (pMonitor->hDev == hDev) break; pLink = &pMonitor->pMonitorNext; pMonitor = pMonitor->pMonitorNext; } if (pMonitor == NULL) { /* No monitor has been found */ return STATUS_INVALID_PARAMETER; } /* We destroy primary monitor - set next as primary */ if (pMonitor->IsPrimary && pMonitor->pMonitorNext != NULL) pMonitor->pMonitorNext->IsPrimary = TRUE; /* Update Next ptr in previous monitor */ *pLink = pMonitor->pMonitorNext; /* Finally destroy monitor */ IntDestroyMonitorObject(pMonitor); return STATUS_SUCCESS; } /* UserUpdateMonitorSize * * Reset size of the monitor using atached device * * Arguments * * PMONITOR * pGdiDevice Pointer to the PDEVOBJ, which size has changed * * Return value * Returns a NTSTATUS */ NTSTATUS NTAPI UserUpdateMonitorSize(IN HDEV hDev) { PMONITOR pMonitor; SIZEL DeviceSize; /* Find monitor attached to given device */ for (pMonitor = gMonitorList; pMonitor != NULL; pMonitor = pMonitor->pMonitorNext) { if (pMonitor->hDev == hDev) break; } if (pMonitor == NULL) { /* No monitor has been found */ return STATUS_INVALID_PARAMETER; } /* Get the size of the hdev */ PDEVOBJ_sizl((PPDEVOBJ)hDev, &DeviceSize); /* Update monitor size */ pMonitor->rcMonitor.left = 0; pMonitor->rcMonitor.top = 0; pMonitor->rcMonitor.right = pMonitor->rcMonitor.left + DeviceSize.cx; pMonitor->rcMonitor.bottom = pMonitor->rcMonitor.top + DeviceSize.cy; pMonitor->rcWork = pMonitor->rcMonitor; /* Destroy monitor region... */ if (pMonitor->hrgnMonitor) { GreSetObjectOwner(pMonitor->hrgnMonitor, GDI_OBJ_HMGR_POWNED); GreDeleteObject(pMonitor->hrgnMonitor); } /* ...and create new one */ pMonitor->hrgnMonitor = NtGdiCreateRectRgn( pMonitor->rcMonitor.left, pMonitor->rcMonitor.top, pMonitor->rcMonitor.right, pMonitor->rcMonitor.bottom); if (pMonitor->hrgnMonitor) IntGdiSetRegionOwner(pMonitor->hrgnMonitor, GDI_OBJ_HMGR_PUBLIC); // // Should be Virtual accumulation of all the available monitors. // gpsi->rcScreenReal = pMonitor->rcMonitor; return STATUS_SUCCESS; } /* IntGetMonitorsFromRect * * Returns a list of monitor handles/rectangles. The rectangles in the list are * the areas of intersection with the monitors. * * Arguments * * pRect * Rectangle in desktop coordinates. If this is NULL all monitors are * returned and the rect list is filled with the sizes of the monitors. * * phMonitorList * Pointer to an array of HMONITOR which is filled with monitor handles. * Can be NULL * * prcMonitorList * Pointer to an array of RECT which is filled with intersection rects in * desktop coordinates. * Can be NULL, will be ignored if no intersecting monitor is found and * flags is MONITOR_DEFAULTTONEAREST * * dwListSize * Size of the phMonitorList and prcMonitorList arguments. If this is zero * phMonitorList and prcMonitorList are ignored. * * dwFlags * Either 0 or MONITOR_DEFAULTTONEAREST (ignored if rect is NULL) * * Returns * The number of monitors which intersect the specified region. */ static UINT IntGetMonitorsFromRect(OPTIONAL IN LPCRECTL pRect, OPTIONAL OUT HMONITOR *phMonitorList, OPTIONAL OUT PRECTL prcMonitorList, OPTIONAL IN DWORD dwListSize, OPTIONAL IN DWORD dwFlags) { PMONITOR pMonitor, pNearestMonitor = NULL, pPrimaryMonitor = NULL; UINT cMonitors = 0; ULONG iNearestDistance = 0xffffffff; /* Find monitors which intersects the rectangle */ for (pMonitor = gMonitorList; pMonitor != NULL; pMonitor = pMonitor->pMonitorNext) { RECTL MonitorRect, IntersectionRect; MonitorRect = pMonitor->rcMonitor; TRACE("MonitorRect: left = %d, top = %d, right = %d, bottom = %d\n", MonitorRect.left, MonitorRect.top, MonitorRect.right, MonitorRect.bottom); /* Save primary monitor for later usage */ if (dwFlags == MONITOR_DEFAULTTOPRIMARY && pMonitor->IsPrimary) pPrimaryMonitor = pMonitor; /* Check if a rect is given */ if (pRect == NULL) { /* No rect given, so use the full monitor rect */ IntersectionRect = MonitorRect; } /* We have a rect, calculate intersection */ else if (!RECTL_bIntersectRect(&IntersectionRect, &MonitorRect, pRect)) { /* Rects did not intersect */ if (dwFlags == MONITOR_DEFAULTTONEAREST) { ULONG cx, cy, iDistance; /* Get x and y distance */ cx = min(abs(MonitorRect.left - pRect->right), abs(pRect->left - MonitorRect.right)); cy = min(abs(MonitorRect.top - pRect->bottom), abs(pRect->top - MonitorRect.bottom)); /* Calculate distance square */ iDistance = cx * cx + cy * cy; /* Check if this is the new nearest monitor */ if (iDistance < iNearestDistance) { iNearestDistance = iDistance; pNearestMonitor = pMonitor; } } continue; } /* Check if there's space in the buffer */ if (cMonitors < dwListSize) { /* Save monitor data */ if (phMonitorList != NULL) phMonitorList[cMonitors] = UserHMGetHandle(pMonitor); if (prcMonitorList != NULL) prcMonitorList[cMonitors] = IntersectionRect; } /* Increase count of found monitors */ cMonitors++; } /* Nothing has been found? */ if (cMonitors == 0) { /* Check if we shall default to the nearest monitor */ if (dwFlags == MONITOR_DEFAULTTONEAREST && pNearestMonitor) { if (phMonitorList && dwListSize > 0) phMonitorList[cMonitors] = UserHMGetHandle(pNearestMonitor); cMonitors++; } /* Check if we shall default to the primary monitor */ else if (dwFlags == MONITOR_DEFAULTTOPRIMARY && pPrimaryMonitor) { if (phMonitorList != NULL && dwListSize > 0) phMonitorList[cMonitors] = UserHMGetHandle(pPrimaryMonitor); cMonitors++; } } return cMonitors; } PMONITOR NTAPI UserMonitorFromRect( PRECTL pRect, DWORD dwFlags) { ULONG cMonitors, LargestArea = 0, i; PRECTL prcMonitorList = NULL; HMONITOR *phMonitorList = NULL; HMONITOR hMonitor = NULL; /* Check if flags are valid */ if (dwFlags != MONITOR_DEFAULTTONULL && dwFlags != MONITOR_DEFAULTTOPRIMARY && dwFlags != MONITOR_DEFAULTTONEAREST) { EngSetLastError(ERROR_INVALID_FLAGS); return NULL; } /* Find intersecting monitors */ cMonitors = IntGetMonitorsFromRect(pRect, &hMonitor, NULL, 1, dwFlags); if (cMonitors <= 1) { /* No or one monitor found. Just return handle. */ goto cleanup; } /* There is more than one monitor. Find monitor with largest intersection. Temporary reset hMonitor */ hMonitor = NULL; /* Allocate helper buffers */ phMonitorList = ExAllocatePoolWithTag(PagedPool, sizeof(HMONITOR) * cMonitors, USERTAG_MONITORRECTS); if (phMonitorList == NULL) { EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); goto cleanup; } prcMonitorList = ExAllocatePoolWithTag(PagedPool, sizeof(RECT) * cMonitors, USERTAG_MONITORRECTS); if (prcMonitorList == NULL) { EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); goto cleanup; } /* Get intersecting monitors again but now with rectangle list */ cMonitors = IntGetMonitorsFromRect(pRect, phMonitorList, prcMonitorList, cMonitors, 0); /* Find largest intersection */ for (i = 0; i < cMonitors; i++) { ULONG Area = (prcMonitorList[i].right - prcMonitorList[i].left) * (prcMonitorList[i].bottom - prcMonitorList[i].top); if (Area >= LargestArea) { hMonitor = phMonitorList[i]; LargestArea = Area; } } cleanup: if (phMonitorList) ExFreePoolWithTag(phMonitorList, USERTAG_MONITORRECTS); if (prcMonitorList) ExFreePoolWithTag(prcMonitorList, USERTAG_MONITORRECTS); return UserGetMonitorObject(hMonitor); } PMONITOR FASTCALL UserMonitorFromPoint( IN POINT pt, IN DWORD dwFlags) { RECTL rc; HMONITOR hMonitor = NULL; /* Check if flags are valid */ if (dwFlags != MONITOR_DEFAULTTONULL && dwFlags != MONITOR_DEFAULTTOPRIMARY && dwFlags != MONITOR_DEFAULTTONEAREST) { EngSetLastError(ERROR_INVALID_FLAGS); return NULL; } /* Fill rect (bottom-right exclusive) */ rc.left = pt.x; rc.right = pt.x + 1; rc.top = pt.y; rc.bottom = pt.y + 1; /* Find intersecting monitor */ IntGetMonitorsFromRect(&rc, &hMonitor, NULL, 1, dwFlags); return UserGetMonitorObject(hMonitor); } /* PUBLIC FUNCTIONS ***********************************************************/ /* NtUserEnumDisplayMonitors * * Enumerates display monitors which intersect the given HDC/cliprect * * Arguments * * hdc * Handle to a DC for which to enum intersecting monitors. If this is NULL * it returns all monitors which are part of the current virtual screen. * * pUnsafeRect * Clipping rectangle with coordinate system origin at the DCs origin if the * given HDC is not NULL or in virtual screen coordinated if it is NULL. * Can be NULL * * phUnsafeMonitorList * Pointer to an array of HMONITOR which is filled with monitor handles. * Can be NULL * * prcUnsafeMonitorList * Pointer to an array of RECT which is filled with intersection rectangles. * Can be NULL * * dwListSize * Size of the hMonitorList and monitorRectList arguments. If this is zero * hMonitorList and monitorRectList are ignored. * * Returns * The number of monitors which intersect the specified region or -1 on failure. */ INT APIENTRY NtUserEnumDisplayMonitors( OPTIONAL IN HDC hdc, OPTIONAL IN LPCRECTL pUnsafeRect, OPTIONAL OUT HMONITOR *phUnsafeMonitorList, OPTIONAL OUT PRECTL prcUnsafeMonitorList, OPTIONAL IN DWORD dwListSize) { UINT cMonitors, i; INT iRet = -1; HMONITOR *phMonitorList = NULL; PRECTL prcMonitorList = NULL; RECTL rc, *pRect; RECTL DcRect = {0}; NTSTATUS Status; /* Get rectangle */ if (pUnsafeRect != NULL) { Status = MmCopyFromCaller(&rc, pUnsafeRect, sizeof(RECT)); if (!NT_SUCCESS(Status)) { TRACE("MmCopyFromCaller() failed!\n"); SetLastNtError(Status); return -1; } } if (hdc != NULL) { PDC pDc; INT iRgnType; /* Get visible region bounding rect */ pDc = DC_LockDc(hdc); if (pDc == NULL) { TRACE("DC_LockDc() failed!\n"); /* FIXME: setlasterror? */ return -1; } iRgnType = REGION_GetRgnBox(pDc->prgnVis, &DcRect); DC_UnlockDc(pDc); if (iRgnType == 0) { TRACE("NtGdiGetRgnBox() failed!\n"); return -1; } if (iRgnType == NULLREGION) return 0; if (iRgnType == COMPLEXREGION) { /* TODO: Warning */ } /* If hdc and pRect are given the area of interest is pRect with coordinate origin at the DC position */ if (pUnsafeRect != NULL) { rc.left += DcRect.left; rc.right += DcRect.left; rc.top += DcRect.top; rc.bottom += DcRect.top; } /* If hdc is given and pRect is not the area of interest is the bounding rect of hdc */ else { rc = DcRect; } } if (hdc == NULL && pUnsafeRect == NULL) pRect = NULL; else pRect = &rc; UserEnterShared(); /* Find intersecting monitors */ cMonitors = IntGetMonitorsFromRect(pRect, NULL, NULL, 0, MONITOR_DEFAULTTONULL); if (cMonitors == 0 || dwListSize == 0 || (phUnsafeMonitorList == NULL && prcUnsafeMonitorList == NULL)) { /* Simple case - just return monitors count */ TRACE("cMonitors = %u\n", cMonitors); iRet = cMonitors; goto cleanup; } /* Allocate safe buffers */ if (phUnsafeMonitorList != NULL && dwListSize != 0) { phMonitorList = ExAllocatePoolWithTag(PagedPool, sizeof (HMONITOR) * dwListSize, USERTAG_MONITORRECTS); if (phMonitorList == NULL) { EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); goto cleanup; } } if (prcUnsafeMonitorList != NULL && dwListSize != 0) { prcMonitorList = ExAllocatePoolWithTag(PagedPool, sizeof(RECT) * dwListSize,USERTAG_MONITORRECTS); if (prcMonitorList == NULL) { EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); goto cleanup; } } /* Get intersecting monitors */ cMonitors = IntGetMonitorsFromRect(pRect, phMonitorList, prcMonitorList, dwListSize, MONITOR_DEFAULTTONULL); if (hdc != NULL && pRect != NULL && prcMonitorList != NULL) { for (i = 0; i < min(cMonitors, dwListSize); i++) { _Analysis_assume_(i < dwListSize); prcMonitorList[i].left -= DcRect.left; prcMonitorList[i].right -= DcRect.left; prcMonitorList[i].top -= DcRect.top; prcMonitorList[i].bottom -= DcRect.top; } } /* Output result */ if (phUnsafeMonitorList != NULL && dwListSize != 0) { Status = MmCopyToCaller(phUnsafeMonitorList, phMonitorList, sizeof(HMONITOR) * dwListSize); if (!NT_SUCCESS(Status)) { SetLastNtError(Status); goto cleanup; } } if (prcUnsafeMonitorList != NULL && dwListSize != 0) { Status = MmCopyToCaller(prcUnsafeMonitorList, prcMonitorList, sizeof(RECT) * dwListSize); if (!NT_SUCCESS(Status)) { SetLastNtError(Status); goto cleanup; } } /* Return monitors count on success */ iRet = cMonitors; cleanup: if (phMonitorList) ExFreePoolWithTag(phMonitorList, USERTAG_MONITORRECTS); if (prcMonitorList) ExFreePoolWithTag(prcMonitorList, USERTAG_MONITORRECTS); UserLeave(); return iRet; } /* NtUserGetMonitorInfo * * Retrieves information about a given monitor * * Arguments * * hMonitor * Handle to a monitor for which to get information * * pMonitorInfoUnsafe * Pointer to a MONITORINFO struct which is filled with the information. * The cbSize member must be set to sizeof(MONITORINFO) or * sizeof(MONITORINFOEX). Even if set to sizeof(MONITORINFOEX) only parts * from MONITORINFO will be filled. * * pDevice * Pointer to a UNICODE_STRING which will receive the device's name. The * length should be CCHDEVICENAME * Can be NULL * * Return value * TRUE on success; FALSE on failure (calls SetLastNtError()) * */ BOOL APIENTRY NtUserGetMonitorInfo( IN HMONITOR hMonitor, OUT LPMONITORINFO pMonitorInfoUnsafe) { PMONITOR pMonitor; MONITORINFOEXW MonitorInfo; NTSTATUS Status; BOOL bRet = FALSE; PWCHAR pwstrDeviceName; TRACE("Enter NtUserGetMonitorInfo\n"); UserEnterShared(); /* Get monitor object */ pMonitor = UserGetMonitorObject(hMonitor); if (!pMonitor) { TRACE("Couldnt find monitor %p\n", hMonitor); goto cleanup; } /* Check if pMonitorInfoUnsafe is valid */ if(pMonitorInfoUnsafe == NULL) { SetLastNtError(STATUS_INVALID_PARAMETER); goto cleanup; } pwstrDeviceName = ((PPDEVOBJ)(pMonitor->hDev))->pGraphicsDevice->szWinDeviceName; /* Get size of pMonitorInfoUnsafe */ Status = MmCopyFromCaller(&MonitorInfo.cbSize, &pMonitorInfoUnsafe->cbSize, sizeof(MonitorInfo.cbSize)); if (!NT_SUCCESS(Status)) { SetLastNtError(Status); goto cleanup; } /* Check if size of struct is valid */ if (MonitorInfo.cbSize != sizeof(MONITORINFO) && MonitorInfo.cbSize != sizeof(MONITORINFOEXW)) { SetLastNtError(STATUS_INVALID_PARAMETER); goto cleanup; } /* Fill monitor info */ MonitorInfo.rcMonitor = pMonitor->rcMonitor; MonitorInfo.rcWork = pMonitor->rcWork; MonitorInfo.dwFlags = 0; if (pMonitor->IsPrimary) MonitorInfo.dwFlags |= MONITORINFOF_PRIMARY; /* Fill device name */ if (MonitorInfo.cbSize == sizeof(MONITORINFOEXW)) { RtlStringCbCopyNExW(MonitorInfo.szDevice, sizeof(MonitorInfo.szDevice), pwstrDeviceName, (wcslen(pwstrDeviceName)+1) * sizeof(WCHAR), NULL, NULL, STRSAFE_FILL_BEHIND_NULL); } /* Output data */ Status = MmCopyToCaller(pMonitorInfoUnsafe, &MonitorInfo, MonitorInfo.cbSize); if (!NT_SUCCESS(Status)) { TRACE("GetMonitorInfo: MmCopyToCaller failed\n"); SetLastNtError(Status); goto cleanup; } TRACE("GetMonitorInfo: success\n"); bRet = TRUE; cleanup: TRACE("Leave NtUserGetMonitorInfo, ret=%i\n", bRet); UserLeave(); return bRet; } /* NtUserMonitorFromPoint * * Returns a handle to the monitor containing the given point. * * Arguments * * pt * Point for which to find monitor * * dwFlags * Specifies the behaviour if the point isn't on any of the monitors. * * Return value * If the point is found a handle to the monitor is returned; if not the * return value depends on dwFlags */ HMONITOR APIENTRY NtUserMonitorFromPoint( IN POINT pt, IN DWORD dwFlags) { RECTL rc; HMONITOR hMonitor = NULL; /* Check if flags are valid */ if (dwFlags != MONITOR_DEFAULTTONULL && dwFlags != MONITOR_DEFAULTTOPRIMARY && dwFlags != MONITOR_DEFAULTTONEAREST) { EngSetLastError(ERROR_INVALID_FLAGS); return NULL; } /* Fill rect (bottom-right exclusive) */ rc.left = pt.x; rc.right = pt.x + 1; rc.top = pt.y; rc.bottom = pt.y + 1; UserEnterShared(); /* Find intersecting monitor */ IntGetMonitorsFromRect(&rc, &hMonitor, NULL, 1, dwFlags); UserLeave(); return hMonitor; } /* NtUserMonitorFromRect * * Returns a handle to the monitor having the largest intersection with a * given rectangle * * Arguments * * pRectUnsafe * Pointer to a RECT for which to find monitor * * dwFlags * Specifies the behaviour if no monitor intersects the given rect * * Return value * If a monitor intersects the rect a handle to it is returned; if not the * return value depends on dwFlags */ HMONITOR APIENTRY NtUserMonitorFromRect( IN LPCRECTL pRectUnsafe, IN DWORD dwFlags) { ULONG cMonitors, LargestArea = 0, i; PRECTL prcMonitorList = NULL; HMONITOR *phMonitorList = NULL; HMONITOR hMonitor = NULL; RECTL Rect; NTSTATUS Status; /* Check if flags are valid */ if (dwFlags != MONITOR_DEFAULTTONULL && dwFlags != MONITOR_DEFAULTTOPRIMARY && dwFlags != MONITOR_DEFAULTTONEAREST) { EngSetLastError(ERROR_INVALID_FLAGS); return NULL; } /* Copy rectangle to safe buffer */ Status = MmCopyFromCaller(&Rect, pRectUnsafe, sizeof (RECT)); if (!NT_SUCCESS(Status)) { SetLastNtError(Status); return NULL; } UserEnterShared(); /* Find intersecting monitors */ cMonitors = IntGetMonitorsFromRect(&Rect, &hMonitor, NULL, 1, dwFlags); if (cMonitors <= 1) { /* No or one monitor found. Just return handle. */ goto cleanup; } /* There is more than one monitor. Find monitor with largest intersection. Temporary reset hMonitor */ hMonitor = NULL; /* Allocate helper buffers */ phMonitorList = ExAllocatePoolWithTag(PagedPool, sizeof(HMONITOR) * cMonitors, USERTAG_MONITORRECTS); if (phMonitorList == NULL) { EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); goto cleanup; } prcMonitorList = ExAllocatePoolWithTag(PagedPool, sizeof(RECT) * cMonitors, USERTAG_MONITORRECTS); if (prcMonitorList == NULL) { EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); goto cleanup; } /* Get intersecting monitors again but now with rectangle list */ cMonitors = IntGetMonitorsFromRect(&Rect, phMonitorList, prcMonitorList, cMonitors, 0); /* Find largest intersection */ for (i = 0; i < cMonitors; i++) { ULONG Area = (prcMonitorList[i].right - prcMonitorList[i].left) * (prcMonitorList[i].bottom - prcMonitorList[i].top); if (Area >= LargestArea) { hMonitor = phMonitorList[i]; LargestArea = Area; } } cleanup: if (phMonitorList) ExFreePoolWithTag(phMonitorList, USERTAG_MONITORRECTS); if (prcMonitorList) ExFreePoolWithTag(prcMonitorList, USERTAG_MONITORRECTS); UserLeave(); return hMonitor; } HMONITOR APIENTRY NtUserMonitorFromWindow( IN HWND hWnd, IN DWORD dwFlags) { PWND pWnd; HMONITOR hMonitor = NULL; RECTL Rect = {0, 0, 0, 0}; TRACE("Enter NtUserMonitorFromWindow\n"); /* Check if flags are valid */ if (dwFlags != MONITOR_DEFAULTTONULL && dwFlags != MONITOR_DEFAULTTOPRIMARY && dwFlags != MONITOR_DEFAULTTONEAREST) { EngSetLastError(ERROR_INVALID_FLAGS); return NULL; } UserEnterShared(); /* If window is given, use it first */ if (hWnd) { /* Get window object */ pWnd = UserGetWindowObject(hWnd); if (!pWnd) goto cleanup; /* Find only monitors which have intersection with given window */ Rect.left = Rect.right = pWnd->rcWindow.left; Rect.top = Rect.bottom = pWnd->rcWindow.bottom; } /* Find monitors now */ IntGetMonitorsFromRect(&Rect, &hMonitor, NULL, 1, dwFlags); cleanup: TRACE("Leave NtUserMonitorFromWindow, ret=%p\n", hMonitor); UserLeave(); return hMonitor; }