【C#】获取电脑DPI

心不动则不痛 提交于 2020-03-31 16:08:59
public static class DPIGeter
    {
        /// <summary>
        /// 获取DPI
        /// </summary>
        /// <param name="dpix"></param>
        /// <param name="dpiy"></param>
        public static void GetDPI(ref float dpix, ref float dpiy)
        {
            SetProcessDPIAware();//此处会忽视系统DWM虚拟化,不建议使用
            IntPtr screenDC = GetDC(IntPtr.Zero);
            dpix = GetDeviceCaps(screenDC, LOGPIXELSX);
            dpiy = GetDeviceCaps(screenDC, LOGPIXELSY);
            ReleaseDC(IntPtr.Zero, screenDC);
        }
        /// <summary>
        /// 获取DPI缩放比例
        /// </summary>
        /// <param name="dpiscalex"></param>
        /// <param name="dpiscaley"></param>
        public static void GetDPIScale(ref float dpiscalex, ref float dpiscaley)
        {
            int x = GetSystemMetrics(SM_CXSCREEN);
            int y = GetSystemMetrics(SM_CYSCREEN);
            IntPtr hdc = GetDC(IntPtr.Zero);
            int w = GetDeviceCaps(hdc, DESKTOPHORZRES);
            int h = GetDeviceCaps(hdc, DESKTOPVERTRES);
            ReleaseDC(IntPtr.Zero, hdc);
            dpiscalex = (float)w / x;
            dpiscaley = (float)h / y;
        }
        [DllImport("user32.dll")]
        static extern IntPtr GetDC(IntPtr ptr);

        [DllImport("user32.dll", EntryPoint = "ReleaseDC")]
        public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDc);

        [DllImport("gdi32.dll")]
        public static extern IntPtr CreateDC(
        string lpszDriver, // driver name
        string lpszDevice, // device name
        string lpszOutput, // not used; should be NULL
        Int64 lpInitData // optional printer data
        );

        [DllImport("gdi32.dll")]
        public static extern int GetDeviceCaps(
        IntPtr hdc, // handle to DC
        int nIndex // index of capability
        );

        [DllImport("user32.dll")]
        internal static extern bool SetProcessDPIAware();

        [DllImport("user32")]
        public static extern int GetSystemMetrics(
        int nIndex
        );

        [DllImport("user32.dll", EntryPoint = "GetDesktopWindow", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr GetDesktopWindow();

        [DllImport("user32.dll")]
        public static extern int GetWindowRect(IntPtr hwnd, out Rect lpRect);

        public struct Rect
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }

        const int DRIVERVERSION = 0;
        const int TECHNOLOGY = 2;
        const int HORZSIZE = 4;
        const int VERTSIZE = 6;
        const int HORZRES = 8;
        const int VERTRES = 10;
        const int BITSPIXEL = 12;
        const int PLANES = 14;
        const int NUMBRUSHES = 16;
        const int NUMPENS = 18;
        const int NUMMARKERS = 20;
        const int NUMFONTS = 22;
        const int NUMCOLORS = 24;
        const int PDEVICESIZE = 26;
        const int CURVECAPS = 28;
        const int LINECAPS = 30;
        const int POLYGONALCAPS = 32;
        const int TEXTCAPS = 34;
        const int CLIPCAPS = 36;
        const int RASTERCAPS = 38;
        const int ASPECTX = 40;
        const int ASPECTY = 42;
        const int ASPECTXY = 44;
        const int SHADEBLENDCAPS = 45;
        const int LOGPIXELSX = 88;
        const int LOGPIXELSY = 90;
        const int SIZEPALETTE = 104;
        const int NUMRESERVED = 106;
        const int COLORRES = 108;
        const int PHYSICALWIDTH = 110;
        const int PHYSICALHEIGHT = 111;
        const int PHYSICALOFFSETX = 112;
        const int PHYSICALOFFSETY = 113;
        const int SCALINGFACTORX = 114;
        const int SCALINGFACTORY = 115;
        const int VREFRESH = 116;
        const int DESKTOPVERTRES = 117;
        const int DESKTOPHORZRES = 118;
        const int BLTALIGNMENT = 119;
        const int SM_CXSCREEN = 0;//'屏幕宽度
        const int SM_CYSCREEN = 1;//'屏幕高度
        const int SM_CXVSCROLL = 2;//'垂直滚动条的宽度
        const int SM_CYHSCROLL = 3;//'水平滚动条的宽度
        const int SM_CYCAPTION = 4;//'Height of windows caption 实际标题高度加上SM_CYBORDER
        const int SM_CXBORDER = 5;//'Width of no-sizable borders 无法测量的窗口框架宽度
        const int SM_CYBORDER = 6;// 'Height of non-sizable borders 无法测量的窗口框架高度
        const int SM_CXDLGFRAME = 7;// 'Width of dialog box borders
        const int SM_CYDLGFRAME = 8;//'Height of dialog box borders
        const int SM_CYHTHUMB = 9;//'Height of scroll box on horizontal scroll bar 水平滚动条上滑块的高度
        const int SM_CXHTHUMB = 10;//' Width of scroll box on horizontal scroll bar 水平滚动条上滑块的宽度
        const int SM_CXICON = 11;// 'Width of standard icon 图标宽度
        const int SM_CYICON = 12;//'Height of standard icon 图标高度
        const int SM_CXCURSOR = 13;//'Width of standard cursor 光标宽度
        const int SM_CYCURSOR = 14;//'Height of standard cursor 光标高度
        const int SM_CYMENU = 15;// 'Height of menu 以像素计算的单个菜单条的高度
        const int SM_CXFULLSCREEN = 16;// 'Width of client area of maximized window
        const int SM_CYFULLSCREEN = 17;// 'Height of client area of maximized window
        const int SM_CYKANJIWINDOW = 18;//'Height of Kanji window
        const int SM_MOUSEPRESENT = 19;//'True is a mouse is present 如果为TRUE或不为0的值则安装了鼠标,否则没有安装。
        const int SM_CYVSCROLL = 20;//'Height of arrow in vertical scroll bar
        const int SM_CXHSCROLL = 21;//'Width of arrow in vertical scroll bar
        const int SM_DEBUG = 22;//'True if deugging version of windows is running
        const int SM_SWAPBUTTON = 23;//'True if left and right buttons are swapped.
        const int SM_CXMIN = 28;// 'Minimum width of window
        const int SM_CYMIN = 29;//'Minimum height of window
        const int SM_CXSIZE = 30;//'Width of title bar bitmaps
        const int SM_CYSIZE = 31;//'height of title bar bitmaps
        const int SM_CXMINTRACK = 34;// 'Minimum tracking width of window
        const int SM_CYMINTRACK = 35;//'Minimum tracking height of window
        const int SM_CXDOUBLECLK = 36;// 'double click width
        const int SM_CYDOUBLECLK = 37;// 'double click height
        const int SM_CXICONSPACING = 38;//'width between desktop icons
        const int SM_CYICONSPACING = 39;//'height between desktop icons
        const int SM_MENUDROPALIGNMENT = 40;//'Zero if popup menus are aligned to the left of the memu bar item. True if it is aligned to the right.
        const int SM_PENWINDOWS = 41;// 'The handle of the pen windows DLL if loaded.
        const int SM_DBCSENABLED = 42;// 'True if double byte characteds are enabled
        const int SM_CMOUSEBUTTONS = 43;//'Number of mouse buttons.
        const int SM_CMETRICS = 44;// 'Number of system metrics
        const int SM_CLEANBOOT = 67;//'Windows 95 boot mode. 0 = normal, 1 = safe, 2 = safe with network
        const int SM_CXMAXIMIZED = 61;//'default width of win95 maximised window
        const int SM_CXMAXTRACK = 59;// 'maximum width when resizing win95 windows
        const int SM_CXMENUCHECK = 71;// 'width of menu checkmark bitmap
        const int SM_CXMENUSIZE = 54;//'width of button on menu bar
        const int SM_CXMINIMIZED = 57;// 'width of rectangle into which minimised windows must fit.
        const int SM_CYMAXIMIZED = 62;//'default height of win95 maximised window
        const int SM_CYMAXTRACK = 60;//'maximum width when resizing win95 windows
        const int SM_CYMENUCHECK = 72;//'height of menu checkmark bitmap
        const int SM_CYMENUSIZE = 55;//'height of button on menu bar
        const int SM_CYMINIMIZED = 58;// 'height of rectangle into which minimised windows must fit.
        const int SM_CYSMCAPTION = 51;// 'height of windows 95 small caption
        const int SM_MIDEASTENABLED = 74;// 'Hebrw and Arabic enabled for windows 95
        const int SM_NETWORK = 63;//'bit o is set if a network is present.
        const int SM_SECURE = 44;//'True if security is present on windows 95 system
        const int SM_SLOWMACHINE = 73;// 'true if machine is too slow to run win95.
    }
