(Day 48) Windows automatically scales up my window by the monitor scale, destroying pixel-perfection!

I've done pretty much the same as Casey so far (day 48). I create a 960x540 buffer and a window of the same size, but I get a 1180x626 window with blurry pixels, that doesn't show the whole buffer. If I drag the borders of the window and make it bigger, I see that the buffer is shown at 1200x675, exactly 1.25X the original size.

I found that this scaling factor is determined by my display settings. My monitor's "Change the size of text, apps, and other items" option was set to 125%, and when I changed it to 100% my window looked right. But how can I have control over my pixels on monitors that don't have the scale set at 100%?

I didn't see this addressed in the 48 episodes I've watched, in the forums, or in some other episodes I've searched about the Windows API. I've checked the Windows API documentation and it seemed like calling SetProcessDpiAwarenessContext() might solve this, but I tried calling it and the compiler doesn't detect that function. Maybe it's because it's a Windows10 function.

Thanks.

Edited by Opoiregwfetags on Reason: Initial post
SetProcessDpiAwarenessContext is fine to use, but as docs say it will work only for Win10 version.

When you include <windows.h> it only declares functions for specific windows version you are targeting.
If you are ok with unconditionally targeting Windows 10, then you can simply set define to enable Win10 functions in windows header files:
1
#define WINVER 0x0A00

(do this before any windows include, or simply in cl.exe arguments)

If you want to support older Windows version, you will need to declare function pointer to this function and load it dynamically with LoadLibrary/GetProcAddress.

On older Windows versions you can do similar functionality with SetProcessDpiAwareness (Win 8.1 and up) or SetProcessDpiAware (Vista and up).

Alternative to all this code is to declare your DPI stuff in application manifest, then no extra code will be needed:
Setting default awareness with the application manifest

Edited by Mārtiņš Možeiko on
Thanks a lot for the concise and fast response! I chose to do it via manifest file for simplicity and it worked.

Here's what I did in case someone with the same problem finds this post:
I put this code I found somewhere in a file called "win32_handmade.exe.manifest" in my build directory.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"
    xmlns:asmv1="urn:schemas-microsoft-com:asm.v1"
    xmlns:asmv2="urn:schemas-microsoft-com:asm.v2"
    xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <assemblyIdentity version="1.0.0.0" name="handmade.exe" />
    <asmv3:application>
        <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
            <dpiAware>true</dpiAware>
        </asmv3:windowsSettings>
    </asmv3:application>
</asmv1:assembly>

I thought I'd have to do this command mt.exe -manifest "w:\build\win32_handmade.exe.manifest" -outputresource:"w:\build\win32_handmade.exe;1" when I build, but I found that it wasn't necessary as long as the manifest file is in the build directory.

Right, manifest files can be simply placed next to .exe file. As long as it has same name as .exe, Windows will use it.
You need to embed it into .exe only if you want to simplify distribution - to have just one .exe instead of two files.
Ok, then I'll keep that line in my build.bat. Thanks again!