I remember taking a code somewhere (probably in the OS itself) to do this (I used it to print the screen when I made a mistake, so 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 class (e.g., in a form) these two references to the methods of api Win32, 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 the handle
of the process in which you want to take the 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 method Process.GetProcessesByName()
takes the process name. If I had 3 notepads open, this method would return an array containing these 3 processes. I’m randomly taking the first open (note that this would be a mistake if I didn’t have at least one open Notepad).
Then we call the method PrintarAplicativo
passing the Handle from the main screen of that process. An application can have several windows inside it, and each window has its own Handle (I remember that for having worked hard 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 take the print of "subtelas" within that process.
This method returns the Bitmap
ready, then in this example I open a dialog box for the user to choose where to save this file (but you wouldn’t even need to do it, just save directly to some directory without the user nor be bothered).
To the Chrome in particular, it is complicated because from what I know Chrome creates about 30 processes, note in my case:
However, I did the test below, and of all these processes, only one has the main window Handle:
var processes = 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));
}
}
Which resulted in the following image:
Damn, man, you helped me, man, thank you so much!
– Frederico Sampaio
@Fredericosampaio for nothing!!! D
– Alisson