"Extend my Windows desktop onto this monitor" programmatically "Extend my Windows desktop onto this monitor" programmatically windows windows

"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"