Winforms: 为什么Graphics.DpiX/DpiY总是返回96

一、问题描述

Windows中缺省的DPI值为96。在Vista中,我们把DPI设为150%,也就是144。可如果此时我们去获取属性System.Drawing.Graphics.DpiX或者System.Drawing.Graphics.DpiY的值,我们发现得到的仍然是96,而不是144

二、原因分析

修改WindowsDPI值,所有窗口的字体会变大,因此窗口的布局(Layout)也有可能不同。Windows程序员可以根据WindowsDPI设置去定义窗口的布局,但我们发现很多程序员在根据DPI定义窗口布局的时候遇到了很多问题。所以Windows的解决办法就是不建议程序员根据DPI设置调整窗口布局,Windows会根据系统设置自动按比例放大窗口的所有元素(包括文字和控件)。这样虽然降低了程序员的灵活性和自主性,但至少保证了窗口布局在所有DPI设置时都是正确的。

于是从Vista开始,Windows添加了一个叫SetProcessDPIAwareAPI。缺省的情况下,该函数不被调用,因此我们的进程不知道DPI已经修改,那我们得到的DPI也总是其缺省值96了。

三、建议

如前所述,我们不建议程序员试图去获取DPI设置值,并根据该值去调整窗口布局。如果确实需要得到系统的DPI的设置值,我们必须调用API SetProcessDPIAware。下面是一个例子:

public class Utility

{

private const int LOGPIXELSX = 88;

private const int LOGPIXELSY = 90;

public static int DpiX

{

get

{

if (Environment.OSVersion.Version.Major >= 6)

SetProcessDPIAware();

IntPtr hDC = GetDC(new HandleRef(null, IntPtr.Zero));

return GetDeviceCaps(hDC, LOGPIXELSX);

}

}

public static int DpiY

{

get

{

if (Environment.OSVersion.Version.Major >= 6)

SetProcessDPIAware();

IntPtr hDC = GetDC(new HandleRef(null, IntPtr.Zero));

return GetDeviceCaps(hDC, LOGPIXELSY);

}

}

[DllImport("user32.dll")]

private extern static bool SetProcessDPIAware();

[DllImport("user32.dll")]

private extern static IntPtr GetDC(HandleRef hWnd);

[DllImport("gdi32.dll")]

private extern static int GetDeviceCaps(IntPtr hdc, int nIndex);

}

上述代码先得到显示器的DC,然后得到该DCX方向和Y方向的DPI值。另外值得注意的是,由于API SetProcessDPIAwareVista才被引入,所以在调用该API之前,我们需要判断Windows的版本号。Vista的主版本号是6

你可能感兴趣的:(windows)