从 UWP 应用程序中提取图标

2021-12-28 00:00:00 icons winapi c++ uwp

在尝试实现打开方式"功能时,我遇到了从 UWP 应用程序中提取图标的问题.因此,在收到推荐的应用程序列表以在 SHAssocEnumHandlers,我试图在 IAssocHandler::GetIconLocation 和经典的 ExtractIcon().例如,使用 Paint 等程序一切正常.我有 Paint 二进制文件的完整路径,可以从中提取图标.但是像3D builder"、Photos"和其他 UWP 应用程序获得的图标位置看起来像 @{Microsoft.Windows.Photos_16.511.8630.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Files/资产/PhotosAppList.png}.我尝试了几个不同的 API 来提取图标,每次都收到 FILE_NOT_FOUND 错误.那么,谁能给我一个提示,在这种情况下可以使用哪个函数来提取图标?

While trying to implement "Open With" functionality I encountered a problem with extracting icons from UWP applications. So, after receiving list of recommended applications to open particular file with the help of SHAssocEnumHandlers, I'm trying to extract icons for each of these applications with the help of IAssocHandler::GetIconLocation and classical ExtractIcon(). Everything works ok with programs like Paint, for example. I have full path to Paint binary and can extract icon from it. But with applications like "3D builder", "Photos" and other UWP applications obtained icon location looks like @{Microsoft.Windows.Photos_16.511.8630.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Files/Assets/PhotosAppList.png}. I tried couple of different APIs to extract icon and each time received FILE_NOT_FOUND error. So, can anyone give me a hint which function can be used to extract icon in that case?

更新添加了部分源代码以澄清情况:

UPDATE Some parts of source code added to clarify the situation:

// m_handlers is a member of type std::vector<CComPtr<IAssocHandler>>

HRESULT FileManager::GetAssocHandlers(const std::wstring& strFileExtension, ASSOC_FILTER filter)
{
    HRESULT hr = S_OK;
    CComPtr<IEnumAssocHandlers> enumerator;

    m_handlers.clear();

    hr = SHAssocEnumHandlers(strFileExtension.c_str(), filter, &enumerator);
    if (SUCCEEDED(hr))
    {
        for (CComPtr<IAssocHandler> handler;
            enumerator->Next(1, &handler, nullptr) == S_OK;
            handler.Release())
        {
            m_handlers.push_back(handler);
        }
    }

    return hr;
}

HRESULT FileManager::GetAssociatedPrograms(BSTR bstrFileName, BSTR* bstrRet)
{
    ...
    hr = GetAssocHandlers(strFileExtension, ASSOC_FILTER_RECOMMENDED);
    if (SUCCEEDED(hr))
    {
        ...
        for (auto& handler : m_handlers)
        {
            ...
            if (SUCCEEDED(handler->GetIconLocation(&tmpStr, &resourceIndex)))
            {
                // And this is where I get classic full file path to regular
                // applications like "MS Paint" or this weird path mentioned
                // above for "Photos" UWP application for example which can't
                // be used in regular ExtractIcon functions.
            }
        }
    }
}

推荐答案

看起来我已经找到了解决方案.根据 MSDN,为 UWP 应用程序提供的图标位置路径称为间接字符串".我们可以将此间接字符串传递给 SHLoadIndirectString 函数,并将接收图标 PNG 文件的常规完整路径.在我将 @{Microsoft.Windows.Photos_16.511.8630.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Files/Assets/PhotosAppList.png} 传递给 SHLoadIndirectString() 后,我收到了这样的路径:C:Program FilesWindowsAppsMicrosoft.Windows.Photos_16.511.8630.0_neutral_split.scale-125_8wekyb3d8bbweAssetsPhotosAppList.scale-125.png 然后我可以用它来显示图标本身没有任何问题.

Looks like I've found the solution. The icon location path provided for UWP application is called "indirect string" according to MSDN. We can pass this indirect string to SHLoadIndirectString function and will receive the regular full path to the icon PNG file. In my case after passing @{Microsoft.Windows.Photos_16.511.8630.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Files/Assets/PhotosAppList.png} to SHLoadIndirectString() I received path like that: C:Program FilesWindowsAppsMicrosoft.Windows.Photos_16.511.8630.0_neutral_split.scale-125_8wekyb3d8bbweAssetsPhotosAppList.scale-125.png and after that I can use it to display the icon itself w/o any problem.

相关文章