首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用C#以编程方式更改Windows 10显示

如何使用C#以编程方式更改Windows 10显示
EN

Stack Overflow用户
提问于 2016-02-05 20:45:28
回答 5查看 25.4K关注 0票数 26

我正试图找到一种方法,以编程方式使用C#更改Windows 10中的显示缩放。

我还要说的是,我并不是要创建一个自动强制用户屏幕改变分辨率/缩放的应用程序。它只是一个工具,使我能够从托盘上切换天平,因为这是我经常要做的测试。所以特意为这次行动设计的。

因此,当用户通过下面的官方对话框手动设置注册表项(HKEY_CURRENT_USER\Control Panel\Desktop)时,我能够跟踪哪些注册表项:

但是,显然直接使用注册表意味着我需要重新启动机器才能生效。

我知道您可以使用Pinvoke来更改屏幕分辨率:设置显示分辨率

我想知道是否也有办法为给定的屏幕更改这个"%“?也就是说..。我上面的屏幕上写着150%,我希望能够通过100%-500%的全部范围来编程地修改它。

EN

回答 5

Stack Overflow用户

发布于 2019-09-23 16:38:10

获得/设置C++的API。

我能够反向工程系统设置应用程序,并提出了一个API。它的代码出现在我的github https://github.com/lihas/windows-DPI-scaling-sample中。

我跳过了在这个答案中解释许多术语,因为我已经在我对这个问题(https://stackoverflow.com/a/57397039/981766)的上一个回答中这样做了。

API摘要

  1. :DpiHelper
  2. 方法
    1. GetDPIScalingInfo(),以及
    2. SetDPIScaling()

获取显示的新闻部信息

DPIScalingInfo()调用adapterID和sourceID。

代码语言:javascript
运行
复制
DpiHelper::DPIScalingInfo DpiHelper::GetDPIScalingInfo(LUID adapterID, UINT32 sourceID)

设置显示的DPI

使用SetDPIScaling()调用adapterID、sourceID和百分比新闻部来设置。就像。如果要将数据源的DPI缩放设置为175%,请在最后一个参数中传递175。

代码语言:javascript
运行
复制
bool DpiHelper::SetDPIScaling(LUID adapterID, UINT32 sourceID, UINT32 dpiPercentToSet)

回购中的DpiHelper.h有这两种方法的详细文档。

还可以阅读DpiHelper.h和回购的自述文件文档。我已经在公共领域中发布了回购中的所有代码,所以以任何您想要的方式使用它。

样本应用程序

我还创建了一个MFC应用程序,它使用这个助手库获取/设置DPI缩放。这将帮助您理解如何使用DpiHelper类。

下面是它的样子。

关于新闻部在窗口上缩放的说明

  1. DPI缩放是源的属性,而不是目标的属性(这些术语参见ViPN )。
  2. 显示的新闻部缩放取决于三个因素-分辨率,显示器的物理尺寸,预期的观看距离。Windows用于计算推荐值的确切公式是未知的。
  3. 在OS术语中,DPI缩放值与建议的DPI缩放显示值相比有一定的意义。因此,尽管我们在系统设置应用程序中看到了100%、125%等,但OS并不理解比例的缩放。相反,使用以上步骤的数目,或低于建议的缩放。就像。DPI标度值为-1将意味着比建议的DPI标度低1步。因此,如果对于监视器,推荐值为150%,-1将意味着125%。

我使用WinDbg预览(MS )和吉德拉进行逆向工程。有一段时间,当我准备放弃缺乏IDA专业许可证时,有人建议我Ghidra。从那以后我就一直是粉丝。

感谢吉德拉!!!

票数 13
EN

Stack Overflow用户

发布于 2017-04-21 19:05:51

在寻找完全相同的问题时,我找到了你的问题并找到了一个可能的解决方案。

我发现这个%值的每个监视器切换都在Computer\HKEY_CURRENT_USER\Control Panel\Desktop\PerMonitorSettings\*monitorId*\DpiValue的注册表中。看起来,该值的含义取决于屏幕(大小和dpi),有关详细信息,请参阅这个编辑职位

对于我的24英寸1080 p屏幕,0表示100%,1表示125%。本Technet条款似乎有点解释了这个值。

不幸的是,仅更改注册表值是不够的。但是,您可以通过在写入注册表后更改分辨率来刷新dpi。

下面的代码设置dpi,然后切换分辨率低和后高的分辨率以触发dpi更新。

代码语言:javascript
运行
复制
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using Microsoft.Win32;

namespace SetDpiScale
{
    public partial class Form1 : Form
    {
        public enum DMDO
        {
            DEFAULT = 0,
            D90 = 1,
            D180 = 2,
            D270 = 3
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        struct DEVMODE
        {
            public const int DM_PELSWIDTH = 0x80000;
            public const int DM_PELSHEIGHT = 0x100000;
            private const int CCHDEVICENAME = 32;
            private const int CCHFORMNAME = 32;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
            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 DMDO dmDisplayOrientation;
            public int dmDisplayFixedOutput;

            public short dmColor;
            public short dmDuplex;
            public short dmYResolution;
            public short dmTTOption;
            public short dmCollate;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHFORMNAME)]
            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;
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static extern int ChangeDisplaySettings([In] ref DEVMODE lpDevMode, int dwFlags);

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            ChangeDPI(0); // 100%
        }
        private void button2_Click(object sender, EventArgs e)
        {
            ChangeDPI(1); // 125%
        }

        void ChangeDPI(int dpi)
        {
            RegistryKey key = Registry.CurrentUser.OpenSubKey("Control Panel", true);

            key = key.OpenSubKey("Desktop", true);
            key = key.OpenSubKey("PerMonitorSettings", true);
            key = key.OpenSubKey("*monitor id where to change the dpi*", true); // my second monitor here

            key.SetValue("DpiValue", dpi);

            SetResolution(1920, 1080); // this sets the resolution on primary screen
            SetResolution(2560, 1440); // returning back to my primary screens default resolution
        }

        private static void SetResolution(int w, int h)
        {
            long RetVal = 0;

            DEVMODE dm = new DEVMODE();

            dm.dmSize = (short)Marshal.SizeOf(typeof(DEVMODE));

            dm.dmPelsWidth = w;
            dm.dmPelsHeight = h;

            dm.dmFields = DEVMODE.DM_PELSWIDTH | DEVMODE.DM_PELSHEIGHT;


            RetVal = ChangeDisplaySettings(ref dm, 0);
        }
    }
}
票数 5
EN

