1


2

SetClassLong(hWnd、GCL_HICON、hIcon)はWinForms Form.Iconを置き換えることはできません

WinFormsアプリケーションで特定の ICO`ファイルをアイコンとして使用したいと思います。 Alt-Tabbing時にタイトルバーに小さなアイコン(16x16)と通常のアイコン(32x32)を指定できるようにするため、単一の `System.Drawing.Iconを受け入れる Form.Icon`プロパティを使用できません`オブジェクト。低解像度アイコンまたは通常のアイコンの使用を強制します。

私はhttps://stackoverflow.com/questions/2234988/how-to-set-hicon-on-a-window-ico-with-multiple-sizes [関連質問]を投稿しましたが、これは非常に簡単な解決策を思い付きましたネイティブWin32アプリケーションの場合:

SetClassLong(hWnd, GCL_HICON, hIcon32x32);
SetClassLong(hWnd, GCL_HICONSM, hIcon16x16);

「フォーム」に同じトリックを適用しようとしても機能しません。 次のP / Invoke定義があります。

[DllImport ("User32.dll")]
extern static int SetClassLong(System.IntPtr hWnd, int index, int value);

const int GCL_HICON   = -14;
const int GCL_HICONSM = -34;

そして、私は単に呼び出します:

System.IntPtr hIcon32x32 = ...;
System.IntPtr hIcon16x16 = ...;
SetClassLong(this.Handle, GCL_HICON, hIcon32x32.ToInt32());
SetClassLong(this.Handle, GCL_HICONSM, hIcon16x16.ToInt32());

そして、決して `Form.Icon`を呼び出さないでください。 ただし、これは機能しません。

  1. フォーム内のアイコンは、デフォルトのWinForms提供のアイコンのままです。

  2. Alt-Tabを押しても、WinFormsのデフォルトアイコンが表示されます。

…​but, what’s interesting, is that when I press Alt-Tab, I see for a 非常に短い瞬間、「GCL_HICON」を使用して定義したアイコン(または「GCL_HICON」を使用しない場合は「GCL_HICONSM」)。 背後で何かが発生しているようで、WindowsにWinFormsのデフォルトアイコンを使用してアイコンをペイントさせます。

何を間違えたのか、舞台裏で何が起こっているのかがわかりません。

編集: `Form.Icon`をディスク上のアイコンにバインドするのではなく、その場で作成された2つの異なるアイコンを提供できるようにしたいです。 そのため、P / Invokeコードを使用してメモリ内のアイコンを指定しようとしています。

2 Answer


3


これをテストしたり、逆アセンブルされたWinFormsコードを見たりして実際にこれを検証したことはないので、この答えが「信頼できる公式ソース」の報奨条件を満たしているかどうかはわかりません。 しかし、私はかなり信頼できると思うので、とにかく試してみます!

ウィンドウ_class_に関連付けられたアイコンを設定しています。 SetClassLong [Ptr]`関数と `GCL_HICON /` GCL_HICONSM`インデックスを使用して実行していますが、http://msdn.microsoft.com/en-us/libraryで設定するのと同じ効果があります。クラスが登録された時点の/windows/desktop/ms633577.aspx [WNDCLASSEX]構造。 これにより、そのクラスのウィンドウの_default_アイコンが設定されます。

ただし、個々のウィンドウは独自のアイコンを設定して、クラスが提供するデフォルトのアイコンをオーバーライドできます。 これを行うには、「WM_SETICON」メッセージを送信し、「wParam」として「ICON_BIG」または「ICON_SMALL」を、「lParam」としてアイコンのハンドルを渡します。 おそらく、これがWinFormsが行っていることです。 WinFormsはウィンドウクラスではなく `WM_SETICON`を使用してデフォルトアイコンを設定しているため、割り当てているデフォルトウィンドウクラスアイコンの代わりに「デフォルト」WinFormsアイコンが表示されるのはこのためです。 WinFormsアイコンの唯一の「デフォルト」は、別のカスタムアイコンを割り当てない場合、フレームワークによって自動的に割り当てられることです。 「デフォルト」の他の定義には当てはまりません。Win32の観点から使用される可能性のあるものは確かではありません。

