【问题标题】:Change 2nd Monitor Display Setting to Duplicate将第二台显示器显示设置更改为重复
【发布时间】:2013-02-15 18:22:52
【问题描述】:

我正在尝试以编程方式使第二个监视器具有重复显示。我下面的功能应该将第二台显示器的显示更改为“重复显示”,即让第二台显示器显示第一台/主显示器上的所有内容。

我的问题:当我运行我的函数时,它成功地找到了第二台显示器,并通过更改 DEVMODE dmPosition 将显示器的 x 坐标更改为 0,即主显示器屏幕的左侧。 x 财产。我的两台显示器都会自行刷新(它们变黑然后重新显示屏幕),但第二台显示器仍然具有扩展显示而不是重复显示。

有什么想法可以让我的第二台显示器有重复显示吗?

一些相关信息:
- 我的第二台显示器是液晶电视,通过 HDMI 连接到我的笔记本电脑
- 我的功能代码与MSDN Page 上的示例完全相同,该示例描述了如何连接第二台显示器而无需重新启动。不过,我已经更改了 LINE 30。
- 我知道我可以使用一个 WinAPI 函数调用更改 Windows 7 上的显示,但我需要我的程序在 Windows 2000 及更高版本上工作。

// From http://support.microsoft.com/kb/308216/en-gb Title: You must restart...
BOOL TVManager::AddUnattachedDisplayDeviceToDesktop()
{
    DWORD DispNum = 0;
    DISPLAY_DEVICE DisplayDevice;
    DEVMODE defaultMode;
    HDC hdc;
    int nWidth;
    BOOL bFoundSecondary = FALSE;

    hdc    = GetDC(0);
    nWidth = GetDeviceCaps(hdc, HORZRES);
    ReleaseDC(0, hdc);

    // Initialize DisplayDevice.
    ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
    DisplayDevice.cb = sizeof(DisplayDevice);

    // Get display devices.
    while ((EnumDisplayDevices(NULL, DispNum, &DisplayDevice, 0)) && (bFoundSecondary == FALSE))
    { 
        ZeroMemory(&defaultMode, sizeof(DEVMODE));
        defaultMode.dmSize = sizeof(DEVMODE);
        if (!EnumDisplaySettings((LPTSTR)DisplayDevice.DeviceName, ENUM_REGISTRY_SETTINGS, &defaultMode)) {
            printf("1\n");
            return FALSE; // Store default failed
        }

        if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)) {
            //Found the first secondary device.
            _tprintf(_T("Found the first secondary device: Name: %s, Pos: %d, Width: %d\n"), DisplayDevice.DeviceName, defaultMode.dmPosition.x, nWidth);
            bFoundSecondary           = TRUE;
            defaultMode.dmPosition.x = 0; // LINE CHANGED: ONLY CHANGE FROM MSDN'S CODE
            defaultMode.dmFields      = DM_POSITION; 
            ChangeDisplaySettingsEx((LPTSTR)DisplayDevice.DeviceName, &defaultMode, NULL, CDS_NORESET|CDS_UPDATEREGISTRY, NULL); 
            _tprintf(_T("Check for error: %u\n"), GetLastError()); // prints "Check for error: 0" which means no error occurred

            // A second call to ChangeDisplaySettings updates the monitor.
            ChangeDisplaySettings(NULL, 0); 
            _tprintf(_T("Check for error: %u\n"), GetLastError()); // prints "Check for error: 0" which means no error occurred
        } 

        // Reinitialize DisplayDevice. 
        ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
        DisplayDevice.cb = sizeof(DisplayDevice);
        DispNum++;
    } // End while the display devices. 

    return TRUE;
}

【问题讨论】:

标签: c++ winapi multiple-monitors


【解决方案1】:

Windows XP 及更早版本使用与 Vista 及更高版本 (WDDM) 不同的显示驱动程序模型 (XPDM)。 XPDM 上的镜像很大程度上取决于您的显卡供应商。一般的想法是,为了扩展桌面,你提供一个扩展驱动程序;要镜像桌面的一部分,您需要提供镜像驱动程序。

在大多数情况下,每个扩展驱动程序都负责图形卡上的一个输出。假设您有一个双 DVI 卡,那么您应该在设备管理器中看到两个扩展驱动程序,每个驱动程序负责一个 DVI 端口。如果您想将显示器设置为扩展桌面,请启用扩展驱动程序并为其提供合理的位置。

镜像比较棘手。这是不同卡供应商之间的行为可能会有所不同的地方。从操作系统的角度来看,这就是正在发生的事情。与显卡端口关联的扩展驱动程序被禁用。如果尚未启用镜像驱动程序,则启用它。然后将镜像驱动器放置在 (0, 0) 处。然后你的显卡/驱动程序内部发生了一些诡计,显示器显示镜像驱动程序的屏幕缓冲区内的内容。

为了在 XPDM 上将显示器设置为镜像模式,您需要找到它当前显示内容的扩展驱动程序并将其禁用。这可能是你所要做的。一些供应商会自动为您完成其余的工作并开始镜像主显示器。一些供应商会在您的显示器进入扩展模式之前执行您最后一次执行的操作。如果您发现您的显示器没有显示任何内容,您可以尝试启用镜像驱动程序。如果您设法找到镜像驱动程序并启用它,那么之后会发生什么是任何人的猜测。没有一种通用的方法可以将显示器连接到镜像驱动程序。

【讨论】:

  • 感谢您的详细解释 :) 我觉得非常接近实现这一目标,我想我可以通过一点努力。当你说The extend driver associated with the graphics card port is disabled 时,有没有办法可以使用 WinAPI 调用来禁用扩展驱动程序?我知道如何枚举所有显示设备(甚至是非活动的),我只是不知道是否可以禁用该驱动程序/显示器(顺便说一句,它们是一样的吗?)。
  • 意思有点过头了。我的意思是禁用从 EnumDisplayDevices 获得的显示设备,例如\\.\DISPLAY1,通过调用 ChangeDisplaySettingsEx。
  • 嘿,杰克,你到哪儿了吗?我面临同样的问题,我已经得出结论,Camford 认为没有通用的方法。你唯一能做的就是单独处理每个显卡和版本。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-03
  • 1970-01-01
  • 2011-10-08
相关资源
最近更新 更多