Capture screenshot of active window?

C#ScreenshotActive Window

C# Problem Overview


I am making a screen capturing application and everything is going fine. All I need to do is capture the active window and take a screenshot of this active window. Does anyone know how I can do this?

C# Solutions


Solution 1 - C#

Rectangle bounds = Screen.GetBounds(Point.Empty);
using(Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
{
    using(Graphics g = Graphics.FromImage(bitmap))
    {
         g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
    }
    bitmap.Save("test.jpg", ImageFormat.Jpeg);
}

for capturing current window use

 Rectangle bounds = this.Bounds;
 using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
 {
    using (Graphics g = Graphics.FromImage(bitmap))
    {
        g.CopyFromScreen(new Point(bounds.Left,bounds.Top), Point.Empty, bounds.Size);
    }
    bitmap.Save("C://test.jpg", ImageFormat.Jpeg);
 }

Solution 2 - C#

ScreenCapture sc = new ScreenCapture();
// capture entire screen, and save it to a file
Image img = sc.CaptureScreen();
// display image in a Picture control named imageDisplay
this.imageDisplay.Image = img;
// capture this window, and save it
sc.CaptureWindowToFile(this.Handle,"C:\\temp2.gif",ImageFormat.Gif);

http://www.developerfusion.com/code/4630/capture-a-screen-shot/

Solution 3 - C#

I suggest next solution for capturing any current active window (not only our C# application) or entire screen with cursor position determination relative to left-top corner of window or screen respectively:

public enum enmScreenCaptureMode
{
	Screen,
	Window
}

class ScreenCapturer
{
	[DllImport("user32.dll")]
	private static extern IntPtr GetForegroundWindow();

	[DllImport("user32.dll")]
	private static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);

	[StructLayout(LayoutKind.Sequential)]
	private struct Rect
	{
		public int Left;
		public int Top;
		public int Right;
		public int Bottom;
	}

	public Bitmap Capture(enmScreenCaptureMode screenCaptureMode = enmScreenCaptureMode.Window)
	{
		Rectangle bounds;

		if (screenCaptureMode == enmScreenCaptureMode.Screen)
		{
			bounds = Screen.GetBounds(Point.Empty);
			CursorPosition = Cursor.Position;
		}
		else
		{
			var foregroundWindowsHandle = GetForegroundWindow();
			var rect = new Rect();
			GetWindowRect(foregroundWindowsHandle, ref rect);
			bounds = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
			CursorPosition = new Point(Cursor.Position.X - rect.Left, Cursor.Position.Y - rect.Top);
		}

		var result = new Bitmap(bounds.Width, bounds.Height);

		using (var g = Graphics.FromImage(result))
		{
			g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
		}

		return result;
	}

	public Point CursorPosition
	{
		get;
		protected set;
	}
}

Solution 4 - C#

Here is a snippet to capture either the desktop or the active window. It has no reference to Windows Forms.

public class ScreenCapture
{
    [DllImport("user32.dll")]
    private static extern IntPtr GetForegroundWindow();

    [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
    public static extern IntPtr GetDesktopWindow();

    [StructLayout(LayoutKind.Sequential)]
    private struct Rect
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }   

    [DllImport("user32.dll")]
    private static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);
    
    public static Image CaptureDesktop()
    {
        return CaptureWindow(GetDesktopWindow());
    }

    public static Bitmap CaptureActiveWindow()
    {
        return CaptureWindow(GetForegroundWindow());
    }

    public static Bitmap CaptureWindow(IntPtr handle)
    {
        var rect = new Rect();
        GetWindowRect(handle, ref rect);
        var bounds = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
        var result = new Bitmap(bounds.Width, bounds.Height);

        using (var graphics = Graphics.FromImage(result))
        {
            graphics.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
        }

        return result;
    }
}

How to capture the whole screen:

var image = ScreenCapture.CaptureDesktop();
image.Save(@"C:\temp\snippetsource.jpg", ImageFormat.Jpeg);

