c# – 使用User32.ChangeDisplaySettings设置分辨率仅在最大分辨率上失败(‘badmode’错误)

所以我要做的是使用ChangeDisplaySettings在C#的主显示器上设置屏幕分辨率.我已经在我拥有的多台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

举个例子,假设我在1920×1080的显示器上运行.

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

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");
}

*请注意,这实际上不是程序中的代码.我刚刚制作了这个简化版本,将其简化为必需品来说明问题.

该程序将打印出来:

-2

如前所述,这是DISP_CHANGE_BADMODE的值,并且分辨率将无法更改.

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

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

这是我发现的一个帮助我入门的教程:

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

[由于明显的垃圾邮件防范系统,我删除了超链接.鉴于第一个是msdn.microsoft链接,这是一个代码项目,但是,w / e]

请注意,在评论部分,似乎有人直接使用提供的源文件,并且遇到类似的问题.引用它们:

hello ,
i’m using Resolution.cs on my c# application
and it doesn’t work with high resolutions like ” 1366*768 ” & ” 1280*720 ”
can any one help ???

但是,尽管教程中似乎推荐使用ChangeDisplaySettings,但我找不到任何有关解决此问题的信息(这可能是特定于操作系统的,但我目前还没有任何非Windows 7计算机可以测试,甚至如果我这样做,它将无法解决它在Windows 7计算机上不起作用的问题)

最佳答案
事实证明,我正在使用的教程假设没有任何东西可以将任何显示模式参数更改为在较低分辨率期间无效的东西(例如增加刷新率,这是限制在由于我使用相同的两个显示器进行测试,并且最大分辨率的最大刷新率低于任何其他分辨率,我会遇到这个问题.)

比本教程中所示的更安全的方法是使用显示模式的索引或仅使用EnumDisplayModes并且从不接触DEVMODE结构内的数据.

以下是我掀起的示例程序的摘录,该程序将分辨率更改为指定的参数,然后再返回.

            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");
            }

这里使用的函数如下:

    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;
    }

转载注明原文:c# – 使用User32.ChangeDisplaySettings设置分辨率仅在最大分辨率上失败(‘badmode’错误) - 代码日志