The process would be:
- Get the rectangle of the window using its Handle.
- Get the handle of the monitor where the window locates.
- Get the information (in particular, rectangle of working area) of the monitor using its Handle.
- Calculate the direction of available space.
using System;
using System.Runtime.InteropServices;
public enum Direction { None, TopLeft, TopRight, BottomRight, BottomLeft }
public static class WindowHelper
{
public static Direction GetAvailableDirection(IntPtr windowHandle)
{
if (!GetWindowRect(windowHandle, out RECT buffer))
return Direction.None;
System.Drawing.Rectangle windowRect = buffer;
IntPtr monitorHandle = MonitorFromWindow(windowHandle, MONITOR_DEFAULTTO.MONITOR_DEFAULTTONULL);
if (monitorHandle == IntPtr.Zero)
return Direction.None;
MONITORINFO info = new() { cbSize = (uint)Marshal.SizeOf<MONITORINFO>() };
if (!GetMonitorInfo(monitorHandle, ref info))
return Direction.None;
System.Drawing.Rectangle workingAreaRect = info.rcWork;
bool isWindowAlignedTop = (windowRect.Top - workingAreaRect.Top) < (workingAreaRect.Bottom - windowRect.Bottom);
bool isWindowAlignedLeft = (windowRect.Left - workingAreaRect.Left) < (workingAreaRect.Right - windowRect.Right);
return (isWindowAlignedTop, isWindowAlignedLeft) switch
{
(true, true) => Direction.BottomRight,
(true, false) => Direction.BottomLeft,
(false, true) => Direction.TopRight,
(false, false) => Direction.TopLeft
};
}
[DllImport("User32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetWindowRect(
IntPtr hWnd,
out RECT lpRect);
[DllImport("User32.dll")]
private static extern IntPtr MonitorFromWindow(
IntPtr hwnd,
MONITOR_DEFAULTTO dwFlags);
private enum MONITOR_DEFAULTTO : uint
{
MONITOR_DEFAULTTONULL = 0x00000000,
MONITOR_DEFAULTTOPRIMARY = 0x00000001,
MONITOR_DEFAULTTONEAREST = 0x00000002,
}
[DllImport("User32.dll", CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetMonitorInfo(
IntPtr hMonitor,
ref MONITORINFO lpmi);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct MONITORINFO
{
public uint cbSize;
public RECT rcMonitor;
public RECT rcWork;
public uint dwFlags;
}
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
public static implicit operator System.Drawing.Rectangle(RECT rect)
{
return new System.Drawing.Rectangle(
rect.left,
rect.top,
rect.right - rect.left,
rect.bottom - rect.top);
}
}
}
Please note that calling app must have an application manifest which includes DPI awareness for correct calculation.