如何刷新explorer.exe图标缓存
2022-05-23 / Hell

在做客户端定制化时,遇到了问题。客户在新版本时,更换了应用程序图标。在安装新版本的应用后,桌面上的快捷方式还是老版本。
这是因为explorer.exe有缓存,一般情况下,重启explorer.exe即可更新图标。但是偶现几例顽固现场,重启也不生效。

通过搜索,发现翻来覆去都是几个固定的方法:

  1. 删除IconCache.db
  2. 删除%LOCALAPPDATA%\Microsoft\Windows\Explorer路径下的iconcache
  3. 使用ie4uinit.exe
    1
    2
    ie4uinit.exe -ClearIconCache
    ie4uinit.exe -show
    但是经过测试发现效果并不好。经过测试,发现系统的磁盘清理工具有效果。
    ![磁盘清理工具](disk clean.png)
    那么问题就变得简单起来,如何安装程序执行后,进行一次磁盘清理操作呢?
    磁盘清理工具C:\WINDOWS\system32\cleanmgr.exe提供了一些参数:
    1
    cleanmgr [/d <driveletter>] [/sageset:n]  [/sagerun:n] [/TUNEUP:n] [/LOWDISK] [/VERYLOWDISK]
    但是没有一个符合我的需要,我只是需要调用一下以清除缩略图,但是并没有可以实现的方式。
    但是看到一篇文章:Creating a Disk Cleanup Handler,既然我们可以创建磁盘清理项,那其自带的应该也是类似方式提供的。
    在文章末尾Example Registration of a Disk Cleanup Handler,发现了注册表路径:缩略图清理注册表,可以看到,它的GUID是{889900c3-59f3-4c2f-ae21-a409ea01e605},我们根据接口,尝试一波调用,就成功了:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93

    #include <EmptyVC.h>

    class VolumeCacheCallback : public IEmptyVolumeCacheCallBack
    {
    public:
    // 通过 IEmptyVolumeCacheCallBack 继承
    virtual HRESULT __stdcall QueryInterface(REFIID riid, void** ppvObject) override
    {
    return E_NOTIMPL;
    }
    virtual ULONG __stdcall AddRef(void) override
    {
    return 0;
    }
    virtual ULONG __stdcall Release(void) override
    {
    return 0;
    }
    virtual HRESULT __stdcall ScanProgress(DWORDLONG dwlSpaceUsed, DWORD dwFlags, LPCWSTR pcwszStatus) override
    {
    printf_s("Scanning files %llu\n", dwlSpaceUsed);
    return S_OK;
    }
    virtual HRESULT __stdcall PurgeProgress(DWORDLONG dwlSpaceFreed, DWORDLONG dwlSpaceToFree, DWORD dwFlags, LPCWSTR pcwszStatus) override
    {
    printf_s("Cleanning files %llu\n", dwlSpaceFreed);
    return S_OK;
    }
    };

    bool cleaner()
    {
    HRESULT hr = E_FAIL;
    IEmptyVolumeCache2* pCache2 = nullptr;
    bool bComInit = false;
    bool bRet = false;
    do
    {
    hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
    if (S_OK != hr && S_FALSE != hr) {
    if (RPC_E_CHANGED_MODE != hr) {
    break;
    }
    }
    else {
    bComInit = true;
    }

    CLSID clean_Thumbnail_Cache = { 0 };
    hr = CLSIDFromString(L"{889900c3-59f3-4c2f-ae21-a409ea01e605}", &clean_Thumbnail_Cache);
    if (FAILED(hr))
    {
    printf_s("CLSIDFromString failed\n");
    break;
    }
    hr = ::CoCreateInstance(clean_Thumbnail_Cache, NULL, CLSCTX_INPROC_SERVER, __uuidof(IEmptyVolumeCache2), (void**)&pNetFwP2);
    if (FAILED(hr) || nullptr == pCache2)
    {
    printf_s("CoCreateInstance Failed : 0x%08X\n", hr);
    break;
    }
    DWORDLONG space_used = 0;
    VolumeCacheCallback callback;
    hr = pCache2->GetSpaceUsed(&space_used, &callback);
    if (FAILED(hr))
    {
    printf_s("GetSpaceUsed Failed : 0x%08X\n", hr);
    break;
    }
    printf_s("Scanning files Complete\n");

    hr = pCache2->Purge(space_used, &callback);
    if (FAILED(hr))
    {
    printf_s("Purge Failed : 0x%08X\n", hr);
    break;
    }

    printf_s("Cleanning files Complete\n");

    bRet = true;
    } while (false);

    if (nullptr != pCache2) {
    pCache2->Release();
    }

    if (bComInit) {
    CoUninitialize();
    }
    return bRet;
    }
PermaLink:
https://lazywang.life/2022/05/23/how-to-refresh-explorer-icon-cache/