首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用User32.ChangeDisplaySettings设置分辨率仅在最大分辨率(“坏模式”错误)上失败

使用User32.ChangeDisplaySettings设置分辨率仅在最大分辨率(“坏模式”错误)上失败
EN

Stack Overflow用户
提问于 2012-03-18 06:06:23
回答 3查看 11.7K关注 0票数 5

因此,我要做的是使用C#在ChangeDisplaySettings中在主显示器上设置屏幕分辨率。我已经在我拥有的多台windows 7计算机上测试过这一点,结果总是一样的:任何*有效的分辨率(在右击桌面的“屏幕分辨率”菜单中列出的那些)都会正常工作,除了在该菜单中可以选择的最大分辨率之外,这将导致User32.ChangeDisplaySettings返回-2,即DISP_CHANGE_BADMODE,这意味着所请求的显示模式无效。

*在一些具有较大主显示器的计算机上,我没有费心地测试每一个分辨率,而只是选择了一些任意的小分辨率&最大值,因为每个分辨率上都有太多的分辨率无法测试。在我的测试中,我有足够的信心说最大分辨率总是失败,而较小的决议通常/总是成功(我从来没有在测试中失败过)。

关于ChangeDisplaySettings的文档:http://msdn.microsoft.com/en-us/library/dd183411%28VS.85%29.aspx

关于它使用的DEVMODE结构的文档:http://msdn.microsoft.com/en-us/library/dd183565%28v=vs.85%29.aspx

举个例子,假设我运行在1920x1080显示器上。

我手动(或以编程方式)将我的决议设置为其他内容,不关心它是什么或如何更改,然后运行以下代码:

代码语言:javascript
运行
复制
DEVMODE dm = new DEVMODE();
dm.dmDeviceName = new String(new char[32]);
dm.dmFormName = new String(new char[32]);
dm.dmSize = (short)Marshal.SizeOf(dm);
if (User32.EnumDisplaySettings(null, User32.ENUM_CURRENT_SETTINGS, ref dm) != 0)
{
     dm.dmPelsWidth = 1920;
     dm.dmPelsHeight = 1080;
     Console.WriteLine("" + User32.ChangeDisplaySettings(ref dm, User32.CDS_UPDATEREGISTRY) + "\n");
}

*注意,这实际上不是程序中的代码。我只是做了这个简化的版本,把它削减到最基本的需求来说明这一点。

程序会打印出来:

代码语言:javascript
运行
复制
-2

正如前面提到的,它是DISP_CHANGE_BADMODE的值,而决议将无法改变。

现在,如果我分别将1080和1920的值更改为900和1600,则此监视器上的另一个支持分辨率,然后将分辨率设置为1600x900以外的其他分辨率,然后运行这个程序,它实际上会将分辨率更改为1600x900,并返回DISP_CHANGE_SUCCESSFUL。

注意,使用其他标志(如CDS_RESET (0x40000000或1073741824)代替CDS_UPDATEREGISTRY )也会导致相同的错误。

这是一个我发现的帮助我开始学习的教程:

www.codeproject.com/Articles/6810/Dynamic-Screen-Resolution

我删除了超链接,因为明显的垃圾邮件预防系统。考虑到第一个是msdn.microsoft链接,这是一个代码项目,但是,w/e,这有点傻。

注意,在注释部分,似乎有人直接使用了提供的源文件,并且遇到了类似的问题。引用他们的话:

你好,我在我的c#应用程序上使用Resolution.cs,它不适用于像“1366*768”和“1280*720”这样的高分辨率的应用程序,有人能帮忙吗?

然而,尽管教程推荐ChangeDisplaySettings是多么的普遍,我还是找不到解决这个问题的任何信息(这很可能是操作系统特有的,但我目前没有任何非Windows 7计算机进行测试,即使我这样做了,它也解决不了它在Windows 7计算机上工作的问题)。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-03-18 18:34:21

事实证明,我使用的教程假设,在分辨率较低的时候,任何显示模式参数都不会更改为无效的参数(例如提高刷新速率,而刷新速率是在监视器一侧设置的)。而且,由于我使用相同的两个监视器进行测试,而且最大分辨率的最大刷新率比其他任何分辨率都要低,所以我会遇到这个问题。)

一个比本教程中说明的更安全的方法是使用显示模式的索引,或者只使用EnumDisplayModes,并且永远不要接触DEVMODE结构中的数据。

下面是一个示例程序的摘录,该示例程序将分辨率更改为指定的参数,然后再返回。

