Поделиться через


Создание обработчиков эскизов

Начиная с Windows Vista, более активно используются эскизные изображения файлов, чем в более ранних версиях Windows. Они используются во всех представлениях, в диалоговых окнах и для любого типа файла, предоставляющего их. Отображение эскизов также было изменено. Непрерывный спектр выбираемых пользователем размеров доступен вместо дискретных размеров, таких как иконки и миниатюры.

Интерфейс IThumbnailProvider упрощает предоставление эскизов по сравнению со старой версией IExtractImage или IExtractImage2. Обратите внимание, что существующий код, использующий IExtractImage или IExtractImage2, по-прежнему действителен и поддерживается.

Пример RecipeThumbnailProvider

Пример RecipeThumbnailProvider, рассмотренный в этом разделе, включен в набор средств разработки программного обеспечения (SDK) для Windows. Расположение установки по умолчанию — 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 должен быть первым выбором интерфейса инициализации по возможности.

Так как файл изображения в образце не внедрен в файл рецепта и не является частью его потока файлов, в примере используется IInitializeWithItem. Реализация метода IInitializeWithItem::Initialize просто передает свои параметры переменным частного класса.

IThumbnailProvider имеет только один метод—GetThumbnail, который вызывается с наибольшим требуемым размером изображения в пикселях. Хотя параметр называется cx, его значение используется как максимальный размер размера изображения x и y. Если извлеченный эскиз не равен квадрату, то длинная ось ограничена cx, а пропорции исходного изображения сохраняются.

При возвращении GetThumbnail предоставляет дескриптор извлеченного изображения. Он также предоставляет значение, указывающее цветной формат изображения и наличие допустимых альфа-данных.

Реализация GetThumbnail в примере начинается с вызова частного метода _GetBase64EncodedImageString.

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

Тип файла рецепта — это просто XML-файл, зарегистрированный в качестве уникального расширения имени файла. Он содержит элемент с именем Picture, который предоставляет относительный путь и имя файла изображения, используемого в качестве эскиза для этого конкретного файла рецепта. Элемент Picture состоит из атрибута Source, указывающего базовый 64-кодированный образ и необязательный атрибут Size.

Размер имеет два значения, Small и Large. Это позволяет предоставить несколько узлов picture с отдельными изображениями. Полученное изображение зависит от максимального размера (cx) в вызове GetThumbnail. Поскольку Windows никогда не увеличивает изображение больше его максимального размера, для разных разрешений могут быть предоставлены разные изображения. Однако для простоты пример опускает атрибут Size и предоставляет только одно изображение для всех ситуаций.

Метод _GetBase64EncodedImageString, реализация которого показана здесь, использует API объектной модели XML-документа (DOM), чтобы получить узел 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 затем использует API компонента образов Windows (WIC) для извлечения растрового изображения из потока и получения дескриптора для этого растрового изображения. Альфа-информация задана, 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