Search code examples
winapicomwindows-shell

How can I set icons to virtual files in a namespace extension?


I'm trying to add icons to the virtual files in a namespace extension. The files are .docx, .pdf and other non-windows default extensions but it isn't clear to me how to do this. IDefaultExtractIconInit::SetNormalIcon(LPCWSTR pszFile, int iIcon) accepts a file path to the icon and an icon Id. Calls to SHGetFileInfo to get the icon path and index fail to return the path but returns success. SHGetFileInfo will return the correct icon index to the system icon cache and I'd like to use it, but passing that index to SetNormalIcon(NULL, idx) fails to set the correct icon. How can I set the file icons?

STDMETHODIMP CShellFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT *rgfReserved, void **ppv) {
    *ppv        = NULL;
    HRESULT hr  = E_NOTIMPL;
    if (IID_IExtractIcon == riid) {
        IDefaultExtractIconInit *pdxi   = NULL;
        hr                              = SHCreateDefaultExtractIcon(IID_PPV_ARGS(&pdxi));
        if (SUCCEEDED(hr)) {
            BOOL isFolder   = FALSE;
            hr              = m_pPidlMgr->IsFolder(apidl[0], &isFolder);
            if(SUCCEEDED(hr)) {
                pdxi->SetFlags(GIL_FORSHELL);
                hr = pdxi->SetNormalIcon(L"Shell32.dll", isFolder ? 4 : 1);
                if (SUCCEEDED(hr)) 
                    hr = pdxi->QueryInterface(riid, ppv);
            }
            pdxi->Release();
        }
    }
    return hr;
}

Solution

  • Not really documented but when you pass NULL as a filename the index is a SHSTOCKICONID value, not a system imagelist index! You can see a SIID_* value used in the example on this page. I'm not sure if IDefaultExtractIconInit can be used if you only know the system imagelist index.

    If your namespace extension only returns icons from the system imagelist you might get away with just supporting IShellIcon in your shell folder implementation. Otherwise you might have to create a custom IExtractIcon object.