How to capture the active window:

var image = ScreenCapture.CaptureActiveWindow();
image.Save(@"C:\temp\snippetsource.jpg", ImageFormat.Jpeg);

Originally found here: http://www.snippetsource.net/Snippet/158/capture-screenshot-in-c

Solution 5 - C#

KvanTTT's code worked great. I extended it a bit to allow a little more flexibility on save format, as well as the ability to save by hWnd, .NET Control/Form. You can get a bitmap or save to file, with a few options.

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace MosaiqPerformanceMonitor {
	 public enum CaptureMode {
		  Screen, Window
	 }

	 public static class ScreenCapturer {
		  [DllImport("user32.dll")]
		  private static extern IntPtr GetForegroundWindow();

		  [DllImport("user32.dll")]
		  private static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);

		  [StructLayout(LayoutKind.Sequential)]
		  private struct Rect {
				public int Left;
				public int Top;
				public int Right;
				public int Bottom;
		  }

		  [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
		  public static extern IntPtr GetDesktopWindow();

		  /// <summary> Capture Active Window, Desktop, Window or Control by hWnd or .NET Contro/Form and save it to a specified file.  </summary>
		  /// <param name="filename">Filename.
		  /// <para>* If extension is omitted, it's calculated from the type of file</para>
		  /// <para>* If path is omitted, defaults to %TEMP%</para>
		  /// <para>* Use %NOW% to put a timestamp in the filename</para></param>
		  /// <param name="mode">Optional. The default value is CaptureMode.Window.</param>
		  /// <param name="format">Optional file save mode.  Default is PNG</param>
		  public static void CaptureAndSave(string filename, CaptureMode mode = CaptureMode.Window, ImageFormat format = null) {
				ImageSave(filename, format, Capture(mode));
		  }

		  /// <summary> Capture a specific window (or control) and save it to a specified file.  </summary>
		  /// <param name="filename">Filename.
		  /// <para>* If extension is omitted, it's calculated from the type of file</para>
		  /// <para>* If path is omitted, defaults to %TEMP%</para>
		  /// <para>* Use %NOW% to put a timestamp in the filename</para></param>
		  /// <param name="handle">hWnd (handle) of the window to capture</param>
		  /// <param name="format">Optional file save mode.  Default is PNG</param>
		  public static void CaptureAndSave(string filename, IntPtr handle, ImageFormat format = null) {
				ImageSave(filename, format, Capture(handle));
		  }

		  /// <summary> Capture a specific window (or control) and save it to a specified file.  </summary>
		  /// <param name="filename">Filename.
		  /// <para>* If extension is omitted, it's calculated from the type of file</para>
		  /// <para>* If path is omitted, defaults to %TEMP%</para>
		  /// <para>* Use %NOW% to put a timestamp in the filename</para></param>
		  /// <param name="c">Object to capture</param>
		  /// <param name="format">Optional file save mode.  Default is PNG</param>
		  public static void CaptureAndSave(string filename, Control c, ImageFormat format = null) {
				ImageSave(filename, format, Capture(c));
		  }
		  /// <summary> Capture the active window (default) or the desktop and return it as a bitmap </summary>
		  /// <param name="mode">Optional. The default value is CaptureMode.Window.</param>
		  public static Bitmap Capture(CaptureMode mode = CaptureMode.Window) {
				return Capture(mode == CaptureMode.Screen ? GetDesktopWindow() : GetForegroundWindow());
		  }

		  /// <summary> Capture a .NET Control, Form, UserControl, etc. </summary>
		  /// <param name="c">Object to capture</param>
		  /// <returns> Bitmap of control's area </returns>
		  public static Bitmap Capture(Control c) {
				return Capture(c.Handle);
		  }


		  /// <summary> Capture a specific window and return it as a bitmap </summary>
		  /// <param name="handle">hWnd (handle) of the window to capture</param>
		  public static Bitmap Capture(IntPtr handle) {
				Rectangle bounds;
				var rect = new Rect();
				GetWindowRect(handle, ref rect);
				bounds = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
				CursorPosition = new Point(Cursor.Position.X - rect.Left, Cursor.Position.Y - rect.Top);

				var result = new Bitmap(bounds.Width, bounds.Height);
				using (var g = Graphics.FromImage(result))
					 g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);

				return result;
		  }

		  /// <summary> Position of the cursor relative to the start of the capture </summary>
		  public static Point CursorPosition;


		  /// <summary> Save an image to a specific file </summary>
		  /// <param name="filename">Filename.
		  /// <para>* If extension is omitted, it's calculated from the type of file</para>
		  /// <para>* If path is omitted, defaults to %TEMP%</para>
		  /// <para>* Use %NOW% to put a timestamp in the filename</para></param>
		  /// <param name="format">Optional file save mode.  Default is PNG</param>
		  /// <param name="image">Image to save.  Usually a BitMap, but can be any
		  /// Image.</param>
		  static void ImageSave(string filename, ImageFormat format, Image image) {
				format = format ?? ImageFormat.Png;
				if (!filename.Contains("."))
					 filename = filename.Trim() + "." + format.ToString().ToLower();

				if (!filename.Contains(@"\"))
					 filename = Path.Combine(Environment.GetEnvironmentVariable("TEMP") ?? @"C:\Temp", filename);

				filename = filename.Replace("%NOW%", DateTime.Now.ToString("[email protected]"));
				image.Save(filename, format);
		  }
	 }
}

Solution 6 - C#

I assume you use Graphics.CopyFromScreen to get the screenshot.

You can use P/Invoke to GetForegroundWindow (and then get its position and size) to determine which region you need to copy from.

Solution 7 - C#

You can use the code from this question: https://stackoverflow.com/questions/158151/how-can-i-save-screenshot-directly-to-a-file-in-windows

Just change WIN32_API.GetDesktopWindow() to the Handle property of the window you want to capture.

Solution 8 - C#

If you want to use managed code: This will capture any window via the ProcessId.

I used the following to make the window active.

Microsoft.VisualBasic.Interaction.AppActivate(ProcessId);
Threading.Thread.Sleep(20);

I used the print screen to capture a window.

SendKeys.SendWait("%{PRTSC}");
Threading.Thread.Sleep(40);
IDataObject objData = Clipboard.GetDataObject();

Solution 9 - C#

Use the following code :

            // Shot size = screen size
            Size shotSize = Screen.PrimaryScreen.Bounds.Size;

            // the upper left point in the screen to start shot
            // 0,0 to get the shot from upper left point
            Point upperScreenPoint = new Point(0, 0);

            // the upper left point in the image to put the shot
            Point upperDestinationPoint = new Point(0, 0);

            // create image to get the shot in it
            Bitmap shot = new Bitmap(shotSize.Width, shotSize.Height);

            // new Graphics instance 
            Graphics graphics = Graphics.FromImage(shot);

            // get the shot by Graphics class 
            graphics.CopyFromScreen(upperScreenPoint, upperDestinationPoint, shotSize);

            // return the image
            pictureBox1.Image = shot;

Solution 10 - C#

Works if the Desktop scaling is set.

public class ScreenCapture
{
    [DllImport("user32.dll")]
    private static extern IntPtr GetForegroundWindow();

    [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
    public static extern IntPtr GetDesktopWindow();

    [StructLayout(LayoutKind.Sequential)]
    private struct Rect
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }

    [DllImport("user32.dll")]
    private static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);

    public static Image CaptureDesktop()
    {
        return CaptureWindow(GetDesktopWindow());
    }

    public static Bitmap CaptureActiveWindow()
    {
        return CaptureWindow(GetForegroundWindow());
    }

    public static Bitmap CaptureWindow(IntPtr handle)
    {
        var rect = new Rect();
        GetWindowRect(handle, ref rect);
        GetScale getScale = new GetScale();
        var bounds = new Rectangle(rect.Left, rect.Top, (int)((rect.Right - rect.Left)* getScale.getScalingFactor()), (int)((rect.Bottom - rect.Top )* getScale.getScalingFactor()));
        var result = new Bitmap(bounds.Width, bounds.Height);

        using (var graphics = Graphics.FromImage(result))
        {
            graphics.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
        }

        return result;
    }
}

