/// <summary> /// Get the min/max window size for this window /// Correctly accounting for the task bar size and position /// </summary> /// <param name="hwnd"></param> /// <param name="lParam"></param> private void WmGetMinMaxInfo(System.IntPtr hwnd, System.IntPtr lParam) { // Get the point position to determine what screen we are on GetCursorPos(out var lMousePosition); // Now get the current screen var lCurrentScreen = mBeingMoved ? // If being dragged get it from the mouse position MonitorFromPoint(lMousePosition, MonitorOptions.MONITOR_DEFAULTTONULL) : // Otherwise get it from the window position (for example being moved via Win + Arrow) // in case the mouse is on another monitor MonitorFromWindow(hwnd, MonitorOptions.MONITOR_DEFAULTTONULL); var lPrimaryScreen = MonitorFromPoint(new POINT(0, 0), MonitorOptions.MONITOR_DEFAULTTOPRIMARY); // Try and get the current screen information var lCurrentScreenInfo = new MONITORINFO(); if (GetMonitorInfo(lCurrentScreen, lCurrentScreenInfo) == false) { return; } // Try and get the primary screen information var lPrimaryScreenInfo = new MONITORINFO(); if (GetMonitorInfo(lPrimaryScreen, lPrimaryScreenInfo) == false) { return; } // NOTE: Always update it // If this has changed from the last one, update the transform //if (lCurrentScreen != mLastScreen || mMonitorDpi == null) mMonitorDpi = VisualTreeHelper.GetDpi(mWindow); // Store last know screen mLastScreen = lCurrentScreen; // Get work area sizes and rations var currentX = lCurrentScreenInfo.RCWork.Left - lCurrentScreenInfo.RCMonitor.Left; var currentY = lCurrentScreenInfo.RCWork.Top - lCurrentScreenInfo.RCMonitor.Top; var currentWidth = (lCurrentScreenInfo.RCWork.Right - lCurrentScreenInfo.RCWork.Left); var currentHeight = (lCurrentScreenInfo.RCWork.Bottom - lCurrentScreenInfo.RCWork.Top); var currentRatio = (float)currentWidth / (float)currentHeight; var primaryX = lPrimaryScreenInfo.RCWork.Left - lPrimaryScreenInfo.RCMonitor.Left; var primaryY = lPrimaryScreenInfo.RCWork.Top - lPrimaryScreenInfo.RCMonitor.Top; var primaryWidth = (lPrimaryScreenInfo.RCWork.Right - lPrimaryScreenInfo.RCWork.Left); var primaryHeight = (lPrimaryScreenInfo.RCWork.Bottom - lPrimaryScreenInfo.RCWork.Top); var primaryRatio = (float)primaryWidth / (float)primaryHeight; if (lParam != IntPtr.Zero) { // Get min/max structure to fill with information var lMmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO)); // // NOTE: The below setting of max sizes we no longer do // as through observations, it appears Windows works // correctly only when the max window size is set to // EXACTLY the size of the primary window // // Anything else and the behavior is wrong and the max // window width on a secondary monitor if larger than the // primary then goes too large // // lMmi.PointMaxPosition.X = 0; // lMmi.PointMaxPosition.Y = 0; // lMmi.PointMaxSize.X = lCurrentScreenInfo.RCMonitor.Right - lCurrentScreenInfo.RCMonitor.Left; // lMmi.PointMaxSize.Y = lCurrentScreenInfo.RCMonitor.Bottom - lCurrentScreenInfo.RCMonitor.Top; // // Instead we now just add a margin to the window itself // to compensate when maximized // // // NOTE: rcMonitor is the monitor size // rcWork is the available screen size (so the area inside the task bar start menu for example) // Size limits (used by Windows when maximized) // relative to 0,0 being the current screens top-left corner // Set to primary monitor size lMmi.PointMaxPosition.X = lPrimaryScreenInfo.RCMonitor.Left; lMmi.PointMaxPosition.Y = lPrimaryScreenInfo.RCMonitor.Top; lMmi.PointMaxSize.X = lPrimaryScreenInfo.RCMonitor.Right; lMmi.PointMaxSize.Y = lPrimaryScreenInfo.RCMonitor.Bottom; // Set min size var minSize = new Point(mWindow.MinWidth * mMonitorDpi.Value.DpiScaleX, mWindow.MinHeight * mMonitorDpi.Value.DpiScaleX); lMmi.PointMinTrackSize.X = (int)minSize.X; lMmi.PointMinTrackSize.Y = (int)minSize.Y; // Now we have the max size, allow the host to tweak as needed Marshal.StructureToPtr(lMmi, lParam, true); } // Set monitor size CurrentMonitorSize = new Rectangle(currentX, currentY, currentWidth + currentX, currentHeight + currentY); // Get margin around window CurrentMonitorMargin = new Thickness( (lCurrentScreenInfo.RCWork.Left - lCurrentScreenInfo.RCMonitor.Left) / mMonitorDpi.Value.DpiScaleX, (lCurrentScreenInfo.RCWork.Top - lCurrentScreenInfo.RCMonitor.Top) / mMonitorDpi.Value.DpiScaleY, (lCurrentScreenInfo.RCMonitor.Right - lCurrentScreenInfo.RCWork.Right) / mMonitorDpi.Value.DpiScaleX, (lCurrentScreenInfo.RCMonitor.Bottom - lCurrentScreenInfo.RCWork.Bottom) / mMonitorDpi.Value.DpiScaleY ); // Store new size mScreenSize = new Rect(lCurrentScreenInfo.RCWork.Left, lCurrentScreenInfo.RCWork.Top, currentWidth, currentHeight); }
static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi);