Get a screenshot of a specific application

I know that I can get a screenshot of the entire screen using Graphics.CopyFromScreen (). However, what if I just want a screenshot of a specific application?

+44
c # winapi screenshot
May 21 '09 at 3:57
source share
4 answers

Here is the code to get you started:

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

It works, but needs to be improved:

  • You might want to use a different mechanism to get the process descriptor (or at least do the security encoding).
  • If your target window is not in the foreground, you will get a screenshot that matches the correct size / position, but will be filled with what is in the foreground (you probably want to pull this window in the foreground)
  • You might want to do something different than just save bmp to the temp directory
+31
May 21 '09 at 5:24
source share

PrintWindow win32 api will capture the bitmap of the window, even if the window is closed by other windows or if it is turned off:

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

The link to RECT above can be resolved by the following 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; } } 
+89
May 26 '09 at 15:15
source share

Based on Alconja's answer, I made several improvements:

 [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; } 
+8
May 21 '09 at 6:54 a.m.
source share

You can see the P / Invoking win32 way to do this, an article about it ... sort of.

Basically, use the DC setting for the bitmap and send WM_PRINT to the appropriate application window. This is rather unpleasant, everything is said, but it may work for you.

Functions you might need: SendMessage , GetDC , CreateCompatibleBitmp, and SelectObject .

I can’t say that I’ve ever done this before, but that’s how I would attack this problem. (Well, I probably would have done it in pure C, but anyway, roughly the way I would have attacked it).

+1
May 21 '09 at 4:39 a.m.
source share



All Articles