Me gustaría poder establecer "Extender mi escritorio de Windows en este monitor" a través del código. Un script de PowerShell sería ideal. WMI parece el camino a seguir, pero no tengo conocimiento en WMI."Extienda mi escritorio de Windows en este monitor" programáticamente
Respuesta
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.
;
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"
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}")
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
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.
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.]
- 1. ¿Utiliza una computadora de escritorio separada en un monitor externo?
- 2. ¿Cómo activo un segundo monitor en C#?
- 3. ¿Cómo ocultar íconos de escritorio programáticamente?
- 4. Windows: Cómo cambiar el brillo de la retroiluminación del monitor
- 5. Automatizar configuración de monitor doble En Vista
- 6. Desbloquear Windows programáticamente
- 7. ¿Obtiene programáticamente estadísticas de disco io por proceso en Windows?
- 8. Serial/Com Port monitor para Windows x64
- 9. ¿Cómo evito que mi tabla html se extienda?
- 10. Añadiendo accesos directos de escritorio a "Mi PC" en el servidor de Windows 2008
- 11. ¿Obtiene programáticamente estadísticas de red por proceso en Windows?
- 12. ¿Mostrando un formulario de Windows en un monitor secundario?
- 13. Uso de Windows Firewall programáticamente
- 14. Extienda MediaController para android
- 15. cliente de escritorio OLAP no Windows?
- 16. ¿Cuál es mi entorno de escritorio actual?
- 17. ¿Es posible cambiar programáticamente el protector de pantalla y/o fondo de escritorio de un usuario?
- 18. ¿Cómo puedo crear programáticamente este enlace personalizado?
- 19. ¿Cómo puedo cambiar el fondo de mi escritorio con python?
- 20. Encender/apagar el monitor
- 21. ¿Cómo configuro la orientación del monitor en Windows 7?
- 22. Redirigir usuario a navegador de escritorio en Windows 8
- 23. ¿Cómo acoplar una aplicación en el escritorio de Windows?
- 24. Dibuje OpenGL en el escritorio de Windows sin una ventana
- 25. Extienda TTPhotoViewController con TTPhotoView personalizado
- 26. WPF vs Windows Forms en aplicaciones de escritorio
- 27. ¿Cómo informo a otras aplicaciones que mi aplicación es parte del escritorio de Windows?
- 28. Mylyn como aplicación para mi escritorio
- 29. Cómo copiar/pegar programáticamente en Windows Phone?
- 30. Buscar la carpeta windows programáticamente en C#
Por favor, no poner esto en el código de producción –
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. –