views:

1828

answers:

4

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?

+3  A: 

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;
lc
That doesn't solve it: embedding the icon as a project resource is just the same as setting it in the form designer -- it duplicates the icon data, which is what I'm trying to avoid.
John Bartholomew
It should already be embedded as a resource when you add the icon as the project icon, no?
lc
Not that I can see... the icon used for the executable seems to be entirely independent of the .NET resource system.
John Bartholomew
@John: Sorry, you're wrong. It's stored in the executable as an icon resource. (Just tested using VS 2008 and Colin Wilson's XN Resource Editor.) It stores the application icon as resource 0 (zero), so that's the resource name you'll probably have to use.
Ken White
The icon associated with the executable file is stored as a normal win32 icon resource. This is the resource you see when you look in XN resource editor. That is *different* from the the .NET resource system (which *does* store resources in the executable, but not in the same format).
John Bartholomew
+2  A: 

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

var icon = Icon.ExtractAssociatedIcon(Assembly.GetExecutingAssembly().Location);
Sunlight
No no no no no! This is ridiculously slow compared to lc's answer below.
Ken White
Please explain why this is slow? If it's because it's using reflection that can be easily solved by using Application.ExecutablePath instead of Assembly.GetExecutingAssembly().Location.
John Bartholomew
+3  A: 

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.

vanmelle
A: 

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.

miken