如果我们有两个以上的显示器,但并是总是会用到。比如说我在办公室有一台显示器可以用于扩展桌面,但是回家之后就没有了第二台显示器来用于扩展。或者说我在家用的扩展显示器和在办公地点所使用的扩展显示器分辨率不一样。如果您是和我一样不习惯关闭电脑,而是直接合起本子就走人的人,那么调整显示器分辨率无疑是一个麻烦的事情。因为大多的驱动写得都不那么贴心,需要你点击一次两次分页,设置起来十分麻烦。我的本子就是这样。于是我想着,写一个小软件来解决这件事情。

前两天写了一个用于在Windows控制台下的小软件,它虽然很小,很快,但对于大多数对字符模式有情绪的人来说并不方便。于是我又写了一款很小的基于对话框的软件,当然主要是为了自己用起来方便。

这款小软件的作用就是

  1. 快速开启和关闭扩展显示器。
  2. 快速调整多个(最多至十个)显示器的分辨率。

软件很小,完全免费,您可以从下面的链接获取使用:

多显示器分辨率快速修改软件

关于原代码,重要部分如下:

int CmulscrApp::EnumAllMonitors(DISPLAY_DEVICE m_nDD[], DEVMODE m_nDM[], int index)
{
DISPLAY_DEVICE dd;
dd.cb = sizeof(dd);
DWORD dev = 0; // device index
int id = 0; // monitor number;

while (id<index && EnumDisplayDevices(0, dev, &dd, 0))
{
if (!(dd.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
{
// ignore virtual mirror displays

// get information about the display’s position and the current display mode
DEVMODE dm;
ZeroMemory(&dm, sizeof(dm));
dm.dmSize = sizeof(dm);
if (EnumDisplaySettingsEx(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm, 0) == FALSE)
EnumDisplaySettingsEx(dd.DeviceName, ENUM_REGISTRY_SETTINGS, &dm, 0);

m_nDD[id]=dd;
m_nDM[id]=dm;

id++;
}

dev++;
}
return id;
}

BOOL CmulscrApp::SetDisplayResolution(DISPLAY_DEVICE dd, DEVMODE dm, long PelsWidth, long PelsHeight, POINT pt)
{
dm.dmSize = sizeof(dm);
dm.dmPelsWidth = PelsWidth;
dm.dmPelsHeight = PelsHeight;
dm.dmPosition.x = pt.x;
dm.dmPosition.y = pt.y;
dm.dmFields = DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT;
LONG results=ChangeDisplaySettingsEx(dd.DeviceName,&dm,NULL,CDS_TEST,NULL);
if ( results!=DISP_CHANGE_SUCCESSFUL)
{
return FALSE;
}

return (ChangeDisplaySettingsEx(dd.DeviceName,&dm,NULL,CDS_UPDATEREGISTRY,NULL)==DISP_CHANGE_SUCCESSFUL);
}

……

……

……

……

DISPLAY_DEVICE    m_nDD[MONITORNO];
DEVMODE            m_nDM[MONITORNO];
int index=EnumAllMonitors(m_nDD,m_nDM,MONITORNO);
int x[MONITORNO]={0};
int y[MONITORNO]={0};
for(int i=0; i<index; i++)
{
x[i]=m_nDM[i].dmPelsWidth;
y[i]=m_nDM[i].dmPelsHeight;
}

CmulscrDlg dlg(x,y);
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: Place code here to handle when the dialog is
//  dismissed with OK
POINT pt;
pt.x=0;
pt.y=0;

if(dlg.m_off)
{
int primaryMonitor=0;

for(int i=0; i<index; i++)
{
if (m_nDD[i].StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
primaryMonitor=i;
else
SetDisplayResolution(m_nDD[i],m_nDM[i],0,0,pt);
}
pt.x=m_nDM[primaryMonitor].dmPelsWidth;
pt.y=m_nDM[primaryMonitor].dmPelsHeight;
SetDisplayResolution(m_nDD[primaryMonitor],m_nDM[primaryMonitor],
m_nDM[primaryMonitor].dmPosition.x,m_nDM[primaryMonitor].dmPosition.y,
pt);
}
else
{
if(dlg.m_on)
{
for(int i=0; i<index; i++)
{
pt.x=m_nDM[i].dmPosition.x;
pt.y=m_nDM[i].dmPosition.y;
if (!(m_nDD[i].StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE))
{
SetDisplayResolution(m_nDD[i],m_nDM[i],0,0,pt);
SetDisplayResolution(m_nDD[i],m_nDM[i],dlg.x[i],dlg.y[i],pt);
}
}
}
int posx=0;
for(int i=0; i<MONITORNO; i++)
{
posx+=dlg.x[i];
pt.x=posx+1;
if(x[i]!=dlg.x[i]||y[i]!=dlg.y[i])
{
x[i]=dlg.x[i];
y[i]=dlg.y[i];
SetDisplayResolution(m_nDD[i],m_nDM[i],x[i],y[i],pt);
}
}
}
}
else if (nResponse == IDCANCEL)
{
// TODO: Place code here to handle when the dialog is
//  dismissed with Cancel
}

开启扩展桌面的思路其实很简单,就是设置两次扩展桌面,第一次更改显卡给定的默认设置,第二次再给一个正确的设置,这样才能激活扩展显示器。

关闭扩展桌面的思路也很简单,就是设置扩展桌面的分辨率为0,让它不可见。

希望以上的软件和原代码对您用帮助。

int CmulscrApp::EnumAllMonitors(DISPLAY_DEVICE m_nDD[], DEVMODE m_nDM[], int index)
{
DISPLAY_DEVICE dd;
dd.cb = sizeof(dd);
DWORD dev = 0; // device index
int id = 0; // monitor number;

while (id<index && EnumDisplayDevices(0, dev, &dd, 0))
{
if (!(dd.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
{
// ignore virtual mirror displays

// get information about the display’s position and the current display mode
DEVMODE dm;
ZeroMemory(&dm, sizeof(dm));
dm.dmSize = sizeof(dm);
if (EnumDisplaySettingsEx(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm, 0) == FALSE)
EnumDisplaySettingsEx(dd.DeviceName, ENUM_REGISTRY_SETTINGS, &dm, 0);

m_nDD[id]=dd;
m_nDM[id]=dm;

id++;
}

dev++;
}
return id;
}

转载请注明文章来自糗世界博客

Tags: , , , ,

17 Responses to “基于对话框的Window扩展显示器软件”

  1. xwy 说道:

    能不能发“基于windows扩展屏”完整程序给我?我现在急着要,xiewenyuecool@yahoo.cn,谢谢了

    [回复]

    admin 回复:

    @xwy, 已经发送给你了示例程序。希望可以帮助到你。

    [回复]

    xwy 回复:

    @admin, 谢谢,程序已经收到!我已经知道怎样拿到系统分辨率了,但现在我要的那个软件功能是有二个功能:一个是英特尔双显示复制模式;另外是扩展的桌面模式,怎样来区别它们?

    [回复]

    admin 回复:

    To load a mirror driver the registry key for this device needs to set the “Attach.ToDesktop” value to 1 and then you call ChangeDisplaySettingsEx with “CDS_UPDATEREGISTRY” on the mirror driver. You then set the mode you wish to switch to and call ChangeDisplaySettingsEx again on the mirror driver.

    The mirror driver does not properly unload at mode switch and generally if there are references to a drawing surface the driver will not unload. So, in my experience to get a mirror driver to mode switch you need an application that will detect WM_DISPLAYCHANGE messages. You also need to set “Attach.ToDesktop” to 0 after you load the display driver. This will help unload the display driver and on WM_DISPLAYCHANGE you can then go through the procedure to unload the mirror driver.

    If you wish to immediately unload the mirror driver without a display change you simply need to follow the same steps as what loaded it. Set “Attach.ToDesktop” to 0 and then perform the “CDS_UPDATEREGISTRY”. You can then call “ChangeDisplaySettingsEx” again with no parameters to force unloading. Although this seems to work again everything is done by referencing the display surface so if there are outstanding references to the display surface the driver will not be unloaded. The mirror driver sample in the DDK does not do all of this and has some missing pieces such as not implementing the WM_DISPLAYCHANGE and not resetting the “Attach.ToDesktop” value after loading the mirror driver.

    [回复]

  2. ZZC 说道:

    I read your article, it’s very good, I have downloaded the program afforded, bu I founded it could not run, maybe the procedure you gave is not the one, and I want to write a procedure and it needs to consult your code, I wish I coulde read your code and receive your help from it, thank you very mush, waiting for your directions.

    [回复]

    admin 回复:

    @ZZC, 这个软件应该是支持windows XP的。其它的,我就没有办法了。如果你要示例程序,我已经把它发送到了你的信箱。相信你很快就可以搞定的。还有,你公司的产品挺有意思,是你自己开发的吗?

    [回复]

    admin 回复:

    @ZZC, 软件已经更新,有兴趣的话可以再试试。

    [回复]

  3. sdd 说道:

    楼主啊,给我个“多显示器分辨率快速修改软件’的源代码,你的那个下载链接下载下来的.exe运行不了。

    [回复]

    admin 回复:

    @sdd, 可能是操作系统的原因。具体的等我再多找几台机子试试再回复你。

    [回复]

  4. sdd 说道:

    thank you,期待你的回复。

    [回复]

    admin 回复:

    @sdd, 软件已经更新,这次应该可以正常使用了。希望您能喜欢。

    [回复]

  5. kyo 说道:

    您好, 谢谢您提供的软件. 对我很有帮助.
    我也找到了您提供的基于命令行版本的软件, 可那是交互性的. 我一般喜欢把程序封闭成批处理. 我希望您能提供一个接受参数版本的软件(如分辨率自配置文件中读取, 程序只需要一个 on/off 命令入口即可), 这样我便可以在无人干扰的情况下运行他.
    如果您不方便, 可不可以把源代码发我一份, 我可以尝试着修改一下.

    [回复]

    admin 回复:

    @kyo, 谢谢你对这个软件的支持。这周末我看有没有时间把它做成直接接受参数的命令。到时候给你消息。

    [回复]

    kyo 回复:

    @admin, 恩. 谢谢. 如果您忙的话可以把源码发给我, 我来改一下. 我现在用 expect 配合 CLI 版本的也能凑合着用.

    [回复]

    admin 回复:

    @kyo, 软件已经改好了。祝你好运。

    [回复]

    kyo 回复:

    @admin, 十分感谢.
    btw, 广告竟然被 adBlock 过滤掉了. 让我找了好久.

    [回复]

  6. [...] 于是基于之前《基于对话框的Window扩展显示器软件》及《 修改显示器分辨率的小软件 [...]

Leave a Reply

You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">