You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无外接显示器时设置Windows屏幕分辨率的C#方案问询

解决无显示器连接时Windows自动修改分辨率的C#方案

针对你遇到的Surface自动化依赖固定分辨率,但断开显示器后系统自动降至1024x768的问题,我整理了两个可行的C#实现方案,替代无法使用的NirCmd工具:


核心背景说明

Windows默认依赖显示器的EDID信息识别支持的分辨率,断开物理显示器后,系统会切换到最低兼容模式。你的现有代码仅在有显示器时生效,是因为EnumDisplaySettings需要读取有效显示设备的模式信息,无显示器时无法获取合法的DEVMODE结构。


方案1:注册表强制锁定无显示器分辨率(永久生效)

通过修改系统注册表,强制显卡在无显示器连接时使用指定分辨率,无需依赖物理显示器的EDID信息。

C#实现代码

using Microsoft.Win32;
using System;

public static class ResolutionLocker
{
    /// <summary>
    /// 强制设置无显示器时的默认分辨率(需管理员权限)
    /// </summary>
    /// <param name="targetWidth">目标宽度,如2560</param>
    /// <param name="targetHeight">目标高度,如1440</param>
    public static void LockDefaultResolution(int targetWidth, int targetHeight)
    {
        try
        {
            // 打开显卡配置的注册表根项
            using (RegistryKey videoKey = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Control\Video", true))
            {
                if (videoKey == null)
                {
                    throw new InvalidOperationException("无法访问显示设置注册表项");
                }

                // 遍历所有显卡设备子项
                foreach (string subKeyName in videoKey.GetSubKeyNames())
                {
                    using (RegistryKey deviceKey = videoKey.OpenSubKey($"{subKeyName}\\0000", true))
                    {
                        if (deviceKey == null) continue;

                        // 写入强制分辨率配置
                        deviceKey.SetValue("DefaultSettings.XResolution", targetWidth, RegistryValueKind.DWord);
                        deviceKey.SetValue("DefaultSettings.YResolution", targetHeight, RegistryValueKind.DWord);
                        deviceKey.SetValue("DefaultSettings.RefreshRate", 60, RegistryValueKind.DWord); // 可按需调整刷新率
                    }
                }

                Console.WriteLine("分辨率锁定成功,重启电脑后生效");
            }
        }
        catch (UnauthorizedAccessException)
        {
            Console.WriteLine("请以管理员权限运行此程序");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"操作失败:{ex.Message}");
        }
    }
}

注意事项

  • 必须以管理员权限运行程序,否则无法修改系统注册表。
  • 修改完成后需要重启电脑才能生效。
  • 此方案会全局强制显卡使用指定分辨率,适合需要长期固定设置的场景。

方案2:模拟虚拟显示器(动态生效)

通过Windows API创建虚拟显示器,让系统始终认为有一个显示器连接,从而保持指定分辨率,无需重启。

C#实现代码

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
public struct DEVMODE
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string dmDeviceName;
    public short dmSpecVersion;
    public short dmDriverVersion;
    public short dmSize;
    public short dmDriverExtra;
    public int dmFields;
    public int dmPositionX;
    public int dmPositionY;
    public int dmDisplayOrientation;
    public int dmDisplayFixedOutput;
    public short dmColor;
    public short dmDuplex;
    public short dmYResolution;
    public short dmTTOption;
    public short dmCollate;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string dmFormName;
    public short dmLogPixels;
    public int dmBitsPerPel;
    public int dmPelsWidth;
    public int dmPelsHeight;
    public int dmDisplayFlags;
    public int dmDisplayFrequency;
    public int dmICMMethod;
    public int dmICMIntent;
    public int dmMediaType;
    public int dmDitherType;
    public int dmReserved1;
    public int dmReserved2;
    public int dmPanningWidth;
    public int dmPanningHeight;
}

public static class VirtualDisplayManager
{
    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    public static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, uint dwFlags);

    [DllImport("user32.dll")]
    public static extern int ChangeDisplaySettingsEx(string lpszDeviceName, ref DEVMODE lpDevMode, IntPtr hwnd, uint dwflags, IntPtr lParam);

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct DISPLAY_DEVICE
    {
        public int cb;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
        public string DeviceName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
        public string DeviceString;
        public uint StateFlags;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
        public string DeviceID;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
        public string DeviceKey;
    }

    public const uint CDS_UPDATEREGISTRY = 0x00000001;
    public const uint CDS_ADDMODE = 0x00000020;
    public const uint DISPLAY_DEVICE_ACTIVE = 0x00000001;
    private const int DM_PELSWIDTH = 0x00080000;
    private const int DM_PELSHEIGHT = 0x00100000;
    private const int DM_DISPLAYFREQUENCY = 0x00400000;

    /// <summary>
    /// 创建虚拟显示器并设置指定分辨率
    /// </summary>
    /// <param name="targetWidth">目标宽度</param>
    /// <param name="targetHeight">目标高度</param>
    public static void CreateVirtualDisplay(int targetWidth, int targetHeight)
    {
        DISPLAY_DEVICE displayDevice = new DISPLAY_DEVICE();
        displayDevice.cb = Marshal.SizeOf(displayDevice);

        // 枚举未激活的显示设备(虚拟显示器)
        for (uint i = 0; EnumDisplayDevices(null, i, ref displayDevice, 0); i++)
        {
            if ((displayDevice.StateFlags & DISPLAY_DEVICE_ACTIVE) == 0)
            {
                DEVMODE devMode = new DEVMODE();
                devMode.dmSize = (short)Marshal.SizeOf(devMode);
                devMode.dmDeviceName = displayDevice.DeviceName;
                devMode.dmPelsWidth = targetWidth;
                devMode.dmPelsHeight = targetHeight;
                devMode.dmDisplayFrequency = 60;
                devMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;

                // 应用分辨率设置并激活虚拟显示器
                int result = ChangeDisplaySettingsEx(displayDevice.DeviceName, ref devMode, IntPtr.Zero, CDS_UPDATEREGISTRY | CDS_ADDMODE, IntPtr.Zero);
                if (result == 0)
                {
                    Console.WriteLine($"虚拟显示器创建成功,分辨率已设置为 {targetWidth}x{targetHeight}");
                    return;
                }
            }
        }

        Console.WriteLine("未找到可用的虚拟显示器设备(部分显卡可能不支持)");
    }
}

注意事项

  • 无需重启,运行后立即生效,适合临时调整或自动化脚本场景。
  • 部分老旧显卡可能不支持虚拟显示器功能,需要提前测试兼容性。
  • 若需开机自动运行,可将程序添加到Windows启动项中。

内容的提问来源于stack exchange,提问作者Jan021981

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:02:10