有时候Windows会出现图标显示错乱的问题,比如张冠李戴,该显示这个图标的显示了别的文件图标,或者是图标显示一团黑或者是图标空白,这很有可能是 Windows的图标缓存受到破坏所致。(至于Windows为何设置图标缓存,我想可能是出于性能考虑,因为如果显示图标的时候再去到每个文件里面去找图标会不会太慢了呢)

如果Windows 图标显示错乱,用一些常用软件比如Windows优化大师的【重建图标缓存】功能就可以使图标恢复正常,那么这个功能是如何编程实现的呢?

有一种说法是:删除C:/Documents and Settings/用户名/Local Settings/Application Data/IconCache.db 文件。但是这个方法需要重新启动系统才可生效。其实有更好的方法,不需要重新启动系统就可生效。我在 http://www.codeproject.com/KB/winsdk/nsetfoldericons.aspx找到了答案。请注意这篇文章中的refreshicons()函数:

void CShellIconChangerDlg::RefreshIcons()            
{            
    CString val;            
    HKEY hKey;            

    LONG result = ::RegOpenKeyEx(HKEY_CURRENT_USER,            
        "Control Panel//Desktop//WindowMetrics",            
        0,KEY_READ,&hKey);            
    BYTE buff[256];            
    ZeroMemory(buff,255);            
    DWORD sz = sizeof buff;            
    DWORD typ = REG_SZ;            
    RegQueryValueEx(hKey,"Shell Icon Size",0,&typ,buff,&sz);            
    RegCloseKey(hKey);            

    val = buff;            

    int i = atoi(val);            
    i++;            
    val.Format("%d",i);            

    result = ::RegOpenKeyEx(HKEY_CURRENT_USER,            
        "Control Panel//Desktop//WindowMetrics",            
        0,KEY_WRITE,&hKey);            
    RegSetValueEx(hKey,"Shell Icon Size",0,REG_SZ,            
        (const BYTE*)val.GetBuffer(0),val.GetLength());            
    val.ReleaseBuffer();            
    RegCloseKey(hKey);            

    ::SendMessage(HWND_BROADCAST ,            
        WM_SETTINGCHANGE,SPI_SETNONCLIENTMETRICS,NULL);            


    i = atoi(val);            
    i--;            
    val.Format("%d",i);            

    result = ::RegOpenKeyEx(HKEY_CURRENT_USER,            
        "Control Panel//Desktop//WindowMetrics",            
        0,KEY_WRITE,&hKey);            
    RegSetValueEx(hKey,"Shell Icon Size",0,REG_SZ,            
        (const BYTE*)val.GetBuffer(0),val.GetLength());            
    val.ReleaseBuffer();            
    RegCloseKey(hKey);            

    ::SendMessage(HWND_BROADCAST ,            
        WM_SETTINGCHANGE,SPI_SETNONCLIENTMETRICS,NULL);            
}



正是完成了重建图标缓存的操作。至于原理,看代码是这个意思:先把windows图标显示大小增加了1,然后广播一个 WM_SETTINGCHANGE 消息,最后又把图标大小改回了原来的值,在广播一个 WM_SETTINGCHANGE消息。


不过那个代码是VC++的,我给小小的改造了一下,把CString 改为 wxString,现在用wxDev-C++可以编译了,而且能够成功的刷新图标缓存,。改后的代码如下:

#include "windows.h"            
#include "wx.h"            

void RefreshIcons()            
{            
    wxString val;            
    HKEY hKey;            

    LONG result = ::RegOpenKeyEx(HKEY_CURRENT_USER,            
        "Control Panel//Desktop//WindowMetrics",            
        0,KEY_READ,&hKey);            
    BYTE buff[256];            
    ZeroMemory(buff,255);            
    DWORD sz = sizeof buff;            
    DWORD typ = REG_SZ;            
    RegQueryValueEx(hKey,"Shell Icon Size",0,&typ,buff,&sz);            
    RegCloseKey(hKey);            

    val = wxString::Format( "%s",buff);            

    long i;            
    val.ToLong(&i);            
    i++;            
    val=wxString::Format("%d",i);            

    result = ::RegOpenKeyEx(HKEY_CURRENT_USER,            
        "Control Panel//Desktop//WindowMetrics",            
        0,KEY_WRITE,&hKey);            

    //MessageBox(0,val.mb_str(),"",MB_OK);            

    RegSetValueEx(hKey,"Shell Icon Size",0,REG_SZ,            
        (const BYTE*)val.mb_str(),val.Length());            

    RegCloseKey(hKey);            

    ::SendMessage(HWND_BROADCAST ,            
        WM_SETTINGCHANGE,SPI_SETNONCLIENTMETRICS,NULL);            


    val.ToLong(&i);            
    i--;            
    val=wxString::Format("%d",i);            

    result = ::RegOpenKeyEx(HKEY_CURRENT_USER,            
        "Control Panel//Desktop//WindowMetrics",            
        0,KEY_WRITE,&hKey);            

    //MessageBox(0,val.mb_str(),"",MB_OK);            

    RegSetValueEx(hKey,"Shell Icon Size",0,REG_SZ,            
        (const BYTE*)val.mb_str(),val.Length());            

    RegCloseKey(hKey);            

    ::SendMessage(HWND_BROADCAST ,            
        WM_SETTINGCHANGE,SPI_SETNONCLIENTMETRICS,NULL);            
}