using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Drawing; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms; using CC_Functions.W32.Native; namespace CC_Functions.W32 { /// /// Object representing a window handle in the Windows API. Provides a simplified interface for basic interactions /// public sealed class Wnd32 : IEquatable { #region Exposed #region CreateInstance private Wnd32(IntPtr handle) => HWnd = handle; /// /// Base method. Generates a window object from the specified handle /// /// The handle /// The window public static Wnd32 FromHandle(IntPtr handle) => new Wnd32(handle); /// /// Gets the main window of the process /// /// The process /// The window. Might be IntPtr.Zero public static Wnd32 GetProcessMain(Process process) => FromHandle(process.MainWindowHandle); /// /// Generates a window from metadata. Parameters should be null if they are not used /// /// /// The class name of the window. Use the name you found before using the ClassName-parameter of /// a window /// /// The windows name (title) /// The window. Might be IntPtr.Zero public static Wnd32 FromMetadata(string? lpClassName = null, string? lpWindowName = null) => FromHandle(user32.FindWindow(lpClassName, lpWindowName)); /// /// Gets the window that is visible at the specified point /// /// The point to scan /// The window. Might be IntPtr.Zero public static Wnd32 FromPoint(Point point) => FromHandle(user32.WindowFromPoint(point.X, point.Y)); /// /// Gets all windows at the specific point /// /// The point to scan /// Whether windows need to be visible /// The windows public static Wnd32[] AllFromPoint(Point point, bool visible = false) => All.Where(s => s.Position.Contains(point) && s.Shown || !visible).ToArray(); /// /// Gets the window associated with the forms handle /// /// Form to get window from /// The window. Might be IntPtr.Zero public static Wnd32 FromForm(Form form) => FromHandle(form.Handle); /// /// Gets ALL windows. In most cases you will want to use Wnd32.Visible /// /// public static Wnd32[] All { get { _windowHandles = new List(); if (!user32.EnumDesktopWindows(IntPtr.Zero, FilterCallback, IntPtr.Zero)) throw new Win32Exception("There was a native error. This should never happen!"); return _windowHandles.Select(FromHandle).ToArray(); } } /// /// Gets all visible windows /// public static Wnd32[] Visible => All.Where(s => s.Shown).ToArray(); /// /// Gets the foreground window /// public static Wnd32 Foreground => FromHandle(user32.GetForegroundWindow()); /// /// The current programs console window. Do NOT use this if you are not targeting a console app or allocating a console /// public static Wnd32 ConsoleWindow => FromHandle(kernel32.GetConsoleWindow()); #endregion CreateInstance #region InstanceActions public Wnd32[] Children { get { List childHandles = new List(); GCHandle gcChildHandlesList = GCHandle.Alloc(childHandles); IntPtr pointerChildHandlesList = GCHandle.ToIntPtr(gcChildHandlesList); try { user32.EnumChildWindows(HWnd, EnumWindow, pointerChildHandlesList); } finally { gcChildHandlesList.Free(); } return childHandles.Select(FromHandle).ToArray(); } } public Wnd32 Parent { get { IntPtr result = user32.GetParent(HWnd); if (result == IntPtr.Zero) throw new Win32Exception(Marshal.GetLastWin32Error()); return FromHandle(result); } } /// /// The windows title /// public string Title { get { int length = user32.GetWindowTextLength(HWnd); StringBuilder sb = new StringBuilder(length + 1); user32.GetWindowText(HWnd, sb, sb.Capacity); return sb.ToString(); } set => user32.SetWindowTextW(HWnd, value); } /// /// The windows position in screen-space /// public Rectangle Position { get { RECT rect = new RECT(); user32.GetWindowRect(HWnd, ref rect); return new Rectangle(new Point(rect.Left, rect.Top), new Size(rect.Width, rect.Height)); } set { RECT rect = new RECT(); user32.GetWindowRect(HWnd, ref rect); user32.MoveWindow(HWnd, value.X, value.Y, value.Width, value.Height, true); } } /// /// Gets whether the window is the foreground window or brings it to the front. "False" must not be assigned! /// /// Thrown when the value is "False" public bool IsForeground { get => user32.GetForegroundWindow() == HWnd; set { if (value) user32.SetForegroundWindow(HWnd); else throw new InvalidOperationException( "You can't set a Window not to be in the foreground. Move another one over it!"); } } /// /// Whether the window is enabled. Functionally similar to WinForms' "Control.Enabled" /// public bool Enabled { get => user32.IsWindowEnabled(HWnd); set => user32.EnableWindow(HWnd, value); } /// /// Gets the windows icon /// public Icon Icon { get { IntPtr hIcon = user32.SendMessage(HWnd, 0x7F, 1, 0); if (hIcon == IntPtr.Zero) hIcon = user32.SendMessage(HWnd, 0x7F, 0, 0); if (hIcon == IntPtr.Zero) hIcon = user32.SendMessage(HWnd, 0x7F, 2, 0); return Icon.FromHandle(hIcon); } } /// /// Whether the window is visible /// public bool Shown { get => user32.IsWindowVisible(HWnd); set => user32.ShowWindow(HWnd, value ? 9 : 0); } /// /// Gets the windows class name, This is basically only useful for finding window class-names of specified programs /// public string ClassName { get { StringBuilder className = new StringBuilder(256); user32.GetClassName(HWnd, className, className.Capacity); return className.ToString(); } } /// /// Sets the window state /// public FormWindowState State { get { int style = user32.GetWindowLong(HWnd, -16); if ((style & 0x01000000) == 0x01000000) return FormWindowState.Maximized; if ((style & 0x20000000) == 0x20000000) return FormWindowState.Minimized; return FormWindowState.Normal; } set { switch (value) { case FormWindowState.Minimized: user32.ShowWindow(HWnd, 11); break; case FormWindowState.Normal: user32.ShowWindow(HWnd, 1); break; case FormWindowState.Maximized: user32.ShowWindow(HWnd, 3); break; default: throw new ArgumentException("The provided WindowState was invalid", "value"); } } } /// /// Overlays the window over others /// public bool Overlay { set { Rectangle tmp = Position; user32.SetWindowPos(HWnd, value ? new IntPtr(-1) : new IntPtr(-2), tmp.X, tmp.Y, tmp.Width, tmp.Height, value ? (uint) 3 : 0); } } /// /// Forces the window to close /// /// Thrown if the window could not be closed public void Destroy() { if (!user32.DestroyWindow(HWnd)) throw new Exception("Failed."); } /// /// Whether the IntPtr is a window and still exists /// public bool StillExists => user32.IsWindow(HWnd); /// /// Creates a user-readable string from the windows hWnd, title and position /// /// The created string public override string ToString() => $"{HWnd}; {Title}; {Position}"; /// /// Equality operator, uses the hWnd field /// /// Object (Window) to compare /// Equality result public override bool Equals(object obj) => Equals(obj as Wnd32); /// /// Equality operator, uses the hWnd field /// /// Window to compare /// Equality result public bool Equals(Wnd32 other) => !IsNull(other) && other != null && HWnd.Equals(other.HWnd); /// /// Equality operator, uses the hWnd field /// /// Equality result public override int GetHashCode() => HWnd.GetHashCode(); /// /// Equality operator, uses the hWnd field /// /// Window to compare /// Window to compare /// Equality result public static bool operator ==(Wnd32 left, Wnd32 right) => !AreNull(left, right) && left.HWnd == right.HWnd; /// /// Equality operator, uses the hWnd field /// /// Window to compare /// Window to compare /// Equality result public static bool operator !=(Wnd32 left, Wnd32 right) => AreNull(left, right) || left.HWnd != right.HWnd; private static bool AreNull(params Wnd32[] windows) => windows.Any(IsNull); private static bool IsNull(Wnd32 window) { try { window.ToString(); return false; } catch (NullReferenceException) { return true; } } #endregion InstanceActions #endregion Exposed #region Internal /// /// The windows' handle /// public readonly IntPtr HWnd; private static List _windowHandles; private static bool FilterCallback(IntPtr hWnd, int lParam) { StringBuilder sbTitle = new StringBuilder(1024); user32.GetWindowText(hWnd, sbTitle, 1024); _windowHandles.Add(hWnd); return true; } private bool EnumWindow(IntPtr hWnd, IntPtr lParam) { GCHandle gcChildhandlesList = GCHandle.FromIntPtr(lParam); if (gcChildhandlesList.Target == null) return false; List childHandles = gcChildhandlesList.Target as List; childHandles?.Add(hWnd); return true; } #endregion Internal } }