Stack Overflow用户

发布于 2020-07-15 13:56:24

如果要更改系统范围的DPI缩放(在多个监视器设置或只有一个监视器的情况下,主监视器的系统新闻部缩放),则可以使用SystemParametersInfo()

此API有一个未记录的参数,它实现了以下功能:SPI_SETLOGICALDPIOVERRIDE

来自微软文档

代码语言:javascript
运行
复制
SPI_SETLOGICALDPIOVERRIDE   Do not use. 
0x009F

用法:

代码语言:javascript
运行
复制
SystemParametersInfo(SPI_SETLOGICALDPIOVERRIDE, relativeIndex, (LPVOID)0, 1);

要想弄清楚上面的relativeIndex变量使用什么值,您必须了解OS期望新闻部缩放值是如何指定的(在此解释)。

简单地说,relativeIndex告诉您上面有多少个步骤,或者低于建议的DPI缩放值。就像。如果建议DPI缩放值为125%,并且您希望将150%设置为缩放,则relativeIndex将为1(比125%高出一步),或者如果要设置100%,则relativeIndex将为-1 (比125%低一步)。

并非所有步骤都是相同大小的。

代码语言:javascript
运行
复制
100,125,150,175,200,225,250,300,350, 400, 450, 500

直到250%时,台阶的单位增加了25%,之后的单位增加了50%。

因此,您必须首先获得建议的DPI值,对于这个值,可以使用相同的SPI_GETLOGICALDPIOVERRIDE参数。

代码语言:javascript
运行
复制
SystemParametersInfo(SPI_GETLOGICALDPIOVERRIDE, 0, (LPVOID)&dpi, 1);

上面dpi变量中返回的值也要以一种特殊的方式来理解。数值将为负数,其大小将表明上述清单中新闻部比例百分比的指数。

因此,如果此API返回-1,建议的DPI缩放值将为125%。

样本代码:

代码语言:javascript
运行
复制
#include <iostream>
#include <Windows.h>

using namespace std;


static const UINT32 DpiVals[] = { 100,125,150,175,200,225,250,300,350, 400, 450, 500 };

/*Get default DPI scaling percentage.
The OS recommented value.
*/
int GetRecommendedDPIScaling()
{
    int dpi = 0;
    auto retval = SystemParametersInfo(SPI_GETLOGICALDPIOVERRIDE, 0, (LPVOID)&dpi, 1);

    if (retval != 0)
    {
        int currDPI = DpiVals[dpi * -1];
        return currDPI;
    }

    return -1;
}

void SetDpiScaling(int percentScaleToSet)
{
    int recommendedDpiScale = GetRecommendedDPIScaling();

    if (recommendedDpiScale > 0)
    {
        int index = 0, recIndex = 0, setIndex = 0 ;
        for (const auto& scale : DpiVals)
        {
            if (recommendedDpiScale == scale)
            {
                recIndex = index;
            }
            if (percentScaleToSet == scale)
            {
                setIndex = index;
            }
            index++;
        }
        
        int relativeIndex = setIndex - recIndex;
        SystemParametersInfo(SPI_SETLOGICALDPIOVERRIDE, relativeIndex, (LPVOID)0, 1);
    }
}

int main()
{
    for (;;)
    {
        int n = 0, dpiToSet = 0;
        cout << R"(
            1. Show Recommended DPI
            2. Set DPI
            Anything else to exit
)";
        cin >> n;
        switch (n)
        {
        case 1:
            cout << "recommened scaling: " << GetRecommendedDPIScaling() << "%" << endl;
            break;
        case 2:
            cout << "enter scaling to set in percentage" << endl;
            cin >> dpiToSet;
            SetDpiScaling(dpiToSet);
            break;
        default:
            exit(0);
            break;
        }
    }
    return 0;
}

源代码:https://github.com/lihas/windows-DPI-scaling-sample

这是一个示例运行。

Pros and cons

关于我以前的方法(https://stackoverflow.com/a/58066736/981766https://stackoverflow.com/a/57397039/981766)

Pros

  1. 这是一个非常简单的API。因此,当您只需要在多个监视器设置中更改主监视器的DPI缩放时,或者如果只有一个监视器,则更喜欢这种方法。

Cons

  1. 无法在多监视器设置上设置非主监视器的DPI缩放。
  2. 不返回当前应用的DPI缩放(尽管您可以使用其他OS )
  3. 不会给你最大的,最小的新闻部缩放值。尽管如果您尝试在此范围之外设置,OS不允许它,并且将使用最近允许的。

参考资料

  1. https://social.msdn.microsoft.com/Forums/vstudio/en-US/3259c521-b3ed-4121-97da-70a08fb8bb19/change-setting?forum=windowsgeneraldevelopmentissues (稍不准确)
  2. 如何用python代码设置Windows规模和布局
  3. https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfoa?redirectedfrom=MSDN
  4. https://github.com/lihas/windows-DPI-scaling-sample
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35233182

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档