Solution 11 - C#

A little tweak to method static void ImageSave() will grant you the option where to save it. Credit goes to Microsoft (http://msdn.microsoft.com/en-us/library/sfezx97z.aspx)

static void ImageSave(string filename, ImageFormat format, Image image, SaveFileDialog saveFileDialog1)
    { 
        saveFileDialog1.Filter = "JPeg Image|*.jpg|Bitmap Image|*.bmp|Gif Image|*.gif";
        saveFileDialog1.Title = "Enregistrer un image";
        saveFileDialog1.ShowDialog();

        // If the file name is not an empty string open it for saving.
        if (saveFileDialog1.FileName != "")
        {
            // Saves the Image via a FileStream created by the OpenFile method.
            System.IO.FileStream fs =
               (System.IO.FileStream)saveFileDialog1.OpenFile();
            // Saves the Image in the appropriate ImageFormat based upon the
            // File type selected in the dialog box.
            // NOTE that the FilterIndex property is one-based.
            switch (saveFileDialog1.FilterIndex)
            {
                case 1:
                    image.Save(fs,
                       System.Drawing.Imaging.ImageFormat.Jpeg);
                    break;

                case 2:
                    image.Save(fs,
                       System.Drawing.Imaging.ImageFormat.Bmp);
                    break;

                case 3:
                    image.Save(fs,
                       System.Drawing.Imaging.ImageFormat.Gif);
                    break;
            }

            fs.Close();
        }



    }

Your button_click event should be coded something like this...

private void btnScreenShot_Click(object sender, EventArgs e)
    {
        
        SaveFileDialog saveFileDialog1 = new SaveFileDialog();
        

        ScreenCapturer.CaptureAndSave(filename, mode, format, saveFileDialog1);

    }//

Solution 12 - C#

Based on ArsenMkrt's reply, but this one allows you to capture a control in your form (I'm writing a tool for example that has a WebBrowser control in it and want to capture just its display). Note the use of PointToScreen method:

