win32-automation-agent/Domain/DesktopHandler.cs
2026-01-08 21:33:01 +03:00

196 lines
7.0 KiB
C#

using AutoAgent.Domain.Exceptions;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
namespace AutoAgent.Domain
{
public static class DesktopHandler
{
private static Rectangle GetCaptureArea(IntPtr hwnd, Models.Point pt, Models.AreaSize size)
{
Rectangle area;
if (hwnd == IntPtr.Zero)
{
area = Rectangle.FromLTRB(User32Dll.GetSystemMetrics(76),
User32Dll.GetSystemMetrics(77),
User32Dll.GetSystemMetrics(78),
User32Dll.GetSystemMetrics(79));
}
else
{
if (User32Dll.GetClientRect(hwnd, out var rect))
{
User32Dll.RECT br = new () { X = rect.Right, Y = rect.Bottom };
if (User32Dll.ClientToScreen(hwnd, ref rect) && User32Dll.ClientToScreen(hwnd, ref br))
{
area = new Rectangle(rect.X, rect.Y, br.X - rect.X, br.Y - rect.Y);
}
else
{
throw new CaptureAreaException($"Could not convert client coordinates to screen coordinates for HWND: {hwnd}");
}
}
else
{
throw new CaptureAreaException($"Failed to get client rectangle for HWND: {hwnd}");
}
}
if (size.Width > 0 && size.Height > 0)
{
area = new Rectangle(
Math.Max(area.X, area.X + pt.X),
Math.Max(area.Y, area.Y + pt.Y),
Math.Min(size.Width, area.Right - pt.X),
Math.Min(size.Height, area.Bottom - pt.Y));
}
if (area.Width <= 0 || area.Height <= 0)
{
throw new CaptureAreaException($"Final capture rectangle has invalid dimensions: {area}");
}
return area;
}
private static bool GetWindowInfo(ref Models.WindowInfo data, IntPtr hwnd)
{
int length = User32Dll.GetWindowTextLength(hwnd);
if (length > 0)
{
var sb = new StringBuilder(length + 1);
User32Dll.GetWindowText(hwnd, sb, sb.Capacity);
data.Title = sb.ToString();
if (User32Dll.GetCursorPos(out var pt) && User32Dll.ScreenToClient(hwnd, ref pt))
{
data.CursorPosition = new Models.Point { X = pt.X, Y = pt.Y };
}
if (User32Dll.GetWindowRect(hwnd, out var wRect))
{
var rect = Rectangle.FromLTRB(wRect.Left, wRect.Top, wRect.Right, wRect.Bottom);
data.WindowPosition = new Models.Point { X = rect.X, Y = rect.Y };
data.WindowSize = new Models.AreaSize { Width = rect.Width, Height = rect.Height };
}
if (User32Dll.GetClientRect(hwnd, out var cRect))
{
var rect = Rectangle.FromLTRB(cRect.Left, cRect.Top, cRect.Right, cRect.Bottom);
data.ContentSize = new Models.AreaSize { Width = rect.Width, Height = rect.Height };
}
return true;
}
return false;
}
private static bool TryGetWindowInfo(IntPtr hwnd, ref IntPtr foreground, out Models.WindowInfo info)
{
info = new();
if (User32Dll.IsWindowVisible(hwnd))
{
info.Hwnd = hwnd.ToInt32();
if ((info.ThreadId = (int)User32Dll.GetWindowThreadProcessId(hwnd, out uint pid)) != 0)
{
info.Pid = (int)pid;
if (GetWindowInfo(ref info, hwnd))
{
info.IsActive = foreground.ToInt32() == info.Hwnd;
return true;
}
}
}
return false;
}
public static Task<IEnumerable<Models.WindowInfo>> GetWindows(ushort max = 0, IEnumerable<int>? whitelist = null)
{
if (max == 0) max = UInt16.MaxValue;
if (whitelist == null) whitelist = Array.Empty<int>();
return Task.Run(() =>
{
var foreground = User32Dll.GetForegroundWindow();
List<Models.WindowInfo> container = new();
User32Dll.EnumWindows(delegate (IntPtr hwnd, IntPtr lParam)
{
bool found = true;
if (container.Count >= max) return false;
foreach (var w in whitelist)
{
if (w == hwnd.ToInt32())
{
found = true;
break;
}
found = false;
}
if (found && TryGetWindowInfo(hwnd, ref foreground, out var info))
{
container.Add(info);
}
return true;
}, IntPtr.Zero);
return (IEnumerable<Models.WindowInfo>)container;
});
}
public static Task<(Models.AreaSize size, byte[] pngImage)> GetScreenshot(Models.Point pos, Models.AreaSize size, IntPtr hwnd = 0)
{
return Task.Run(() =>
{
Rectangle area = GetCaptureArea(hwnd, pos, size);
using (Bitmap screenshot = new Bitmap(area.Width, area.Height, PixelFormat.Format32bppArgb))
{
using (Graphics g = Graphics.FromImage(screenshot))
{
g.CopyFromScreen(area.X, area.Y, 0, 0, area.Size, CopyPixelOperation.SourceCopy);
}
using (MemoryStream ms = new MemoryStream())
{
screenshot.Save(ms, ImageFormat.Png);
return (new Models.AreaSize { Width = screenshot.Width, Height = screenshot.Height }, ms.ToArray());
}
}
});
}
public static Task<(byte r, byte g, byte b)> GetPixelColor(Models.Point pos, IntPtr hwnd = 0)
{
return Task.Run(() =>
{
Rectangle area = GetCaptureArea(hwnd, pos, new Models.AreaSize { Width = 1, Height = 1 });
using (Bitmap screenPixel = new Bitmap(1, 1))
{
using (Graphics g = Graphics.FromImage(screenPixel))
{
g.CopyFromScreen(area.Left, area.Top, 0, 0, screenPixel.Size);
}
var color = screenPixel.GetPixel(0, 0);
return (color.R, color.G, color.B);
}
});
}
}
}