问题
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:
- SO: Enabling a Second Monitor
- 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