同 WinForms 篇,高 DPI 環境日益普及,原生 C++ 應用程式若無 DPI 感知會面臨模糊、截斷、版面破裂。本實驗示範如何透過資訊清單宣告 DPI 感知、使用 CDPI 輔助類縮放 UI 元素、主題文字繪製 API 達成真正的高 DPI 相容。
同 WinForms 篇:控制台 > 顯示 > 選擇「較大 - 150%」(144 DPI)。
HighDPIApp.sln,設定 HighDPINativeApp 為啟動專案。| UI 元素 | 144 DPI 外觀 |
|---|---|
| 視窗大小 | 較大 (虛擬化放大) |
| 按鈕大小 | 較大 |
| 文字大小 | 較大 |
| 按鈕文字截斷 | 是 |
| 視窗文字截斷 | 是 |
| 模糊效果 | 是 (整體 bitmap 伸縮) |
原因: 預設啟用 DPI 虛擬化 (Vista 引入),整個視窗內容以 bitmap 形式放大,導致模糊、文字截斷、版面不精確。
DeclareDPIAware.manifest。<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"
xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:application>
<asmv3:windowsSettings xmlns="https://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>
| UI 元素 | 144 DPI 外觀 |
|---|---|
| 視窗大小 | 相同 (96 DPI 像素) |
| 按鈕大小 | 相同 |
| 文字大小 | 較大 |
| 按鈕文字截斷 | 是 |
| 視窗文字截斷 | 是 |
| 模糊效果 | 無 |
使用專案內建的 CDPI 類 (g_metrics 實例) 將設計時像素轉換為當前 DPI 對應的邏輯像素。
// 在 DemoApp::CreateChildWindows 中
SIZE buttonSize = { 60, 26 };
g_metrics.ScaleSize(&buttonSize); // 依 DPI 縮放大小
POINT ptButton1Pos = { 10, 55 };
g_metrics.ScalePoint(&ptButton1Pos);
POINT ptButton2Pos = { 85, 55 }; // 相對按鈕 1 右側 75 像素
g_metrics.ScalePoint(&ptButton2Pos);
POINT ptButton3Pos = { 160, 55 };
g_metrics.ScalePoint(&ptButton3Pos);
結果:按鈕大小與間距隨 DPI 正確縮放,版面不錯位。
// DemoApp::Initialize 中 CreateWindow 參數
g_metrics.ScaleX(420), // 寬度
g_metrics.ScaleY(200) // 高度
// DemoApp::OnRender
// TextOut(ps.hdc, rcText.left, rcText.top, szText, lstrlen(szText));
OffsetRect(&rcText, g_metrics.ScaleX(8), g_metrics.ScaleY(8));
HTHEME hTheme = OpenThemeData(hWnd, VSCLASS_TEXTSTYLE);
if (hTheme)
{
DrawThemeText(hTheme, ps.hdc, TEXT_BODYTEXT, 0, szText, -1, DT_SINGLELINE, 0, &rcText);
CloseThemeData(hTheme);
}
else
{
DrawText(ps.hdc, szText, -1, &rcText, DT_SINGLELINE); // 回退
}
DrawThemeText 支援主題渲染、高 DPI 字體縮放、ClearType、自動換行/截斷處理。g_metrics.ScaleX/Y 調整文字矩形位置。視窗大小正確、按鈕大小間距正確、文字清晰無截斷、長寬比維持、無模糊——達成真正的高 DPI 感知。
<dpiAware>true</dpiAware> → 關閉虛擬化,接管繪製責任。CDPI 類 (ScaleX/ScaleY/ScaleSize/ScalePoint) 將所有硬式編碼像素轉換為邏輯像素。DrawThemeText 等主題 API,自動處理高 DPI 字體度量。