附:
 SetProcessDPIAware 和 IsProcessDPIAware , 通过调用SetProcessDPIAware , 我们告诉系统不要对我们的程序进行DWM虚拟化。
这里还有特殊情况也提一下: 我们在高DPI下通过窗口句柄取到的坐标信息是和目标程序是否支持DWM虚拟化相关联的, 我们对支持DWM虚拟化的程序窗口调用GetWindowRect, 取到的坐标也是经过DWM缩放后的坐标; 对禁用DWM虚拟化程序的窗口调用GetWindowRect, 取到的坐标则是没有经过缩放的原始坐标。

 最后我们再讨论下Win8.1 对高DPI的支持, WIn8.1对高DPi以3种方式支持 Process_DPI_Awareness : 
typedef enum _Process_DPI_Awareness { 
  Process_DPI_Unaware            = 0,
  Process_System_DPI_Aware       = 1,
  Process_Per_Monitor_DPI_Aware  = 2
} Process_DPI_Awareness;
下面我们依次讨论这3种方式: 

第一种Unaware, 该种方式是告诉系统, 我的程序不支持DPI aware, 请通过DWM虚拟化帮我们实现。 该方式和上面Win7/Win8对高DPI的支持的实现基本一样,主要区别是它通过GetWindowRect取到的坐标都是经过DWM缩放后的, 无论对方窗口是不是支持DWM虚拟化。
 
第二种方式是System DPI aware, 该方式下告诉系统, 我的程序会在启动的显示器上自己支持DPI aware, 所以不需要对我进行DWM 虚拟化。 但是当我的程序被拖动到其他DPI不一样的显示器时, 请对我们先进行system DWM虚拟化缩放。
 
第三种方式是Per Monitor DPI aware, 该方式是告诉系统, 请永远不要对我进行DWM虚拟化,我会自己针对不同的Monitor的DPi缩放比率进行缩放。
 
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!