25

我希望能够通过代码设置“将我的 Windows 桌面扩展到此显示器上”。PowerShell 脚本将是理想的。WMI 似乎是前进的方向,但我对 WMI 的了解为零。

4

9 回答 9

43

Windows 7、8 和 10 应该附带一个执行此操作的小程序:displayswitch.exe。 此页面列出了以下参数:

displayswitch.exe /internal Disconnect projector (same as "Show only on 1" from the Display Properties dialog)
displayswitch.exe /clone        Duplicate screen
displayswitch.exe /extend    Extend screen
displayswitch.exe /external Projector only (disconnect local) (same as "Show only on 2" from the Display Properties dialog)

要一键解决所提出的问题,只需创建一个包含单行的 *.bat 文件

call displayswitch.exe /extend

并将其保存到您的桌面。

[我在 Windows 8.1 上对此进行了测试,并已确认可以在 Windows 10 上运行。]

于 2014-08-02T12:10:00.337 回答
5

我制作了一个不使用 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;
    }
}

我只在新安装的计算机上对此进行了测试。

于 2010-03-17T13:57:17.853 回答
3

此类操作无法从 PowerShell 直接访问,因为这些设置没有 .NET 接口。很多核心操作系统的东西都是非托管代码,只能通过 win32 API 调用来操作。虽然您可能对 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"
于 2008-11-09T04:22:53.140 回答
2

第一个可能的解决方案是……通过 GUI(但没有用户交互)

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.
; 
于 2008-11-08T20:11:15.270 回答
2

自动热键中的 2 行

第二次显示:

RunWait C:\Windows\System32\DisplaySwitch.exe /extend

第二次显示关闭:

RunWait C:\Windows\System32\DisplaySwitch.exe /internal

-

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
#Persistent 

Any1stKeyUWantToTurnOn::RunWait C:\Windows\System32\DisplaySwitch.exe /extend
Any2stKeyUWantToTurnOff::RunWait C:\Windows\System32\DisplaySwitch.exe /internal

或者

您可以在github / BNK3R-Boy / DisplaySwitch上查看并试用我的工具。我马上发表了。

于 2018-04-18T18:33:55.067 回答
1

这是我用于切换显示器的 AutoIt-Script,因为我的 ATI 显卡不允许我同时激活 3 个显示器。我有 2 台显示器和一台电视机。这个脚本正在做 VonC 的脚本所做的事情,但是以一种更有效和更快的方式。

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,您也可以将其转换为可在任何机器上运行的可执行文件。

于 2010-08-14T00:01:30.563 回答
1

这是 C# 中的另一个解决方案(通过如何在 C# 中为 Windows-7 设置主监视器):

[Flags]
public enum SetDisplayConfigFlags : uint
{
    SDC_TOPOLOGY_INTERNAL = 0x00000001,
    SDC_TOPOLOGY_CLONE = 0x00000002,
    SDC_TOPOLOGY_EXTEND = 0x00000004,
    SDC_TOPOLOGY_EXTERNAL = 0x00000008,
    SDC_APPLY = 0x00000080
}

[DllImport("user32.dll", CharSet = CharSet.Unicode)]
private static extern long SetDisplayConfig(uint numPathArrayElements,
    IntPtr pathArray, uint numModeArrayElements, IntPtr modeArray, SetDisplayConfigFlags flags);

static void CloneDisplays() {
    SetDisplayConfig(0, IntPtr.Zero, 0, IntPtr.Zero, SetDisplayConfigFlags.SDC_TOPOLOGY_CLONE | SetDisplayConfigFlags.SDC_APPLY);
}

static void ExtendDisplays() {
    SetDisplayConfig(0, IntPtr.Zero, 0, IntPtr.Zero, SetDisplayConfigFlags.SDC_TOPOLOGY_EXTEND | SetDisplayConfigFlags.SDC_APPLY);
}

static void ExternalDisplay() {
    SetDisplayConfig(0, IntPtr.Zero, 0, IntPtr.Zero, SetDisplayConfigFlags.SDC_TOPOLOGY_EXTERNAL | SetDisplayConfigFlags.SDC_APPLY);
}

static void InternalDisplay() {
    SetDisplayConfig(0, IntPtr.Zero, 0, IntPtr.Zero, SetDisplayConfigFlags.SDC_TOPOLOGY_INTERNAL | SetDisplayConfigFlags.SDC_APPLY);
}
于 2021-09-08T02:34:56.403 回答
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}")
于 2009-05-21T07:04:39.487 回答
0

windows键+P键会做同样的事情

于 2018-07-25T15:37:10.610 回答