Создание обработчиков эскизов
Начиная с 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;
}
Связанные темы