Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Windows Volume Mixer icon size is too large

In the Windows Volume Mixer, when your application plays sounds, it adds your application's icon and a custom volume slider to adjust volume specific to that application... nice! However, when you use a large-sized icon for your application (especially important in high-DPI when Windows scales your icons for the Taskbar, etc.), the icon in the Volume Mixer doesn't scale correctly. Specifically, the following code is what I use to set the application's icon:

// set icons the normal way
cWnd.SetIcon( theApp.LoadIcon( res_id ), FALSE );
cWnd.SetIcon( theApp.LoadIcon( res_id ), TRUE );

// set hi-res if available
OSVERSIONINFO osv;
osv.dwOSVersionInfoSize = sizeof( osv );
if ( GetVersionEx( &osv ) ) {
    // if we're Vista or more recent, use hi-def icons
    if ( osv.dwMajorVersion >= 6 ) {
        HICON hIcon = (HICON)::LoadImage( theApp.m_hInstance, MAKEINTRESOURCE( res_id ), IMAGE_ICON, 256, 256, LR_SHARED );
        if ( hIcon ) {
            cWnd.SetIcon( hIcon, TRUE );
        }
    }
}

The culprit is the "hi-res if available" part. If I include that, the Taskbar icon looks great but the Volume Mixer isn't scaled and looks terrible. If I exclude that, the Taskbar icon looks bad (terrible scaling) but the Volume Mixer at least is the right size:

Desktop Scaling 125% with 256x256 icon setDesktop Scaling 125% with regular icons

Has anyone found a solution that makes it so that BOTH icons look good?

EDIT: In my icon file, I have the following resolutions: 256x256, 48x48, 32x32, 24x24, and 16x16, all 32-bit. The 256x256 one is PNG compressed, the others are raw. All of the sizes look great at the resolutions they are in the file (I was trying to put the ICO here or in imgur but apparently neither allow icons). Additionally I have tried including some 8-bit images but that doesn't seem to change things.

EDIT: I'm using GetDeviceCaps( hdc, LOGPIXELSX ) (and Y) to determine the Desktop scaling. Normally desktop scaling is 100% and I get the normal 96 result. But more and more I'm seeing computers default to 125%. This can be changed via right-click Desktop, Personalize, other: Display... there's a slider there (requires log out/in for change).

EDIT: I also want to point out that the Tray ICON suffers a similar scaling issue fate when in high-DPI modes (that is, when using Shell_NotifyIcon). In this case, however, I'm able to use GetDeviceCaps( hdc, LOGPIXELSX ) to determine what Windows wants.. if I have the size, provide it directly, otherwise provide the 256x256 one and Windows does scale it correctly.

EDIT: Sadness ensues. This problem may be a Windows issue. While capturing images for demonstration purposes, I noticed the Volume Mixer icon itself looks poor. For comparison: Volume Mixer Comparison

FINAL EDIT: As described below, the workaround for the issue is to scale the icons. So, the final code that works is to load a pointer to the LoadIconWithScaleDown function from Comctl32.dll (not shown) and use that if it was available, or fall back to the "regular/old" way:

HICON hIcon = 0;
if ( FAILED( comctl32Loader.LoadIconWithScaleDown( theApp.m_hInstance, MAKEINTRESOURCE( res_id ), GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), &hIcon ) ) ) {
    hIcon = theApp.LoadIcon( res_id );
}
cWnd.SetIcon( hIcon, FALSE );
if ( FAILED( comctl32Loader.LoadIconWithScaleDown( theApp.m_hInstance, MAKEINTRESOURCE( res_id ), GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), &hIcon ) ) ) {
    hIcon = theApp.LoadIcon( res_id );
}
cWnd.SetIcon( hIcon, TRUE );
like image 724
mark Avatar asked Jul 30 '13 14:07

mark


People also ask

How do I reduce the size of the icons on my desktop?

Right-click (or press and hold) the desktop, point to View, and then select Large icons, Medium icons, or Small icons. Tip: You can also use the scroll wheel on your mouse to resize desktop icons. On the desktop, press and hold Ctrl while you scroll the wheel to make icons larger or smaller.

How do I resize icons in Windows 11?

These are the three hotkeys for resizing icons: Ctrl + Shift + 2: Change to small icons. Ctrl + Shift + 3: Change to medium icons. Ctrl + Shift + 4: Change to large icons.

How do I change the volume on my mixer icon?

If you want to view Volume mixer on the PC and have enabled volume icon on the system tray, follow the steps below and check if the issue is resolved. Right click on the volume icon and select Open Volume Mixer from the context menu. Check if the window is accessible on the computer.

