I\'m writing a simple Windows Forms utility to screenshot either the entire screen or an active window and save the file. The winform has a button called \'Capture\' that, w
I ended up taking a different route.
I allow the user to resize my form window to cover exactly the area they need to screenshot, and then when they click the button, the form hides itself, takes a screenshot of the area it was covering and appears again. Contrary to my initial plan, I believe this will be more beneficial, as my targeted users (friends at an overclocking forum I'm part of) seldom take screenshots of just one window. They mostly need a couple of windows covered (temp monitoring, clockspeed monitoring, stability test etc.).
Thanks for all the answers guys. They definitely got me thinking, and made me realize what my options were.
Should anyone else need it, this is the code I use for the button that captures only part of the screen:
try
{
this.Hide();
Thread.Sleep(250);
bmpScreenshot = new Bitmap(this.Bounds.Width, this.Bounds.Height, PixelFormat.Format32bppArgb);
gfxScreenshot = Graphics.FromImage(bmpScreenshot);
gfxScreenshot.CopyFromScreen(this.Bounds.X, this.Bounds.Y, 0, 0, this.Bounds.Size, CopyPixelOperation.SourceCopy);
bmpScreenshot.Save(SaveLocation, ImageFormat.Png);
tbxStatus.AppendText(Environment.NewLine);
tbxStatus.AppendText(Environment.NewLine);
tbxStatus.AppendText("Screenshot saved at " + SaveLocation);
numSuffix++;
}
catch (Exception ex)
{
tbxStatus.AppendText(Environment.NewLine);
tbxStatus.AppendText(Environment.NewLine);
tbxStatus.AppendText("Unable to take screenshot. Exception: " + ex.ToString());
}
finally
{
this.Show();
}
Your comments seem to understand that once your app gets the focus (when you click on it) the other app has lost it and is no longer 'active'.
A possible alternative: your application gets a WM_SETFOCUS message when it gets focus. The wParam of that message is a handle to whichever window has just given up the focus -- and that window belongs to the app you want to capture.
Of course, that window will only be a subwindow or control, but you can figure out which app owns that button.
As far as I can see your code uses the bounds of its own form to capture the "active" window. That is probably not what you intend.
If you want to use the mouse to "print" a window (and not hotkey which probably is easier to implement) you need to be able to from your own form let the user point to another window to capture. Here is an idea describing how to do that:
You will probably need to use P/Invoke to get information about all top-level windows on the desktop.
Note that "mouse capture" is very different from "screen capture". When an application "captures the mouse" it takes ownership of the mouse cursor and doesn't the ability to track the mouse even when it is moved outside the bounds of the window of the application.
You need to borrow the design of commercially available screen capturing apps, such as Psp. I think you need to use a 'hot' key to trigger the capturing of the active window. Instead of doing it on Capture_Click event. This way, you can hide your application's window so that it does not become the active window. Then when the user pushes the 'hot' key, you can capture it.
What about SendKeys?
Windows.Forms.SendKeys.Send("%{PRTSC}");
It will copy currently selected window in to Clipboard object.
Than calling
BitmapSource image = Clipboard.GetImage();
you can get your image back
In your button_Click
method, to capture a window other than the one which is doing the capturing, the only possible way I can see is to make use of the user32
Windows API.
You will first need to platform invoke some methods like this:
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowLong(IntPtr hWnd, GetWindowLongNIndex nIndex);
I recommend www.pinvoke.net/ for more info about this.
Here is my own Window
class (work in progress, but useable) which you are welcome to use as an example: http://pastebin.com/fj2tEaPY
Some useful properties in there for you are:
AllWindows
TaskbarWindows
ForegroundWindow
You'll need to get the handle of your current window (use get ForegroundWindow
, then the Handle
property), then find the window which you want to capture the image of, perhaps using code similar to that in TaskbarWindows
. Once you have the window, you will need to send the keypresses Alt
+ PrtScn
(again maybe using user32
API, but I won't go into it.) Then use the static ForegroundWindow
property to set the orignal window as the forground using the handle which you saved at the start.
Good luck!