88 lines
3.9 KiB
PowerShell
88 lines
3.9 KiB
PowerShell
param([ValidateSet(30, 60)][int]$RefreshRate = 60)
|
|
$ErrorActionPreference = 'Stop'
|
|
Add-Type @'
|
|
using System;
|
|
using System.Runtime.InteropServices;
|
|
public static class VdiDisplayMode {
|
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
|
public struct Device {
|
|
public int cb;
|
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string Name;
|
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string Description;
|
|
public int Flags;
|
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string Id;
|
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string Key;
|
|
}
|
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
|
public struct Mode {
|
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string name;
|
|
public short spec, driver, size, extra;
|
|
public int fields, x, y, orientation, fixedOutput;
|
|
public short color, duplex, yres, tt, collate;
|
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string form;
|
|
public short logPixels;
|
|
public int bpp, width, height, flags, hz, icmMethod, icmIntent, media, dither,
|
|
reserved1, reserved2, panWidth, panHeight;
|
|
}
|
|
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
|
static extern bool EnumDisplayDevices(string name, uint index, ref Device dev, uint flags);
|
|
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
|
static extern bool EnumDisplaySettings(string name, int index, ref Mode mode);
|
|
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
|
static extern int ChangeDisplaySettingsEx(string name, ref Mode mode, IntPtr window, uint flags, IntPtr param);
|
|
|
|
public static string Find() {
|
|
for (uint i = 0; ; i++) {
|
|
var d = new Device();
|
|
d.cb = Marshal.SizeOf(typeof(Device));
|
|
if (!EnumDisplayDevices(null, i, ref d, 0)) return null;
|
|
if ((d.Flags & 1) != 0 && d.Description.IndexOf("Virtual Display Driver", StringComparison.OrdinalIgnoreCase) >= 0)
|
|
return d.Name;
|
|
}
|
|
}
|
|
public static string Current(string name) {
|
|
var m = new Mode();
|
|
m.size = (short)Marshal.SizeOf(typeof(Mode));
|
|
if (!EnumDisplaySettings(name, -1, ref m)) return "unavailable";
|
|
return m.width + "x" + m.height + "@" + m.hz;
|
|
}
|
|
public static int Apply(string name, int refreshRate) {
|
|
for (int i = 0; ; i++) {
|
|
var m = new Mode();
|
|
m.size = (short)Marshal.SizeOf(typeof(Mode));
|
|
if (!EnumDisplaySettings(name, i, ref m)) return -99;
|
|
if (m.width == 2560 && m.height == 1440 && m.hz == refreshRate) {
|
|
m.fields = 0x80000 | 0x100000 | 0x400000;
|
|
int test = ChangeDisplaySettingsEx(name, ref m, IntPtr.Zero, 2, IntPtr.Zero);
|
|
if (test != 0) return test;
|
|
return ChangeDisplaySettingsEx(name, ref m, IntPtr.Zero, 1, IntPtr.Zero);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
'@
|
|
$log = 'C:/ProgramData/VDI/set-2k-result.txt'
|
|
$expectedMode = "2560x1440@$RefreshRate"
|
|
try {
|
|
for ($i = 0; $i -lt 12; $i++) {
|
|
$dev = [VdiDisplayMode]::Find()
|
|
if ($dev) {
|
|
if ([VdiDisplayMode]::Current($dev) -eq $expectedMode) {
|
|
"$(Get-Date -Format o) device=$dev result=0 mode=$expectedMode (already correct)" | Set-Content $log
|
|
exit 0
|
|
}
|
|
$result = [VdiDisplayMode]::Apply($dev, $RefreshRate)
|
|
$mode = [VdiDisplayMode]::Current($dev)
|
|
if ($result -eq 0 -and $mode -eq $expectedMode) {
|
|
"$(Get-Date -Format o) device=$dev result=0 mode=$mode" | Set-Content $log
|
|
exit 0
|
|
}
|
|
}
|
|
Start-Sleep 5
|
|
}
|
|
throw "2K mode not applied: device=$dev result=$result mode=$mode"
|
|
} catch {
|
|
"$(Get-Date -Format o) ERROR $_" | Set-Content $log
|
|
exit 1
|
|
}
|