生成缩略图处理程序

从 Windows Vista 开始,与早期版本的 Windows 相比,使用文件特定的缩略图图像的量更大。 它们用于所有视图、对话以及提供它们的任何文件类型。 缩略图显示也已更改。 用户可选择大小的连续范围可用,而不是图标和缩略图等离散大小。

IThumbnailProvider 接口使提供缩略图比较旧的 IExtractImageIExtractImage2 更加简单。 但请注意,使用 IExtractImageIExtractImage2 的现有代码仍然有效且受支持。

RecipeThumbnailProvider 示例

本节中剖析的 RecipeThumbnailProvider 示例包含在 Windows 软件开发工具包 (SDK) 中。 其默认安装位置为 C:\Program Files\Microsoft SDKs\Windows\v6.0\Samples\WinUI\Shell\AppShellIntegration\RecipeThumbnailProvider。 但是,此处也包含大部分代码。

RecipeThumbnailProvider 示例演示了使用 .recipe 扩展名注册的新文件类型的缩略图处理程序的实现。 此示例演示了如何使用不同的缩略图处理程序 API 来为自定义文件类型注册缩略图提取组件对象模型 (COM) 服务器。 本主题将引导你完成示例代码,重点介绍编码选项和准则。

缩略图处理程序必须始终结合以下接口之一实现 IThumbnailProvider

在某些情况下,无法使用流进行初始化。 在缩略图处理程序未实现 IInitializeWithStream 的情况下,当流发生更改时,它必须选择退出在系统索引器默认放置它的隔离进程中运行。 若要选择退出进程隔离功能,请设置以下注册表值。

HKEY_CLASSES_ROOT
   CLSID
      {The CLSID of your thumbnail handler}
         DisableProcessIsolation = 1

如果实现 IInitializeWithStream 并执行基于流的初始化,则处理程序将更加安全可靠。 通常,禁用进程隔离仅适用于旧处理程序;避免对任何新代码禁用此功能。 IInitializeWithStream 应尽可能成为初始化接口的首选。

由于示例中的图像文件未嵌入到 .recipe 文件中,并且不是其文件流的一部分,因此在示例中使用了 IInitializeWithItemIInitializeWithItem::Initialize 方法的实现只是将其参数传递给私有类变量。

IThumbnailProvider 只有一种方法(GetThumbnail),该方法使用图像的最大所需大小(以像素为单位)调用。 尽管 参数名为 cx,但其值将用作图像的 x 和 y 尺寸的最大大小。 如果检索到的缩略图不是正方形的,则较长的轴受 cx 限制,并保留原始图像的纵横比。

返回时, GetThumbnail 为检索到的图像提供句柄。 它还提供一个值,该值指示图像的颜色格式以及它是否具有有效的 alpha 信息。

示例中的 GetThumbnail 实现从调用专用 _GetBase64EncodedImageString 方法开始。

