2010年2月23日 星期二

DPI Virtualization

這是一個在Vista之後才出現的系統設定
目的是要讓一些原本不是DPI aware的應用程式
可以達到如同DPI aware(WPF視窗都屬於此類)一樣的效果
根據微軟的說法,是希望在各種屬性的平台上面都可以有舒適的效果
請參考Writing High-DPI Win32 Applications - DPI Virtualization

舉例來說,在Win7同樣是1920x1080的解析度之下
同樣透過GetSystemMetrics這個API去讀取解析度
DPI 設定WPF視窗WinForm視窗Win32 Console
100% (96)1920x10801920x10801920x1080
125% (120)1920x10801920x10801920x1080
150% (144)1920x10801280x7201280x720

在DPI=144(150%)的時候,非DPI aware的程式會將解析度自動調整
參考在WPF中取得螢幕的解析度
就發現在WPF程式中使用SystemParameters會得到一樣的結果
這是因為預設在150%以上的時候,DPI Virtualization會被啟動
如果點選自訂DPI設定,就會發現Use Windows XP Style DPI Scaling沒有被勾選了(在100%或是125%則是預設被勾選的)

如果只是在WPF中或是純粹在WinForm底下做處理倒是沒關係
但是有時候會有透過舊有的程式取得資訊的時候
這時候如果不知道DPI Virtualization的設定
就可能出現一些非預期的結果
(請在Win7 150%的設定下VS2008按滑鼠右鍵就知道我在說什麼)

我在MSDN上面提問,但是卻沒有回應,應該是沒有提供這樣的API
不過因為系統設定基本上都會寫在註冊表中
所以我就直接對在同樣設定下,diff有沒有勾選該選項的註冊表
發現其中有一個值是會跟著改變的

[HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM]
"UseDpiScaling"=dword:00000000

所以透過讀取註冊表的API就可以判斷是否有DPI Virtualization的設定

bool IsDpiVirtualization()
{
/// open the key of Desktop Window Manager
RegistryKey k = Registry.CurrentUser.OpenSubKey(
"Software\\Microsoft\\Windows\\DWM");

if (k != null)
{
/// get the value if it exists
if ((int)k.GetValue("UseDpiScaling", 0) == 1)
{
k.Close();
return true;
}
k.Close();
}
return false;
}

--
參考資料
Writing High-DPI Win32 Applications
Current Word - 「XP Style DPI Scaling」
API to get "Use Windows XP Style DPI Scaling" setting
RegistryKey.OpenSubKey 方法
Registry.GetValue 方法

沒有留言:

張貼留言