I am using the following code to get the WindowRect for a process on my machine (been testing with the Windows 8.1 calculator).
RECT rc;
GetWindowRect(hWnd, out rc);
var bmp = new Bitmap(rc.Right - rc.Left, rc.Bottom - rc.Top, PixelFormat.Format32bppArgb);
var gfxBmp = Graphics.FromImage(bmp);
IntPtr hdcBitmap = gfxBmp.GetHdc();
PrintWindow(hWnd, hdcBitmap, 0);
gfxBmp.ReleaseHdc(hdcBitmap);
gfxBmp.Dispose();
But on Windows 8.1, the bitmap produced is cropped (in the case of the calculator, by about 100 pixels width and 150 height).
RECT is defined as:
[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
}
I've been pulling my hair out with this, can anyone spot what I'm doing wrong?
Cheers
Rich
Related
I want to save the snapshot of a window with the title ending in - Scrivener in a PNG file. To do this, I wrote following method (based on this answer):
[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
}
private void button1_Click(object sender, EventArgs e)
{
Process[] processes = Process.GetProcesses();
Process scrivenerProcess = null;
foreach (Process curProcess in processes)
{
Console.WriteLine("Name: " + curProcess.ProcessName + ", title: " + curProcess.MainWindowTitle);
if (curProcess.MainWindowTitle.EndsWith("- Scrivener"))
{
scrivenerProcess = curProcess;
break;
}
}
if (scrivenerProcess == null)
{
Console.WriteLine("Scrivener not found");
return;
}
var rect = new RECT();
GetWindowRect(new HandleRef(this, scrivenerProcess.MainWindowHandle), out rect);
int width = rect.Right - rect.Left;
int height = rect.Bottom - rect.Top;
var bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
Graphics graphics = Graphics.FromImage(bmp);
graphics.CopyFromScreen(rect.Left, rect.Top, 0, 0, new System.Drawing.Size(width, height), CopyPixelOperation.SourceCopy);
bmp.Save("C:\\usr\\dp\\ref\\marcomm\\2020_04_22_wordCounter\\2020-04-24-TestScreenshot.png", ImageFormat.Png);
Console.WriteLine("Heyo!");
}
There are several problems with this code:
First, if the application I want to capture (Scrivener) is not in the foreground while I'm calling that code, the resulting screenshot is empty.
Second, if the Scrivener window is in the foreground, I get the screenshot of the parent window (see below).
How do I need to change my code in order for it to
a. work even when the window is not in foreground and
b. only capture the word count window (not its parent)?
Here is the code.
Here's your problem:
scrivenerProcess.MainWindowHandle
From the documentation:
The main window is the window opened by the process that currently has the focus
In your screenshot, the window you're after does not have Focus (it has a white background with grey text, indicating it's inactive).
Unfortunately, to enumerate a process' other windows you need to use P/Invoke as they aren't exposed via the Process class. Use EnumWindows or EnumChildWindows.
I have a form with rounded borders by codes below:
[DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")]
private static extern IntPtr CreateRoundRectRgn
(
int nLeftRect, // x-coordinate of upper-left corner
int nTopRect, // y-coordinate of upper-left corner
int nRightRect, // x-coordinate of lower-right corner
int nBottomRect, // y-coordinate of lower-right corner
int nWidthEllipse, // height of ellipse
int nHeightEllipse // width of ellipse
);
public Form1()
{
InitializeComponent();
Region = System.Drawing.Region.FromHrgn(CreateRoundRectRgn(0, 0, Width, Height, 30, 30));
}
But the problem is:When I Maximize the form, It doesn't maximize correctly.
It Maximizes like this:Image
Please Help Me...
I Found The Answer ...
I should clear the all borders that I set before like this:
private void btnMaximize_Click(object sender, EventArgs e)
{
if (this.WindowState == FormWindowState.Maximized)
{
this.WindowState = FormWindowState.Normal;
btnMaximize.Image = Properties.Resources.maximize_Black;
Region = System.Drawing.Region.FromHrgn(CreateRoundRectRgn(0, 0, Width, Height, 30, 30));
}
else
{
this.WindowState = FormWindowState.Maximized;;
btnMaximize.Image = Properties.Resources.maximize_Black_copy;
Region = System.Drawing.Region.FromHrgn(CreateRoundRectRgn(0, 0, Width, Height, 0, 0));
}
}
Thanks For All Friends Wanted To Help Me.
I am trying to make a screenshot to the window of a process in Windows 7 64 bit, the problem is that I always get error in the following line:
var bmp = new Bitmap (width, height, PixelFormat.Format32bppArgb);
Saying "invalid parameters", I made a throw to see the errors and width and height are always 0.
Before in 32 bits it worked well, but now in 64 bits it does not work anymore.
The code :
public void CaptureApplication()
{
string procName = "firefox";
var proc = Process.GetProcessesByName(procName)[0];
var rect = new User32.Rect();
User32.GetWindowRect(proc.MainWindowHandle, ref rect);
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
var bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb);
Graphics graphics = Graphics.FromImage(bmp);
graphics.CopyFromScreen(rect.left, rect.top, 0, 0, new Size(width, height), CopyPixelOperation.SourceCopy);
bmp.Save("c:\\tmp\\test.png", ImageFormat.Png);
}
private class User32
{
[StructLayout(LayoutKind.Sequential)]
public struct Rect
{
public int left;
public int top;
public int right;
public int bottom;
}
[DllImport("user32.dll")]
public static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);
}
How do I fix this error?
Getting the process of firefox returns an array of processes and you are looking for the one with an rectangle with realistic sizes which is the main process.
Process[] procs = Process.GetProcessesByName(procName);
var rect = new User32.Rect();
int width = 0;
int height = 0:
foreach (Process proc in procs)
{
User32.GetWindowRect(proc.MainWindowHandle, ref rect);
width = rect.right - rect.left;
height = rect.bottom - rect.top;
// break foreach if an realistic rectangle found => main process found
if (width != 0 && height != 0)
{
break;
}
}
Currently, I'm using WinAPI in a c# project that deal with Dual-Screen configurations. My question is really simple: how to get the list of all window handle that are about 75% of their size on a specific monitor?
Best regards,
To get the screen with the largest portion of the window you can use this:
System.Windows.Forms.Screen screen = System.Windows.Forms.Screen.FromHandle(form.Handle);
Then you just have to calculate how many % there is on this screen.
Rectangle screenBounds = screen.Bounds;
Rectangle formBounds = form.Bounds;
Rectangle intersection = formBounds.Intersect(screenBounds);
int formArea = formBounds.Width * formBounds.Height;
int intersectArea = intersection.Width * intersection.Height;
int percent = intersectArea * 100 / formArea;
Ok, I created a more generic version, that is able to use any window handle.
Thank you all for your answers!
//Get the Screen object where the Hwnd handle is
System.Windows.Forms.Screen screen = System.Windows.Forms.Screen.FromHandle(Hwnd);
//Create rectangles object
Rectangle screenBound = screen.Bounds;
RECT handleRect = new RECT();
//Get dimensions of the Hwnd handle /!\ don't pass a Rectangle object
if (!GetWindowRect(Hwnd, ref handleRect))
{
//ERROR
}
//Getting the intersection between the two rectangles
Rectangle handleBound = new Rectangle(handleRect.Left, handleRect.Top, handleRect.Right-handleRect.Left, handleRect.Bottom-handleRect.Top);
Rectangle intersection = Rectangle.Intersect(screenBound, handleBound);
//Get the area of the handle
int formArea = handleBound.Width * handleBound.Height;
//Get the area of the intersection
int intersectArea = intersection.Width * intersection.Height;
//Calculate percentage
int percentage = intersectArea * 100 / formArea;
This is the RECT structure:
[StructLayout(LayoutKind.Sequential)]
private 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
}
Ok, i have made a form with this code: this.FormBorderStyle = FormBorderStyle.None; Ok, i have also added a border radius with this code:
[DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")]
private static extern IntPtr CreateRoundRectRgn
(
int nLeftRect, // x-coordinate of upper-left corner
int nTopRect, // y-coordinate of upper-left corner
int nRightRect, // x-coordinate of lower-right corner
int nBottomRect, // y-coordinate of lower-right corner
int nWidthEllipse, // height of ellipse
int nHeightEllipse // width of ellipse
);
public Form4()
{
InitializeComponent();
Region = System.Drawing.Region.FromHrgn(CreateRoundRectRgn(0, 0, Width, Height, 20, 20));
}
So, what i need is the add a small black border around the form that curves with the border-radius. How do i do that?
Ok, i added this, it works, but it does not go with the border, it just goes strait: e.Graphics.DrawRectangle(Pens.Black, new Rectangle(0, 0, Width - 1, Height - 1));
and this:
ControlPaint.DrawBorder(e.Graphics, this.ClientRectangle, Color.Black, ButtonBorderStyle.Solid);
Override the form's OnPaintBackground() method and simply draw the border with the Graphics methods, using the passed e.Graphics object.
Note that you don't have to pinvoke when you use the Region(GraphicsPath) constructor. That same GraphicsPath will also be handy to draw the border.