//Project: WebCapture
//Filename: ScreenshotUtils.cs
//Author: George Birbilis (http://zoomicon.com)
//Version: 20130820

using System.Drawing;
using System.Windows.Forms;

namespace WebCapture
{
  public static class ScreenshotUtils
  {

    public static Rectangle Offseted(this Rectangle r, Point p)
    {
      r.Offset(p);
      return r;
    }

    public static Bitmap GetScreenshot(this Control c)
    {
      return GetScreenshot(new Rectangle(c.PointToScreen(Point.Empty), c.Size));
    }

    public static Bitmap GetScreenshot(Rectangle bounds)
    {
      Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height);
      using (Graphics g = Graphics.FromImage(bitmap))
        g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
      return bitmap;
    }

    public const string DEFAULT_IMAGESAVEFILEDIALOG_TITLE = "Save image";
    public const string DEFAULT_IMAGESAVEFILEDIALOG_FILTER = "PNG Image (*.png)|*.png|JPEG Image (*.jpg)|*.jpg|Bitmap Image (*.bmp)|*.bmp|GIF Image (*.gif)|*.gif";

    public const string CUSTOMPLACES_COMPUTER = "0AC0837C-BBF8-452A-850D-79D08E667CA7";
    public const string CUSTOMPLACES_DESKTOP = "B4BFCC3A-DB2C-424C-B029-7FE99A87C641";
    public const string CUSTOMPLACES_DOCUMENTS = "FDD39AD0-238F-46AF-ADB4-6C85480369C7";
    public const string CUSTOMPLACES_PICTURES = "33E28130-4E1E-4676-835A-98395C3BC3BB";
    public const string CUSTOMPLACES_PUBLICPICTURES = "B6EBFB86-6907-413C-9AF7-4FC2ABF07CC5";
    public const string CUSTOMPLACES_RECENT = "AE50C081-EBD2-438A-8655-8A092E34987A";

