На самом деле я не проверял это, тестируя его или просматривая дизассемблированный код WinForms, поэтому я не уверен, будет ли этот ответ удовлетворять условию "надежных и / или официальных источников". Но я думаю, что я весьма [заслуживает доверия], поэтому я все равно попробую!
Вы устанавливаете значок, связанный с окном class . Вы делаете это с помощью функции SetClassLong[Ptr]
и индексов GCL_HICON
/ GCL_HICONSM
, но это имеет тот же эффект, что и установка в структуре WNDCLASSEX
во время регистрации класса , Это устанавливает значок по умолчанию для окон этого класса.
Однако отдельные окна могут устанавливать свои собственные значки, переопределяя значок по умолчанию, предоставляемый их классом. Вы делаете это, отправляя сообщение WM_SETICON
, передавая либо ICON_BIG
, либо ICON_SMALL
как wParam
, а дескриптор к значку как lParam
. Предположительно, это то, что делает WinForms. Вот почему значок WinForms по умолчанию появляется вместо значка класса окна по умолчанию, который вы назначаете, потому что WinForms устанавливает свой значок по умолчанию, используя WM_SETICON
, а не через класс окна. Единственное, что «по умолчанию» в значке WinForms, это то, что он автоматически назначается платформой, если вы не назначаете другой пользовательский значок. Он не подходит ни под какое другое определение «по умолчанию» - определенно не то, которое можно использовать с точки зрения Win32.
Свойство Form.Icon
определенно использует WM_SETICON
для изменения значка, поэтому оно работает так, как ожидается. Теперь вы говорите, что не хотите устанавливать свойство Icon, потому что
Я действительно хочу иметь возможность предоставлять две разные иконки, созданные на лету, а не привязывать Form.Icon к иконке на диске. Вот почему я пытаюсь использовать код P / Invoke для указания значков в памяти.
Но это не значит, что вы не можете установить свойство Icon
. Вы можете указать дескриптор для значка (HICON
) здесь, так же, как вы можете использовать P / Invoke. Все, что вам нужно, это статический метод 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);
Только одна вещь, которую вы делаете неправильно: при условии, что «большая» иконка всегда будет иметь размер 32x32 пикселей, а «маленькая» иконка всегда будет иметь размер 16x16 пикселей. По крайней мере, я предполагаю, что вы делаете это из имен переменных. Если так, то это неверное предположение. Это только самые распространенные размеры. Они не гарантируются одинаковыми во всех средах. Вот почему важно, чтобы в вашем файле .ico были большие иконки; например, значок 48x48. Так как вы устанавливаете значки динамически, у Windows не будет доступа к большему значку для даунсамплинга, и вы можете получить что-то действительно размытое и безобразное, когда ваш значок 32x32 увеличен.
Чтобы получить действительные размеры , вызовите функцию 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);
}