john1990_1 Ответов: 1

Как сделать: "copyfromscreen" осведомлен о масштабировании рабочего стола windows?


Приведенный ниже код при вызове для получения пикселя на нескольких экранах или на одном экране с увеличением дисплея на нем, например 150%, он не получает правильный пиксель в 3840x2160 пикселей, он получает еще один пиксель из-за увеличения, как исправить это плз?

Что я уже пробовал:

static Color GetPixel(Point p)
{
    using (var bitmap = new Bitmap(1, 1))
    {
        using (var graphics = Graphics.FromImage(bitmap))
        {
            graphics.CopyFromScreen(p, new Point(0, 0), new Size(1, 1));
        }
        return bitmap.GetPixel(0, 0);
    }
}



Я делаю это:
if (formMain.WindowState != FormWindowState.Minimized)
                {
                    if (
                     (ClassGetPixelWithDisplayZoomInMind.get_pixel(formMain.PointToScreen(new Point(formMain.pictureBoxCleanup.Right + 50, formMain.pictureBoxCleanup.Top + 20))) == Color.Gray) &&
                     (ClassGetPixelWithDisplayZoomInMind.get_pixel(formMain.PointToScreen(new Point(formMain.pictureBoxCleanup.Right + 50 + 1, formMain.pictureBoxCleanup.Top + 20))) == Color.DarkGray) &&
                     (ClassGetPixelWithDisplayZoomInMind.get_pixel(formMain.PointToScreen(new Point(formMain.pictureBoxCleanup.Right + 50 + 2, formMain.pictureBoxCleanup.Top + 20))) == Color.Brown) &&
                     (ClassGetPixelWithDisplayZoomInMind.get_pixel(formMain.PointToScreen(new Point(formMain.pictureBoxCleanup.Right + 50, formMain.pictureBoxCleanup.Top + 21))) == Color.RosyBrown) &&
                     (ClassGetPixelWithDisplayZoomInMind.get_pixel(formMain.PointToScreen(new Point(formMain.pictureBoxCleanup.Right + 50 + 1, formMain.pictureBoxCleanup.Top + 21))) == Color.DarkSlateGray) &&
                     (ClassGetPixelWithDisplayZoomInMind.get_pixel(formMain.PointToScreen(new Point(formMain.pictureBoxCleanup.Right + 50 + 2, formMain.pictureBoxCleanup.Top + 21))) == Color.DarkGray) &&
                     (ClassGetPixelWithDisplayZoomInMind.get_pixel(formMain.PointToScreen(new Point(formMain.pictureBoxCleanup.Right + 50, formMain.pictureBoxCleanup.Top + 22))) == Color.SlateGray) &&
                     (ClassGetPixelWithDisplayZoomInMind.get_pixel(formMain.PointToScreen(new Point(formMain.pictureBoxCleanup.Right + 50 + 1, formMain.pictureBoxCleanup.Top + 22))) == Color.LightSlateGray) &&
                     (ClassGetPixelWithDisplayZoomInMind.get_pixel(formMain.PointToScreen(new Point(formMain.pictureBoxCleanup.Right + 50 + 2, formMain.pictureBoxCleanup.Top + 22))) == Color.LightGray))
                    {
                        Program.DoMouseClick(formMain.PointToScreen(new Point(formMain.pictureBoxCleanup.Right + 50 + 1, formMain.pictureBoxCleanup.Top + 21)));
                    }
                }


А это:



private void FormMain_Paint(object sender, PaintEventArgs e)
{
    ClassSetGetPixel.SetPixel(this, pictureBoxCleanup.Right + 50, 20, Color.Gray);
    ClassSetGetPixel.SetPixel(this, pictureBoxCleanup.Right + 50 + 1,20, Color.DarkGray);
    ClassSetGetPixel.SetPixel(this, pictureBoxCleanup.Right + 50 + 2, 20, Color.Brown);
    ClassSetGetPixel.SetPixel(this, pictureBoxCleanup.Right + 50, 21, Color.RosyBrown);
    ClassSetGetPixel.SetPixel(this, pictureBoxCleanup.Right + 50 + 1, 21, Color.White);
    ClassSetGetPixel.SetPixel(this, pictureBoxCleanup.Right + 50 + 2, 21, Color.DarkGray);
    ClassSetGetPixel.SetPixel(this, pictureBoxCleanup.Right + 50, 22, Color.SlateGray);
    ClassSetGetPixel.SetPixel(this, pictureBoxCleanup.Right + 50 + 1, 22, Color.LightSlateGray);
    ClassSetGetPixel.SetPixel(this, pictureBoxCleanup.Right + 50 + 2, 22, Color.LightGray);
}

1 Ответов

Рейтинг:
2

gggustafson

