首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 呼叫 Windows API 修改螢幕解析度與重新率

     編輯:關於C語言

前言

在開發全螢幕遊戲、多媒體播放器或自動化測試工具時,常需要以程式碼動態調整顯示器的解析度與重新率。.NET Framework 本身未提供直接的 Managed API,必須透過 P/Invoke 呼叫 user32.dll 中的 ChangeDisplaySettings 函式。本文完整示範如何定義結構體、匯入非受控函式,並安全地套用新的顯示模式。

核心結構體與常數定義

DEVMODE 結構體包含顯示裝置的詳細設定,欄位順序與大小必須與 Win32 API 完全一致,否則會導致呼叫失敗或系統不穩定。

using System;
using System.Runtime.InteropServices;

public class DisplaySettings
{
    // 螢幕旋轉枚舉
    public enum DMDO : short
    {
        DEFAULT = 0,
        D90 = 1,
        D180 = 2,
        D270 = 3
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public struct DEVMODE
    {
        // 必要旗標常數
        public const int DM_DISPLAYFREQUENCY = 0x400000;
        public const int DM_PELSWIDTH = 0x80000;
        public const int DM_PELSHEIGHT = 0x100000;

        private const int CCHDEVICENAME = 32;
        private const int CCHFORMNAME = 32;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
        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 DMDO dmDisplayOrientation;
        public int dmDisplayFixedOutput;

        public short dmColor;
        public short dmDuplex;
        public short dmYResolution;
        public short dmTTOption;
        public short dmCollate;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHFORMNAME)]
        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;
    }

    // 匯入 user32.dll
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern int ChangeDisplaySettings(ref DEVMODE lpDevMode, int dwFlags);

    // 回傳碼常數
    private const int DISP_CHANGE_SUCCESSFUL = 0;
    private const int DISP_CHANGE_RESTART = 1;
    private const int DISP_CHANGE_FAILED = -1;
    private const int DISP_CHANGE_BADMODE = -2;
    // ... 其他錯誤碼略
}

變更解析度與重新率的完整範例

以下方法將螢幕設定為 1024×768、85Hz。實務上建議先呼叫 EnumDisplaySettings 列舉支援的模式,確認目標模式存在後再套用。

public static bool SetResolution(int width, int height, int frequency)
{
    DEVMODE dm = new DEVMODE();
    dm.dmSize = (short)Marshal.SizeOf(typeof(DEVMODE));
    dm.dmPelsWidth = width;
    dm.dmPelsHeight = height;
    dm.dmDisplayFrequency = frequency;
    dm.dmFields = DEVMODE.DM_PELSWIDTH | DEVMODE.DM_PELSHEIGHT | DEVMODE.DM_DISPLAYFREQUENCY;

    int result = ChangeDisplaySettings(ref dm, 0); // 0 = CDS_UPDATEREGISTRY | CDS_NORESET

    switch (result)
    {
        case DISP_CHANGE_SUCCESSFUL:
            Console.WriteLine("顯示模式變更成功。");
            return true;
        case DISP_CHANGE_RESTART:
            Console.WriteLine("需重新啟動電腦才能生效。");
            return true;
        default:
            Console.WriteLine($"變更失敗,錯誤碼:{result}");
            return false;
    }
}

進階技巧與注意事項

  • 測試模式:呼叫時傳入 CDS_TEST (0x00000002) 可先驗證模式是否支援,不實際套用。
  • 永久生效:加上 CDS_UPDATEREGISTRY (0x00000001) 將設定寫入登錄檔,重開機後保持。
  • 多螢幕支援:需使用 ChangeDisplaySettingsEx 指定裝置名稱(dmDeviceName)。
  • 權限問題:Vista 以降作業系統需管理員權限或應用程式 Manifest 宣告 requireAdministrator。
  • 錯誤處理:務必檢查回傳碼,失敗時可透過 Marshal.GetLastWin32Error() 取得詳細錯誤資訊。

完整可執行範例

class Program
{
    static void Main()
    {
        // 設定為 1920x1080 @ 60Hz
        bool ok = DisplaySettings.SetResolution(1920, 1080, 60);
        if (!ok) Console.WriteLine("請確認目標解析度/重新率為顯示器支援模式。");
        Console.ReadKey();
    }
}

總結

透過 P/Invoke 呼叫 ChangeDisplaySettings 是 C# 控制顯示模式的標準做法。關鍵在於正確定義 DEVMODE 結構體、妥善處理旗標與錯誤碼,並在部署前於目標硬體充分測試,確保使用者體驗不受干擾。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved