0
votes

My application is DPI-Aware, here's the full manifest:

<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly xmlns:asmv1="urn:schemas-microsoft-com:asm.v1"
                manifestVersion="1.0">
    <assemblyIdentity name="SlackUI"
                      type="win32"
                      version="1.0.0.0" />
    <asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
        <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
            <dpiAware>true</dpiAware>
        </asmv3:windowsSettings>
    </asmv3:application>
</asmv1:assembly>

And I am setting my NotifyIcon icon property like this:

notifyIcon.Icon = new Icon(Program.Settings.Data.WhiteNotificationIcon ?
                Properties.Resources.NotifyWhite : Properties.Resources.NotifyColor, SystemInformation.SmallIconSize)

However, this is not working for DPI scaling equal or above 150% on my Windows 8.1 system. When it's set to 100% SystemInformation.SmallIconSize reports a 16x16 size (correct), when it's 125% it reports a 20x20 size (correct), above that, for instance 150%, it should report a 24x24 size but instead reports 16x16 and loads the wrong resolution from my icon file.

Reading the following article (http://blog.quppa.net/2011/01/07/small-icon-size-dpi-in-windows/) it tells me that...

Both WPF and WinForms wrap around the Win32 GetSystemMetrics function taking the arguments SM_CXSMICON (small icon width) and SM_CYSMICON (small icon height).

Which means there's probably no need to call GetSystemMetrics myself, right?

Any idea on how can I solve this?

P.S: I'm talking about an open-source application that I'm developing, so if you want to take a closer look at the full source code you can do so here.

1
Strong hint that your manifest is not in fact doing its job. You could pinvoke IsProcessDPIAware() to double-check. Watch out for the Visual Studio hosting process, turn it off with Project + Properties, Debug tab.Hans Passant
@HansPassant I've added [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] internal static extern bool IsProcessDPIAware(); and it returns true all the time, even if I remove the whole manifest file.rfgamaral

1 Answers

1
votes

Strong hint that your manifest is not in fact doing its job

It is not. From your github SlackUI/SlackUI.csproj file:

<ItemGroup>
  <None Include="app.manifest">
    <SubType>Designer</SubType>
  </None>
</ItemGroup>

What it should look like is:

<PropertyGroup>
  <ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>

Note the highly specific <ApplicationManifest> element, required to let MSBuild know that this should be the manifest for the executable. I tested your version by pasting it into a .csproj file, building and then using File + Open + File, select the .exe file from the bin/Debug directory. Opened the RT_MANIFEST node and double-clicked resource #1. It was just the default one that the compiler auto-generates, not the modified one from the app.manifest file.

So that's why it doesn't work. I have no fantastic theory how this happened, maybe you added it by hand. You fix it by right-clicking app.manifest in the Solution Explorer window and deleting it. Now use Project > Add New Item > General > Application Manifest File. Paste the changes again.