Как я могу избавиться от строки заголовка процесса при создании снимка экрана? - PullRequest
0 голосов
/ 11 ноября 2018

Итак, сейчас я делаю скриншот приложения, выполняя это:

using (var bitmap = new Bitmap(Screen.PrimaryScreen.WorkingArea.Width, Screen.PrimaryScreen.WorkingArea.Height))
using (var graphics = Graphics.FromImage(bitmap))
{
    graphics.CopyFromScreen(new Point(Screen.PrimaryScreen.WorkingArea.Left, Screen.PrimaryScreen.WorkingArea.Top), new Point(0, 0), Screen.PrimaryScreen.WorkingArea.Size);
    bitmap.Save(@"C:\Users\Neoray\Desktop\Test.png", ImageFormat.Bmp);
}

Это работает достаточно хорошо, но проблема в том, что мне нужно избавиться от строки заголовка, которая там находится (не имеет значения, будет ли она впоследствии, путем изменения изображения или при создании самого скриншота).

Надеюсь, кто-нибудь может мне помочь с этим.

1 Ответ

0 голосов
/ 11 ноября 2018

Как отмечается в комментариях, этот метод будет возвращать ClientArea окна процесса, исключая Caption (Title Bar) только тогда, когда окно действительно имеет Caption.Не все приложения это делают (в смысле WinForms ).
Кроме того, нет никаких гарантий того, что оно может работать с развернутым окном, отображаемым с использованием DirectX API.
В этом случае будет необходимодля реализации совершенно другого метода.
В любом случае, он должен корректно работать с отображаемым образцом.


Перегруженный основной метод принимает как имя процесса, так и идентификатор процесса.

Параметры :

string ProcessName или int ProcessId:
Укажитедружественное к процессу имя (отображаемое в диспетчере задач, без учета регистра) или идентификатор процесса (также доступен в диспетчере задач).
Его можно легко изменить, чтобы он также принимал заголовок окна.

bool ClientAreaOnly:
Переключатель.Позволяет указать, хотите ли вы снимок экрана только для раздела ClientArea или для всех границ Windows.

float Dpi:
Вы можете определить разрешение в точках на дюйм:окончательный Bitmap.

Пример использования :
- Снимок экрана главного окна процесса с именем [Some Process Name]
- Указывает толькорассмотрим ClientArea (окно Caption и Borders будут исключены)
- указывает, что разрешение Bitmap должно быть 120Dpi
- сохраняет Bitmap в формате PNG,с именем ScreenShot.png, в [Some Path]

using (Bitmap bitmap = ProcessWindowScreenshot("[Some Process Name]", true, 120))
{
    bitmap.Save(@"[Some Path]\ScreenShot.png", ImageFormat.Png);
}

Основные методы :

using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Runtime.InteropServices;

public Bitmap ProcessWindowScreenshot(string ProcessName, bool ClientAreaOnly, float Dpi)  {
    using (var process = Process.GetProcessesByName(ProcessName)
                                .FirstOrDefault(p => p.MainWindowHandle != IntPtr.Zero))  {
        if (process == null) return null;
        return GetProcessWindowScreenshot(GetProcessWindowRect(process.Id, ClientAreaOnly), Dpi);
    }
}

public Bitmap ProcessWindowScreenshot(int ProcessId, bool ClientAreaOnly, float Dpi)  {
    return GetProcessWindowScreenshot(GetProcessWindowRect(ProcessId, ClientAreaOnly), Dpi);
}

private Bitmap GetProcessWindowScreenshot(Rectangle WindowArea, float Dpi)
{
    using (Bitmap bitmap = new Bitmap(WindowArea.Width, WindowArea.Height, PixelFormat.Format32bppArgb))
    {
        if (Dpi < 96f) Dpi = 96f;
        bitmap.SetResolution(Dpi, Dpi);
        using (Graphics graphics = Graphics.FromImage(bitmap))
        {
            graphics.SmoothingMode = SmoothingMode.HighQuality;
            graphics.InterpolationMode = InterpolationMode.High;
            graphics.CopyFromScreen(WindowArea.Location, Point.Empty, WindowArea.Size, CopyPixelOperation.SourceCopy);
            return (Bitmap)bitmap.Clone();
        };
    };
}

private Rectangle GetProcessWindowRect(int ProcessId, bool IsClientArea)
{
    IntPtr hWnd = Process.GetProcessById(ProcessId).MainWindowHandle;
    if (IsClientArea) {
        return GetWindowClientRectangle(hWnd);
    }
    else {
        return GetWindowRectangle(hWnd);
    }
}

Объявления и помощники Windows APIметоды :

[UIPermission(SecurityAction.Demand, Action = SecurityAction.Demand, Window = UIPermissionWindow.AllWindows)]
public static Rectangle GetWindowRectangle(IntPtr WindowHandle)  {
    SafeNativeMethods.GetWindowRect(WindowHandle, out RECT rect);
    return rect.ToRectangle();
}

[UIPermission(SecurityAction.Demand, Action = SecurityAction.Demand, Window = UIPermissionWindow.AllWindows)]
public static Rectangle GetWindowClientRectangle(IntPtr WindowHandle)  {
    SafeNativeMethods.GetClientRect(WindowHandle, out RECT rect);
    SafeNativeMethods.ClientToScreen(WindowHandle, out POINT point);
    return rect.ToRectangleOffset(point);
}

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
    public int Left;
    public int Top;
    public int Right;
    public int Bottom;

    public Rectangle ToRectangle() => Rectangle.FromLTRB(Left, Top, Right, Bottom);
    public Rectangle ToRectangleOffset(POINT p) => Rectangle.FromLTRB(p.x, p.y, Right + p.x, Bottom + p.y);
}

[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
    public int x;
    public int y;
}

[SuppressUnmanagedCodeSecurity]
internal static class SafeNativeMethods
{
    [DllImport("User32.dll", SetLastError = true)]
    internal static extern bool ClientToScreen(IntPtr hWnd, out POINT point);

    [DllImport("User32.dll", SetLastError = true)]
    internal static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);

    [DllImport("User32.dll", SetLastError = true)]
    internal static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
}
...