Criando manipuladores de miniaturas
A partir do Windows Vista, um uso maior é feito de imagens em miniatura específicas do arquivo do que em versões anteriores do Windows. Eles são usados em todos os modos de exibição, em caixas de diálogo e para qualquer tipo de arquivo que os forneça. A exibição em miniatura também foi alterada. Um espectro contínuo de tamanhos selecionáveis pelo usuário está disponível em vez dos tamanhos discretos, como Ícones e Miniaturas.
A interface IThumbnailProvider torna o fornecimento de uma miniatura mais simples do que o IExtractImage ou IExtractImage2 mais antigo. Observe, no entanto, que o código existente que usa IExtractImage ou IExtractImage2 ainda é válido e tem suporte.
O exemplo RecipeThumbnailProvider
O exemplo RecipeThumbnailProvider dissecado nesta seção está incluído no SDK (Software Development Kit) do Windows. Seu local de instalação padrão é C:\Arquivos de Programas\Microsoft SDKs\Windows\v6.0\Samples\WinUI\Shell\AppShellIntegration\RecipeThumbnailProvider. No entanto, a maior parte do código também está incluída aqui.
O exemplo RecipeThumbnailProvider demonstra a implementação de um manipulador de miniaturas para um novo tipo de arquivo registrado com uma extensão .recipe. O exemplo ilustra o uso das diferentes APIs do manipulador de miniaturas para registrar servidores COM (Component Object Model) de extração em miniatura para tipos de arquivo personalizados. Este tópico orienta você pelo código de exemplo, destacando as opções e diretrizes de codificação.
Um manipulador de miniaturas deve sempre implementar IThumbnailProvider em conjunto com uma destas interfaces:
Há casos em que a inicialização com fluxos não é possível. Em cenários em que o manipulador de miniaturas não implementa IInitializeWithStream, ele deve recusar a execução no processo isolado em que o indexador do sistema o coloca por padrão quando há uma alteração no fluxo. Para recusar o recurso de isolamento do processo, defina o seguinte valor do Registro.
HKEY_CLASSES_ROOT
CLSID
{The CLSID of your thumbnail handler}
DisableProcessIsolation = 1
Se você implementar IInitializeWithStream e fizer uma inicialização baseada em fluxo, seu manipulador será mais seguro e confiável. Normalmente, desabilitar o isolamento do processo destina-se apenas a manipuladores herdados; evite desabilitar esse recurso para qualquer novo código. IInitializeWithStream deve ser sua primeira opção de interface de inicialização sempre que possível.
Como o arquivo de imagem no exemplo não está inserido no arquivo .recipe e não faz parte de seu fluxo de arquivos, IInitializeWithItem é usado na amostra. A implementação do método IInitializeWithItem::Initialize simplesmente passa seus parâmetros para variáveis de classe privada.
IThumbnailProvider tem apenas um método, GetThumbnail, que é chamado com o maior tamanho desejado da imagem, em pixels. Embora o parâmetro seja chamado de cx, seu valor é usado como o tamanho máximo das dimensões x e y da imagem. Se a miniatura recuperada não for quadrada, o eixo mais longo será limitado por cx e a taxa de proporção da imagem original será preservada.
Quando retorna, GetThumbnail fornece um identificador para a imagem recuperada. Ele também fornece um valor que indica o formato de cor da imagem e se ela tem informações alfa válidas.
A implementação getThumbnail no exemplo começa com uma chamada para o método de _GetBase64EncodedImageString privado.
IFACEMETHODIMP CRecipeThumbProvider::GetThumbnail(UINT cx,
HBITMAP *phbmp,
WTS_ALPHATYPE *pdwAlpha)
{
PWSTR pszBase64EncodedImageString;
HRESULT hr = _GetBase64EncodedImageString(cx, &pszBase64EncodedImageString);
O tipo de arquivo .recipe é simplesmente um arquivo XML registrado como uma extensão de nome de arquivo exclusivo. Ele inclui um elemento chamado Imagem que fornece o caminho relativo e o nome do arquivo da imagem a ser usado como miniatura para este arquivo .recipe específico. O elemento Picture consiste no atributo Source que especifica uma imagem codificada em base 64 e um atributo Size opcional.
O tamanho tem dois valores, Pequeno e Grande. Isso permite que você forneça vários nós de imagem com imagens separadas. A imagem recuperada depende do valor de tamanho máximo (cx) fornecido na chamada para GetThumbnail. Como o Windows nunca dimensiona a imagem maior que seu tamanho máximo, imagens diferentes podem ser fornecidas para resoluções diferentes. No entanto, para simplificar, o exemplo omite o atributo Size e fornece apenas uma imagem para todas as situações.
O método _GetBase64EncodedImageString , cuja implementação é mostrada aqui, usa APIs do DOM (Modelo de Objeto de Documento XML) para recuperar o nó Imagem . Desse nó, ele extrai a imagem dos dados do atributo 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 passa a cadeia de caracteres recuperada para _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);
O método _GetStreamFromString , cuja implementação é mostrada aqui, que converte a imagem codificada em um fluxo.
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 usa APIs do WIC (Componente de Imagem do Windows) para extrair um bitmap do fluxo e obter um identificador para esse bitmap. As informações alfa são definidas, WIC é corretamente encerrado e o método termina com êxito.
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;
}
Tópicos relacionados