thomasb
thomasb

Reputation: 6037

Refresh start menu icons in Windows 8

I have an application that works weirdly: the setup process copies the files to a temp folder, then checks a few things, and if everything is ok, moves the files to the final folder.

The problem is that the installer creates the shortcuts before the files are moved.

The result is that on the start menu (the one with the tiles), the icon is the "default sortcut" one.

In the start menu

I have tried to force the refresh of the system using this link (broadcast a WM_SETTINGCHANGE message) but it doesn't seem to work for the Windows 8 start menu.

Even rebooting the OS doesn't seem to refresh the icon, the only thing that works is to reinstall the soft on top of itself.

How can I force the icons refresh for the Win8 start menu ?

Thanks

Upvotes: 1

Views: 2484

Answers (1)

Cody Gray
Cody Gray

Reputation: 244682

First off, you don't tell us why your install process needs to work the way that it does. I agree that's weird, but I assume you have a good reason for doing it that way. If not, I suggest starting there and fixing the installer rather than putting band-aids on individual problems. You're bound to run into other problems later, and the root fix is bound to be much simpler and easier to maintain than a bunch of band-aids.

Anyway, if you must go down this path… The reason that broadcasting a WM_SETTINGCHANGE message doesn't work is because this doesn't have anything to do with icons. Those are managed separately by Explorer and don't get rebuilt unless you delete its icon cache. That, naturally, prompts it to rebuild it. It's a common troubleshooting technique for end users, but it's not something you want to do programmatically. Talk about an ugly hack. And altering the global state to solve a local problem.

Besides, if rebooting the OS doesn't work, you know it's not as simple as you make it sound in your question: a property in need of a refresh. The reason that reinstalling on top of the existing installation works is because when the shortcut gets created in the beginning, its target executable already exists in the expected place (put there by the previous installation) with a valid icon.

What I recommend doing is writing some code to change the icon of the existing shortcut. Make sure that you execute it after you've copied the executable file to its final destination. The method that allows you to do that is IShellLink::SetIconLocation, which takes two parameters: a path to the icon (this would be the path to your executable file), and the index of the icon (this would probably be 0 assuming that the icon you want is the first and only one contained in the executable).

Of course, in order to call SetIconLocation, you're going to have to obtain an object representing your shortcut that implements IShellLink. This is a COM interface, which I don't believe is wrapped anywhere by the .NET Framework. General information on creating shortcuts from C# is available in the answers to this question. More specifically, there's a link to this wrapper class that you can use to do most of the dirty work. I don't think it contains a method for setting/changing the icon, but that can be trivially added.

Alternatively, you can get at these same properties using the Windows Scripting Host (WSH) wrapper, WshShortcut. It has an IconLocation property that works much the same way except that it takes only a single string argument, with the index delimited from the path by a comma: myApp.exe, 0. It's not particularly well documented (best I can find), but to get an existing shortcut, you just use the CreateShortcut method and specify the path to the existing shortcut. For example:

public void SetShortcutIcon(string shortcutPath, string iconPath, int iconIndex)
{
    // Note: no error checking is performed for the parameters!
    // This is not production-ready code!
    // If a shortcut does not exist at the specified path, you should
    // create a new one instead.
    // If iconPath does not specify a valid executable file, you should
    // set a default icon or perhaps abort.
    IWshRuntimeLibrary.WshShell wsh = new IWshRuntimeLibrary.WshShell();
    IWshRuntimeLibrary.IWshShortcut shortcut = wsh.CreateShortcut(shortcutPath);
    shortcut.IconLocation = String.Format("{0}, {1}", iconPath, iconIndex);
    shortcut.Save();
}

Note that in order for the above code to compile, you will also need to add a reference to the Windows Script Host Object Model to your application. To do this, right-click on the "References" folder in the Solution Explorer, click the "COM" tab, and find "Windows Script Host Object Model" in the list.

I just tested this and it works; the effect is instant.

Upvotes: 3

Related Questions