winmr-api/Services/Scanners/WindowScanner.cs

131 lines
4.8 KiB
C#

using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
using WebmrAPI.Models;
using WebmrAPI.Utils;
namespace WebmrAPI.Services.Scanners
{
public class WindowScanner : AbstractScanner<WindowInfo>
{
[StructLayout(LayoutKind.Explicit)]
private struct RECT
{
[FieldOffset(0)]
public int Left;
[FieldOffset(4)]
public int Top;
[FieldOffset(8)]
public int Right;
[FieldOffset(12)]
public int Bottom;
[FieldOffset(0)]
public int X;
[FieldOffset(4)]
public int Y;
}
private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetCursorPos(out RECT lpPoint);
[DllImport("user32.dll")]
private static extern int GetWindowText(IntPtr hwnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetClientRect(IntPtr hwnd, out RECT lpRect);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool ScreenToClient(IntPtr hWnd, ref RECT lpPoint);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
override public ScanTarget Target { get => ScanTarget.Windows; }
private bool GetWindowInfo(WindowInfo info, IntPtr hwnd)
{
int length = GetWindowTextLength(hwnd);
if (length > 0)
{
var sb = new StringBuilder(length + 1);
GetWindowText(hwnd, sb, sb.Capacity);
info.Title = sb.ToString();
if (GetCursorPos(out RECT pt) && ScreenToClient(hwnd, ref pt))
{
info.CursorPosition = new GeometryPoint(pt.X, pt.Y);
}
if (GetWindowRect(hwnd, out RECT wRect))
{
info.WindowGeometry = Geometry.FromLTRB(wRect.Left, wRect.Top, wRect.Right, wRect.Bottom);
}
if (GetClientRect(hwnd, out RECT cRect))
{
info.ContentGeometry = BaseGeometry.FromLTRB(cRect.Left, cRect.Top, cRect.Right, cRect.Bottom);
}
return true;
}
return false;
}
override internal Task<bool> ScanAsync(Dictionary<long, WindowInfo> data)
{
return Task.Run(() =>
{
var foreground = GetForegroundWindow();
EnumWindows(delegate (IntPtr hwnd, IntPtr lParam)
{
if (IsWindowVisible(hwnd))
{
WindowInfo? info;
if (!GetFromCacheOrNew(hwnd.ToInt64(), out info))
{
info.Hwnd = hwnd;
int threadId;
if ((threadId = GetWindowThreadProcessId(hwnd, out int pid)) != 0)
{
info.PID = pid;
info.ThreadId = threadId;
}
else
{
info = null;
}
}
if (info != null && GetWindowInfo(info, hwnd))
{
info.IsActive = foreground == info.Hwnd;
data.Add(hwnd.ToInt64(), info);
}
}
return true;
}, IntPtr.Zero);
return true;
});
}
public WindowScanner(IScanProvider scanner, LazyConcurrentContainer<WindowInfo> container)
: base(scanner, container) { }
}
}