简体   繁体   中英

Disconnect and Reconnect Displays Programmatically

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:

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

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.

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();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM