Screenshot of active window outside borders - c#

I recently found a code to make a screenshot of the active window. It's actually working however the image is a little bit too big, it goes a little bit outside the borders of the current window.
This is the screenshot taken with my program:
This is the screenshot taken with alt+printscreen:
This is my class:
public static class Screenshotter
{
[DllImport("user32.dll")]
static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32.dll")]
private static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, uint nFlags);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left; // x position of upper-left corner
public int Top; // y position of upper-left corner
public int Right; // x position of lower-right corner
public int Bottom; // y position of lower-right corner
}
public static void MakeScreenshot()
{
var foregroundWindowsHandle = GetForegroundWindow();
var rect = new RECT();
GetWindowRect(foregroundWindowsHandle, out rect);
Rectangle bounds = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
Bitmap bmp = new Bitmap(bounds.Width, bounds.Height);
using (Graphics g = Graphics.FromImage(bmp))
{
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
}
bmp.Save("test.png", ImageFormat.Png);
}
}
I just want it screenshots the active window and not a little bit outside the window. I hope somebody can help me :)

I ran into a problem with the symptoms you have described. In my case, it was due to delay between the moments when a window is registered in system as "foreground" and when it actually fully shown on the screen in front of other windows. You probably observe the same. When you do g.CopyFromScreen(...), you get the pixels from a screen's region that may be still in transition from previous foreground window to the current.
In the first saved image, you can see a screen shot of foreground window (command prompt) made in 150 milliseconds after my image capturing program start:
As you can see, it is a mixture of previous foreground window's pixels (Visual Studio) and new one.
It took another 150 ms to fully update the screen:
So, it is not your screenshot has wrong size - it's the new foreground window has not "inflated" yet to its final boundaries.
A simple (and ugly) solution is: insert Thread.Sleep(...) before your call g.CopyFromScreen(...) to give the system enough time to fully replace the pixels on the screen.

Related

Hijacking another processes form