IFACEMETHODIMP CRecipeThumbProvider::GetThumbnail(UINT cx, 
                                                  HBITMAP *phbmp, 
                                                  WTS_ALPHATYPE *pdwAlpha)
{
    PWSTR pszBase64EncodedImageString;
    HRESULT hr = _GetBase64EncodedImageString(cx, &pszBase64EncodedImageString);

.recipe 文件类型只是注册为唯一文件扩展名的 XML 文件。 它包含一个名为 Picture 的元素,该元素提供图像的相对路径和文件名,用作此特定 .recipe 文件的缩略图。 Picture 元素由指定 base 64 编码图像的 Source 属性和可选的 Size 属性组成。

Size 有两个值,小和大。 这样,就可以为多个 图片 节点提供单独的图像。 然后检索到的图像取决于调用 GetThumbnail (cx) 提供的最大大小值。 由于 Windows 永远不会调整大小超过其最大大小的图像,因此可以针对不同的分辨率提供不同的图像。 但是,为简单起见,该示例省略了 Size 属性,并且为所有情况只提供一个图像。

_GetBase64EncodedImageString 方法的实现如下所示,它使用 XML 文档对象模型 (DOM) API 来检索 Picture 节点。 从该节点提取 属性数据中的图像。

HRESULT CRecipeThumbProvider::_GetBase64EncodedImageString(UINT /* cx */, 
                                                           PWSTR *ppszResult)
{
    *ppszResult = NULL;

    IXMLDOMDocument *pXMLDoc;
    HRESULT hr = _LoadXMLDocument(&pXMLDoc);
    if (SUCCEEDED(hr))
    {
        BSTR bstrQuery = SysAllocString(L"Recipe/Attachments/Picture");
        hr = bstrQuery ? S_OK : E_OUTOFMEMORY;
        if (SUCCEEDED(hr))
        {
            IXMLDOMNode *pXMLNode;
            hr = pXMLDoc->selectSingleNode(bstrQuery, &pXMLNode);
            if (SUCCEEDED(hr))
            {
                IXMLDOMElement *pXMLElement;
                hr = pXMLNode->QueryInterface(&pXMLElement);
                if (SUCCEEDED(hr))
                {
                    BSTR bstrAttribute = SysAllocString(L"Source");
                    hr = bstrAttribute ? S_OK : E_OUTOFMEMORY;
                    if (SUCCEEDED(hr))
                    {
                        VARIANT varValue;
                        hr = pXMLElement->getAttribute(bstrAttribute, &varValue);
                        if (SUCCEEDED(hr))
                        {
                            if ((varValue.vt == VT_BSTR) && varValue.bstrVal && varValue.bstrVal[0])
                            {
                                hr = SHStrDupW(varValue.bstrVal, ppszResult);
                            }
                            else
                            {
                                hr = E_FAIL;
                            }
                            VariantClear(&varValue);
                        }
                        SysFreeString(bstrAttribute);
                    }
                    pXMLElement->Release();
                }
                pXMLNode->Release();
            }
            SysFreeString(bstrQuery);
        }
        pXMLDoc->Release();
    }
    return hr;
}

然后,GetThumbnail 将检索到的字符串传递给_GetStreamFromString

IFACEMETHODIMP CRecipeThumbProvider::GetThumbnail(UINT cx, 
                                                  HBITMAP *phbmp, 
                                                  WTS_ALPHATYPE *pdwAlpha)
{
    PWSTR pszBase64EncodedImageString;
    HRESULT hr = _GetBase64EncodedImageString(cx, &pszBase64EncodedImageString);
    if (SUCCEEDED(hr))
    {
        IStream *pImageStream;
        hr = _GetStreamFromString(pszBase64EncodedImageString, &pImageStream);

_GetStreamFromString 方法,其实现如下所示,用于将编码图像转换为流。

HRESULT CRecipeThumbProvider::_GetStreamFromString(PCWSTR pszImageName, 
                                                   IStream **ppImageStream)
{
    HRESULT hr = E_FAIL;

    DWORD dwDecodedImageSize = 0;
    DWORD dwSkipChars        = 0;
    DWORD dwActualFormat     = 0;

    // Base64-decode the string
    BOOL fSuccess = CryptStringToBinaryW(pszImageName, 
                                         NULL, 
                                         CRYPT_STRING_BASE64,
                                         NULL, 
                                         &dwDecodedImageSize, 
                                         &dwSkipChars, 
                                         &dwActualFormat);
    if (fSuccess)
    {
        BYTE *pbDecodedImage = (BYTE*)LocalAlloc(LPTR, dwDecodedImageSize);
        if (pbDecodedImage)
        {
            fSuccess = CryptStringToBinaryW(pszImageName, 
                                            lstrlenW(pszImageName), 
                                            CRYPT_STRING_BASE64,
                                            pbDecodedImage, 
                                            &dwDecodedImageSize, 
                                            &dwSkipChars, 
                                            &dwActualFormat);
            if (fSuccess)
            {
                *ppImageStream = SHCreateMemStream(pbDecodedImage, 
                                                   dwDecodedImageSize);
                if (*ppImageStream != NULL)
                {
                    hr = S_OK;
                }
            }
            LocalFree(pbDecodedImage);
        }
    }
    return hr;
}

然后,GetThumbnail 使用 Windows 图像处理组件 (WIC) API 从流中提取位图并获取该位图的句柄。 alpha 信息已设置,WIC 已正确退出,并且该方法会成功终止。

IFACEMETHODIMP CRecipeThumbProvider::GetThumbnail(UINT cx, 
                                                  HBITMAP *phbmp, 
                                                  WTS_ALPHATYPE *pdwAlpha)
{
    PWSTR pszBase64EncodedImageString;
    HRESULT hr = _GetBase64EncodedImageString(cx, &pszBase64EncodedImageString);
    if (SUCCEEDED(hr))
    {
        IStream *pImageStream;
        hr = _GetStreamFromString(pszBase64EncodedImageString, &pImageStream);
        if (SUCCEEDED(hr))
        {
            hr = WICCreate32BitsPerPixelHBITMAP(pImageStream, 
                                                cx, 
                                                phbmp, 
                                                pdwAlpha);;

            pImageStream->Release();
        }
        CoTaskMemFree(pszBase64EncodedImageString);
    }
    return hr;
}

缩略图处理程序

缩略图处理程序指南

IID_PPV_ARGS