4

I'm writing a C# app that changes the default recycle bin icon on the desktop. I'm doing this by transferring the icons to a specific place on the drive and updating the registry to point to the new icons. This works quite well.

However, the problem is when I'm uninstalling the app and want to set back the icons as default. When I test with the built in function in Windows, I notice that Windows sometimes changes the registry to %SystemRoot%\System32\imageres.dll,50 for empty icon and %SystemRoot%\System32\imageres.dll,49 for full icon AND sometimes %SystemRoot%\System32\imageres.dll,-55 for empty icon and %SystemRoot%\System32\imageres.dll,-54 for full icon. I really can't seem to find the logic in sometimes using 50 and 49 and sometimes -55 -54 for the default recycle bin icon nor can I find any information regarding this issue.

I've also tried deleting the icon cache in User\username\AppData\Local without any effect. The problem is when I'm setting back the default icons (with using for example 50 and 49) it wont update automatically. I have to manually refresh every time in order to change its state (empty/full). If I afterwards go to the built in function in Windows and set back default icons it changes to -55 or -54 if I used 50 and 49 and it then works. Wtf? There must be somewhere else in the registry which triggers this.. can you help me?

The place in registry I'm working with:

HKEY_CURRENT_USER\
Software\
Microsoft\
Windows\
CurrentVersion\
Explorer\
CLSID\
{645FF040-5081-101B-9F08-00AA002F954E}\
DefaultIcon

Edit 18/04-2011 After Anders' post i've come up with this:

[System.Runtime.InteropServices.DllImport("User32.dll")]
public static extern int SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni);
[System.Runtime.InteropServices.DllImport("User32.dll")]
public static extern long SendMessageTimeout(int hWnd, int Msg, int wParam, int lParam, int fuFlags, int uTimeout, out int lpdwResult);

private const int SPI_SETICONS = 0x0058;
private const int SPIF_UPDATEINIFILE = 0x1;
private const int SPIF_SENDWININICHANGE = 0x2;
private const int HWND_BROADCAST = 0xffff;
private const int WM_SETTINGCHANGE = 0x001A;
private const int SMTO_ABORTIFHUNG = 0x0002;
private const int SPI_SETNONCLIENTMETRICS = 0x0002;

        int res = 0;
        RegistryKey iconSizeKey = Registry.CurrentUser.OpenSubKey("Control Panel\\Desktop\\WindowMetrics", true);
        int iconSize = Int16.Parse((string)iconSizeKey.GetValue("Shell Icon Size"));
        int newIconSize = iconSize - 1;
        iconSizeKey.SetValue("Shell Icon Size", newIconSize, RegistryValueKind.String);
        SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, SPI_SETNONCLIENTMETRICS, 0, SMTO_ABORTIFHUNG, 100000, out res);
        iconSizeKey.SetValue("Shell Icon Size", iconSize, RegistryValueKind.String);
        SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, SPI_SETNONCLIENTMETRICS, 0, SMTO_ABORTIFHUNG, 100000, out res);

But it doesn't change anything :(

Edit 19/02-2011 After Anders' post I've updated this:

[System.Runtime.InteropServices.DllImport("Shell32.dll")]
private static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);

And tried all these combinations:

    SHChangeNotify(0x8000000, 0x1000, IntPtr.Zero, IntPtr.Zero);
    SHChangeNotify(0x08000000, 0x1000, IntPtr.Zero, IntPtr.Zero);
    SHChangeNotify(0x00008000, 0x1000, IntPtr.Zero, IntPtr.Zero);
    SHChangeNotify(0x00002000, 0x1000, IntPtr.Zero, IntPtr.Zero);

Still doesn't work :(

  • 3
    I can't imagine what makes you choose to do this. The user owns the desktop and has tools aplenty to make changes. Does it not bother you that you are relying on implementation details in the registry? – David Heffernan Apr 18 '11 at 19:47
  • It does bother me. But whats the alternative? I really don't see providing guides for changing the icon (with built-in win methods) as an option. –  Apr 19 '11 at 09:18
  • 2
    @s0mmer Why do you need to do this at all? Why would your users accept you messing with their system in this way. If I installed software that did this on my machine I'd be very angry and would uninstall it quick. – David Heffernan Apr 19 '11 at 09:24
  • @David Heffernan: I want to ease the process of installing a specific icon on a users computer. The user will get informed about the proces and will have to accept this before the app wil do anything. –  Apr 19 '11 at 11:42
  • @s0mmer Why would the user want the icon for their recycle bin changed? What sort of app is this? – David Heffernan Apr 19 '11 at 11:44
  • @David Heffernan: I'm sorry, but I think that's irrelevant. The app changes the recycle bin icon and nothing else. –  Apr 19 '11 at 11:52
  • @s0mmer Well good luck in your endeavours. – David Heffernan Apr 19 '11 at 11:53
  • If all you are doing is changing the icons, couldn't this be done with a theme instead of an application? – cadrell0 Apr 19 '11 at 20:39
  • @cadrell0: It has to work with WinXP and newer. And also it should be easy to install/uninstall. –  Apr 19 '11 at 21:03
  • @s0mmer Windows Vista/7 is drastically different from Windows XP. When I am downloading applications, it is not uncommon to see different versions for Windows XP and Windows 7. Themes are very easy to install and remove. – cadrell0 Apr 20 '11 at 15:02

1 Answers1

1

-55 is a resource id, 50 is a resource index. The resource id is set by the developer, the index is a count starting from 0 (The count could change in a service pack etc, but they are usually pretty stable). You can view resource id's with a tool like Resource Hacker (Look in Icon Group for icon id's)

When you pick a icon in the icon picker dialog, the index is normally used. I would expect a specific windows reset button to use the resource id...

See this answer for a way to force a shell icon refresh

Community
  • 1
  • 1
Anders
  • 97,548
  • 12
  • 110
  • 164
  • Thanks for your reply. I will try using the id, and forcing a shell icon refresh when I get home from work. I will get back to you. –  Apr 14 '11 at 08:49
  • I'm having a hard time converting the code to C# - could you help me? –  Apr 16 '11 at 08:47
  • I'm done converting the code - please check out my edit. Am I doing something wrong? –  Apr 18 '11 at 19:39
  • @s0mmer: It looks ok to me, maybe you could try adding a little sleep before posting the message the 2nd time. Or you could change tactic and try SHChangeNotify with SHCNE_ASSOCCHANGED or maybe SHCNE_UPDATEIMAGE or SHCNE_UPDATEITEM... – Anders Apr 18 '11 at 20:34
  • @Anders: I will try this out when I get home. I'll get back to you. –  Apr 19 '11 at 11:43
  • @Anders: I already used the SHChangeNotify for refreshing desktop, but I now tried with a lot of combinations like you suggested. Still no luck :( Do you wan't me to paste full sourcecode on fx. pastebin? –  Apr 19 '11 at 19:44
  • @Anders: Oh yes, I also tried inserting 5 secs of sleep just right before 2nd SendMessageTimeout without any luck :( –  Apr 19 '11 at 19:51
  • @s0mmer: What did you do to fix it? – Anders May 04 '11 at 09:47