Программно «Расширить мой рабочий стол Windows на этот монитор»

Asked
Viewd33537

20

Я хотел бы иметь возможность установить «Расширить мой рабочий стол Windows на этот монитор» с помощью кода. Сценарий PowerShell был бы идеальным. WMI кажется подходящим вариантом, но я ничего не знаю о WMI.

8 ответов

0

Мне пришлось внести небольшие изменения, чтобы скрипт VonC работал на моей машине. Теперь он стал более общим.

 ;
; — toggle-screen2.au3
;

#include <WinAPI.au3>
; exec cpanel app `display settings`
Run(_WinAPI_ExpandEnvironmentStrings("%windir%") & "\system32\control.exe desk.cpl,@0,3?")

; wait for window to be active
WinWaitActive("Display Properties")

; select 2nd display
Send("!d")
Send("{DOWN}")

; toggle the ‘extend desktop’ checkbox
Send("!e")

; close the dialog
Send("{ENTER}")
 
2

Первое возможное решение - ... через графический интерфейс (но без взаимодействия с пользователем)

сценарий VB (здесь также описывается , но на языке Autoit ):

 Option Explicit
Dim WshShell, Dummy, Splash

On Error Resume Next

Set WshShell = WScript.CreateObject("WScript.Shell")

'Main
Call DoIt
WScript.Quit

Sub DoIt
wshshell.Run("%systemroot%\system32\control.exe desk.cpl,@0,3")

' Give Display Properties time to load
WScript.Sleep 1000
WshShell.SendKeys "2"
WScript.Sleep 10
WshShell.SendKeys "%E"
WScript.Sleep 500
WshShell.SendKeys "%A"
WshShell.SendKeys "{TAB}"
WshShell.SendKeys "{TAB}"
WshShell.SendKeys "{TAB}"
WshShell.SendKeys "{TAB}"
WshShell.SendKeys "{TAB}"
WshShell.SendKeys "{TAB}"
WshShell.SendKeys "{TAB}"
WshShell.SendKeys "{TAB}"
WshShell.SendKeys "{TAB}"
WshShell.SendKeys "{TAB}"
WshShell.SendKeys "{ENTER}"
End Sub 'DoIt
 

В Autoit это будет:

 ;
; — toggle-screen.au3
;

; exec cpanel app `display settings`
Run(”C:\WINDOWS\system32\control.exe desk.cpl,@0,3?”)

; wait for window to be active
WinWaitActive(”Display Settings”)

; select 2nd display
Send(”{TAB}”)
Send(”{DOWN}”)

; work back to the ‘extend desktop’ control
Send(”+{TAB}”)
Send(”+{TAB}”)
Send(”+{TAB}”)
Send(”+{TAB}”)
Send(”+{TAB}”)
Send(”+{TAB}”)
Send(”+{TAB}”)
Send(”+{TAB}”)
Send(”+{TAB}”)

; toggle ‘extend desktop’ control and apply
Send(”{SPACE}”)
Send(”{ENTER}”)

; wait for window to be active
WinWaitActive(”Display Settings”)

; accept
Send(”{TAB}”)
Send(”{ENTER}”)

;
; — E.O.F.
; 
 
6

Я сделал более чистую версию, в которой не используются ключи отправки.

 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;
    }
}
 

Я тестировал это только на недавно установленном компьютере.

3

Операции такого типа недоступны напрямую из PowerShell в том смысле, что для этих параметров нет интерфейса .NET. Многие основные элементы ОС представляют собой неуправляемый код, которым можно управлять только с помощью вызовов API Win32. Хотя вы можете что-то узнать о WMI, я некоторое время искал и не смог найти удовлетворительный класс WMI, который мог бы управлять этим параметром.

Следующим шагом будет непосредственное изменение реестра. Похоже, что настройка находится где-то в HKLM: \ system \ CurrentControlSet \ control \ video. Я считаю, что это тот, который называется «Attach.ToDesktop».

Это частичное решение, поэтому я помечаю его как ответ сообщества.

Я не уверен, что это правильный раздел реестра, и в настоящий момент у меня нет системы, на которой я мог бы протестировать несколько мониторов. Это делается с целью определить, какой из контроллеров является основным, и затем выводит значение ключа Attach.ToDesktop.

 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.PSPath
Get-ItemProperty -path . -name "Attach.ToDesktop"