using System.Drawing; using System.Drawing.Imaging; using System.Globalization; using System.Runtime.InteropServices; using System.Text; namespace DummyCursor.Spy { public class SpiedWindow : EventArgs { public SpiedWindow(IntPtr handle) { Handle = handle; } public IntPtr Handle { get; } public Rectangle Area { get { RECT rect; GetWindowRect(Handle, out rect); return rect; } } public Rectangle ClientArea { get { RECT rectW; GetWindowRect(Handle, out rectW); RECT rectC; GetClientRect(Handle, out rectC); POINT pt = new Point(rectW.X, rectW.Y); ScreenToClient(Handle, ref pt); rectW.X -= pt.X; rectW.Y -= pt.Y; rectW.Width = rectC.Width; rectW.Height = rectC.Height; return rectW; } } public string Caption { get { var len = GetWindowTextLength(Handle); var str = new StringBuilder(len + 1); GetWindowText(Handle, str, len + 1); return str.ToString(); } } public SpiedWindow GetParentWindow() { return new SpiedWindow(GetParent(Handle)); } public void SeParentWindow(IntPtr parentHandle) { SetParent(Handle, parentHandle); } public IEnumerable GetChildren() { var children = new List(); EnumChildWindows(Handle, (hWnd, lp) => { children.Add(new SpiedWindow(hWnd)); return true; }, IntPtr.Zero); return children; } public override string ToString() { return Caption; } public void PrintTo(Graphics graphics, Point itemLocation) { using var bmp = GetScreenShot(); if (bmp != null) graphics.DrawImage(bmp, itemLocation); } private Bitmap GetScreenShot() { var sz = Area.Size; if (sz == Size.Empty) return null; var bmp = new Bitmap(sz.Width, sz.Height, PixelFormat.Format32bppArgb); using var g = Graphics.FromImage(bmp); var hdc = g.GetHdc(); PrintWindow(Handle, hdc, PW_RENDERFULLCONTENT); g.ReleaseHdc(hdc); return bmp; } public static SpiedWindow FindByCaption(string caption) { var hWnd = WndFinder.FindWindowsWithText(caption).FirstOrDefault(); if (hWnd == IntPtr.Zero) return null; return new SpiedWindow(hWnd); } #region Under the Hood [DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)] static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName); [DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)] static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)] private static extern IntPtr GetParent(IntPtr hWnd); [DllImport("user32.dll", SetLastError = true)] private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] static extern bool ScreenToClient(IntPtr hWnd, ref POINT lpPoint); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] private static extern int GetWindowTextLength(IntPtr hWnd); private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam); [StructLayout(LayoutKind.Sequential)] private struct RECT { public int Left, Top, Right, Bottom; public RECT(int left, int top, int right, int bottom) { Left = left; Top = top; Right = right; Bottom = bottom; } public RECT(Rectangle r) : this(r.Left, r.Top, r.Right, r.Bottom) { } public int X { get { return Left; } set { Right -= (Left - value); Left = value; } } public int Y { get { return Top; } set { Bottom -= (Top - value); Top = value; } } public int Height { get { return Bottom - Top; } set { Bottom = value + Top; } } public int Width { get { return Right - Left; } set { Right = value + Left; } } public Point Location { get { return new Point(Left, Top); } set { X = value.X; Y = value.Y; } } public Size Size { get { return new Size(Width, Height); } set { Width = value.Width; Height = value.Height; } } public static implicit operator Rectangle(RECT r) { return new Rectangle(r.Left, r.Top, r.Width, r.Height); } public static implicit operator RECT(Rectangle r) { return new RECT(r); } public static bool operator ==(RECT r1, RECT r2) { return r1.Equals(r2); } public static bool operator !=(RECT r1, RECT r2) { return !r1.Equals(r2); } public bool Equals(RECT r) { return r.Left == Left && r.Top == Top && r.Right == Right && r.Bottom == Bottom; } public override bool Equals(object obj) { if (obj is RECT) return Equals((RECT)obj); if (obj is Rectangle) return Equals(new RECT((Rectangle)obj)); return false; } public override int GetHashCode() { return ((Rectangle)this).GetHashCode(); } public override string ToString() { return string.Format(CultureInfo.CurrentCulture, "{{Left={0},Top={1},Right={2},Bottom={3}}}", Left, Top, Right, Bottom); } } [StructLayout(LayoutKind.Sequential)] public struct POINT { public int X; public int Y; public POINT(int x, int y) { this.X = x; this.Y = y; } public static implicit operator System.Drawing.Point(POINT p) { return new System.Drawing.Point(p.X, p.Y); } public static implicit operator POINT(System.Drawing.Point p) { return new POINT(p.X, p.Y); } public override string ToString() { return $"X: {X}, Y: {Y}"; } } private static uint PW_RENDERFULLCONTENT = 2; [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool PrintWindow(IntPtr hwnd, IntPtr hDC, uint nFlags); [DllImport("gdi32.dll")] private static extern bool MoveToEx(IntPtr hdc, int X, int Y, IntPtr lpPoint); [DllImport("user32.dll", SetLastError = true)] private static extern IntPtr GetDC(IntPtr hWnd); [DllImport("user32.dll", SetLastError = true)] private static extern IntPtr GetWindowDC(IntPtr hWnd); [DllImport("user32.dll")] private static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC); [DllImport("gdi32.dll", EntryPoint = "BitBlt", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool BitBlt([In] IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, [In] IntPtr hdcSrc, int nXSrc, int nYSrc, TernaryRasterOperations dwRop); public enum TernaryRasterOperations : uint { SRCCOPY = 0x00CC0020, SRCPAINT = 0x00EE0086, SRCAND = 0x008800C6, SRCINVERT = 0x00660046, SRCERASE = 0x00440328, NOTSRCCOPY = 0x00330008, NOTSRCERASE = 0x001100A6, MERGECOPY = 0x00C000CA, MERGEPAINT = 0x00BB0226, PATCOPY = 0x00F00021, PATPAINT = 0x00FB0A09, PATINVERT = 0x005A0049, DSTINVERT = 0x00550009, BLACKNESS = 0x00000042, WHITENESS = 0x00FF0062, CAPTUREBLT = 0x40000000 //only if WinVer >= 5.0.0 (see wingdi.h) } private const int WM_PRINT = 0x0317; [DllImport("user32.dll")] public static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam); #endregion Under the Hood } }