Compilazione di gestori di anteprime

A partire da Windows Vista, un uso maggiore è costituito da immagini di anteprima specifiche del file rispetto alle versioni precedenti di Windows. Vengono usati in tutte le visualizzazioni, nelle finestre di dialogo e per qualsiasi tipo di file che le fornisce. È stata modificata anche la visualizzazione delle anteprime. È disponibile uno spettro continuo di dimensioni selezionabili dall'utente anziché le dimensioni discrete, ad esempio Icone e Anteprime.

L'interfaccia IThumbnailProvider rende l'anteprima più semplice rispetto alla precedente IExtractImage o IExtractImage2. Si noti, tuttavia, che il codice esistente che usa IExtractImage o IExtractImage2 è ancora valido e supportato.

Esempio RecipeThumbnailProvider

L'esempio RecipeThumbnailProvider analizzato in questa sezione è incluso in Windows Software Development Kit (SDK). Il percorso di installazione predefinito è C:\Programmi\Microsoft SDKs\Windows\v6.0\Samples\WinUI\Shell\AppShellIntegration\RecipeThumbnailProvider. Tuttavia, anche la maggior parte del codice è inclusa qui.

L'esempio RecipeThumbnailProvider illustra l'implementazione di un gestore di anteprima per un nuovo tipo di file registrato con estensione recipe. L'esempio illustra l'uso delle diverse API del gestore di anteprima per registrare i server COM (Thumbnail Extraction Component Object Model) per i tipi di file personalizzati. Questo argomento illustra il codice di esempio, evidenziando le scelte di codifica e le linee guida.

Un gestore di anteprima deve sempre implementare IThumbnailProvider insieme a una di queste interfacce:

In alcuni casi l'inizializzazione con flussi non è possibile. Negli scenari in cui il gestore dell'anteprima non implementa IInitializeWithStream, deve rifiutare esplicitamente l'esecuzione nel processo isolato in cui l'indicizzatore di sistema lo inserisce per impostazione predefinita quando viene apportata una modifica al flusso. Per rifiutare esplicitamente la funzionalità di isolamento del processo, impostare il valore del Registro di sistema seguente.

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

Se si implementa IInitializeWithStream ed si esegue un'inizializzazione basata su flusso, il gestore è più sicuro e affidabile. In genere, la disabilitazione dell'isolamento dei processi è destinata solo ai gestori legacy; evitare di disabilitare questa funzionalità per qualsiasi nuovo codice. IInitializeWithStream deve essere la prima scelta dell'interfaccia di inizializzazione quando possibile.

Poiché il file di immagine nell'esempio non è incorporato nel file con estensione recipe e non fa parte del flusso di file, nell'esempio viene usato IInitializeWithItem . L'implementazione del metodo IInitializeWithItem::Initialize passa semplicemente i parametri alle variabili di classe private.

IThumbnailProvider ha un solo metodo, GetThumbnail, chiamato con le dimensioni desiderate più grandi dell'immagine, in pixel. Anche se il parametro è denominato cx, il relativo valore viene usato come dimensione massima delle dimensioni x e y dell'immagine. Se l'anteprima recuperata non è quadrata, l'asse più lungo è limitato da cx e le proporzioni dell'immagine originale vengono mantenute.

Quando viene restituito, GetThumbnail fornisce un handle all'immagine recuperata. Fornisce anche un valore che indica il formato di colore dell'immagine e se contiene informazioni alfa valide.

L'implementazione GetThumbnail nell'esempio inizia con una chiamata al metodo _GetBase64EncodedImageString privato.

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

Il tipo di file .recipe è semplicemente un file XML registrato come estensione di file univoca. Include un elemento denominato Picture che fornisce il percorso relativo e il nome file dell'immagine da usare come anteprima per questo particolare file con estensione recipe. L'elemento Picture è costituito dall'attributo Source che specifica un'immagine con codifica base 64 e un attributo Size facoltativo.

Size ha due valori, Small e Large. In questo modo è possibile fornire più nodi Immagine con immagini separate. L'immagine recuperata dipende quindi dal valore di dimensione massima (cx) fornito nella chiamata a GetThumbnail. Poiché Windows non ridimensiona mai l'immagine più grande della dimensione massima, è possibile fornire immagini diverse per risoluzioni diverse. Tuttavia, per semplicità, l'esempio omette l'attributo Size e fornisce una sola immagine per tutte le situazioni.

Il metodo _GetBase64EncodedImageString , la cui implementazione è illustrata di seguito, usa le API DOM (Document Object Model) XML per recuperare il nodo Picture . Da tale nodo estrae l'immagine dai dati dell'attributo 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 quindi la stringa recuperata a _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);

Il metodo _GetStreamFromString , la cui implementazione è illustrata di seguito, che converte l'immagine codificata in un flusso.

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 quindi le API Windows Imaging Component (WIC) per estrarre una bitmap dal flusso e ottenere un handle per tale bitmap. Le informazioni alfa sono impostate, WIC viene chiuso correttamente e il metodo termina correttamente.

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;
}

Gestori di anteprime

Linee guida per il gestore delle anteprime

IID_PPV_ARGS