/* 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> ScanAsync(ushort max = 0) { if (max == 0) max = UInt16.MaxValue; return await Task.Run(() => { var foreground = GetForegroundWindow(); List 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