2008-11-08 21 views

Respuesta

4

Una primera solución posible es ... a través de la interfaz gráfica de usuario (pero sin interacción del usuario)

VB script (también described here pero en Autoit idioma):

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 

En AutoIt, que sería:

; 
; — 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. 
; 
+8

Por favor, no poner esto en el código de producción –

+1

Icky! Sé que hay algunos casos miserables en los que todo lo que puedes hacer es la robótica de GUI, pero de alguna manera no creo que este sea uno de ellos. –

3

Este tipo de operación no es directamente accesible desde PowerShell en el sentido de que no hay una interfaz .NET para estas configuraciones Una gran cantidad de cosas del sistema operativo central es un código no administrado que solo puede ser manipulado a través de llamadas API de win32. Aunque es posible que tenga algo con WMI, busqué durante un tiempo y no pude encontrar una clase WMI satisfactoria que pueda manipular esta configuración.

El siguiente paso sería modificar el registro directamente. Parece que la configuración se encuentra en HKLM: \ system \ CurrentControlSet \ control \ video - en algún lugar. Creo que es el llamado "Attach.ToDesktop".

Esta es una solución parcial, por lo que estoy marcando como respuesta wiki de la comunidad.

No estoy seguro de que esta sea la clave de registro correcta, y no tengo un sistema en el que pueda probar monitores múltiples en este momento. El propósito de esto es determinar cuál es el controlador primario y luego genera el valor de la clave 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" 
0

Tuve que hacer algunas pequeñas modificaciones para que la secuencia de comandos de VonC funcionara en mi máquina. Ahora es un poco más genérico.

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

He hecho una versión más limpia que no utiliza 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; 
    } 
} 

Solo he probado esto en una computadora recién instalada. I created a a snippet here if you would like to make changes to it

1

Aquí está mi AutoIt-Script para cambiar monitores ya que mi tarjeta de gráficos ATI no me permite tener 3 monitores activos al mismo tiempo. Tengo 2 monitores conectados y un televisor. Este script está haciendo lo que hace el script de VonC, pero de una manera más efectiva y rápida.

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 

¡Simplemente reemplace "SAMSUNG" con el nombre de su tercer monitor/televisor y listo! Como seguramente sabe, puede convertirlo en un ejecutable que se ejecuta en cualquier máquina, incluso sin AutoIt instalado.

14

Se supone que Windows 7, 8 y 10 vienen con un pequeño programa que hace exactamente esto: displayswitch.exe. This page listas de los siguientes parámetros:

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

Para un solo clic solución al problema planteado, basta con crear un *.bat-file que contiene la línea simple

call displayswitch.exe/extend 

y guárdalo en tu escritorio.

[He probado esto en Windows 8.1, y se ha confirmado que funciona en Windows 10.]

Cuestiones relacionadas