C# – WPF – 添加图标后的项目大小(从资源加载图标或从项目EXE拉取)

Edit1:已编辑的标题

Edit2:添加了方法3

Edit3:添加了方法4

我正在创建一个非常小的应用程序/实用程序,总共只有20KB.我的包含各种尺寸的图标文件是40KB.

我添加图标的方法是右键单击解决方案资源管理器中的项目,然后单击“现有项目…”,然后我再次右键单击我的项目,转到“属性” – > “应用程序”,在“图标和清单”下,我为整个项目选择了我的新图标.

这样做会在我的所有表单,exe,任务栏等中显示我的图标…除了系统托盘图标.

我加载系统托盘图标的方法是从EXE中提取图标:

方法1:

Icon ico = System.Drawing.Icon.ExtractAssociatedIcon(Assembly.GetExecutingAssembly().Location);
notifyIcon.Icon = ico;

现在我加载了所有图标的总项目大小是20KB 40KB = 60KB< – 这就是我所追求的. 我想知道这是否是加载我所有图标的正确方法? 我知道我可以在项目“资源”中添加我的图标并执行: 方法2:

notifyIcon.Icon = PROJECTNAME.Properties.Resources.icon;

但是,这只会使图标大小加倍,然后在顶部添加项目大小.所以:

20KB(项目规模)40KB(EXE图标)40KB(资源图标)= 100KB

方法3

“Discord”在下面的答案中发布了另一种直接从可执行资源中获取文件的方法.

IntPtr hIcon = LoadIcon(GetModuleHandle(null), new IntPtr(32512));
notifyIcon.Icon = Icon.FromHandle(hIcon);

[DllImport("user32.dll")]
static extern IntPtr LoadIcon (IntPtr hInstance, IntPtr iconName);
[DllImport("kernel32.dll")]
static extern IntPtr GetModuleHandle (string moduleName);

方法1和方法3现在唯一的问题是图标在32×32中提取然后缩小到16×16,这在系统托盘中看起来不太好.

这个答案来自“vanmelle”:Avoiding duplicate icon resources in a .NET (C#) project描述了如何在16×16中获取图标但不确定这是否会获得32×32版本的HiDPI分辨率

方法4

从项目EXE中提取图标似乎要么是16×16还是32×32,具体取决于所使用的代码.不能做到这两点并让操作系统选择它想要的HiDPI系统.不幸的是,我打算使用我的系统托盘图标创建另一个图标文件,只有我的应用程序图标的16×16和32×32版本,然后像这样使用它:(幸运的是我的16×16,32×32应用程序图标只有4KB)

notifyIcon.Icon = new System.Drawing.Icon(Properties.Resources.ico, System.Windows.Forms.SystemInformation.SmallIconSize);

如果需要,此方法将调用16×16图标或32×32图标.

你可以这样做:

notifyIcon.Icon = new System.Drawing.ico;

但是这将始终调用32×32图标并将其缩小到16×16,这在系统托盘中可能看起来不太好.

最初,我这样做是将图标添加到“资源”并让notifyIcon从那里调用它.然后在解决方案资源管理器 – 项目名称 – > “属性” – > “应用程序”我会在那里选择项目图标.这会加载我的图标大小两次,使我的项目从(20KB 40KB图标)跳到100KB

目前,我正在使用方法1.我想知道是否有更好的方法来加载我的图标并保持我的应用程序大小小而不是添加两次图标大小?

虽然我确实知道60KB和100KB之间的差异并不是什么大不了的事情,但我只想在将来的参考资料中学到这一点.另外,想知道我的第一种方法是否有任何警告?

我来自Web开发背景,是C#和WPF的新手.

最佳答案 您在项目属性中添加的图标将添加到标识符为32512(IDI_APPLICATION)的可执行文件资源(.rsrc部分)中.如果您不喜欢依赖Icon.ExtractAssociatedIcon,您可以使用更简单的方法来提取它 – 使用LoadIcon函数.它不包含在.NET中,所以有更多的代码:

IntPtr hIcon = LoadIcon(GetModuleHandle(null), new IntPtr(32512));
notifyIcon.Icon = Icon.FromHandle(hIcon);

[DllImport("user32.dll")]
static extern IntPtr LoadIcon (IntPtr hInstance, IntPtr iconName);
[DllImport("kernel32.dll")]
static extern IntPtr GetModuleHandle (string moduleName);

有关详细信息,请参阅Using the same icon for the .exe and a form in a Windows Forms application without duplicating it?问题.

WPF包含在HICON和ImageSource之间来回转换图标的方法,因此,如果要在表单上显示图标,例如,您也可以这样做(请参阅Imaging.CreateBitmapSourceFromHIcon等).

如果Icon.ExtractAssociatedIcon工作正常,我认为没有理由为此烦恼.但是可能存在一些问题,此功能可能不会提取所有图标,而只会提取特定尺寸.

另见Avoiding duplicate icon resources in a .NET C# project问题.

点赞