131 lines
4.8 KiB
C#
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) { }
|
|
}
|
|
}
|