Reputation: 937
I have two monitors:
DISPLAY2: 3840x2160 (primary (no idea why it's called DISPLAY2 though)
DISPLAY1: 1920x1080 (located right of primary)
I wrote a small program to print their geometry, and it outputs:
\\.\DISPLAY2; x=0, y=0; 3840x2160
\\.\DISPLAY1; x=3840, y=278; 1920x1080
Which looks correct. However, if I call SetProcessDpiAwareness((PROCESS_DPI_AWARENESS) 1);
, then it will print:
\\.\DISPLAY2; x=0, y=0; 7680x4320
\\.\DISPLAY1; x=7680, y=556; 3840x2160
Why did the sizes just doubled ?
Note that I'm not using any scaling factor on my monitors, to able to figure out what's going on first. But here's what it prints if I set a 2x scaling on the primary monitor:
\\.\DISPLAY2; x=0, y=0; 3840x2160
\\.\DISPLAY1; x=7680, y=556; 3840x2160
Why is the secondary monitor starting at x=7680 ?
Here's the code I used to print the values:
#include <Windows.h>
#include <iostream>
#include <ShellScalingAPI.h>
#pragma comment(lib, "Shcore.lib")
#pragma comment(lib, "User32.lib")
BOOL monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM)
{
MONITORINFOEX info;
memset(&info, 0, sizeof(MONITORINFOEX));
info.cbSize = sizeof(MONITORINFOEX);
if (!GetMonitorInfo(hMonitor, &info))
return false;
std::cout << info.szDevice << "; x="<< info.rcMonitor.left << ", y=" << info.rcMonitor.top << "; "
<< (info.rcMonitor.right - info.rcMonitor.left) << "x" << (info.rcMonitor.bottom - info.rcMonitor.top)
<< "\n";
return true;
}
int main()
{
int result = SetProcessDpiAwareness((PROCESS_DPI_AWARENESS) 1);
if (result) {
std::cout << "Failed to call SetProcessDpiAwareness\n";
return 1;
}
EnumDisplayMonitors(0, 0, monitorEnumCallback, reinterpret_cast<LPARAM>(&result));
return 0;
}
Upvotes: 3
Views: 240
Reputation: 47962
It might be instructive to (1) print the system DPI for each case, and (2) to also try SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE). The DPI for your two monitors are probably different (or at least Windows thinks they are).
You've told Windows that you're aware of a single system-wide DPI. To ensure that apps do the right thing in this case, Windows has concocted a virtual screen coordinate system that lets apps that base all their layout on the DPI of the main monitor get good results on both monitors. If it had used the DPI of the main monitor, your program might not choose the best icon sizes and coordinates when drawing on the secondary monitor. Likewise, if it has used the DPI of the secondary monitor, apps wouldn't be able to do pixel-perfect positioning on the primary. Using double the higher DPI and then downscaling is probably a reasonable compromise if you look at all the interactions with GDI drawing (ClearType), Direct2D, mouse and pointer messages, etc.
If your app were per-monitor DPI aware, I suspect you'd get true values across the board.
Upvotes: 3