避免在.NET(C#)项目中重复使用图标资源

23

我正在使用Visual C# 2008 Express。我想在应用程序(即.exe文件显示的图标)和主窗体中使用相同的图标。不幸的是,VC#似乎对此并不太聪明,并坚持复制图标数据。

似乎没有办法选择“已经嵌入”的图标以供表单或项目图标使用(仅选择文件),并且仅使用相同的文件来生成两个图标似乎会导致文件被嵌入两次。这不是大问题(现在硬盘空间很便宜,对吧?),但它让我感到困扰。

有什么办法可以避免这种情况吗?例如,在构建窗体时以编程方式加载可执行文件的图标?一些关于类似事情的论坛帖子似乎表明,.NET资源不使用旧的Windows资源系统--是否有从框架内部获取旧样式资源的方法?还是必须绑定Win32 API函数才能做到这一点?


为什么不使用继承?在一个自定义的表单类中定义图标并在任何地方使用它。 - Tute
我还记得我的Delphi编程时光...self.Icon = Application.Icon; :P ... 在.NET中太难了 :D - Learner
5个回答

16

你说得对,这很烦人。

你需要自己加载图标,而不是依赖于由设计师生成的代码。将图标保存为项目资源,然后在窗体的构造函数中将该资源加载到窗体的 Icon 属性中:

this.Icon = Properties.Resources.myIconResourceName;

那并不能解决问题:将图标嵌入项目资源中与在表单设计器中设置它完全相同--这会复制图标数据,而我正试图避免这种情况。 - John Bartholomew
当你将图标添加为项目图标时,它不应该已经作为资源嵌入其中了吗? - lc.
我看不出来...用于可执行文件的图标似乎完全独立于.NET资源系统。 - John Bartholomew
3
可执行文件相关联的图标被存储为普通的 Win32 图标资源。当您查看 XN 资源编辑器时,这就是您所看到的资源。这与 .NET 资源系统不同(.NET 资源系统确实将资源存储在可执行文件中,但不以相同的格式存储)。 - John Bartholomew
1
如果您想像我一样在运行时更改窗体图标,那么此答案很有用。您只需在项目资源中添加图标,并在加载窗体时更改其图标即可。 - Andrea Antonangeli

11
你需要使用Icon.ExtractAssociatedIcon方法,传入你的可执行文件即可。
var icon = Icon.ExtractAssociatedIcon(Assembly.GetExecutingAssembly().Location);

5
为什么这个很慢?如果是因为使用反射,可以通过使用Application.ExecutablePath代替Assembly.GetExecutingAssembly().Location来轻松解决。 - John Bartholomew
最佳解决方案!不会在资源中重复图标,并在任务栏中显示最佳质量的图标。谢谢! - Geograph
可能对您来说没问题,但请注意,这对UNC路径无效。 - Patrick Kursawe

7

是的,这很烦人。但是使用Icon.ExtractAssociatedIcon提出的答案存在问题,它将检索32x32图标,然后在您的窗体窗口或任务栏上缩小为16x16图标,除非您的32x32图标非常巧妙地构建,否则看起来会很糟糕。

我使用互操作来解决这个问题(将第一行放在窗体构造函数中):

this.Icon = ExtractSmallIconFromLibrary(Application.ExecutablePath);
...

public static Icon ExtractSmallIconFromLibrary(string file) {
    IntPtr[] reficon = new IntPtr[1];
    int nextracted = ExtractIconEx(file, 0, null, reficon, 1);
    if (nextracted < 1)
        return null;
    Icon unmanaged_icon = Icon.FromHandle(reficon[0]);
    Icon icon = (Icon)unmanaged_icon.Clone();
    DestroyIcon(unmanaged_icon.Handle);
    return icon;
}

[DllImport("Shell32", CharSet = CharSet.Auto)]
extern static int ExtractIconEx(
    [MarshalAs(UnmanagedType.LPTStr)] 
    string lpszFile,
    int nIconIndex,
    IntPtr[] phIconLarge,
    IntPtr[] phIconSmall,
    int nIcons
    );

[DllImport("user32.dll", CharSet = CharSet.Auto)]
extern static bool DestroyIcon(IntPtr handle);

但这也不是很好,因为你确实需要32x32的图标,比如Alt-Tab图标列表。所以你真正需要提取整个图标,这是一项更大的工作。也许有一种简单的方法将两个图标合并成一个。或者你可以像这个codeproject程序一样,在第一次提取时用大量代码提取整个图标。


3

我认为,在许多情况下,包含一个重复的图标最终比试图从未管理的资源中提取它更有效 - 考虑到您不能对UNC路径使用Icon.ExtractAssociatedIcon。


1

我有一个类似的问题。

我有一个exe图标,我想重复使用它来制作子窗体,而不增加文件大小。

//From MyApp
MySubForm msf = new MySubForm();
msf.Icon = this.Icon;
msf.Show();

我不知道这是否有用,但我无论如何都想分享一下。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接