Disconnect and Reconnect Displays Programmatically

给你一囗甜甜゛ 提交于 2019-12-23 20:16:25

问题


Question: What is the best way to programmatically disconnect and reconnect displays programmatically?

The Goal: Kill the video output (black screen with no backlight) on a display and later turn it back on. Imagine unplugging the video cord from the monitor, then plugging it back in.

My Attempt:

// Get the monitor to disable
uint iDevNum = 0;
DISPLAY_DEVICE displayDevice = new DISPLAY_DEVICE();
displayDevice.cb = Marshal.SizeOf(displayDevice);
EnumDisplayDevices(null, iDevNum, ref displayDevice, 0))

DEVMODE devMode = new DEVMODE();
EnumDisplaySettings(displayDevice.DeviceName, 0, ref devMode);

//
// Do something here to disable this display device!
//

// Save the display settings
ChangeDisplaySettingsEx(displayDevice.DeviceName, ref devMode, 
    IntPtr.Zero, ChangeDisplaySettingsFlags.CDS_NONE, IntPtr.Zero);

I can interact with each display, but I can't figure out how to disconnect one.

It is similar to "Disconnect this display" in the Screen Resolution properties in Windows 7:

Notes:

  • Turning off video output on all displays won't work because I need the other monitors to stay on.
  • The desktop area on the "dead" display does NOT need to be usable when it is off. Also, it is fine if windows move around.

References:

  1. SO: Enabling a Second Monitor
  2. How to Turn Off a Monitor

回答1:


There's a github project that I STILL haven't got around, but it's a starting point. You need to use Win7 specific API in order to change settings. ChangeDisplaySettings won't work.

Have a look: https://github.com/ChrisEelmaa/MultiMonitorHelper

This is what you need to do:

update the IDisplay interface to support TurnOff() method,

and then call it:

var displayModel = DisplayFactory.GetDisplayModel();
var displayList = displayModel.GetActiveDisplays().ToList();
var firstDisplay = displayList[0].TurnOff();

How to implement TurnOff()? I WOULD imagine this is how(I might be wrong here now):

You need to break the connection between GPU & monitor through breaking the "paths". You can break path between source and target like this:

Call SetDisplayConfig() and pass inside specific paths and make sure you map out the DISPLAYCONFIG_PATH_ACTIVE from the DISPLAY_PATH_INFO structure flags integer.

http://msdn.microsoft.com/en-us/library/windows/hardware/ff553945(v=vs.85).aspx

Sorry for not being more helpful, but this is pretty hardcore stuff, it took me quite a while to even understand the basics of that API. It's a starting point :-),

take a look at the example how to rotate specific monitor in Win7: How do I set the monitor orientation in Windows 7?

In all honesty, just wrap the DisplaySwitch.exe for Win7, and pass /internal or /external(depending if you want to disable/enable first/second monitor), this might or might not work for >2 monitors.




回答2:


1) Get MultiMonitorHelper from here: https://github.com/ChrisEelmaa/MultiMonitorHelper/tree/master

2) Extend Win7Display to disconnect the display:

using MultiMonitorHelper.DisplayModels.Win7.Enum;
using MultiMonitorHelper.DisplayModels.Win7.Struct;

/// <summary>
/// Disconnect a display.
/// </summary>
public void DisconnectDisplay(int displayNumber)
{
    // Get the necessary display information
    int numPathArrayElements = -1;
    int numModeInfoArrayElements = -1;
    StatusCode error = CCDWrapper.GetDisplayConfigBufferSizes(
        QueryDisplayFlags.OnlyActivePaths,
        out numPathArrayElements,
        out numModeInfoArrayElements);

    DisplayConfigPathInfo[] pathInfoArray = new DisplayConfigPathInfo[numPathArrayElements];
    DisplayConfigModeInfo[] modeInfoArray = new DisplayConfigModeInfo[numModeInfoArrayElements];
    error = CCDWrapper.QueryDisplayConfig(
        QueryDisplayFlags.OnlyActivePaths,
        ref numPathArrayElements,
        pathInfoArray,
        ref numModeInfoArrayElements,
        modeInfoArray,
        IntPtr.Zero);
    if (error != StatusCode.Success)
    {
        // QueryDisplayConfig failed
    }

    // Check the index
    if (pathInfoArray[displayNumber].sourceInfo.modeInfoIdx < modeInfoArray.Length)
    {
        // Disable and reset the display configuration
        pathInfoArray[displayNumber].flags = DisplayConfigFlags.Zero;
        error = CCDWrapper.SetDisplayConfig(
            pathInfoArray.Length,
            pathInfoArray,
            modeInfoArray.Length,
            modeInfoArray,
            (SdcFlags.Apply | SdcFlags.AllowChanges | SdcFlags.UseSuppliedDisplayConfig));
        if (error != StatusCode.Success)
        {
            // SetDisplayConfig failed
        }
    }
}

3) Extend Win7Display to reconnect the display using an answer from this post:

using System.Diagnostics;

/// <summary>
/// Reconnect all displays.
/// </summary>
public void ReconnectDisplays()
{
    DisplayChanger.Start();
}

private static Process DisplayChanger = new Process
{
    StartInfo =
    {
        CreateNoWindow = true,
        WindowStyle = ProcessWindowStyle.Hidden,
        FileName = "DisplaySwitch.exe",
        Arguments = "/extend"
    }
};

4) Update the methods in IDisplay.

5) Implement the methods:

IDisplayModel displayModel = DisplayFactory.GetDisplayModel();
List<IDisplay> displayList = displayModel.GetActiveDisplays().ToList();

displayList[0].DisconnectDisplay(0);
displayList[0].ReconnectDisplays();


来源:https://stackoverflow.com/questions/26169268/disconnect-and-reconnect-displays-programmatically

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!