"Extend my Windows desktop onto this monitor" programmatically
Windows 7, 8 and 10 are supposed to come with a small program that does exactly this: displayswitch.exe. This page lists the following parameters:
displayswitch.exe /internal Disconnect projector (same as "Show only on 1" from the Display Properties dialog)displayswitch.exe /clone Duplicate screendisplayswitch.exe /extend Extend screendisplayswitch.exe /external Projector only (disconnect local) (same as "Show only on 2" from the Display Properties dialog)
For a one-click solution to the problem posed, simply create a *.bat-file containing the single line
call displayswitch.exe /extend
and save it to your desktop.
[I tested this on Windows 8.1, and it has been confirmed to work on Windows 10.]
I've made a cleaner version that does not use sendkeys.
public class DisplayHelper{ [DllImport("user32.dll")] static extern DISP_CHANGE ChangeDisplaySettings(uint lpDevMode, uint dwflags); [DllImport("user32.dll")] static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, uint dwFlags); enum DISP_CHANGE : int { Successful = 0, Restart = 1, Failed = -1, BadMode = -2, NotUpdated = -3, BadFlags = -4, BadParam = -5, BadDualView = -1 } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] struct DISPLAY_DEVICE { [MarshalAs(UnmanagedType.U4)] public int cb; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string DeviceName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string DeviceString; [MarshalAs(UnmanagedType.U4)] public DisplayDeviceStateFlags StateFlags; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string DeviceID; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string DeviceKey; } [Flags()] enum DisplayDeviceStateFlags : int { /// <summary>The device is part of the desktop.</summary> AttachedToDesktop = 0x1, MultiDriver = 0x2, /// <summary>The device is part of the desktop.</summary> PrimaryDevice = 0x4, /// <summary>Represents a pseudo device used to mirror application drawing for remoting or other purposes.</summary> MirroringDriver = 0x8, /// <summary>The device is VGA compatible.</summary> VGACompatible = 0x16, /// <summary>The device is removable; it cannot be the primary display.</summary> Removable = 0x20, /// <summary>The device has more display modes than its output devices support.</summary> ModesPruned = 0x8000000, Remote = 0x4000000, Disconnect = 0x2000000 } public static void EnableSecondaryDisplay() { var secondaryIndex = 1; var secondary = GetDisplayDevice(secondaryIndex); var id = secondary.DeviceKey.Split('\\')[7]; using (var key = Registry.CurrentConfig.OpenSubKey(string.Format(@"System\CurrentControlSet\Control\VIDEO\{0}", id), true)) { using (var subkey = key.CreateSubKey("000" + secondaryIndex)) { subkey.SetValue("Attach.ToDesktop", 1, RegistryValueKind.DWord); subkey.SetValue("Attach.RelativeX", 1024, RegistryValueKind.DWord); subkey.SetValue("DefaultSettings.XResolution", 1024, RegistryValueKind.DWord); subkey.SetValue("DefaultSettings.YResolution", 768, RegistryValueKind.DWord); subkey.SetValue("DefaultSettings.BitsPerPel", 32, RegistryValueKind.DWord); } } ChangeDisplaySettings(0, 0); } private static DISPLAY_DEVICE GetDisplayDevice(int id) { var d = new DISPLAY_DEVICE(); d.cb = Marshal.SizeOf(d); if (!EnumDisplayDevices(null, (uint)id, ref d, 0)) throw new NotSupportedException("Could not find a monitor with id " + id); return d; }}
I have only tested this on a newly installed computer.
This sort of operation is not directly accessible from PowerShell in the sense that there is not a .NET interface to these settings. A lot of core OS stuff is unmanaged code which can only be manipulated via win32 API calls. While you may be on to something with WMI, I searched for a while and wasn't able to find a satisfactory WMI class which is able to manipulate this setting.
The next step would be to modify the registry directly. It looks like the setting lies under HKLM:\system\CurrentControlSet\control\video--somewhere. I believe it's the one called "Attach.ToDesktop".
This is a partial solution, so I'm marking as community wiki answer.
I'm not certain this is the right registry key, and I don't have a system on which I can test multi-monitor at the moment. The purpose of this is to determine which is the primary controller, and then it outputs the value of the Attach.ToDesktop key.
param ( $ControllerName = "$( throw 'ControllerName is a mandatory parameter' )")$regPath = "HKLM:\system\CurrentControlSet\control\video"$devDescStr = "Device Description"Set-Location -path $regPath$regSubKey = Get-ChildItem -recurse -include 0000$devDescProperty = $regSubKey | Get-ItemProperty -name $devDescStr -erroraction SilentlyContinue $priDescProperty = $devDescProperty | Where-Object { $_.$devDescStr -match $ControllerName }Set-Location -path $priDescProperty.PSPathGet-ItemProperty -path . -name "Attach.ToDesktop"