Form.Icon`プロパティはアイコンを修正するために間違いなく WM_SETICON`を使用しているため、期待通りに動作しています。 今、あなたはあなたがIconプロパティを設定したくないと言う

_ Form.Iconをディスク上のアイコンにバインドするのではなく、オンザフライで作成された2つの異なるアイコンを提供できるようにしたいのです。 そのため、P / Invokeコードを使用してメモリ内のアイコンを指定しようとしています。 _

しかし、それは Icon`プロパティを設定できないという意味ではありません。 P / Invokeを使用する場合と同様に、ここでアイコン( `HICON)のハンドルを指定できます。 必要なのは、静的なhttp://msdn.microsoft.com/en-us/library/system.drawing.icon.fromhandle.aspx [Icon.FromHandle]メソッドのみです。このメソッドは、新しい` Icon`オブジェクトを`HICON`を指定しました。 次に、この Icon`オブジェクトをフォームの Icon`プロパティに割り当てます。

ただし、その必要はありません。 必要に応じて、P / Invokeを使用できます。

const int WM_SETICON = 0x80;

enum IconType
{
    ICON_BIG   = 1;
    ICON_SMALL = 0;
}

[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd,
                                 int message,
                                 IntPtr wParam,
                                 IntPtr lParam);

次に、あなたが持っているものと同じようにそれを呼び出します:

IntPtr hIcon32x32 = ...;
IntPtr hIcon16x16 = ...;
SendMessage(this.Handle, WM_SETICON, (IntPtr)IconType.ICON_BIG, hIcon32x32);
SendMessage(this.Handle, WM_SETICON, (IntPtr)IconType.ICON_SMALL, hIcon16x16);

間違っているのは1つだけです。「大きな」アイコンは常に32x32ピクセルであり、「小さな」アイコンは常に16x16ピクセルであると仮定します。 少なくとも、変数の名前からこれを行うと仮定しています。 もしそうなら、それは無効な仮定です。 これらは最も一般的なサイズです。 すべての環境で同じであるとは限りません。 これが、より大きなアイコンを提供することが重要である理由です .ico file; for example, a 48x48 icon. Since you’re setting the icons 動的に、Windowsはダウンサンプリングするために大きなアイコンにアクセスできず、32x32のアイコンを拡大すると、実際にはぼやけていものになる可能性があります。

_actual_サイズを取得するには、 GetSystemMetrics`関数を呼び出します。 `SM_CXICON`および SM_CYICON`フラグは、それぞれ「大きな」アイコンのXおよびY次元を示します。 SM_CXSMICON`および SM_CYSMICON`フラグは、「小さな」アイコンのX次元とY次元をそれぞれ示します。

const int SM_CXICON   = 11;
const int SM_CYICON   = 12;
const int SM_CXSMICON = 49;
const int SM_CYSMICON = 50;

[DllImport("user32.dll")]
static extern int GetSystemMetrics(int smIndex);
static Size GetBigIconSize()
{
    int x = GetSystemMetrics(SM_CXICON);
    int y = GetSystemMetrics(SM_CYICON);
    return Size(x, y);
}
static Size GetSmallIconSize()
{
    int x = GetSystemMetrics(SM_CXSMICON);
    int y = GetSystemMetrics(SM_CYSMICON);
    return Size(x, y);
}


2


`Form.Icon`を使用できます。 16x16および32x32ピクセルバージョンのアイコンを含む単一のアイコンファイルが必要です。

32x32ピクセルの赤い円と16x16の青い長方形を含む単一のアイコンファイルを使用して、試しました。 小さなウィンドウのアイコンは青い長方形を示し、altタブのアイコンは赤い円を示します。

P / Invokeはまったく必要ありません。