How do I make the taskbar icons smaller in Windows 10?

You can modify the size of your taskbar icons through the Taskbar settings. Right-click the taskbar. Select Taskbar settings. Set Use small taskbar buttons to On.


1 Answers

Yes, I can reproduce the problem you describe when I use the same code as shown in the question. As we've since determined, the issue only manifests itself at high DPI settings. At 100% scaling (~96 dpi), even on Windows Vista and later, you only need to use the "large" version of the icon (SM_CXICON and SM_CYICON; typically 32x32 pixels) for a window, not the 256x256 pixel version. That's what the apps bundled with Windows do, including the Volume Mixer applet that you're testing with.

The issue comes when you're using high DPI settings, which makes the "large" size go up:

╔════════════╦═════════════════╦═════════════════╗
║    DPI     ║ Large Icon Size ║ Small Icon Size ║
║            ║   (SM_C?ICON)   ║  (SM_C?SMICON)  ║
╠════════════╬═════════════════╬═════════════════╣
║  96 (100%) ║     32x32       ║     16x16       ║
║ 120 (125%) ║     40x40       ║     20x20       ║
║ 144 (150%) ║     48x48       ║     24x24       ║
║ 192 (200%) ║     64x64       ║     32x32       ║
╚════════════╩═════════════════╩═════════════════╝

Things work fine regardless of DPI when you load the 256x256 pixel icon, because Windows is automatically scaling it down to the required size. That generates a much better quality icon (without all the jaggies and other artifacts) than attempting to scale up a 32x32 pixel icon. So your guess is correct, the problem is indeed related to scaling.

I'm going to assume that what you're seeing in the Volume Mixer applet when you use a 256x256 pixel icon is a bug—it should be scaling that large icon down to the size it expects, which is a "large" icon (SM_C?ICON). Presumably, it's calling the DrawIconEx function with the cxWidth and cxHeight parameters both set to 0 and not passing the DI_DEFAULTSIZE flag. That's causing the icon to be drawing using its actual size—huge.

You'll have to work around the problem manually, by scaling the icons yourself. Fortunately, Windows Vista introduces a number of functions that are designed explicitly for this purpose. The easiest one to use in this case is LoadIconWithScaleDown. Like the name suggests, it works similarly to the older LoadIcon/LoadImage functions, but rather than scaling up an icon that is too small, it scales down a larger icon—perfect for when you have a giant, high-quality 256x256 pixel icon in your ICO file.

Unfortunately, these functions are not available on older versions of Windows, which will likely have the same problem when used at higher DPI settings. You'll need to find alternatives there, or just settle for jagged, scaled icons on these older OSes.

Sample code:

#include <CommCtrl.h>                  // include Common Controls header
#pragma comment(lib, "comctl32.lib")   // link to Common Controls library

// Embed a standard manifest to use Common Controls v6
#pragma comment(linker, "/manifestdependency:\"type='win32' "                         \
                        "name='Microsoft.Windows.Common-Controls' version='6.0.0.0' " \
                        "processorArchitecture='*' "                                  \
                        "publicKeyToken='6595b64144ccf1df' "                          \
                        "language='*'\"")
// Load and set "large" icon (typically 32x32 pixels, but not necessarily)
HICON hIconLg;
if (SUCCEEDED(LoadIconWithScaleDown(g_hInstance,
                                    MAKEINTRESOURCE(IDI_ICON),
                                    GetSystemMetrics(SM_CXICON),
                                    GetSystemMetrics(SM_CYICON),
                                    &hIconLg)))
{
   SendMessage(hWnd, WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(hIconLg));
}

// Load and set "small" icon (typically 16x16 pixels, but not necessarily)
HICON hIconSm;
if (SUCCEEDED(LoadIconWithScaleDown(g_hInstance,
                                    MAKEINTRESOURCE(IDI_ICON),
                                    GetSystemMetrics(SM_CXSMICON),
                                    GetSystemMetrics(SM_CYSMICON),
                                    &hIconSm)))
{
   SendMessage(hWnd, WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>(hIconSm));
}

Note that to use these new functions, you will need to link to version 6 of the common controls library. That requires that you instruct the compiler to link in comctl32.lib and embed a manifest in your application. Either can be done using the MSVC-specific #pragmas shown in the sample code above, or configured in your project's properties. If you fail to do either of these things, you'll get a link-time error or an "ordinal not found" error when you first launch the app.

like image 139
Cody Gray Avatar answered Sep 18 '22 08:09

Cody Gray