0

I followed this answer and it work great with one monitor (despite it was 11 years old :D). But when I attached my 2nd monitor and use it, it doesn't work anymore. Instead, it always give weird color like all black when x > 2500

enter image description here

Edit: I discovered the problem, it was due to different text scale on both monitor (1st is 125% and 2nd is 100%), I change setting both to 125% and work like a charm. Now the problem is, how can I automatic detect font scaling on other monitor (currently I use this for first monitor)

Doan Van Thang
  • 989
  • 1
  • 10
  • 21
  • What color mode are you using? The monitor has memory and not all the memory is used depending on the color mode. If you are seeing black you are reading memory that is not being used in the color mode that is set. – jdweng Apr 08 '20 at 18:12
  • Read the notes here, about the [System Displays disposition and VirtualScreen](https://stackoverflow.com/a/53026765/7444103) – Jimi Apr 08 '20 at 18:13
  • I discovered the problem, it was due to different text scale on both monitor – Doan Van Thang Apr 09 '20 at 04:06

1 Answers1

0

So the problem is different scales in each monitor

First, I detect index of which monitor the input point is in with this answer :

    private int ConvertMousePointToScreenIndex(Point mousePoint)
    {
        //first get all the screens 
        System.Drawing.Rectangle ret;

        for (int i = 1; i <= Screen.AllScreens.Count(); i++)
        {
            ret = Screen.AllScreens[i - 1].Bounds;
            if (ret.Contains(mousePoint))
                return i - 1;
        }
        return 0;
    }

Second, I just need to get real width / virtual width of that indexed monitor based on this answer

        const int ENUM_CURRENT_SETTINGS = -1;

        public double GetScale(Point point)
        {
            Screen screen = Screen.AllScreens[ConvertMousePointToScreenIndex(point)];
            DEVMODE dm = new DEVMODE();
            dm.dmSize = (short)Marshal.SizeOf(typeof(DEVMODE));
            EnumDisplaySettings(screen.DeviceName, ENUM_CURRENT_SETTINGS, ref dm);

            double RealWidth = dm.dmPelsWidth;
            double VirtualWidth = screen.Bounds.Width;
            return RealWidth / VirtualWidth;
        }

        [DllImport("user32.dll")]
        public static extern bool EnumDisplaySettings(string lpszDeviceName, int iModeNum, ref DEVMODE lpDevMode);

        [StructLayout(LayoutKind.Sequential)]
        public struct DEVMODE
        {
            private const int CCHDEVICENAME = 0x20;
            private const int CCHFORMNAME = 0x20;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
            public string dmDeviceName;
            public short dmSpecVersion;
            public short dmDriverVersion;
            public short dmSize;
            public short dmDriverExtra;
            public int dmFields;
            public int dmPositionX;
            public int dmPositionY;
            public ScreenOrientation dmDisplayOrientation;
            public int dmDisplayFixedOutput;
            public short dmColor;
            public short dmDuplex;
            public short dmYResolution;
            public short dmTTOption;
            public short dmCollate;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
            public string dmFormName;
            public short dmLogPixels;
            public int dmBitsPerPel;
            public int dmPelsWidth;
            public int dmPelsHeight;
            public int dmDisplayFlags;
            public int dmDisplayFrequency;
            public int dmICMMethod;
            public int dmICMIntent;
            public int dmMediaType;
            public int dmDitherType;
            public int dmReserved1;
            public int dmReserved2;
            public int dmPanningWidth;
            public int dmPanningHeight;
        }

And finally, apply it to GetColorAt :

        [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
        public static extern int BitBlt(IntPtr hDC, int x, int y, int nWidth, int nHeight, IntPtr hSrcDC, int xSrc, int ySrc, int dwRop);

        Bitmap screenPixel = new Bitmap(1, 1, PixelFormat.Format32bppArgb);
        public Color GetColorAt(Point location)
        {
            double scale = GetScale(location);
            using (Graphics gdest = Graphics.FromImage(screenPixel))
            {
                using (Graphics gsrc = Graphics.FromHwnd(IntPtr.Zero))
                {
                    IntPtr hSrcDC = gsrc.GetHdc();
                    IntPtr hDC = gdest.GetHdc();
                    int retval = BitBlt(hDC, 0, 0, 1, 1, hSrcDC, (int)Math.Round(point.X * scale), (int)Math.Round(point.Y * scale), (int)CopyPixelOperation.SourceCopy);
                    gdest.ReleaseHdc();
                    gsrc.ReleaseHdc();
                }
            }

            return screenPixel.GetPixel(0, 0);
        }
Doan Van Thang
  • 989
  • 1
  • 10
  • 21