10

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

犯人は「利用可能な場合はハイレゾ」の部分です。それを含めると、タスクバーのアイコンは見栄えがしますが、音量ミキサーはスケーリングされておらず、見栄えが悪くなります。それを除外すると、タスクバーのアイコンは見栄えが悪くなります (スケーリングがひどい) が、ボリューム ミキサーは少なくとも適切なサイズです。

256x256 アイコン セットでデスクトップ スケーリング 125% 通常のアイコンでデスクトップ スケーリング 125%

両方のアイコンが見栄えがするようにするソリューションを見つけた人はいますか?

編集:私のアイコンファイルには、次の解像度があります:256x256、48x48、32x32、24x24、および16x16、すべて32ビット。256x256 のものは PNG で圧縮されており、その他は未加工です。すべてのサイズは、ファイル内の解像度で見栄えがします(ここまたは imgur に ICO を配置しようとしましたが、どうやらアイコンを許可していないようです)。さらに、いくつかの 8 ビット イメージを含めてみましたが、状況は変わらないようです。

編集GetDeviceCaps( hdc, LOGPIXELSX )デスクトップのスケーリングを決定するために(およびY)を使用しています。通常、デスクトップのスケーリングは 100% で、通常の 96 の結果が得られます。しかし、コンピューターのデフォルトが 125% になっていることがますます増えています。これは、デスクトップ、パーソナライズ、その他を右クリックして変更できます。表示... そこにスライダーがあります (変更するにはログアウト/ログインが必要です)。

編集: また、トレイ アイコンは、高 DPI モード (つまり、を使用する場合) で同様のスケーリングの問題が発生することを指摘したいと思いますShell_NotifyIcon。ただし、この場合、GetDeviceCaps( hdc, LOGPIXELSX )Windows が何を望んでいるかを判断するために使用できます。サイズがある場合は直接指定し、そうでない場合は 256x256 を指定すると、Windowsそれを正しくスケーリングします。

編集:悲しみが続く。この問題は、Windows の問題である可能性があります。デモンストレーション用に画像をキャプチャしているときに、ボリューム ミキサーのアイコン自体が見栄えが悪いことに気付きました。比較のために: ボリュームミキサーの比較

最終編集: 以下で説明するように、問題の回避策はアイコンを拡大縮小することです。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 );
4

3 に答える 3

3

はい、質問に示されているのと同じコードを使用すると、あなたが説明した問題を再現できます。我々が決定したように、この問題は高 DPI 設定でのみ現れます。100% のスケーリング (~96 dpi) では、Windows Vista 以降でも、256x256 ピクセルのバージョンではなく、ウィンドウに「大きい」バージョンのアイコン (SM_CXICONおよびSM_CYICON; 通常は 32x32 ピクセル) を使用するだけで済みます。これは、テストしているボリューム ミキサー アプレットを含め、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       ║
╚════════════╩═════════════════╩═════════════════╝

256x256 ピクセルのアイコンを読み込むと、DPI に関係なく問題なく動作します。これは、Windows がアイコンを必要なサイズに自動的に縮小するためです。これにより、32x32 ピクセルのアイコンを拡大しようとするよりもはるかに高品質のアイコンが生成されます (ギザギザやその他のアーティファクトがすべてなくなります) 。あなたの推測は正しいです。問題は実際にスケーリングに関連しています。

256x256 ピクセルのアイコンを使用しているときにボリューム ミキサー アプレットに表示されるのはバグであると想定します。これは、大きなアイコンを期待されるサイズに縮小する必要があるためです。これは「大きな」アイコン ( SM_C?ICON)。おそらく、とパラメータの両方を 0 に設定してフラグを渡さDrawIconExに関数を呼び出しています。これにより、アイコンが実際のサイズ (巨大) を使用して描画されます。cxWidthcxHeightDI_DEFAULTSIZE

アイコンを自分でスケーリングして、手動で問題を回避する必要があります。幸いなことに、Windows Vista には、この目的のために明示的に設計された多くの機能が導入されています。この場合、最も使いやすいのはLoadIconWithScaleDown. 名前が示すように、以前のLoadIcon/LoadImage関数と同様に機能しますが、小さすぎるアイコンを拡大するのではなく、より大きなアイコンを縮小します。ICO に巨大で高品質の 256x256 ピクセルのアイコンがある場合に最適です。ファイル。

残念ながら、これらの機能は古いバージョンの Windows では利用できず、より高い DPI 設定で使用すると同じ問題が発生する可能性があります。そこに代替手段を見つけるか、これらの古い OS ではギザギザのスケーリングされたアイコンに落ち着く必要があります。

サンプルコード:

#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そのためには、アプリケーションにマニフェストをリンクして埋め込むようにコンパイラに指示する必要があります。#pragma上記のサンプル コードに示されている MSVC 固有の を使用するか、プロジェクトのプロパティで構成することができます。これらのいずれかを行わないと、アプリを最初に起動したときに、リンク時エラーまたは「序数が見つかりません」というエラーが発生します。

于 2013-08-02T05:37:32.490 に答える
1

C#/WPF プログラムで同様の問題が発生しました。

私の場合、この問題は ico ファイル内のサイズが欠落しているために発生したようです。アプリの ico ファイルの最小サイズは 64x64 でした。そのファイル内に小さいサイズを追加すると、問題は解決しました。

于 2017-06-14T13:01:49.427 に答える