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

C++Builder 動態切換螢幕解析度:ChangeDisplaySettings 完整實作

     編輯:VC 教學

核心 API:ChangeDisplaySettings / EnumDisplaySettings


LONG ChangeDisplaySettings(LPDEVMODE lpDevMode, DWORD dwFlags);
BOOL EnumDisplaySettings(LPCTSTR lpszDeviceName, DWORD iModeNum, LPDEVMODE lpDevMode);

DEVMODE 關鍵欄位

欄位用途
dmFields指定哪些欄位有效 (位元組合)
dmPelsWidth水平解析度 (像素)
dmPelsHeight垂直解析度
dmBitsPerPel色深 (8/16/24/32)
dmDisplayFrequency重新整理率 (Hz)
dmPosition多螢幕位置

常用 dmFields 旗標


#define DM_PELSWIDTH       0x00080000
#define DM_PELSHEIGHT      0x00100000
#define DM_BITSPERPEL      0x00040000
#define DM_DISPLAYFREQUENCY 0x00400000
#define DM_POSITION        0x00200000

完整實作代碼


void __fastcall TForm1::GetCurrentResolution()
{
    int x = GetSystemMetrics(SM_CXSCREEN);
    int y = GetSystemMetrics(SM_CYSCREEN);
    ShowMessage("目前解析度: " + IntToStr(x) + " x " + IntToStr(y));
}

bool __fastcall TForm1::SetResolution(int width, int height, int freq = 0, int bpp = 0)
{
    DEVMODE dm = {0};
    dm.dmSize = sizeof(DEVMODE);

    // 1. 取得當前模式作為基礎
    if (!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm))
        return false;

    // 2. 設定欲變更欄位
    dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
    dm.dmPelsWidth = width;
    dm.dmPelsHeight = height;
    if (freq > 0) {
        dm.dmFields |= DM_DISPLAYFREQUENCY;
        dm.dmDisplayFrequency = freq;
    }
    if (bpp > 0) {
        dm.dmFields |= DM_BITSPERPEL;
        dm.dmBitsPerPel = bpp;
    }

    // 3. 嘗試變更 (CDS_TEST 先測試)
    LONG result = ChangeDisplaySettings(&dm, CDS_TEST);
    if (result != DISP_CHANGE_SUCCESSFUL)
        return false;

    // 4. 正式套用
    result = ChangeDisplaySettings(&dm, CDS_UPDATEREGISTRY); // 寫入登錄持久化
    return result == DISP_CHANGE_SUCCESSFUL;
}

// 按鈕事件
void __fastcall TForm1::BitBtn1Click(TObject *Sender) { SetResolution(800, 600); }
void __fastcall TForm1::BitBtn2Click(TObject *Sender) { SetResolution(1024, 768); }

ChangeDisplaySettings 返回碼對照

返回值常數含義
0DISP_CHANGE_SUCCESSFUL成功
-1DISP_CHANGE_RESTART需重啟 (舊版驅動)
-2DISP_CHANGE_FAILED驅動拒絕/模式不支援
-3DISP_CHANGE_BADMODE模式無效
-4DISP_CHANGE_NOTUPDATED登錄更新失敗
-5DISP_CHANGE_BADFLAGS旗標錯誤
-6DISP_CHANGE_BADPARAM參數錯誤

多螢幕支援


// 列舉所有顯示裝置
DISPLAY_DEVICE dd = {0}; dd.cb = sizeof(dd);
for (DWORD i = 0; EnumDisplayDevices(NULL, i, &dd, 0); i++) {
    if (dd.StateFlags & DISPLAY_DEVICE_ACTIVE) {
        DEVMODE dm = {0}; dm.dmSize = sizeof(dm);
        EnumDisplaySettings(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm);
        // 針對 dd.DeviceName 呼叫 ChangeDisplaySettings
    }
}

最佳實踐與避坑

  • ✅ 呼叫 CDS_TEST 先驗證模式支援,避免螢幕黑屏無法恢復。
  • ✅ 使用 CDS_UPDATEREGISTRY 持久化,否則重啟後恢復預設。
  • ✅ 提供「恢復預設」按鈕:ChangeDisplaySettings(NULL, 0)。
  • ⚠️ 全螢幕遊戲/獨占模式下調用可能失效或衝突。
  • ⚠️ 筆記型電腦外接螢幕需指定正確裝置名 (\\.\DISPLAY1 等)。
  • ⚠️ 高 DPI 感知程式需自行處理縮放,解析度變更不自動縮放 UI。

現代替代:DXGI / DisplayConfig API (Win10+)


// 更底層、支援 HDR、VRR、多平面覆疊
IDXGIFactory *pFactory; CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&pFactory);
IDXGIAdapter *pAdapter; pFactory->EnumAdapters(0, &pAdapter);
IDXGIOutput *pOutput; pAdapter->EnumOutputs(0, &pOutput);
DXGI_MODE_DESC mode = { width, height, {freq,1}, DXGI_FORMAT_R8G8B8A8_UNORM, 0, DXGI_MODE_SCALING_UNSPECIFIED, DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED };
pOutput->FindClosestMatchingMode(&mode, &matchedMode, NULL);

動態切換解析度流程圖

ChangeDisplaySettings 雖屬經典 API,但在不支援新式 DisplayConfig 的舊系統、簡易工具、腳本控制場景下仍是首選。

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