using System.Diagnostics; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using WhiteMagic.Native; namespace WhiteMagic.Windows; /// /// Factory for enumerating and locating instances. /// public static class WindowFactory { /// Enumerates all top-level windows. public static unsafe IEnumerable GetWindows() { var handles = new List(); GCHandle gch = GCHandle.Alloc(handles); try { delegate* unmanaged[Stdcall] callback = &EnumWindowsCallback; NativeMethods.EnumWindows((nint)callback, GCHandle.ToIntPtr(gch)); } finally { gch.Free(); } return handles.Select(static h => new RemoteWindow(h)); } /// Returns all top-level windows with the specified class name. public static IEnumerable GetWindowsByClassName(string className) { if (className is null) throw new ArgumentNullException(nameof(className)); return GetWindows().Where(w => w.ClassName.Equals(className, StringComparison.Ordinal)); } /// Returns all top-level windows owned by the specified process. public static IEnumerable GetWindowsByProcessId(int processId) { return GetWindows().Where(w => w.ProcessId == (uint)processId); } /// Returns the first top-level window with the specified class name. public static RemoteWindow? GetWindowByClassName(string className) { return GetWindowsByClassName(className).FirstOrDefault(); } /// /// Returns the main window of a process. When /// is unavailable, falls back to the first enumerated window owned by the process. /// public static RemoteWindow? GetMainWindow(System.Diagnostics.Process process) { if (process is null) throw new ArgumentNullException(nameof(process)); if (process.MainWindowHandle != IntPtr.Zero) return new RemoteWindow(process.MainWindowHandle); return GetWindowsByProcessId(process.Id).FirstOrDefault(); } [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] private static int EnumWindowsCallback(IntPtr hWnd, IntPtr lParam) { var handles = (List)GCHandle.FromIntPtr(lParam).Target!; handles.Add(hWnd); return 1; // Continue enumeration. } }