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

C# - WPF - Project size after adding icons (load icon from resources or pull from project EXE)

Edit1:编辑标题

Edit2:添加了方法 3

Edit3:添加了方法 4


我正在创建一个非常小的 app/utility,总共只有 20KB。我的包含各种尺寸的图标文件是 40KB。

我添加图标的方式是通过 right-clicking 我在解决方案资源管理器中的项目并单击 "Existing Item...",然后我将再次 right-click 我的项目,转到 "Properties" -> "Application" 和 "Icon and manifest" 我 select 我的整个项目的新图标。

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

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

方法一:

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

现在我加载了所有图标的项目总大小为 20KB + 40KB = 60KB <- 这就是我所追求的。

我想知道这是否是加载我所有图标的正确方法?

我知道我可以在项目中添加我的图标 "Resources" 并执行:

方法二:

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

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

20KB(项目大小)+ 40KB(EXE 图标)+ 40KB(资源图标)= 100KB

方法三

"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唯一的问题是图标在32x32中提取然后缩小到16x16,这在系统托盘中看起来不太好。

"vanmelle" 的回答:Avoiding duplicate icon resources in a .NET (C#) project 描述了如何获得 16x16 的图标,但不确定这是否会获得 HiDPI 分辨率的 32x32 版本

方法四

从项目 EXE 中提取图标似乎是 16x16 或 32x32,具体取决于所使用的代码。不能两者都做,让 OS 选择它想要的 HiDPI 系统。不幸的是,我要做系统托盘图标的方法是创建另一个图标文件,该文件只有我的应用程序图标的 16x16 和 32x32 版本,然后像这样使用它:(幸运的是我的 16x16、32x32 应用程序图标只有 4KB)

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

如果需要,此方法将调用 16x16 图标或 32x32 图标。

你可以这样做:

notifyIcon.Icon = new System.Drawing.ico;

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


最初,我的做法是将图标添加到 "Resources" 并让 notifyIcon 从那里调用它。然后在解决方案资源管理器中 - 项目名称 -> "Properties" -> "Application" 我会 select 那里的项目图标。这会加载我的图标大小两次,使我的项目从(20KB + 40KB 图标)跳到 100KB

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

虽然我知道 60KB 和 100KB 之间的差异并不是什么大问题,但我只是想大致了解一下以备将来参考。另外,想知道我的第一种方法是否有任何注意事项?

我有 Web 开发背景,对 C# 和 WPF 还很陌生。

这两种方法中的任何一种都可以正常工作。对于像这样简单的事情,没有正确的方法,只要代码能完成工作就没有人会抱怨。

使用 WPF 时,您的可执行文件大小会很快变得非常大,我正在处理一个几十兆字节的 WPF .exe。

您在项目属性中添加的图标将添加到标识符为 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 包含在 HICONImageSource 之间来回转换图标的方法,所以如果你想在窗体上显示图标,例如,你也可以这样做(参见 Imaging.CreateBitmapSourceFromHIcon等)。

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

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