Программа Screen Capture копирует больше, чем выбранная область

Я следовал программе Huw Collingbourne при создании программы захвата экрана на C#. Тем не менее, я заметил пару странных вещей, и независимо от того, использую ли я его созданную программу или мою модифицированную программу, происходит то же самое. Специально я создал программу, которая открывает окно, позволяющее захватить область. Я думаю, что это связано с сидением за моим компьютером, но мне нужно знать, как предвидеть и исправить это, если другие собираются использовать мою программу захвата экрана! Если мой дисплей для Windows 10 установлен на 100%, я получаю немного больше, чем выбранное окно, и если я устанавливаю дисплей на 125% текста, я получаю большую часть выделенной области. Оставив размер по умолчанию, я должен иметь размер 555, 484. но я захватываю гораздо больше.

public partial class Form1 : Form
{
    //https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getwindowrect
    [DllImport("user32.dll")]
    private static extern IntPtr GetForegroundWindow();
    [DllImport("user32.dll")]
    private static extern IntPtr GetDesktopWindow();
    [DllImport("user32.dll")]
    private static extern bool GetWindowRect(IntPtr hWnd, ref Rectangle lpRect);

    //ICON info
    //https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getcursorinfo
    [DllImport("user32.dll")]
    private static extern bool GetIconInfo(IntPtr hIcon, out ICONINFO piconinfo);
    [DllImport("user32.dll")]
    private static extern bool GetCursorInfo(out CURSORINFO pci);


    public struct POINT
    {
        public Int32 x;
        public Int32 y;
    }

    public struct ICONINFO
    {
        public bool fIcon;
        public Int32 xHotspot;
        public Int32 yHotspot;
        public IntPtr hbmMask;
        public IntPtr hbmColor;
    }

    public struct CURSORINFO
    {
        public Int32 cbSize;
        public Int32 flags;
        public IntPtr hCursor;
        public Point ptScreenPos;
    }

    GrabRegionForm grabForm;

    public void GrabRect(Rectangle rect)
    {
        int rectWidth = rect.Width - rect.Left;
        int rectHeight = rect.Height - rect.Top;
        Bitmap bm = new Bitmap(rectWidth, rectHeight);
        Graphics g = Graphics.FromImage(bm);
        g.CopyFromScreen(rect.Left, rect.Top, 0, 0, new Size(rectWidth, rectHeight));
        DrawMousePointer(g, Cursor.Position.X - rect.Left, Cursor.Position.Y - rect.Top);
        this.pb_screengrab.Image = bm;
        Clipboard.SetImage(bm);
    }
}

public partial class GrabRegionForm : Form
{
    public Rectangle formRect;
    private Form1 mainForm;
    [DllImport("user32.dll")]
    public static extern bool ReleaseCapture();
    [DllImport("user32.dll")]
    public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
    private void buttonOK_Click(object sender, EventArgs e)
    {
        formRect = new Rectangle(this.Left, this.Top, this.Left + this.Width, this.Top + this.Height);
        this.Hide();
        mainForm.GrabRect(formRect);
        Close();
    }
}

Снимок экрана с показом на 100 %

Снимок экрана с отображением на 125 %

Область, показывающая окно захвата

Фактически захваченная область


