Ottieni uno screenshot di un’applicazione specifica

So che posso ottenere lo screenshot dell’intero schermo usando Graphics.CopyFromScreen (). Tuttavia, cosa succede se voglio solo lo screenshot di un’applicazione specifica?

Ecco un codice per iniziare:

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

Funziona, ma ha bisogno di miglioramenti:

  • Potresti voler usare un meccanismo diverso per far gestire il processo (o almeno fare qualche codifica difensiva)
  • Se la finestra di destinazione non è in primo piano, finirai con uno screenshot di dimensioni e posizione corrette, ma sarà riempito con qualsiasi cosa sia in primo piano (probabilmente vorrai prima mettere la finestra in primo piano )
  • Probabilmente vuoi fare qualcosa di diverso dal semplice salvataggio del bmp in una directory temporanea

PrintWindow win32 api acquisirà una bitmap della finestra anche se la finestra è coperta da altre windows o se è fuori dallo schermo:

 [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; } 

Il riferimento a RECT sopra può essere risolto con la seguente class:

 [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; } } 

Sulla base della risposta di Alconja, ho apportato alcuni miglioramenti:

 [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; } 

Potresti cercare in P / Invocare il modo win32 di farlo, un articolo in questo senso … una specie di.

Fondamentalmente, passa attraverso la difficoltà di impostare una DC in una bitmap e inviare WM_PRINT alla finestra dell’applicazione in questione. È piuttosto cattivo, tutto sumto, ma potrebbe funzionare per te.

Funzioni che potrebbero essere necessarie: SendMessage , GetDC , CreateCompatibleBitmp e SelectObject .

Non posso dire di averlo mai fatto prima, ma è così che attaccherei il problema. (Beh, probabilmente lo farei in puro C ma ancora, all’incirca nel modo in cui lo attaccherei).