Winapi 加载图标处理程序外壳扩展时,文件图标模糊

Winapi 加载图标处理程序外壳扩展时,文件图标模糊,winapi,shell-extensions,Winapi,Shell Extensions,我有一个带有图标处理程序的shell扩展,它根据文件内容将文件类型的图标设置为绿色或红色图标。图标似乎工作正常,只是当使用大图标时,它们非常模糊,好像它们是从非常小的尺寸放大的。图标.ico文件包含从256x256到16x16的所有图像大小 我使用的是一个非常基本的图标处理程序,但可能缓存还是有问题。如何确保图标已正确加载 HRESULT icon_handler::GetIconLocation(UINT u_flags, PWSTR psz_icon_file, UINT cch_max,

我有一个带有图标处理程序的shell扩展,它根据文件内容将文件类型的图标设置为绿色或红色图标。图标似乎工作正常,只是当使用大图标时,它们非常模糊,好像它们是从非常小的尺寸放大的。图标
.ico
文件包含从256x256到16x16的所有图像大小

我使用的是一个非常基本的图标处理程序,但可能缓存还是有问题。如何确保图标已正确加载

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;
}
使用DebugView登录时,图标处理程序会显示为请求适当的大小:

[30100] phicon_large size:
[30100] 256
[30100] phicon_small size:
[30100] 16
编辑: 根据@Anders的说法,如果我检查加载了
LoadImage
的图像的大小,它似乎也是正确的:

*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());

我以前见过这种信息。我现在不能保证这些信息是准确的

尼科西

指示图标的所需大小。高调的词是 尺寸(高度和宽度,因为它们始终相同) 小图标的尺寸,低字表示小图标的尺寸 大图标。在正常情况下,小图标的大小将是 16大图标通常为32或48,这取决于浏览器的视图模式,对于大图标模式为-32,对于平铺模式为48

似乎
IExtract IconA::Extract
只能提取标准尺寸的图标

另一方面,参考Raymond Chen的

如果您要求IExtract-Icon::Extract在特定位置提取图标 大小,函数可以返回S_FALSE。提取图标和 Extract-Icon-Ex函数不允许 指定自定义大小, 加载图像与图标索引不兼容 (仅限资源ID)

因此,如果您需要提取自定义大小的图标(即系统的“小”和“大”尺寸以外的图标),则需要做更多的工作

调用该函数,该函数是另一个shell助手函数,但用于检索包含图标的shell图像列表。它为图标大小提供了更多选项:
SHIL_SMALL
(通常为16x16)、
SHIL_LARGE
(通常为32x32)、
SHIL_超大
(通常为48x48)和
SHIL_JUMBO
(通常为256x256,仅在Vista和更高版本上使用)。因此,如果您要求使用超大型的SHIL_,您将获得所需的48x48图标

这里仍然需要该函数,但这次将检索shell图像列表中所需图标的索引。使用
SHGFI\u SYSICONINDEX
选项检索

完全未经测试的示例代码,编译器从未接触过:

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;
}
有关详情,请参阅:

更新:


我意外地发现了这样一个,可能是通过指定宽度/高度,删除了
LR\u DEFAULTSIZE
。另外,您必须在
DrawIconEx
之后调用
destroycon
,否则会导致资源泄漏。或者在堆上创建
HICON
,以便只创建一次。

使用
geticonnifoex
检查从
LoadImage
获得的图标,看看它的大小是否正确。谢谢,我检查了这个,加载的图像的大小似乎也正确。不确定这是否适用于这里,但值得一看:下一步尝试:在16x16图标中添加一些内容,以确保它不是用作大图标的图标。如果这没有帮助,请尝试使用每个资源的单个图标图像大小(HICONs可以包含链接回加载它的文件的机密信息)。最初传递到GetIconLocation的标志是什么(u_标志)?我认为SHGetFileInfo只调用IExtractCon和相关接口。
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;
}