因此,我要做的是使用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显示器上。
我手动(或以编程方式)将我的决议设置为其他内容,不关心它是什么或如何更改,然后运行以下代码:
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,则此监视器上的另一个支持分辨率,然后将分辨率设置为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计算机上工作的问题)。
发布于 2012-03-18 18:34:21
事实证明,我使用的教程假设,在分辨率较低的时候,任何显示模式参数都不会更改为无效的参数(例如提高刷新速率,而刷新速率是在监视器一侧设置的)。而且,由于我使用相同的两个监视器进行测试,而且最大分辨率的最大刷新率比其他任何分辨率都要低,所以我会遇到这个问题。)
一个比本教程中说明的更安全的方法是使用显示模式的索引,或者只使用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;
}
发布于 2014-03-07 09:32:38
除了@Avan给出的答案之外,我发现当您将错误的参数传递给dmDisplayFrequency of DevMode结构时,也会出现这个问题。
要解决这个问题,您可以首先从Graphics设备获得所有可用的屏幕分辨率,然后在将其发送到ChangeDisplaySettings函数之前更新频率。
若要获取显示设置列表,请使用EnumDisplaySettings
发布于 2013-01-07 18:01:25
要切换到最高的本机分辨率,必须使用有效值填充dm.dmFields结构。看起来。在调用ChangeDisplaysettings()之前。
https://stackoverflow.com/questions/9756416
复制相似问题