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();
}
}
///
/// 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
}
}