GetSystemMetrics() returns wrong value for SM_CXSCREEN
I've run into an interest开发者_Go百科ing problem. At least in Vista, getSystemMetrics(SM_CXSCREEN) returns an incorrect value when the desktop DPI settings aren't set at 100%. For example, I tried 150% in a 1366x768 screen and getSystemMetrics() returns 911 instead of 1366 (and 1366 / 1.5 ~ 911)
According to the MSDN, getSystemMetrics(SM_CXSCREEN) returns pixels, so I thought this value wouldn't be affected by the DPI settings - but it is. So is there a safer way to find out the true, unscaled screen resolution?
A program must tell the operating system that it is DPI-aware to get the true resolution when you go past 125%. That's best done with a manifest, as explained in this MSDN Library article.
To make you application aware of dpi make and manifest file and put the following text in it.
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>
Before getting the correct pixel metrics from functions like GetSystemMetrics, or GetClientRect, your app must declare to the OS that it knows about DPI and therefore won't screw everything up.
There have been several changes to how this is recommended. See the MSDN docs for more details.
From Windows 10 onwards:
::SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE);
Or from Windows 8.1 onwards:
::SetProcessDpiAwareness(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE);
Or from Vista onwards:
::SetProcessDPIAware();
After calling this, the function GetSystemMetrics etc. should return the correct values to your app in pixels.
精彩评论