Windows音量混音器图标大小过大

在Windows混音器中,当您的应用程序播放声音时,它将添加您的应用程序的图标和自定义音量滑块,以调整特定于该应用程序的音量……太棒了! 但是,当您为应用程序使用大尺寸图标(特别是在Windows缩放任务栏的图标时,在高DPI中非常重要),音量混合器中的图标无法正确缩放。 具体来说,下面的代码是我用来设置应用程序的图标:

// 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 ); } } } 

罪魁祸首是“高分辨率,如果有的话”部分。 如果我包括,任务栏图标看起来不错,但音量混音器不缩放,看起来很糟糕。 如果我排除这一点,任务栏图标看起来不好(可怕的缩放比例),但混音器至less是正确的大小:

桌面缩放125%与256x256图标集桌面缩放125%与常规图标

有没有人find一个解决scheme,使这两个图标看起来不错?

编辑 :在我的图标文件,我有以下决议:256×256,48×48,32×32,24×24,16×16,所有的32位。 256×256是PNG压缩的,其他的都是原始的。 所有的大小看起来都很棒,他们在文件中的决议(我试图把ICO在这里或imgur,但显然不允许图标)。 此外,我试图包括一些8位图像,但似乎并没有改变的事情。

编辑 :我使用GetDeviceCaps( hdc, LOGPIXELSX ) (和Y)来确定桌面缩放。 通常桌面缩放是100%,我得到正常的96结果。 但越来越多,我看到电脑默认为125%。 这可以通过右键单击桌面,个性化,其他:显示…有一个滑块在那里(需要注销/进行更改)。

编辑 :我也想指出,在高DPI模式(即使用Shell_NotifyIcon )时,托盘ICON遭受类似的缩放问题的命运。 然而,在这种情况下,我可以使用GetDeviceCaps( hdc, LOGPIXELSX )来确定Windows需要什么。如果我有这个大小,直接提供它,否则提供256×256,Windows 正确缩放它。

编辑 :悲伤随之而来。 这个问题可能是Windows的问题。 为了演示目的捕获图像,我注意到音量混音器图标本身看起来很差。 为了比较: 混音器比较

最终编辑 :如下所述,该问题的解决方法是缩放图标。 因此,最终的代码是从Comctl32.dll (未显示)加载一个指向LoadIconWithScaleDown函数的指针,并使用该指针(如果可用)或回退到“常规/旧”方式:

 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 ); 

是的,当我使用问题中显示的相同代码时,我可以重现您描述的问题。 正如我们自己确定的那样,这个问题仅在高DPI情况下才显现出来。 在100%缩放( SM_CXICON dpi)的情况下,即使在Windows Vista和更高版本中,您只需使用“大”版图标( SM_CXICONSM_CYICON ;通常为32×32像素)作为窗口,而不是256×256像素版本。 这就是与Windows捆绑在一起的应用程序,包括您正在测试的音量混音器小程序。

当您使用高DPI设置,这使得“大”的大小上升的问题来了:

 ╔════════════╦═════════════════╦═════════════════╗ ║ 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 ║ ╚════════════╩═════════════════╩═════════════════╝ 

当您加载256×256像素图标时,无论DPI如何,事情都可以正常工作,因为Windows会自动将其缩小到所需的大小。 这会产生一个更好的质量图标(没有所有的锯齿和其他文物)比试图扩大一个32×32像素的图标。 所以你的猜测是正确的,这个问题的确与缩放有关。

我打算假设你使用256×256像素图标时在Volume Mixer小程序中看到的是一个错误 – 它应该将大图标缩小到它所期望的大小,这是一个“大”图标SM_C?ICON )。 据推测,它调用DrawIconEx函数与cxWidthcxHeight参数都设置为0,而不是传递DI_DEFAULTSIZE标志。 这导致图标正在使用其实际大小进行绘制。

您必须通过手动缩放图标来手动解决问题。 幸运的是,Windows Vista引入了许多为此目的而明确设计的功能。 在这种情况下最容易使用的是LoadIconWithScaleDown 。 就像名字所暗示的那样,它的工作原理和旧的LoadImage / LoadImage函数类似,但不是放大一个太小的图标,而是缩小一个更大的图标 – 当你有一个巨大的,高质量的256×256像素图标你的ICO文件。

不幸的是,这些功能在较旧版本的Windows上不可用,在较高DPI设置下使用时可能会遇到同样的问题。 您需要在这里找到替代方案,或者只是在这些较旧的操作系统上解决锯齿状缩放图标。

示例代码:

 #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)); } 

请注意,要使用这些新功能,您需要链接到公共控件库的版本6。 这就要求你指示编译器在comctl32.lib链接并在你的应用程序中嵌入一个清单。 可以使用上面示例代码中显示的特定于MSVC的#pragma来完成,也可以在项目属性中进行配置。 如果您无法执行上述任何一项操作,则会在首次启动应用程序时收到链接时错误或“未找到序号”错误。

我遇到了一个类似的问题与C#/ WPF程序。

在我的情况下,这个问题似乎是由ico文件内缺少的大小造成的。 我的应用程序的ico文件的最小尺寸是64×64。 一旦我在文件中添加更小的尺寸,问题就解决了。

非常感谢你们。 我得到了这个工作在我们的Wx应用程序,如果有人想要一些预先烘干的代码放入他们的Wx应用程序,这里是我的下面:

 #ifdef __WXMSW__ #include <Windows.h> #include <CommCtrl.h> #include <wx/msw/private.h> typedef int (WINAPI *func_LoadIconWithScaleDown)(HINSTANCE, LPCWSTR, int, int, HICON*); #endif void MainFrame::BindAppIcon() { #ifdef __WXMSW__ wxDynamicLibrary comctl32("comctl32", wxDL_DEFAULT | wxDL_QUIET); func_LoadIconWithScaleDown load_icon_scaled = reinterpret_cast<func_LoadIconWithScaleDown>(comctl32.GetSymbol("LoadIconWithScaleDown")); int icon_set_count = 0; HICON hIconLg; if (load_icon_scaled && SUCCEEDED(load_icon_scaled(wxGetInstance(), _T("AAAAA_MAINICON"), ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON), &hIconLg))) { ::SendMessage(GetHandle(), WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(hIconLg)); ++icon_set_count; } HICON hIconSm; if (load_icon_scaled && SUCCEEDED(load_icon_scaled(wxGetInstance(), _T("AAAAA_MAINICON"), ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON), &hIconSm))) { ::SendMessage(GetHandle(), WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>(hIconSm)); ++icon_set_count; } if (icon_set_count == 2) return; // otherwise fall back to Wx method of setting icon #endif wxIcon icon = wxXmlResource::Get()->LoadIcon(wxT("MainIcon")); if (!icon.IsOk()) { wxLogInfo(_("Main icon not found")); icon = wxICON(wxvbam); } SetIcon(icon); } 

你的app.rc中的第一行就是这样的:

 AAAAA_MAINICON ICON "icons/app.ico"