Obtenga una captura de pantalla de una aplicación específica

Sé que puedo obtener la captura de pantalla de toda la pantalla usando Graphics.CopyFromScreen (). Sin embargo, ¿qué ocurre si solo quiero la captura de pantalla de una aplicación específica?

Aquí hay un código para comenzar:

public void CaptureApplication(string procName) { var proc = Process.GetProcessesByName(procName)[0]; var rect = new User32.Rect(); User32.GetWindowRect(proc.MainWindowHandle, ref rect); int width = rect.right - rect.left; int height = rect.bottom - rect.top; var bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb); Graphics graphics = Graphics.FromImage(bmp); graphics.CopyFromScreen(rect.left, rect.top, 0, 0, new Size(width, height), CopyPixelOperation.SourceCopy); bmp.Save("c:\\tmp\\test.png", ImageFormat.Png); } private class User32 { [StructLayout(LayoutKind.Sequential)] public struct Rect { public int left; public int top; public int right; public int bottom; } [DllImport("user32.dll")] public static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect); } 

Funciona, pero necesita mejoras:

  • Es posible que desee utilizar un mecanismo diferente para obtener el control del proceso (o al menos hacer una encoding defensiva)
  • Si su ventana de destino no está en primer plano, terminará con una captura de pantalla con el tamaño / posición correctos, pero se rellenará con todo lo que se encuentre en primer plano (es probable que desee colocar primero la ventana en primer plano; )
  • Probablemente desee hacer algo más que guardar el bmp en un directorio temporal

La aplicación PrintWindow win32 capturará un bitmap de la ventana incluso si la ventana está cubierta por otras ventanas o si está fuera de la pantalla:

 [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect); [DllImport("user32.dll")] public static extern bool PrintWindow(IntPtr hWnd, IntPtr hdcBlt, int nFlags); public static Bitmap PrintWindow(IntPtr hwnd) { RECT rc; GetWindowRect(hwnd, out rc); Bitmap bmp = new Bitmap(rc.Width, rc.Height, PixelFormat.Format32bppArgb); Graphics gfxBmp = Graphics.FromImage(bmp); IntPtr hdcBitmap = gfxBmp.GetHdc(); PrintWindow(hwnd, hdcBitmap, 0); gfxBmp.ReleaseHdc(hdcBitmap); gfxBmp.Dispose(); return bmp; } 

La referencia a RECT anterior se puede resolver con la siguiente clase:

 [StructLayout(LayoutKind.Sequential)] public struct RECT { private int _Left; private int _Top; private int _Right; private int _Bottom; public RECT(RECT Rectangle) : this(Rectangle.Left, Rectangle.Top, Rectangle.Right, Rectangle.Bottom) { } public RECT(int Left, int Top, int Right, int Bottom) { _Left = Left; _Top = Top; _Right = Right; _Bottom = Bottom; } public int X { get { return _Left; } set { _Left = value; } } public int Y { get { return _Top; } set { _Top = value; } } public int Left { get { return _Left; } set { _Left = value; } } public int Top { get { return _Top; } set { _Top = value; } } public int Right { get { return _Right; } set { _Right = value; } } public int Bottom { get { return _Bottom; } set { _Bottom = 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 { _Left = value.X; _Top = value.Y; } } public Size Size { get { return new Size(Width, Height); } set { _Right = value.Width + _Left; _Bottom = value.Height + _Top; } } public static implicit operator Rectangle(RECT Rectangle) { return new Rectangle(Rectangle.Left, Rectangle.Top, Rectangle.Width, Rectangle.Height); } public static implicit operator RECT(Rectangle Rectangle) { return new RECT(Rectangle.Left, Rectangle.Top, Rectangle.Right, Rectangle.Bottom); } public static bool operator ==(RECT Rectangle1, RECT Rectangle2) { return Rectangle1.Equals(Rectangle2); } public static bool operator !=(RECT Rectangle1, RECT Rectangle2) { return !Rectangle1.Equals(Rectangle2); } public override string ToString() { return "{Left: " + _Left + "; " + "Top: " + _Top + "; Right: " + _Right + "; Bottom: " + _Bottom + "}"; } public override int GetHashCode() { return ToString().GetHashCode(); } public bool Equals(RECT Rectangle) { return Rectangle.Left == _Left && Rectangle.Top == _Top && Rectangle.Right == _Right && Rectangle.Bottom == _Bottom; } public override bool Equals(object Object) { if (Object is RECT) { return Equals((RECT)Object); } else if (Object is Rectangle) { return Equals(new RECT((Rectangle)Object)); } return false; } } 

En base a la respuesta de Alconja, hice algunas mejoras:

 [StructLayout(LayoutKind.Sequential)] public struct Rect { public int left; public int top; public int right; public int bottom; } [DllImport("user32.dll")] private static extern int SetForegroundWindow(IntPtr hWnd); private const int SW_RESTORE = 9; [DllImport("user32.dll")] private static extern IntPtr ShowWindow(IntPtr hWnd, int nCmdShow); [DllImport("user32.dll")] public static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect); public Bitmap CaptureApplication(string procName) { Process proc; // Cater for cases when the process can't be located. try { proc = Process.GetProcessesByName(procName)[0]; } catch (IndexOutOfRangeException e) { return null; } // You need to focus on the application SetForegroundWindow(proc.MainWindowHandle); ShowWindow(proc.MainWindowHandle, SW_RESTORE); // You need some amount of delay, but 1 second may be overkill Thread.Sleep(1000); Rect rect = new Rect(); IntPtr error = GetWindowRect(proc.MainWindowHandle, ref rect); // sometimes it gives error. while (error == (IntPtr)0) { error = GetWindowRect(proc.MainWindowHandle, ref rect); } int width = rect.right - rect.left; int height = rect.bottom - rect.top; Bitmap bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb); Graphics.FromImage(bmp).CopyFromScreen(rect.left, rect.top, 0, 0, new Size(width, height), CopyPixelOperation.SourceCopy); return bmp; } 

Podrías buscar en P / Invocando la manera win32 de hacer esto, un artículo en este sentido … más o menos.

Básicamente, tome la molestia de configurar un DC en un bitmap y envíe WM_PRINT a la ventana de la aplicación en cuestión. Es bastante desagradable, todo dicho, pero puede funcionar para usted.

Funciones que puede necesitar: SendMessage , GetDC , CreateCompatibleBitmp y SelectObject .

No puedo decir que haya hecho esto antes, pero así es como atacaría el problema. (Bueno, probablemente lo haría en C pura, pero aún así, más o menos como lo atacaría).