在Windows Volume Mixer中,当您的应用程序播放声音时,它会添加应用程序的图标和自定义音量滑块,以调整特定于该应用程序的音量......很好!但是,当您为应用程序使用大尺寸图标时(当Windows缩放任务栏的图标等时,在高DPI中尤为重要),Volume Mixer中的图标无法正确缩放。具体来说,以下代码是我用来设置应用程序图标的代码:
// 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 );
}
}
}
罪魁祸首是“高分辨率(如有)”部分。如果我包含它,任务栏图标看起来很棒,但音量混合器没有缩放,看起来很糟糕。如果我排除它,任务栏图标看起来很糟糕(可怕的缩放),但音量混合器至少是正确的大小:
有没有人找到一个解决方案,使两个图标看起来都很好?
编辑:在我的图标文件中,我有以下分辨率:256x256,48x48,32x32,24x24和16x16,全部是32位。 256x256是PNG压缩的,其他是原始的。所有尺寸在文件中的分辨率看起来都很棒(我试图将ICO放在这里或imgur但显然不允许图标)。此外,我尝试包括一些8位图像,但这似乎没有改变。
编辑:我正在使用GetDeviceCaps( hdc, LOGPIXELSX )
(和Y)来确定桌面缩放。通常桌面缩放是100%,我得到正常的96结果。但是越来越多的我看到计算机默认为125%。这可以通过右键单击桌面,个性化,其他来更改:显示...那里有一个滑块(需要注销/进行更改)。
编辑:我还想指出,在高DPI模式下(即使用Shell_NotifyIcon
时),Tray ICON会出现类似的缩放问题。但是,在这种情况下,我可以使用GetDeviceCaps( hdc, LOGPIXELSX )
来确定Windows想要的内容..如果我有大小,请直接提供,否则提供256x256和Windows 比例它正确。
编辑:悲伤随之而来。此问题可能是Windows问题。在为演示目的捕获图像时,我注意到Volume Mixer图标本身看起来很糟糕。为了比较:
最终编辑:如下所述,问题的解决方法是缩放图标。因此,最终的代码是从LoadIconWithScaleDown
(未显示)加载指向Comctl32.dll
函数的指针,如果它可用,则使用它,或者回退到“常规/旧”方式:
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 );
答案 0 :(得分:3)
是的,当我使用问题中显示的相同代码时,我可以重现您描述的问题。正如我们已经确定的那样,该问题仅在高DPI设置下表现出来。在100%缩放(~96 dpi)时,即使在Windows Vista及更高版本中,您也只需要使用图标的“大”版本(SM_CXICON
和SM_CYICON
;通常为32x32像素) ,而不是256x256像素版本。这就是与Windows捆绑的应用程序所做的事情,包括您正在测试的Volume Mixer applet。
当您使用高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 ║
╚════════════╩═════════════════╩═════════════════╝
当您加载256x256像素图标时,无论DPI如何,都可正常工作,因为Windows会自动将其缩小到所需的大小。与试图扩展 up 32x32像素图标相比,这会生成质量更好的图标(没有所有锯齿和其他工件)。所以你的猜测是正确的,问题确实与缩放有关。
我将假设您在使用256x256像素图标时在Volume Mixer applet中看到的是一个错误 - 它应该将该大图标缩小到它预期的大小,这是一个“大” “图标(SM_C?ICON
)。据推测,它调用DrawIconEx
函数,cxWidth
和cxHeight
参数都设置为0,不传递DI_DEFAULTSIZE
标志。这导致图标使用其实际大小绘制。
您必须通过自己缩放图标来手动解决问题。幸运的是,Windows Vista引入了许多为此目的而明确设计的功能。在这种情况下最容易使用的是LoadIconWithScaleDown
。顾名思义,它的功能类似于较旧的LoadIcon
/ LoadImage
功能,但它不是按比例放大图标,而是缩小图标,非常适合当你拥有巨人时,ICO文件中的高质量256x256像素图标。
不幸的是,这些功能在旧版本的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
来完成,也可以在项目的属性中进行配置。如果您未能执行上述任何一项操作,则在首次启动应用程序时,您将收到链接时错误或“未找到序号”错误。
答案 1 :(得分:1)
我在C#/ WPF程序中遇到了类似的问题。
在我的情况下,问题似乎是由ico文件中缺少大小引起的。我应用程序的ico文件的最小尺寸是64x64。一旦我在该文件中添加了较小的尺寸,问题就解决了。
答案 2 :(得分:0)
非常感谢你们。我在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"