如何获得Windows显示设置?


75

Windows 7中有显示设置(控制面板->显示)。它允许更改文本和屏幕上其他项目的大小。我需要获得此设置,以便能够基于设置值打开/关闭C#应用程序中的某些功能。那可能吗?


1
您对哪种设置感兴趣?有许多。
David Heffernan

如果您使用设置-控制面板->显示打开此页面。只有一种设置可以更改屏幕上文本和其他项目的大小。选项为“ Smaller”,“ Medium”和“ Larger”
newmember

Answers:


52

此设置是屏幕DPI或每英寸点数。

像这样阅读:

float dpiX, dpiY;
Graphics graphics = this.CreateGraphics();
dpiX = graphics.DpiX;
dpiY = graphics.DpiY;

我认为目前X和Y值不可能不同。值96对应于100%字体缩放(较小),值120对应于125%缩放(中等),而144对应于150%缩放(较大)。但是,用户可以设置这些标准值以外的值。

请注意,除非您的应用程序声明为DPI感知的,否则您观察到的值可能会受到DPI虚拟化的影响。


7
我试图运行该代码具有不同的设置和graphics.DpiX的值始终是96
newmember

1
DpiX是90吗?!我注销并重新启动,它从96变为120。我在使用新的WinForms应用程序。我想知道您是否在应用程序中做了一些特别的事情。您是否尝试过全新的WinForms项目?
大卫·赫弗南

1
我尝试设置中等设置,并且-可行!DpiX是120,但对于较大的设置是96 ...
newmember 2011年

9
是的,我想我明白了。问题是您的应用程序未标记为DPI感知,因此可能看起来很模糊。您应该在清单中将应用标记为DPI感知。
大卫·赫弗南

3
@ColonelPanicthis只是任何控件。msdn.microsoft.com/en-us/library/...
大卫赫弗南

81

在所有缩放级别上,graphics.DpiX和DeviceCap.LOGPIXELSX在Surface Pro上均返回96。

相反,我设法通过这种方式计算比例因子:

[DllImport("gdi32.dll")]
static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
public enum DeviceCap
{
    VERTRES = 10,
    DESKTOPVERTRES = 117,

    // http://pinvoke.net/default.aspx/gdi32/GetDeviceCaps.html
}  


private float getScalingFactor()
{
    Graphics g = Graphics.FromHwnd(IntPtr.Zero);
    IntPtr desktop = g.GetHdc();
    int LogicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.VERTRES);
    int PhysicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.DESKTOPVERTRES); 

    float ScreenScalingFactor = (float)PhysicalScreenHeight / (float)LogicalScreenHeight;

    return ScreenScalingFactor; // 1.25 = 125%
}

9
哇,我已经花了很长时间寻找真正的比例因子,这终于解决了我的问题!
安德烈亚斯(Andreas)

10
那一刻,当您正要哭泣并放弃时,您会遇到类似这样的事情。
松饼人2015年

5
请注意,你可能会想使用这两种这一解决方案并标记为接受的解决方案...我的系统上,阅读g.DpiX返回120,但比例因素仍然是1.0。
Todd Myhre

7
仅供参考,在运行Win 10 64位,分辨率3840x2160的Dell Precision 5510笔记本电脑上,显示比例设置为200%(通过右键单击桌面>>显示设置),以上代码中的LogicalScreenHeight和PhysicalScreenHeight都返回相同的内容, 2160。因此在这种情况下,此代码无法获得所需的200%显示比例。
Nerdtron

6
我使用类似的硬件观察到了与@Nerdtron相同的问题。不幸的是,此代码无法在监视器之间可靠地工作。
OfficeAddinDev'3

17

我认为最简单的方法是使用GetDeviceCaps功能。从pinvoke.net

[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
public static extern int GetDeviceCaps(IntPtr hDC, int nIndex);

public enum DeviceCap
{
  /// <summary>
  /// Logical pixels inch in X
  /// </summary>
  LOGPIXELSX = 88,
  /// <summary>
  /// Logical pixels inch in Y
  /// </summary>
  LOGPIXELSY = 90

  // Other constants may be founded on pinvoke.net
}      

和用法:

Graphics g = Graphics.FromHwnd(IntPtr.Zero);            
IntPtr desktop = g.GetHdc();

int Xdpi = GetDeviceCaps(desktop, (int)DeviceCap.LOGPIXELSX);
int Ydpi = GetDeviceCaps(desktop, (int)DeviceCap.LOGPIXELSY);    

通过这种方法,您无需将应用程序标记为dpi感知。


13
不要忘记致电ReleaseHdc
BitsEvolved

@BitsEvolved绝对。这解决了“我的”内存泄漏(在完全不同的上下文中)!非常感谢。
Wolf

1
在提供的链接的GetDeviceCaps函数的注释中,它对LOGPIXELSX和LOGPIXELSY表示以下内容:“在具有多个显示监视器的系统中,此值对于所有监视器都是相同的。” 要注意的事...
RenniePet

16

这就是在WPF中可以做到的。返回值以WPF的逻辑单位为单位,等于1/96英寸。因此,如果您的屏幕DPI设置为96,则将获得值1。

Matrix m =
PresentationSource.FromVisual(Application.Current.MainWindow).CompositionTarget.TransformToDevice;
double dx = m.M11; // notice it's divided by 96 already
double dy = m.M22; // notice it's divided by 96 already

来源


1
谢谢,我认为这是WPF最简单的方法。
Mitra M

10

这是一个在Windows 10中很好用的解决方案。不需要DPI意识或其他任何东西。

public static int GetWindowsScaling()
{
    return (int)(100 * Screen.PrimaryScreen.Bounds.Width / SystemParameters.PrimaryScreenWidth);
}

有趣的是,有时Screen.PrimaryScreen.Bounds.Width不会返回实际的屏幕宽度,而是返回与SystemParameters.PrimaryScreenWidth相同的宽度,我在使用UI Automation时遇到了这个问题。而且我不得不改用Screen.PrimaryScreen.WorkingArea.Width。
sarh

8

我在控制台应用程序中使用这种方式:

float dpiX, dpiY;
using (Graphics graphics = Graphics.FromHwnd(IntPtr.Zero))
{
    dpiX = graphics.DpiX;
    dpiY = graphics.DpiY;
}

8

除了125%以外,以Farshid T的答案为基础可在所有缩放系数中使用。我测试了大约20种不同的缩放系数,并且DPI始终返回96,除非将其设置为125%时返回的DPI为120。120/ 96 = 1.25。不知道为什么会这样,但是此代码似乎适用于任何比例设置。

    [DllImport("gdi32.dll")]
    static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
    public enum DeviceCap
    {
        VERTRES = 10,
        DESKTOPVERTRES = 117,
        LOGPIXELSY = 90,

        // http://pinvoke.net/default.aspx/gdi32/GetDeviceCaps.html

和用法:

        Graphics g = Graphics.FromHwnd(IntPtr.Zero);
        IntPtr desktop = g.GetHdc();
        int LogicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.VERTRES);
        int PhysicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.DESKTOPVERTRES);
        int logpixelsy = GetDeviceCaps(desktop, (int)DeviceCap.LOGPIXELSY);
        float screenScalingFactor = (float)PhysicalScreenHeight / (float)LogicalScreenHeight;
        float dpiScalingFactor = (float)logpixelsy / (float)96;

        if (screenScalingFactor > 1 ||
            dpiScalingFactor > 1)
        {
            // do something nice for people who can't see very well...
        }