    public static SaveFileDialog GetImageSaveFileDialog(
      string title = DEFAULT_IMAGESAVEFILEDIALOG_TITLE, 
      string filter = DEFAULT_IMAGESAVEFILEDIALOG_FILTER)
    {
      SaveFileDialog dialog = new SaveFileDialog();

      dialog.Title = title;
      dialog.Filter = filter;


      /* //this seems to throw error on Windows Server 2008 R2, must be for Windows Vista only
      dialog.CustomPlaces.Add(CUSTOMPLACES_COMPUTER);
      dialog.CustomPlaces.Add(CUSTOMPLACES_DESKTOP);
      dialog.CustomPlaces.Add(CUSTOMPLACES_DOCUMENTS);
      dialog.CustomPlaces.Add(CUSTOMPLACES_PICTURES);
      dialog.CustomPlaces.Add(CUSTOMPLACES_PUBLICPICTURES);
      dialog.CustomPlaces.Add(CUSTOMPLACES_RECENT);
      */

      return dialog;
    }

    public static void ShowSaveFileDialog(this Image image, IWin32Window owner = null)
    {
      using (SaveFileDialog dlg = GetImageSaveFileDialog())
        if (dlg.ShowDialog(owner) == DialogResult.OK)
          image.Save(dlg.FileName);
    }

  }
}

Having the Bitmap object you can just call Save on it

private void btnCapture_Click(object sender, EventArgs e)
{
  webBrowser.GetScreenshot().Save("C://test.jpg", ImageFormat.Jpeg);
}

The above assumes the GC will grab the bitmap, but maybe it's better to assign the result of someControl.getScreenshot() to a Bitmap variable, then dispose that variable manually when finished with each image, especially if you're doing this grabbing often (say you have a list of webpages you want to load and save screenshots of them):

private void btnCapture_Click(object sender, EventArgs e)
{
  Bitmap bitmap = webBrowser.GetScreenshot();
  bitmap.ShowSaveFileDialog();
  bitmap.Dispose(); //release bitmap resources
}

Even better, could employ a using clause, which has the added benefit of releasing the bitmap resources even in case of an exception occuring inside the using (child) block:

private void btnCapture_Click(object sender, EventArgs e)
{
  using(Bitmap bitmap = webBrowser.GetScreenshot())
    bitmap.ShowSaveFileDialog();
  //exit from using block will release bitmap resources even if exception occured
}

Update:

Now WebCapture tool is ClickOnce-deployed (http://gallery.clipflair.net/WebCapture) from the web (also has nice autoupdate support thanks to ClickOnce) and you can find its source code at https://github.com/Zoomicon/ClipFlair/tree/master/Server/Tools/WebCapture

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionuserView Question on Stackoverflow
Solution 1 - C#Arsen MkrtchyanView Answer on Stackoverflow
Solution 2 - C#joeView Answer on Stackoverflow
Solution 3 - C#Ivan KochurkinView Answer on Stackoverflow
Solution 4 - C#Christian MoserView Answer on Stackoverflow
Solution 5 - C#Wade HatlerView Answer on Stackoverflow
Solution 6 - C#bohdan_trotsenkoView Answer on Stackoverflow
Solution 7 - C#Richard SzalayView Answer on Stackoverflow
Solution 8 - C#Klaus HeinrichView Answer on Stackoverflow
Solution 9 - C#Muhanned F.ObaidView Answer on Stackoverflow
Solution 10 - C#Krishnaraj kView Answer on Stackoverflow
Solution 11 - C#Junior CSharpView Answer on Stackoverflow
Solution 12 - C#George BirbilisView Answer on Stackoverflow