代码语言:javascript
运行
复制
            int selB, selG, selF, selH, selW;
            ... //these values get defined, etc.
            DEVMODE OSpecs = new DEVMODE();
            getCurrentRes(ref OSpecs);
            int Ondx = getDMbySpecs(OSpecs.dmPelsHeight, OSpecs.dmPelsWidth, OSpecs.dmDisplayFrequency, OSpecs.dmDisplayFlags, OSpecs.dmBitsPerPel, ref OSpecs);
            Screen Srn = Screen.PrimaryScreen;
            Console.WriteLine("Current res is " + OSpecs.dmPelsHeight + " by " + OSpecs.dmPelsWidth + "\n");
            DEVMODE NSpecs = new DEVMODE();
            int Nndx = getDMbySpecs(selH, selW, selF, selG, selB, ref NSpecs);
                //Note that this function sets both the DEVMODE to the selected display mode and returns the index value of this display mode. It returns -1 if it fails (-1 is the value of ENUM_CURRENT_SETTINGS), and sets the DEVMODE to the current display mode.
            if (Nndx == -1)
            {
                 Console.WriteLine("Could not find specified mode");
            }
            else if (setDisplayMode(ref NSpecs) || setDisplayMode(Nndx)) //This is just to illustrate both ways of doing it. One or the other may be more convenient (ie, the latter if you are getting this from a file, the former if you already have the DEVMODE in your program, etc.)
            {
                //reset display mode to original after waiting long enough to see it changed
                Console.WriteLine("Successful change. Waiting 4 seconds.");
                Thread.Sleep(4000);
                if (setDisplayMode(ref OSpecs) || setDisplayMode(Ondx))
                {
                    //success!
                    Console.WriteLine("Mode reversion succeeded.");
                }
                else
                {
                    Console.WriteLine("Mode reversion failed. Manual reset required.");
                }
            }
            else
            {
                //return
                Console.WriteLine("Resolution change failed. Aborting");
            }

此处使用的函数如下:

代码语言:javascript
运行
复制
    static bool setDisplayMode(int i)
    {
        DEVMODE DM = new DEVMODE();
        DM.dmSize = (short)Marshal.SizeOf(DM);
        User32.EnumDisplaySettings(null, i, ref DM);
        if (User32.ChangeDisplaySettings(ref DM, User32.CDS_TEST) == 0 && User32.ChangeDisplaySettings(ref DM, User32.CDS_UPDATEREGISTRY) == 0)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    static bool setDisplayMode(ref DEVMODE DM)
    {
        if (User32.ChangeDisplaySettings(ref DM, User32.CDS_TEST) == 0 && User32.ChangeDisplaySettings(ref DM, User32.CDS_UPDATEREGISTRY) == 0)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    static int getDMbySpecs(int H, int W, int F, int G, int B, ref DEVMODE DM)
    {
        DM.dmSize = (short)Marshal.SizeOf(DM);
        DEVMODE SelDM = new DEVMODE();
        SelDM.dmSize = (short)Marshal.SizeOf(SelDM);
        int iOMI = 0;
        for (iOMI = 0; User32.EnumDisplaySettings(null, iOMI, ref SelDM) != 0; iOMI++)
        {
            if (( B == -1 || B == SelDM.dmBitsPerPel) && ( H == -1 || H == SelDM.dmPelsHeight) && ( W == -1 || W == SelDM.dmPelsWidth) && ( G == -1 || G == SelDM.dmDisplayFlags) && ( F == -1 || F == SelDM.dmDisplayFrequency))

                break;
        }
        if (User32.EnumDisplaySettings(null, iOMI, ref DM) == 0)
        {
            iOMI = -1;
            getCurrentRes(ref DM);
        }
        return iOMI;
    }
    static void getCurrentRes(ref DEVMODE dm)
    {
        dm = new DEVMODE();
        dm.dmSize = (short)Marshal.SizeOf(dm);
        User32.EnumDisplaySettings(null, User32.ENUM_CURRENT_SETTINGS, ref dm);
        return;
    }
票数 5
EN

Stack Overflow用户

发布于 2014-03-07 09:32:38

除了@Avan给出的答案之外,我发现当您将错误的参数传递给dmDisplayFrequency of DevMode结构时,也会出现这个问题。

要解决这个问题,您可以首先从Graphics设备获得所有可用的屏幕分辨率,然后在将其发送到ChangeDisplaySettings函数之前更新频率。

若要获取显示设置列表,请使用EnumDisplaySettings

票数 2
EN

Stack Overflow用户

发布于 2013-01-07 18:01:25

要切换到最高的本机分辨率,必须使用有效值填充dm.dmFields结构。看起来。在调用ChangeDisplaysettings()之前。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9756416

复制
相关文章

相似问题

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