C# CopyFromScreen via Cursor Position with Windows Scaling

700 Views Asked by At

I ran into a problem...

I am running 2 displays atm, the one on the left is an 4K (running at 3840x2160) the second one is running on 1280x1024.

The 4k-Display is set to scale 150% via the Windows Settings Menu.

I am currently trying to write an C#-Screenshot-Capture the following way:

        for (int f = 0; f < Screen.AllScreens.Length; f++)
        {
            //Create new Form & FormData
            Form rectangleForm = new displayForm();
            FormData rectangleFormData = new FormData();
            //Set Location
            rectangleForm.StartPosition = FormStartPosition.Manual;
            rectangleForm.Location = Screen.AllScreens[f].WorkingArea.Location;
            //Set BackgroundColor
            rectangleForm.BackColor = Color.Wheat;
            //Set TranspacencyKey to BackgroundColor
            rectangleForm.TransparencyKey = rectangleForm.BackColor;
            //Hide Control-, Maximze- and Minimize-Box
            rectangleForm.ControlBox = false;
            rectangleForm.MaximizeBox = false;
            rectangleForm.MinimizeBox = false;
            //Set Form-Style
            rectangleForm.FormBorderStyle = FormBorderStyle.None;
            //Set it to maximze
            rectangleForm.WindowState = FormWindowState.Maximized;
            //Register Mouse-Events
            rectangleForm.MouseDown += rectangleForm_MouseDown;
            rectangleForm.MouseMove += rectangleForm_MouseMove;
            rectangleForm.Paint += rectangleForm_Paint;
            rectangleForm.MouseUp += rectangleForm_MouseUp;
            //Initialize FormData
            rectangleFormData.rectangleForm = rectangleForm;
            resetFormData(rectangleFormData);
     }

   void rectangleForm_MouseDown(object sender, MouseEventArgs e)
    {
        FormData formData = rectangleForms[(Form)sender];
        formData.formMouseDown = e.Location;
        formData.screenshotMouseDown = Cursor.Position;
    }

    void rectangleForm_MouseMove(object sender, MouseEventArgs e)
    {
        FormData formData = rectangleForms[(Form)sender];
        formData.rectangleForm.Invalidate();

        if (e.Button != MouseButtons.Left) return;
        formData.formMouseMove = e.Location;
        formData.screenshotMouseMove = Cursor.Position;
        formData.formRectangle = new Rectangle(Math.Min(formData.formMouseDown.X, formData.formMouseMove.X), Math.Min(formData.formMouseDown.Y, formData.formMouseMove.Y),
                             Math.Abs(formData.formMouseDown.X - formData.formMouseMove.X), Math.Abs(formData.formMouseDown.Y - formData.formMouseMove.Y));
        formData.screenshotRectangle = new Rectangle(Math.Min(formData.screenshotMouseDown.X, formData.screenshotMouseMove.X), Math.Min(formData.screenshotMouseDown.Y, formData.screenshotMouseMove.Y),
                             Math.Abs(formData.screenshotMouseDown.X - formData.screenshotMouseMove.X), Math.Abs(formData.screenshotMouseDown.Y - formData.screenshotMouseMove.Y));
    }

    void rectangleForm_Paint(object sender, PaintEventArgs e)
    {
        FormData formData = rectangleForms[(Form)sender];
        formData.rectangleForm.Invalidate();
        e.Graphics.DrawRectangle(Pens.Red, formData.formRectangle);
    }

void rectangleForm_MouseUp(object sender, MouseEventArgs e) { FormData formData = rectangleForms[(Form)sender]; formData.rectangleForm.Invalidate(); formData.rectangleForm.Hide();

        Bitmap bmp = new Bitmap(formData.screenshotRectangle.Width, formData.screenshotRectangle.Height);
        using (Graphics G = Graphics.FromImage(bmp))
        {
            System.Diagnostics.Trace.WriteLine("TOP: " + formData.rectangleForm.Bounds.Top);
            System.Diagnostics.Trace.WriteLine("LEFT: " + formData.rectangleForm.Location.X);
            System.Diagnostics.Trace.WriteLine("MOUSE X: " + GetCursorPosition().X);

            int sourceX = formData.formRectangle.Location.X + formData.rectangleForm.Left;
            int sourceY = formData.formRectangle.Location.Y + formData.rectangleForm.Top;

            G.CopyFromScreen(new Point(sourceX, sourceY), Point.Empty, formData.screenshotRectangle.Size,
                             CopyPixelOperation.SourceCopy);
            bmp.Save("file.png");
        }
        endScreenshot();
    }

The main problem here is that CopyFromScreen isnt using the windows-scaling which means my Cursor-Position at the TOP-LEFT corner of Display 2 (the small one) is X:5760 Y: 1692 but when I capture an screenshot of ALL Monitors via:

        int screenLeft = SystemInformation.VirtualScreen.Left;
        int screenTop = SystemInformation.VirtualScreen.Top;
        int screenWidth = SystemInformation.VirtualScreen.Width;
        int screenHeight = SystemInformation.VirtualScreen.Height;

        using (Bitmap bmp = new Bitmap(screenWidth, screenHeight))
        {
            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.CopyFromScreen(screenLeft, screenTop, 0, 0, bmp.Size);
            }
            bmp.Save("desktop.png");
        }

The TOP-LEFT Corner position of Display 2 is (as mentioned and should normally be without scaling) X: 3840 Y: 1128 (Y seems to be uninteresting for now)

So is there like any option to tell CopyFromScreen to take care of the Windows Scaling (which in my situation only affects display 1 (4k)) or any other solutions?

greetings kevin

0

There are 0 best solutions below