winipc-ua/Utils/WindowScanner.cs

133 lines
5.0 KiB
C#
Raw Normal View History

2025-08-02 20:18:00 +03:00
/* This software is licensed by the MIT License, see LICENSE file */
/* Copyright © 2024-2025 Gregory Lirent */
#if WINIPC_UA_SERVER
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
using WinIPC.Models;
namespace WinIPC.Utils
{
public class WindowScanner
{
[StructLayout(LayoutKind.Explicit)]
internal 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)]
internal 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)]
internal 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 uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll", SetLastError = true)]
public static extern long GetWindowLongPtr(IntPtr hWnd, int nIndex);
private bool GetWindowInfo(ref WindowInfo data, IntPtr hwnd)
{
int length = GetWindowTextLength(hwnd);
if (length > 0)
{
var sb = new StringBuilder(length + 1);
GetWindowText(hwnd, sb, sb.Capacity);
data.Title = sb.ToString();
if (GetCursorPos(out RECT pt) && ScreenToClient(hwnd, ref pt))
{
data.CursorPosition = new Models.Point { X = pt.X, Y = pt.Y };
}
if (GetWindowRect(hwnd, out RECT 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 (GetClientRect(hwnd, out RECT 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;
}
public async Task<IEnumerable<WindowInfo>> ScanAsync(ushort max = 0)
{
if (max == 0) max = UInt16.MaxValue;
return await Task.Run(() =>
{
var foreground = GetForegroundWindow();
List<WindowInfo> container = new();
EnumWindows(delegate (IntPtr hwnd, IntPtr lParam)
{
if (container.Count >= max) return false;
if (IsWindowVisible(hwnd))
{
WindowInfo data = new();
data.Hwnd = hwnd.ToInt32();
if ((data.ThreadId = (int)GetWindowThreadProcessId(hwnd, out uint pid)) != 0)
{
data.Pid = (int)pid;
if (GetWindowInfo(ref data, hwnd))
{
data.IsActive = foreground.ToInt32() == data.Hwnd;
container.Add(data);
}
}
}
return true;
}, IntPtr.Zero);
return container;
});
}
}
}
#endif