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

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

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

Пример RecipeThumbnailProvider

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

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

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

Метод _GetBase64EncodedImageString , реализация которого показана здесь, использует API-интерфейсы модели DOM для получения узла Picture . Из этого узла извлекается изображение из данных атрибута Source .

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