0

I have a shell extension with an icon handler that sets a file type's icons to a green or red icon, based on file contents. The icons seem to work properly except they are really blurry when using large icons, as if they were zoomed in from a really small size. The icon .ico files contain all image sizes from 256x256 to 16x16.

Icons are blurry

I am using a very basic icon handler, but maybe there could still be some problem with caching or something. How could I make sure the icons are loaded properly?

HRESULT icon_handler::GetIconLocation(UINT u_flags, PWSTR psz_icon_file, UINT cch_max, int* pi_index, UINT* pw_flags)
{
    *pw_flags = GIL_NOTFILENAME | GIL_DONTCACHE;
    return S_OK;
}

HRESULT icon_handler::Extract(PCWSTR psz_file, UINT n_icon_index, HICON* phicon_large, HICON* phicon_small, UINT n_icon_size)
{
    int icon = ICON_GREEN;
    if (m_icon_color_ == 1) {
        icon = ICON_RED;
    }

    if (phicon_large != nullptr)
    {
        const int large_size = LOWORD(n_icon_size);
        *phicon_large = HICON(LoadImageW(global_h_instance, MAKEINTRESOURCE(icon), IMAGE_ICON, large_size, large_size, 
            LR_DEFAULTCOLOR));
    }
    if (phicon_small != nullptr)
    {
        const int small_size = HIWORD(n_icon_size);
        *phicon_small = HICON(LoadImageW(global_h_instance, MAKEINTRESOURCE(icon), IMAGE_ICON, small_size, small_size,
            LR_DEFAULTCOLOR));
    }

    return S_OK;
}

When logging with DebugView the icon handler appears to request appropriate sizes:

[30100] phicon_large size:
[30100] 256
[30100] phicon_small size:
[30100] 16

Edit: As per @Anders, if I check the size of the image loaded with LoadImage it also appears to be correct:

*phicon_large = HICON(LoadImageW(global_h_instance, MAKEINTRESOURCE(icon), IMAGE_ICON, large_size, large_size, 
            LR_DEFAULTCOLOR));
ICONINFOEXW info = {sizeof(ICONINFOEXW)};
GetIconInfoEx(*phicon_large, &info)
BITMAP bmp;
GetObjectW(info.hbmMask, sizeof(BITMAP), &bmp);
OutputDebugStringW(L"Icon size:");
OutputDebugStringW(std::to_wstring(bmp.bmWidth).c_str());
[12376] phicon_large size:
[12376] 256
[12376] Icon size:
[12376] 256
[12376] phicon_small size:
[12376] 16
[12376] Icon size:
[12376] 16

Mr. Ran Dum
  • 151
  • 8
  • 1
    Inspect the icon you get from `LoadImage` with `GetIconInfoEx` to see if it actually is the correct size. – Anders Jul 10 '19 at 10:07
  • Thank you, I checked this and the size of the loaded image also seems to be correct. – Mr. Ran Dum Jul 10 '19 at 10:42
  • Not sure this applies here, but worth a look: [How do I override the default icon selection algorithm?](https://devblogs.microsoft.com/oldnewthing/20121005-00/?p=6393) – IInspectable Jul 10 '19 at 14:44
  • Next thing to try: Add something to the 16x16 icon to make sure it is not that icon it is using as the large icon. And if that does not help, try using a single icon image size per resource (HICONs can contain secret info that links back to the file it is loaded from). – Anders Jul 10 '19 at 14:50
  • What are the flags passed in initially to GetIconLocation (u_flags)? – Simon Mourier Jul 10 '19 at 15:37
  • @SimonMourier u_flags is `GIL_CHECKSHIELD (0x0200)`. Don't know what it means but I guess I'll add `GIL_FORCENOSHIELD` into `pw_flags`, heh. – Mr. Ran Dum Jul 12 '19 at 12:09
  • I am now getting sharp icons most of the time (https://i.imgur.com/u9X6DqD.png) after trying out different tools to create the .ico files. Not sure how much of it is Windows' icon cache so I'm trying to refresh with `nirsoft shellrefresh` and Explorer restart. I'll look into @Anders' single 256px icon for `phicon_large` or Strive Sun's custom Extract function if I cannot figure this out. – Mr. Ran Dum Jul 12 '19 at 12:34
  • @Mr.RanDum hi, Mr.Ran You can take a look at my latest updated answers, which may be helpful to you:) – Strive Sun Jul 18 '19 at 02:57

1 Answers1

1

I've seen this kind of information from past documents.I can't guarantee that this information is accurate now.

nIconSize

Indicates the desired sizes of the icons. The high word is the dimensions (both height and width, since they're always the same) of the small icon, and the low word holds the dimensions of the of the large icon. Under normal circumstances, the small icon size will be 16. The large icon will usually be 32 or 48, depending on which view mode Explorer is in - 32 for large icon mode, 48 for tile mode.

It seems that IExtract IconA:: Extract can only extract icons in standard sizes.

On the other hand, refer Raymond Chen's old thing,

if you ask IExtract­Icon::Extract to extract an icon at a particular size, the function can return S_FALSE.The Extract­Icon and Extract­Icon­Ex functions don’t let you specify a custom size, and Load­Image doesn’t work with icon indices (only resource IDs).

Therefore,If you need to extract icons of custom sizes (i.e., something other than the system's "small" and "large" sizes), then you'll need to do more work.

Call the SHGetImageList function, which is another shell helper function, but one that retrieves a shell image list containing icons. It gives you far more options for icon sizes: SHIL_SMALL (generally 16x16), SHIL_LARGE (generally 32x32), SHIL_EXTRALARGE (generally 48x48), and SHIL_JUMBO (generally 256x256—only on Vista and later). So if you ask for SHIL_EXTRALARGE, you'll get the 48x48 icons that you're looking for.

You'll still need the SHGetFileInfo function here, but this time it will be to retrieve the index of the desired icon in the shell image list. Retrieve that with the SHGFI_SYSICONINDEX option.

Completely untested sample code, never touched by a compiler:

HICON ExtractExtraLargeIcon(LPCTSTR pszPath)
{    
    // Determine the index of the desired icon
    // in the system image list.
    SHGETFILEINFO sfi;
    SHGetFileInfo(pszPath, 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX);

    // Retrieve the system image list.
    // (To get 256x256 icons, we use `SHIL_JUMBO`.)
    IImageList* piml;
    if (SHGetImageList(SHIL_JUMBO, IID_IImageList, (void**)&piml) == S_OK)
    {
        HICON hIcon;
        if (piml->GetIcon(sfi.iIcon, ILD_TRANSPARENT, &hIcon) == S_OK)
        {
           return hIcon;
        }
    }

    // Oops! We failed.
    return NULL;
}

More Details, please refer :

Difference between ExtractIcon and ExtractAssociatedIcon? Need to extract icon of specific size

Extract high resolution icon or thumbnail for file

Updated:

I accidentally found such a post, probably by specifying the width/height, remove LR_DEFAULTSIZE. Also, you must call DestroyIcon after DrawIconEx otherwise you get resource leak. Either that or create the HICON on heap so that it's created only once.

Strive Sun
  • 5,988
  • 1
  • 9
  • 26