Disconnect and reconnect Displays programmatically

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

Goal: Kill the video output (black screen with no backlight) on the display and then turn it back on. Imagine unplugging the video cable from your monitor and 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 cannot figure out how to turn it off.

It is similar to "Disable this screen" in the screen resolution properties in Windows 7:

Windows 7 Screen Resolution Properties

Notes:

  • Disabling video output on all displays will not work because I need the other monitors to stay in place.
  • The desktop area on a "dead" display should NOT be used when it is off. Also, it's okay if the windows are moving.

Literature:

+3


source to share


2 answers


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

2) Extend Win7Display to disable 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 the 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 methods:

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

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

      

+1


source


There's a github project in there that I don't have, but that's a starting point. To change the settings, you need to use the Win7 API. ChangeDisplaySettings won't work.

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

This is what you need to do:

update the interface IDisplay

to support the TurnOff () method,

and then call it:

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

      

How do I implement TurnOff ()? I would guess that this is how (I may be wrong here):



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

Call SetDisplayConfig

() and walk inside the defined paths and make sure you strip out DISPLAYCONFIG_PATH_ACTIVE

of DISPLAY_PATH_INFO

the flags structure .

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

Sorry for not being more useful, but this is pretty hardcore stuff, it took me a while to understand the basics of this API. This is the starting point :-)

take a look at an example how to rotate a specific monitor in Win7: How to adjust the orientation of the monitor in Windows 7?

Honestly everyone, just wrap DisplaySwitch.exe for Win7 and pass / internal or / external (depending on whether you want to disable / enable the first / second monitor) this may or may not work for> 2 monitors.

+1


source







All Articles