コードを使用して「Windows デスクトップをこのモニターに拡張する」を設定できるようにしたいと考えています。PowerShell スクリプトが理想的です。WMI は進むべき道のように思えますが、私は WMI についてまったく知識がありません。
9 に答える
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;
}
}
これは、新しくインストールしたコンピューターでのみテストしました。
この種の操作は、これらの設定への .NET インターフェイスがないという意味で、PowerShell から直接アクセスすることはできません。コア OS の多くは、win32 API 呼び出しを介してのみ操作できるアンマネージ コードです。あなたは WMI で何かに取り組んでいるかもしれませんが、私はしばらく検索しましたが、この設定を操作できる満足のいく WMI クラスを見つけることができませんでした。
次のステップは、レジストリを直接変更することです。設定は HKLM:\system\CurrentControlSet\control\video--somewhere の下にあるようです。「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"
最初に考えられる解決策の 1 つは、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.
;
ATIグラフィックカードでは3台のモニターを同時にアクティブにすることができないため、モニターを切り替えるためのAutoIt-Scriptを次に示します。私は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」を3番目のモニター/テレビの名前に置き換えるだけで、準備は完了です。ご存知のとおり、AutoItがインストールされていなくても、どのマシンでも実行できる実行可能ファイルに変換できます。
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);
}
私のマシンで 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}")