23
votes

I'm using Visual C# 2008 Express. I'd like to use the same icon for the application (ie, the icon shown for the .exe), and for the main form. Unfortunately, VC# doesn't seem to be very smart about this, and insists on duplicating the icon data.

There doesn't seem to be a way of selecting an "already embedded" icon for use in the form or project icon (only selecting a file), and using the same file for both icons just embeds the file twice as far as I can see. It's not a big deal (hard drive space is cheap now, right?), but it bugs me.

Any idea how to avoid this? Is there a way to programatically load the executable's icon for use when the form is constructed, say? A couple of forum posts about similar things seem to suggest that .NET resources don't use the normal old Windows resource system -- is there a way from within the framework of getting at the old-style resources? Or do I have to bind the Win32 API functions to do it?

5
Why not use inheritance? Define the icon in one custom Form class and use it everywhere.Tute
I remember my Delphi programming times... self.Icon = Application.Icon; :P ... too difficult in .NET :DLearner

5 Answers

16
votes

You're right, and it's rather annoying.

You have to load the icons yourself instead of relying on designer-generated code. Save the icon as a project resource, then load the resource into the form's Icon property in the form's constructor:

this.Icon = Properties.Resources.myIconResourceName;
11
votes

You're looking for Icon.ExtractAssociatedIcon. Call passing your executable:

var icon = Icon.ExtractAssociatedIcon(Assembly.GetExecutingAssembly().Location);
7
votes

Yeah, it's pretty annoying. But the problem with the proposed answer of Icon.ExtractAssociatedIcon is that it will retrieve the 32x32 icon, and then downsample to a 16x16 icon in your forms window or on the taskbar, which will look terrible unless your 32x32 icon is very cleverly constructed.

The way I'm doing it is with interop (put the first line in your form constructor):

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);

But this isn't great, either, since you do want the 32x32 icon for things like the Alt-Tab icon list. So you really need to extract the entire icon, which is a bigger job. Maybe there's a straightforward way to combine the two icons into one. Or you can do like this codeproject program, which extracts the whole icon in the first place with a huge pile of code.

3
votes

I think in many cases including a duplicate icon is at the end of the day more efficient than trying to extract it from the unmanaged resource - considering you can't use Icon.ExtractAssociatedIcon for UNC paths.

1
votes

I had a similar problem.

I have and exe icon I want to reuse for subforms without increasing file size.

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

I don't know if this is useful, but I want to share it in anyway.