person John B    schedule 18.12.2018    source источник
comment
См. примечания здесь: Изображение не нарисовано в правильном месте   -  person Jimi    schedule 18.12.2018
comment
Кроме того, если ваше приложение не поддерживает DPIAware, оно подлежит виртуализации, а это означает, что система автоматически масштабирует его. Это означает, что все показатели экрана и значения DPI также виртуализируются. Если это так, см. здесь: Как настроить приложение для правильной работы на компьютере с высоким разрешением. Некоторые заметки, которые я написал на эту тему здесь.   -  person Jimi    schedule 18.12.2018
comment
Спасибо, Джими, все сработало отлично!!!   -  person John B    schedule 21.12.2018
comment
Коррекция. Спасибо, Джими, что отлично сработало для региона как экраны, так и захват экрана 1. но, к сожалению, захват экрана 2-го дисплея не работает.   -  person John B    schedule 21.12.2018
comment
private void GrabScreen() { Rectangle rect = Screen.AllScreens[Cb_selectedScreen.SelectedIndex].Bounds; Bitmap bm = new Bitmap (rect.Width, rect.Height); Графика g = Graphics.FromImage(bm); g.CopyFromScreen(прямоугольник X, прямоугольник Y, 0, 0, размер прямоугольника); DrawMousePointer(g, Cursor.Position.X, Cursor.Position.Y); this.pb_screengrab.Image = bm; Буфер обмена.SetImage(bm); СделатьСамое Верхнее(); ИгратьИлиНе();   -  person John B    schedule 21.12.2018
comment
Прочитайте эти примечания: Использование SetWindowPos с несколькими мониторами и перечитайте примечания в первой ссылке. Вам необходимо установить Bitmap DPI в соответствии с исходным DPI. Таким образом, вам нужен экранный DPI, и вы можете использовать эту информацию для настройки Bitmap DPI. В противном случае будет использоваться разрешение 96 dpi по умолчанию. В Windows 10 по умолчанию (главный) экран DPI,   -  person Jimi    schedule 21.12.2018
comment
Кроме того, вы благодарили за то, что отлично сработало. Но вы не сказали, что сработало. Вам нужно приложение DPIAware и правильно настроить растровое изображение.   -  person Jimi    schedule 21.12.2018
comment
Я действительно ценю твою помощь. Я проверю их. первая ссылка Изображение не нарисовано в правильном месте немного сбивает с толку, поскольку речь идет об электронном письме из файла. Пока мой скриншот. Пытаясь понять, как преобразовать мой захват в то, что у вас было, я использовал Bitmap bm = new Bitmap(rect.Width, rect.Height); а затем g.CopyFromScreen(rect.X, rect.Y, 0, 0, rect.Size);. Извините, я все еще новичок в этом деле, и графика, похоже, очень слабая.   -  person John B    schedule 21.12.2018
comment
В первой ссылке определенно нет писем, упомянутых :)   -  person Jimi    schedule 21.12.2018
comment
Когда я захватываю границы экрана, он захватывает 2400x1350, что странно, потому что мой экран 1920x1080 без изменения настроек DPI. Использование Screen.AllScreens, похоже, получает неправильные границы. Я даже попытался передать это в Screen.FromRectangle, и это было неудачно, потому что у него были неправильные числа для начала. В основном на первом экране он дает серую область справа и внизу, а на втором экране слева дает серую область слева и внизу.   -  person John B    schedule 21.12.2018
comment
ууууу!!! Теперь это исправлено! Мне пришлось выйти и вернуться в Windows с DPI по умолчанию. Из того, что я могу сказать, в VS2017 был более широкий выбор!!! СПАСИБО, ДЖИМИ, за выдающуюся помощь!!!!!!   -  person John B    schedule 21.12.2018


Ответы (1)


ЕСЛИ вы используете более раннюю версию, чем 4.7, а не Windows 10, следуйте примерам Джими и убедитесь, что вы вышли из системы и снова вошли в Windows.

От Джими https://stackoverflow.com/users/7444103/jimi Как настроить приложение для правильной работы на компьютере с высоким значением DPI dpi-setting-e?answertab=active#tab-top">Как настроить приложение для правильной работы на компьютере с высоким значением DPI (например, 150%)?

От Джими https://stackoverflow.com/users/7444103/jimi Использование SetWindowPos с несколькими мониторами Использование SetWindowPos с несколькими мониторами

Если я нацелю свое приложение только на Windows 10, теперь это невероятно просто. Microsoft упростила изменение настроек DPI с помощью версии 4.7 при использовании Windows 10.

https://docs.microsoft.com/en-us/dotnet/framework/winforms/high-dpi-support-in-windows-forms

Объявите совместимость с Windows 10. Затем добавьте следующее в файл app.manifest в XML под коммандой для совместимости с Windows 10.

supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"

Включите учет DPI для каждого монитора в файле app.config. Windows Forms представляет новый элемент для поддержки новых функций и настроек, добавленных начиная с .NET Framework 4.7. Чтобы воспользоваться преимуществами новых функций, поддерживающих высокое разрешение, добавьте в файл конфигурации приложения следующее.

Перейдите к строке XML для System.Windows.Forms.ApplicationConfigurationSection.

add key="DpiAwareness" value="PerMonitorV2"
person John B    schedule 11.02.2019