【笔记】C#得到真正的屏幕大小

2 篇文章 0 订阅

闲来研究下非神经网络的computer vision,啥库都不用,先C#试试手撸截屏器,抄起代码来可快了(见下面的代码)。可是使用的时候发现,为啥截屏只截了一部分呢?

        public static Rectangle GetScreenSize(Form from)
        {
            Rectangle rect = Screen.FromControl(from).Bounds;
            return rect;
        }

        public static Bitmap CaptureScreen(Form from, string outputFilename)
        {
            Rectangle rect = GetScreenSize(from);
            using (Bitmap bitmap = new Bitmap(rect.Width, rect.Height))
            {
                using (Graphics g = Graphics.FromImage(bitmap))
                {
                    g.CopyFromScreen(new Point(0, 0), Point.Empty, rect.Size);
                }
                if (outputFilename.Length > 0)
                {
                    bitmap.Save(outputFilename, ImageFormat.Png);
                }
                return bitmap.Clone(new Rectangle(0, 0, bitmap.Width, bitmap.Height), System.Drawing.Imaging.PixelFormat.DontCare);
            }
        }

然后搜索了各种方案,要么引用PresentationCore的,要么引用GetDpiForSystem的,一堆乱遭遭的;我只想知道我 2560x1600 的屏幕为啥 Screen 只返回 1707x1067
这个应该是DPI的问题,有点时间又没有接触windows了,想当初还是GetDC的年代…突然意识到我的显示屏的DPI应该是比默认值96高的…
所以查了下,默认原来Windows应用并没有给开启这个high DPI awareness…所以不管用什么API统一都是返回的96
所以这里应该有两种解决方案,一个是直接去读取Windows注册表,找到屏幕缩放比例设置的那个位置,另一个是给应用开启high DPI awareness,就是有一个叫SetProcessDpiAwareness的Windows API,在 Shcore.dll 里:

        [DllImport("shcore.dll")]
        public static extern uint SetProcessDpiAwareness(uint mode);

但是文档里写了,Windows 8.1 / Server 2012R2 才支持,那之前的是不是就不用考虑DPI的问题了,但是也得保证能运行呀。所以改成LoadLibrary的形式:

    static class NativeMethods
    {
        [DllImport("kernel32.dll")]
        public static extern IntPtr LoadLibrary(string dllToLoad);

        [DllImport("kernel32.dll")]
        public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);

        [DllImport("kernel32.dll")]
        public static extern bool FreeLibrary(IntPtr hModule);
    }

    // v--- in main form scope
        private void EnableDpiAwareness()
        {
            // skip this procedure if Windows version is below
            // Shcore.dll#SetProcessDpiAwareness [min] Windows 8.1 / Windows Server 2012 R2
            IntPtr shcoreDll = NativeMethods.LoadLibrary(@"Shcore.dll");
            if (shcoreDll != IntPtr.Zero) return;
            IntPtr ptrSetProcessDpiAwareness = NativeMethods.GetProcAddress(shcoreDll, "SetProcessDpiAwareness");
            if (ptrSetProcessDpiAwareness != IntPtr.Zero)
            {
                SetProcessDpiAwareness fnSetProcessDpiAwareness = (SetProcessDpiAwareness)System.Runtime.InteropServices.Marshal.GetDelegateForFunctionPointer(ptrSetProcessDpiAwareness, typeof(SetProcessDpiAwareness));
                fnSetProcessDpiAwareness(/* DPI_AWARENESS_SYSTEM_AWARE */ 1);
            }
            NativeMethods.FreeLibrary(shcoreDll);
        }

然后把EnableDpiAwareness放在mainInitializeComponent 之前运行就好了…所有都正常了…

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值