2

I've tried to find an answer for this on MSDN, but I'm not getting a clear picture of how this is intended to work. All of my work is on Windows 8.1.

Here is my issue. I am working on a Laptop with a high resolution monitor, 3200x1800. I've been using EnumDisplayMonitors to get the bounding rectangle of my screen.

This seems to work fine if my display settings are default. But I've noticed that when I change the Window display settings to provide larger text, the resolution returned by EnumDisplayMonitor changes. Rather than getting 3200x1800 I will get 2133x1200.

I'm guessing since I asked for larger text, Windows chooses to represent the screen as a smaller resolution.

It seems that if I look at the virtual screen properties, everything is represented in the actual coordinates of my screen, i.e. 3200x1800. But the APIs for getting the window and monitor rectangles seem to operate on this "other" coordinate space.

Is there any documentation/Windows APIs to handle the conversion between these "other coordinates" and the "virtual coordinates"? i.e. if I want EnumDisplayMonitor or GetMonitorInfo to give me the true screen coordinates, how could I convert 2133x1200 to 3200x1800?

anoneironaut
  • 1,778
  • 16
  • 28

2 Answers2

5

You have increased the DPI of the video adapter to 150% (144 dots per inch) to keep text readable and avoid having windows the size of a postage stamp. Quite necessary on such high resolution displays. But you haven't told Windows that your program knows how to deal with it.

So it assumes your program is an old one that was never designed to run on such monitors. It helps and lies to you. It gets your program to render its output to a memory buffer, then takes that output, rescales it by 150% and copies it to the video adapter. This is something you can see, text looks fuzzier if you put your program's output next to a program that doesn't ask for this kind of scaling, like Notepad.

And of course, it lies to you when you ask for the size of the screen. It tells you that it is 150% smaller than it really is. So that, after rescaling, a window you create will fill the screen.

Which is all just fine but of course not ideal, your program doesn't look as good as it should. You have to tell Windows that you know how to deal with the higher resolution. Do beware that this looks easier than it is in practice. Getting text to look crisp is trivial, it is bitmaps that are problematic. And in general a fertile source of bugs, even the big companies can get this wrong.

Community
  • 1
  • 1
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Ah this is the answer I think. I was getting very confused because the DPI I received from enumerating the monitor devices was always the same no matter what I changed. But the resolution kept changing. Sounds like Windows is lying to me. So now for a *follow up* question, if I'd prefer to keep my application DPI *unaware* for now, whats the easiest way for me to figure out the DPI? Is there any way to calculate it? – anoneironaut Jul 03 '14 at 15:14
  • If you like to be lied to then you just don't care what it might be. You simply assume 96 dpi. – Hans Passant Jul 03 '14 at 15:19
  • But I'd like to know what the real resolution is for the various monitors and windows. It seems like all the APIs that windows provides to do this will only work if my app is "DPI Aware". So I'm wondering if I can do these conversions without being DPI Aware. – anoneironaut Jul 03 '14 at 15:32
  • Turning off the lie requires declaring your program dpiAware. Rock-hard requirement. – Hans Passant Jul 03 '14 at 15:33
  • Hmm well one thing I noticed was that even though my monitor resolution was reported as 2133x1200, if I use device enumeration to get my monitor resolution it reports 3200x1800. Would it be safe to use this data to estimate the DPI so that I could properly adjust? – anoneironaut Jul 03 '14 at 15:39
  • Do not "adjust" anything, if will be 150% too big. – Hans Passant Jul 03 '14 at 15:41
  • I don't want to adjust my application rendering. I just want to be able to get the "Physical" coordinates of all objects(windows, monitors, etc) in my desktop. Right now I'm getting the lie, but I'm assuming if I just calculate the DPI and apply that to all coordinates and points, I'll get the physical values. – anoneironaut Jul 03 '14 at 15:49
0

Before I start with an answer, let me ask: what are you really trying to do ? Or more specific - why do you need to know the monitor resolution ? The standard way to do this is to call GetWindowRect(GetDesktopWindow(), &rect) I'm not sure if the screen coordinates change based on DPI settings - but you should try that instead of GetMonitorInfo as the latter is for more advanced stuff. And if GetWindowRect still returns back a scaled rect, just call DPtoLP, LPtoDP or other mapping coordinate function as appropriate.

When you adjust the display settings as you described, you are actually changing the DPI settings of the screen. As such, certain APIs go into compatibility mode so that they allow the app to create larger elements and windows without knowing anything about this setting.

Why do you need to know the actual screen resolution since most of the windowing APIs will behave accordingly when the DPI scaling changes?

I suspect you could call SetProcessDPIAware or the manifest file equivalent. But do read this MSDN article first to understand DPI scaling.

selbie
  • 100,020
  • 15
  • 103
  • 173