So, I have been asked to figure out a way to make a program containing sensitive data more secure since we have staff that go afk and put potentially put data at risk.
I have loaded up Visual Studio for C# and found a nice way to get process of the fore mentioned application. Then grab the main window and attach a panel of my very own. This panel will basically now be used like a blind covering the application when its not in use.
Now, I have a program running in system tray waiting for the sensitive data to come on screen and my little panel hijacks the entire window and now nothing can be seen.
My problem now is how ever, that whilst my panel is attacked the main window of the application i am trying to lock out seems to just crash. I am guessing that is because my panel and the application belong to different processes.
Anyway I could do with some advise here.
Here is my panels class.
class LockingPanel : System.Windows.Forms.Panel
{
private IntPtr prn;
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
public void SetParent(IntPtr parent)
{
prn = parent;
SetParent(this.Handle, prn);
}
public IntPtr GetParent() {
return prn;
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(IntPtr hWnd, ref RECT Rect);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left; // x position of upper-left corner
public int Top; // y position of upper-left corner
public int Right; // x position of lower-right corner
public int Bottom; // y position of lower-right corner
}
public void FillParent()
{
RECT rtc = new RECT();
GetWindowRect(prn, ref rtc);
this.Location = new System.Drawing.Point(0, 0);
this.Size = new System.Drawing.Size(rtc.Right, rtc.Bottom);
}
Anybody got a better idea on how I can go about this, or at least make it so that my panel inst going to crash the application.

Screenshot comes out black

I'm trying to make a screen capture manager & recorder, both screenshot & video, although the latter is not important for this question.
The user can select a process he/she wants to be captured and set a hotkey.
The screenshots work fine for the regular desktop and some games. However, when trying to capture a screenshot from some games (e.g Splinter Cell Blacklist), if these games are full-screen, and depending on Windows 7 Aero, the contents are black, or the desktop is showing with a small bar at the top left of the screen.
Here's my initial code:
public static Bitmap GetScreen()
{
Bitmap bmpScreenCapture = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
using (Graphics g = Graphics.FromImage(bmpScreenCapture))
{
g.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
Screen.PrimaryScreen.Bounds.Y,
0, 0,
bmpScreenCapture.Size,
CopyPixelOperation.SourceCopy);
}
return bmpScreenCapture;
}
During my search I found a code project article:
http://www.codeproject.com/Articles/274461/Very-fast-screen-capture-using-DirectX-in-Csharp
And slightly modified the code
public Surface CaptureScreen()
{
Surface s = Surface.CreateOffscreenPlain(d, rc.Width, rc.Height, Format.A8R8G8B8, Pool.Scratch);
d.GetFrontBufferData(0, s);
Surface.ToFile(s, #"C:\test\img.jpg", ImageFileFormat.Jpg);
return s;
}
However, also that image comes out black.
Does anyone have any suggestions as to how this is done?
Use this code (which I found here) to disable Aero before taking any screenshots, then re-enable it.
public readonly uint DWM_EC_DISABLECOMPOSITION = 0;
public readonly uint DWM_EC_ENABLECOMPOSITION = 1;
[DllImport("dwmapi.dll", EntryPoint = "DwmEnableComposition")]
protected static extern uint Win32DwmEnableComposition(uint uCompositionAction);
public void ManageAero(bool a)
{
if (a)
Win32DwmEnableComposition(DWM_EC_ENABLECOMPOSITION );
if (!a)
Win32DwmEnableComposition(DWM_EC_DISABLECOMPOSITIO N);
}

Getting the color of a pixel drawn by DWM in C#

I want to get Screenshots of a possible hidden Window of another application that is using drawing via direct3d or opengl. I tryed a lot of ways to receive this windows content but only got black or transparent pictures. The closest i got was by using a DWM sample here
http://bartdesmet.net/blogs/bart/archive/2006/10/05/4495.aspx
this paints the window onto my c# form but i cant get the pixelcolors. If ill do a form.drawtobitmap the pixels drawn by dwm are missing.
So is their any way to use DWM to recive the capture into a image
or to get the image drawn onto my form?
To answer your question:
You can use GetPixel() Win32 function. But it's overkill in this situation.
Pinvoke GetPixel
MSDN GetPixel
The right way, is to get the device context and bit blit the content.
EDIT:
I've thrown together some code, by using PrintWindow. Seems to work quite well, even with media players. Note that GetWindowRect returns invalid rectangle for minimized Windows. But it's a decent start.
[StructLayout(LayoutKind.Sequential)]
public struct Rect
{
internal Rect(int left, int top, int right, int bottom)
{
Left = left;
Top = top;
Right = right;
Bottom = bottom;
}
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool PrintWindow(IntPtr hwnd, IntPtr hDC, uint nFlags);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowRect(IntPtr hwnd, out Rect lpRect);
public void DumpWindow(IntPtr hwndSource, string filename)
{
Rect rc;
GetWindowRect(hwndSource, out rc);
var bmp = new Bitmap(rc.Right - rc.Left, rc.Bottom - rc.Top, PixelFormat.Format32bppArgb);
using (Graphics gBmp = Graphics.FromImage(bmp))
{
IntPtr hdcBmp = gBmp.GetHdc();
PrintWindow(hwndSource, hdcBmp, 0);
gBmp.ReleaseHdc(hdcBmp);
}
bmp.Save(filename);
}
Edit2:
And if you add a second button to DWM demo form, insert this:
private void button1_Click(object sender, EventArgs e)
{
var w = (Window)lstWindows.SelectedItem;
DumpWindow(w.Handle, "test.bmp");
Process.Start("test.bmp");
}
It still shows an empty image?

Obtain mouse click position relative to active window

Having worked out how to obtain the mouse click position anywhere along the monitor boundaries using low level hooks I receive an X Y coordinate that will contain a value typically between x: -1680 to +1920 and y: 0 to 1200 in my pcs case. Easy enough!
Now the problem is that I now want to calculate the mouse position relative to a given window that I have so I use GetForegroundWindow() and GetWindowRect(HandleRef hWnd, out RECT lpRect) to obtain my active window coordinates.
Where I am stuck is I require the current active desktop (By active I mean which monitor the click occurred on) to calculate the coordinates of my mouse click relative to a window.
Unfortunately I have not been able to find an API call like GetActiveMonitor() or similar so hopefully someone can point me in the right direction?
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
Call it as:
RECT rct = new RECT();
GetWindowRect(hWnd, ref rct);
after get your mouse position like this
int mouserelativepositionX = mousePosition.X - rct.Left;
int mouserelativepositionY = mousePosition.Y - rct.Top;
My guess is that you can know where your mouse is by using an if:
if(mousePosition.X > -1680 && mousePosition.X < 0)
//We are in monitor 1;
else
//Monitor 2;

Get A Window's Bounds By Its Handle

I am trying to get the height and the width of the current active window.
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern bool GetWindowRect(IntPtr hWnd, Rectangle rect);
Rectangle bonds = new Rectangle();
GetWindowRect(handle, bonds);
Bitmap bmp = new Bitmap(bonds.Width, bonds.Height);
This code doesn't work because I need to use RECT and I don't know how.
Things like this are easily answered by google (C# GetWindowRect); you should also know about pinvoke.net -- great resource for calling native APIs from C#.
http://www.pinvoke.net/default.aspx/user32/getwindowrect.html
I guess for completeness I should copy the answer here:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(HandleRef hWnd, out RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left; // x position of upper-left corner
public int Top; // y position of upper-left corner
public int Right; // x position of lower-right corner
public int Bottom; // y position of lower-right corner
}
Rectangle myRect = new Rectangle();
private void button1_Click(object sender, System.EventArgs e)
{
RECT rct;
if(!GetWindowRect(new HandleRef(this, this.Handle), out rct ))
{
MessageBox.Show("ERROR");
return;
}
MessageBox.Show( rct.ToString() );
myRect.X = rct.Left;
myRect.Y = rct.Top;
myRect.Width = rct.Right - rct.Left;
myRect.Height = rct.Bottom - rct.Top;
}
Of course that code will not work. It has to be this way: GetWindowRect(handle, ref rect);. So, edit your GetWindowRect declaration. And Rectangle is just a wrapper of the native RECT. Rectangle and RECT has left, top, right and bottom fields that the Rectangle class changed to read-properties (Left, Top, Right, Bottom). Width is not equivalent to right and Height is not equivalent to bottom. Width is right-left and Height is bottom-top. Of course, RECT don't have these sort of properties. It's just a bare struct.
Creating RECT is an overkill. Rectangle is enough in .NET for native/unmanaged API that need it. You just have to pass it in the appropriate way.

Categories