I remember getting a code somewhere (probably in the OS itself) to do this (I used to print the screen when I made a mistake, then email it to the development team).
Create a reference to a RECT
:
[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;
}
}
Then add in some classes (eg in a form) these two references to the api win32 methods, and create this method PrintarAplicativo()
:
public partial class Form1 : Form
{
[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 PrintarAplicativo(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;
}
}
This method receives handle
of the process in which you want to print. Hence you use it like this, for example:
private void btPrintScreenEcra_Click(object sender, EventArgs e)
{
// tirando um print de algum "notepad" aberto...
var proc = Process.GetProcessesByName("notepad")[0];
using (var bmp = PrintarAplicativo(proc.MainWindowHandle))
{
SaveFileDialog dialog = new SaveFileDialog();
dialog.Filter = "Imagens(*.png, *.jpeg) | *.png; *.jpeg | Todos Arquivos(*.*) | *.* ";
if (dialog.ShowDialog() == DialogResult.OK)
{
bmp.Save(dialog.FileName);
}
}
}
The first Process.GetProcessesByName()
method receives the process name. If I had 3 open notepads, this method would return an array containing those 3 processes. I'm randomly getting the first one open (note that this would give error if it did not have at least one notepad open).
Then we call the PrintarAplicativo
method by passing the handle of the main screen of that process. An application can have several windows in it, and each window has its own Handle (I remember this because I worked a lot with Delphi, and there we used this concept to fire messages with PostMessage from one screen to another). In this case, the main window represents the entire screen of the application, so it would be possible to get the print of "sub-tiles" within that process.
This method returns Bitmap
ready, so in this example I open a dialog box for the user to choose where to save this file (but you do not even need to do that, just save directly to a directory without the user or be bothered) .
For chrome in particular, it is complicated because from what I know chrome creates some 30 processes, note in my case:
However,Ididthetestbelow,andofalltheseprocesses,onlyonehasthemainwindowhandle:
varprocesses=Process.GetProcessesByName("chrome");
// verificar se o processo tem interface gráfica
foreach (var proc in processes.Where(p => p.MainWindowHandle != IntPtr.Zero))
{
using (var bmp = PrintarAplicativo(proc.MainWindowHandle))
{
bmp.Save(string.Format("C:\Users\Alisson\Pictures\chrome-{0}.png", proc.Id));
}
}
That resulted in the following image: