Подтвердить что ты не робот

"Продвинуть рабочий стол Windows на этот монитор" программно

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

4b9b3361

Ответ 1

Windows 7, 8 и 10 должны поставляться с небольшой программой, которая выполняет именно это: displaywitch.exe. Эта страница содержит следующие параметры:

displayswitch.exe/internal  Disconnect projector
displayswitch.exe/clone     Duplicate screen
displayswitch.exe/extend    Extend screen
displayswitch.exe/external  Projector only (disconnect local)

Для решения проблемы с одним щелчком мыши просто создайте *.bat файл, содержащий единственную строку

call displayswitch.exe/extend

и сохраните его на рабочем столе.

[Я тестировал это на Windows 8.1, и было подтверждено, что оно работает в Windows 10.]

Ответ 2

Одно из первых возможных решений - через GUI (но без взаимодействия с пользователем)

VB script (также описанный здесь но в 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.
; 

Ответ 3

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

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

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

Я не уверен, что это правильный раздел реестра, и у меня нет системы, на которой я могу протестировать мультимонитор на данный момент. Целью этого является определение, который является основным контроллером, а затем выводит значение ключа 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"

Ответ 4

Я сделал более чистую версию, которая не использует 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;
    }
}

Я тестировал это только на недавно установленном компьютере. Я создал здесь фрагмент, если вы хотите внести в него изменения

Ответ 5

Вот мой AutoIt- Script для переключения мониторов, так как моя графическая карта ATI не позволяет мне одновременно активировать 3 монитора. У меня есть 2 монитора и телевизор. Этот script делает то, что делает VonC script, но более эффективным и быстрым способом.

Run("C:\WINDOWS\system32\control.exe desk.cpl", "C:\Windows\system32\")
WinWait("Screen Resolution")
ControlCommand("Screen Resolution", "", "ComboBox1", "SetCurrentSelection", "SAMSUNG")

if (ControlCommand("Screen Resolution", "", "ComboBox3", "GetCurrentSelection", "") = "Disconnect this display") Then
    ControlCommand("Screen Resolution", "", "ComboBox1", "SetCurrentSelection", "2")
    ControlCommand("Screen Resolution", "", "ComboBox3", "SetCurrentSelection", "3")
    ControlCommand("Screen Resolution", "", "ComboBox1", "SetCurrentSelection", "0")
    ControlCommand("Screen Resolution", "", "ComboBox3", "SetCurrentSelection", "1")
    ControlClick("Screen Resolution", "", "Button4")
    WinWait("Display Settings")
    ControlClick("Display Settings", "", "Button1")
Else
    ControlCommand("Screen Resolution", "", "ComboBox3", "SetCurrentSelection", "3")
    ControlCommand("Screen Resolution", "", "ComboBox1", "SetCurrentSelection", "2")
    ControlCommand("Screen Resolution", "", "ComboBox3", "SetCurrentSelection", "1")
    ControlClick("Screen Resolution", "", "Button4")
    WinWait("Display Settings")
    ControlClick("Display Settings", "", "Button1")
EndIf

Просто замените "SAMSUNG" на третье имя вашего монитора/телевизора, и все готово! Как вы точно знаете, вы можете преобразовать его в исполняемый файл, который запускается на любой машине, даже если не установлен AutoIt.

Ответ 6

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

;
; — 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}")