3
为了安全起见,您是否也应该添加以下内容:g.ReleaseHdc(desktop);

6

如果使用WPF,请使用以下代码段,

PresentationSource source = PresentationSource.FromVisual(this);

        double dpiX, dpiY;
        if (source != null)
        {
            dpiX = 96.0 * source.CompositionTarget.TransformToDevice.M11;
            dpiY = 96.0 * source.CompositionTarget.TransformToDevice.M22;
        }

5

这是一个非常老的问题,但是从Windows 8.1开始,人们可以使用其他各种功能,例如 GetDpiForWindow

在C#中:

[DllImport("user32.dll")]
static extern int GetDpiForWindow(IntPtr hWnd);

public float GetDisplayScaleFactor(IntPtr windowHandle)
{
    try
    {
        return GetDpiForWindow(windowHandle) / 96f;
    }
    catch
    {
        // Or fallback to GDI solutions above
        return 1;
    }
}

为了在Windows 10周年纪念日上正常运行,您需要app.manifest在C#项目中添加一个:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
          manifestVersion="1.0">
  <application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
      <!-- The combination of below two tags have the following effect : 
      1) Per-Monitor for >= Windows 10 Anniversary Update
      2) System < Windows 10 Anniversary Update -->
      <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitor</dpiAwareness>
      <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
    </windowsSettings>
  </application>

</assembly>

您说这适用于Windows 8.1和更高版本,但是在您引用的Microsoft文档中,它说“要求:Windows 10版本1607”。
RenniePet

哦,是的,的确不错。我想我将此与GetDpiForMonitor api调用混淆了。 docs.microsoft.com/en-us/windows/win32/api/shellscalingapi/…–
Ziriax

1

我认为这应该为您提供所需的信息:

http://www.pinvoke.net/default.aspx/user32.getsystemmetrics

http://pinvoke.net/default.aspx/Enums.SystemMetric

编辑-哦,抱歉,现在似乎有一种更简便的方法可以不加验证地获取此信息,

http://msdn.microsoft.com/zh-CN/library/system.windows.forms.systeminformation.aspx


不幸的是,系统信息无法反映dpi的比例。此外,似乎图形上下文的dpiX / dpiY属性返回96表示150%(至少在surface pro 2上)。因此,您无法区分100%和150%缩放。有人知道合适的方法吗?
Zuppa 2013年

1

Ric Gaudet的答案的更完整版本:

[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
public static extern int GetDeviceCaps(IntPtr hDC, int nIndex);

public enum DeviceCap
{
    VERTRES = 10,
    DESKTOPVERTRES = 117
}

static double GetWindowsScreenScalingFactor(bool percentage = true)
{
    //Create Graphics object from the current windows handle
    Graphics GraphicsObject = Graphics.FromHwnd(IntPtr.Zero);
    //Get Handle to the device context associated with this Graphics object
    IntPtr DeviceContextHandle = GraphicsObject.GetHdc();
    //Call GetDeviceCaps with the Handle to retrieve the Screen Height
    int LogicalScreenHeight = GetDeviceCaps(DeviceContextHandle, (int)DeviceCap.VERTRES);
    int PhysicalScreenHeight = GetDeviceCaps(DeviceContextHandle, (int)DeviceCap.DESKTOPVERTRES);
    //Divide the Screen Heights to get the scaling factor and round it to two decimals
    double ScreenScalingFactor = Math.Round((double)PhysicalScreenHeight / (double)LogicalScreenHeight, 2);
    //If requested as percentage - convert it
    if (percentage)
    {
        ScreenScalingFactor *= 100.0;
    }
    //Release the Handle and Dispose of the GraphicsObject object
    GraphicsObject.ReleaseHdc(DeviceContextHandle);
    GraphicsObject.Dispose();
    //Return the Scaling Factor
    return ScreenScalingFactor;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.