Screenshot non-active external application - c#

I need to take a screenshot of a non-active external application, for example, TeamSpeak or Skype.
I have searched and i didn't find much, i know that it is not possible to screenshot a minimised application, but i think it should be possible to screenshot a non-active application.
PS : I want to screenshot just the application, so if another application is on top of the one i want, would it be a problem?
I have no code right now, i have found a user32 API that can do what i want but i forgot the name..
Thanks for the help.

The API you're after is PrintWindow:
void Example()
{
IntPtr hwnd = FindWindow(null, "Example.txt - Notepad2");
CaptureWindow(hwnd);
}
[DllImport("User32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool PrintWindow(IntPtr hwnd, IntPtr hDC, uint nFlags);
[DllImport("user32.dll")]
static extern bool GetWindowRect(IntPtr handle, ref Rectangle rect);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
public void CaptureWindow(IntPtr handle)
{
// Get the size of the window to capture
Rectangle rect = new Rectangle();
GetWindowRect(handle, ref rect);
// GetWindowRect returns Top/Left and Bottom/Right, so fix it
rect.Width = rect.Width - rect.X;
rect.Height = rect.Height - rect.Y;
// Create a bitmap to draw the capture into
using (Bitmap bitmap = new Bitmap(rect.Width, rect.Height))
{
// Use PrintWindow to draw the window into our bitmap
using (Graphics g = Graphics.FromImage(bitmap))
{
IntPtr hdc = g.GetHdc();
if (!PrintWindow(handle, hdc, 0))
{
int error = Marshal.GetLastWin32Error();
var exception = new System.ComponentModel.Win32Exception(error);
Debug.WriteLine("ERROR: " + error + ": " + exception.Message);
// TODO: Throw the exception?
}
g.ReleaseHdc(hdc);
}
// Save it as a .png just to demo this
bitmap.Save("Example.png");
}
}

Using GetWindowRect coupled with PrintWindow from user32 API should be all you need to implement the feature. PrintWindow will properly capture the contents of a specific application even if it's obscured by another window on top of it.
It's worth noting that this might not work for capturing contents of DirectX windows.

Related

Can you get the position of a window that is inside of another application

So I found an example from an answer provided here
There was an answer that gave this example of code to move the Notepad window to the top left corner of the screen. I tried it and it worked fine. I then tried it on a small project I am working on and I couldn't move it.
NOTE: I did change the "Notepad" to the name at the top of the window I wanted to move.
using System;
using System.Runtime.InteropServices; // For the P/Invoke signatures.
public static class PositionWindowDemo
{
// P/Invoke declarations.
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
const uint SWP_NOSIZE = 0x0001;
const uint SWP_NOZORDER = 0x0004;
public static void Main()
{
// Find (the first-in-Z-order) Notepad window.
IntPtr hWnd = FindWindow("Notepad", null);
// If found, position it.
if (hWnd != IntPtr.Zero)
{
// Move the window to (0,0) without changing its size or position
// in the Z order.
SetWindowPos(hWnd, IntPtr.Zero, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
}
}
}
I will give an example. Consider Visual Studios and how it has the Solution Explorer Window or the Output window, and I can drag them with the mouse and move them or undock them. Would there be a way to have an application that has windows inside of it similar to Visual Studios and get the position of them in a program?
I have seen many answers on here about moving a window or finding the active window etc. However I am not sure if I will be able to access this subWindow that is inside of another application.
Thanks

Why does EnumerateMetafile only work with Aero enabled

My code enumerates a metafile:
private void Parse()
{
Graphics graphics = Graphics.FromHwnd(IntPtr.Zero);
PointF pointf = new PointF();
graphics.EnumerateMetafile(_metafile, pointf, ParseCallback);
}
private bool ParseCallback(EmfPlusRecordType recordType,
int flags, int dataSize, IntPtr data, PlayRecordCallback callbackData)
{
// do stuff
}
My development machine is Windows 7 VirtualBox guest on Ubuntu host.
The code used to work fine. However, when I turned off Aero, the code stopped working: The ParseCallback would never be called.
Only when I turned Aero back on, ParseCallback was executed again.
Why and how can I make this code work on non-Aero-enabled machines?
I don't have a full answer to the "why?" question, but it does not work because you're getting the Graphics GDI+ object from the Window handle. Instead, you want to get it from a GDI DC, like this:
private void Parse()
{
IntPtr hdc = GetDC(IntPtr.Zero); // get entire screen dc
Graphics graphics = Graphics.FromHdc(hdc));
PointF pointf = new PointF();
graphics.EnumerateMetafile(_metafile, pointf, ParseCallback);
ReleaseDC(IntPtr.Zero, hdc);
}
[DllImport("user32.dll")]
static extern IntPtr GetDC(IntPtr hWnd);
[DllImport("user32.dll")]
static extern IntPtr ReleaseDC(IntPtr hwnd, IntPtr hdc);
Note you could also use the Graphics object from the Form OnPaint(PaintEventArgs e) method, it should also work, just like in the official sample code for EnumerateMetafile method here: Graphics.EnumerateMetafile Method

Save open application dimensions and positions on Windows to reopen them via configuration file?

Is there a way to open an application to a saved set of dimensions and positions (on Windows) via a script? I'd also like to, of course, save the dimensions and positions of open applications -- the other side of this script. Any suggestions? If a script can't get this done on a Windows machine is there a way with C#/.NET?
You can do this using a User32.dll call to SetWindowPos.
For example:
[DllImport("User32.dll")]
public static extern IntPtr FindWindow(string className, string windowName);
[DllImport("User32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWindowPos(IntPtr windowHandle, IntPtr parentWindowHandle, int x, int y, int width, int height, PositionFlags positionFlags);
public static readonly IntPtr HWND_TOP = new IntPtr(0);
[Flags]
public enum PositionFlags : uint
{
ShowWindow = 0x40
}
static void Main(string[] args)
{
var windowHandle = FindWindow(null, "Untitled - Notepad");
SetWindowPos(windowHandle, HWND_TOP, 0, 0, 640, 480, PositionFlags.ShowWindow);
}
This will find the window with the title "Untitled - Notepad", move it to 0, 0, and resize it to 640x480. I have added the bare minimal number of PositionFlags and HWND flags, look at the link I provided if you require more and add them in the same way :)
Oh, and to read the dimensions out, take a look at GetWindowRect. Here's an example of how to use this from c#: Example.
Take a look at Application Settings.

Getting A Window's Region

I am trying to a get a window's height and width using this :
[DllImport("User32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool PrintWindow(IntPtr hwnd, IntPtr hDC, uint nFlags);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern bool GetWindowRect(IntPtr handle, out Rectangle rect);
private void timer1_Tick(object sender, EventArgs e)
{
Rectangle bonds = new Rectangle();
GetWindowRect(GetForegroundWindow(), out bonds);
Bitmap bmp = new Bitmap(bonds.Width, bonds.Height);
Graphics memoryGraphics = Graphics.FromImage(bmp);
IntPtr dc = memoryGraphics.GetHdc();
PrintWindow(GetForegroundWindow(), dc, 0x1);
memoryGraphics.ReleaseHdc(dc);
bmp.Save("C:\\Test.gif", ImageFormat.Gif);
}
but bonds.width and height are more than the real window.
Example : My window is 100x150, bond.height is like 400 and bonds.width is like 500. I get a picture with the size of 400x500 that consist of the window in the corner of the picture (which is good) and the rest is black since the picture is way bigger than the window (which is bad)
NOTE : I don't care that the window is aeroless, it's good for me.
So any suggestion, or maybe a better way of getting a region?
You need to use ScreenToClient and translate the coordinates.
GetWindowRect returns the window area relative to the top-left of the screen ( 0, 0 ).

find window Height & Width

how to find focused window Height & Width ..
it might be any windows window like notepad,mspaint etc...
i can get the focused window by help of this code
[DllImport("user32")]
public static extern IntPtr GetForegroundWindow();
hi f3lix it's working but it's return the value depends on the location only.. if i change the location it's return some other values
Kunal it's return error msg....like object refrence not set
I think you have to use user32.dll functions via PInvoke. I'm not sure, but I would do it somewhat like this:
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
static extern bool GetWindowRect(IntPtr hWnd, out Rectangle lpRect);
Rectangle rect = new Rectangle();
GetWindowRect(GetForegroundWindow(), out rect);
Note: I did not try this code, because I am currently not working on Windows...
EDIT:
Rory pointed out to me (see comments) that we can't use the standard Rectangle here and we need to define our own RECT.
[StructLayout(LayoutKind.Sequential)]
public struct RECT {
public int Left;
public int Top;
public int Right;
public int Bottom;
}
Don't forget to replace Rectangle with RECT in the first piece of code.
[DllImport("user32.dll")]
public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
public static Size GetControlSize(IntPtr hWnd)
{
RECT pRect;
Size cSize = new Size();
// get coordinates relative to window
GetWindowRect(hWnd, out pRect);
cSize.Width = pRect.Right - pRect.Left;
cSize.Height = pRect.Bottom - pRect.Top;
return cSize;
}
What exactly is your question?
How to get the focused window?
How to get the width and height of a Window?
If question 2, use Window.ActualWidth and Window.ActualHeight
If your window is inside your aplication, having an MDI app, you might use this,
having
public static extern IntPtr GetForegroundWindow();
with you, try this
int wHeight = Control.FromHandle(GetForegroundWindow()).Height;
int wWidth = Control.FromHandle(GetForegroundWindow()).Width;
If you're building an MDI app, you could use:
parentForm.ActiveMDIChild.Size

Categories

Resources