Когда я разрабатывал известный инструмент цветовой палитре (в Известный Инструмент Палитры Цветов - Окончательная Редакция - Надеюсь[^], Я столкнулся с той же проблемой (только в производственной среде). Я пересмотрел свой код следующим образом, и он, похоже, работает.

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

namespace Known_Colors_Palette
    {

    // ************************************************ class Win32API

    /// <summary>
    /// makes available various Win32 API entry points
    /// </summary>
    public class Win32API
        {

        // **************************************************** BitBlt
        
        [ DllImport ( "gdi32.dll", 
                      EntryPoint = "BitBlt" ) ]
        public static extern bool BitBlt ( IntPtr hdcDest, 
                                           int    nXDest,
                                           int    nYDest, 
                                           int    nWidth, 
                                           int    nHeight, 
                                           IntPtr hdcSrc,
                                           int    nXSrc, 
                                           int    nYSrc, 
                                           int    dwRop );

        // ************************************************* get_pixel

        /// <summary>
        /// obtain the GDI+ Color of the pixel at the specified 
        /// location on the monitor
        /// </summary>
        /// <param name="location">
        /// Point containing the location of the pixel on the monitor 
        /// whose Color is to be obtained
        /// </param>
        /// <returns>
        /// the GDI+ Color of the pixel at the location on the screen
        /// </returns>
        /// <remarks>
        /// The method does not use GetPixel, resulting in four 
        /// benefits: 
        /// 1.  the method will not raise an exception when used 
        ///     in a multi-monitor environment; 
        /// 2.  it is faster than GetPixel; 
        /// 3.  the Bitmap used is only one pixel high and wide;
        /// 4.  the Bitmap is local to this method.
        /// </remarks>
        /// <see>
        /// http://stackoverflow.com/questions/1483928/
        ///     how-to-read-the-color-of-a-screen-pixel
        /// </see>
        public static Color get_pixel ( Point location )
            {
            Bitmap  screen_pixel = new Bitmap (
                                        1,
                                        1,
                                        PixelFormat.Format32bppArgb );

            using ( Graphics destination = Graphics.FromImage ( 
                                                    screen_pixel ) )
                {
                using ( Graphics source = Graphics.FromHwnd ( 
                                                   IntPtr.Zero ) )
                    {
                    IntPtr source_DC = source.GetHdc ( );
                    IntPtr destination_DC = destination.GetHdc ( );

                    BitBlt ( destination_DC,
                             0,
                             0,
                             1,
                             1,
                             source_DC,
                             location.X,
                             location.Y,
                             ( int ) CopyPixelOperation.SourceCopy );
                    }
                }

            return ( screen_pixel.GetPixel ( 0, 0 ) );
            }

        } // class Win32API

    } // namespace Known_Colors_Palette

Это небольшая часть кода Win32API.cs, но она включает в себя ту часть, которая может быть Вам полезна. удачи.


john1990_1

ТХ-х, это не сработало для меня:
Я отредактировал свой вопрос с помощью 2 новых блоков кода, пожалуйста, посмотрите их.

gggustafson

Ты приводишь меня в такое же замешательство, как и сама. Почему в тесте смещение на один пиксель?

john1990_1

I want to make sure formMain is actually shown on the display and there's no lag preventing it from being shown on the display, so I made 3x3 square of colors and this way there's a tiny chance that the pixel colors aren't from my form, because I want my program to order Windows to fake a mouse click on my program (form) in order to select the form in my Google Translate page in my web browser control in my form! I tried everything to select the form like formMain.webBrowser.Document.GetElementByID("source").Focus(); and stuff like that and none of them is always successful so I make a mouse click that always works but I dont want it to click something else I want to make sure the click is on my program (my form).

gggustafson

Я думаю, что ты уже обмотался вокруг Акселя. Вам нужно остановиться и перезапустить, успешно выполнив одну вещь. Похоже, что первое, что вы должны сделать, это написать метод, который будет определять свойства формы, предположительно отображаемой на мониторе. Видишь ли https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-findwindowa?redirectedfrom=MSDN. Тогда мы сможем обсудить следующий шаг.

john1990_1

The window is *my program's window*, my program wants to order a mouse click on MY OWN WINDOW THE SAME PROGRAM THAT ORDERS THE CLICK IS THE SAME PROGRAM THAT RECEIVES THE CLICK, this is because wb.Document.GetElementById("source").Focus() is not working, I want to order a mouse click on my program's window to select focus of input on it, this is used when F1 is pressed and my program opens its window for the user to start typing in the source textbox is the "web browser control" in my program's window, my program is to translate, I want to make sure the window is open because when my Winfors.Net app orders Windows to simulate a mouse click on the same app's window I don't want this mouse simulated click to go somewhere other than my program's window. I think it's pretty much clear!!!

gggustafson

Никогда не кричи. Вы теряете людей, которые могли бы помочь. Делай, как я говорю: Остановись, отойди от проблемы, а потом делай, как я прошу. Вы читали статью, на которую я ссылался?

john1990_1

Я просто делал текст жирным шрифтом, так как я не знаю, как это сделать здесь, я не кричал, Я хочу сделать важные моменты жирными, да, я видел то, на что вы ссылались, это не то, что я хочу, я хочу убедиться, что мое окно открыто и отображается на дисплее, и когда щелчок мыши, который моя программа делает на окне моей программы, он идет к моей программе, а не к чему-то другому, если мое окно не открылось быстро и запаздывало. Я хочу проверить точку на экранах и убедиться, что она находится в моей форме и моя форма отображается!

gggustafson

Итак, окно, которое вы хотите расположить, является текущим окном?

john1990_1

Я хочу, чтобы текущее окно моей программы, которое заказывает клик, Я хочу, чтобы программа, которая заказывает клик, нажимала на себя, когда пользователь нажимает F1 в Windows глобально, моя программа открывает форму окна, и в ней есть элемент управления веб-браузером с навигацией по странице Google Translate, я хочу имитировать щелчок мыши на программе, которая его имитировала (моя программа (приложение)), я хочу имитировать щелчок мыши, чтобы выбрать фокус ввода на текстовом поле "источник" в Google Translate, потому что wb.Document.GetElementById("Soucre").Фокус() не всегда работает.