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.
}
}