Partager via


Génération de gestionnaires de miniatures

À partir de Windows Vista, les images miniatures spécifiques aux fichiers sont davantage utilisées que dans les versions antérieures de Windows. Ils sont utilisés dans toutes les vues, dans les boîtes de dialogue et pour tout type de fichier qui les fournit. L’affichage des miniatures a également été modifié. Un spectre continu de tailles sélectionnables par l’utilisateur est disponible plutôt que les tailles discrètes telles que les icônes et les miniatures.

L’interface IThumbnailProvider rend la fourniture d’une miniature plus simple que l’ancienne IExtractImage ou IExtractImage2. Notez toutefois que le code existant qui utilise IExtractImage ou IExtractImage2 est toujours valide et pris en charge.

Exemple RecipeThumbnailProvider

L’exemple RecipeThumbnailProvider disséqué dans cette section est inclus dans le Kit de développement logiciel (SDK) Windows. Son emplacement d’installation par défaut est C:\Program Files\Microsoft SDKs\Windows\v6.0\Samples\WinUI\Shell\AppShellIntegration\RecipeThumbnailProvider. Toutefois, la majeure partie du code est également incluse ici.

L’exemple RecipeThumbnailProvider illustre l’implémentation d’un gestionnaire de miniatures pour un nouveau type de fichier inscrit avec une extension .recipe. L’exemple illustre l’utilisation des différentes API de gestionnaire de miniatures pour inscrire des serveurs COM (Component Object Model) d’extraction de miniatures pour les types de fichiers personnalisés. Cette rubrique vous guide tout au long de l’exemple de code, en mettant en évidence les choix et les recommandations en matière de codage.

Un gestionnaire de miniatures doit toujours implémenter IThumbnailProvider de concert avec l’une de ces interfaces :

Il existe des cas où l’initialisation avec des flux n’est pas possible. Dans les scénarios où votre gestionnaire de miniatures n’implémente pas IInitializeWithStream, il doit refuser l’exécution dans le processus isolé où l’indexeur système le place par défaut en cas de modification du flux. Pour désactiver la fonctionnalité d’isolation des processus, définissez la valeur de Registre suivante.

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

Si vous implémentez IInitializeWithStream et effectuez une initialisation basée sur un flux, votre gestionnaire est plus sécurisé et plus fiable. En règle générale, la désactivation de l’isolation des processus est uniquement destinée aux gestionnaires hérités ; évitez de désactiver cette fonctionnalité pour tout nouveau code. IInitializeWithStream doit être votre premier choix d’interface d’initialisation dans la mesure du possible.

Étant donné que le fichier image de l’exemple n’est pas incorporé dans le fichier .recipe et ne fait pas partie de son flux de fichier, IInitializeWithItem est utilisé dans l’exemple. L’implémentation de la méthode IInitializeWithItem::Initialize transmet simplement ses paramètres à des variables de classe privée.

IThumbnailProvider n’a qu’une seule méthode, GetThumbnail, appelée avec la plus grande taille souhaitée de l’image, en pixels. Bien que le paramètre soit nommé cx, sa valeur est utilisée comme taille maximale des dimensions x et y de l’image. Si la miniature récupérée n’est pas carrée, l’axe le plus long est limité par cx et les proportions de l’image d’origine sont conservées.

Quand elle retourne, GetThumbnail fournit un handle à l’image récupérée. Il fournit également une valeur qui indique le format de couleur de l’image et si elle contient des informations alpha valides.

L’implémentation GetThumbnail dans l’exemple commence par un appel à la méthode _GetBase64EncodedImageString privée.

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

Le type de fichier .recipe est simplement un fichier XML inscrit en tant qu’extension de nom de fichier unique. Il inclut un élément appelé Picture qui fournit le chemin d’accès relatif et le nom de fichier de l’image à utiliser comme miniature pour ce fichier .recipe particulier. L’élément Picture se compose de l’attribut Source qui spécifie une image encodée en base 64 et d’un attribut Size facultatif.

Size a deux valeurs, Small et Large. Cela vous permet de fournir plusieurs nœuds Picture avec des images distinctes. L’image récupérée dépend ensuite de la valeur de taille maximale (cx) fournie dans l’appel à GetThumbnail. Étant donné que Windows ne dimensionne jamais l’image au-dessous de sa taille maximale, différentes images peuvent être fournies pour différentes résolutions. Toutefois, par souci de simplicité, l’exemple omet l’attribut Size et ne fournit qu’une seule image pour toutes les situations.

La méthode _GetBase64EncodedImageString , dont l’implémentation est illustrée ici, utilise les API DOM (Document Object Model) XML pour récupérer le nœud Image . À partir de ce nœud, il extrait l’image des données de l’attribut 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 transmet ensuite la chaîne récupérée à _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);

Méthode _GetStreamFromString , dont l’implémentation est illustrée ici, qui convertit l’image encodée en flux.

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 utilise ensuite les API WIC (Windows Imaging Component) pour extraire une bitmap du flux et obtenir un handle pour cette bitmap. Les informations alpha sont définies, WIC est correctement arrêté et la méthode se termine correctement.

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

Gestionnaires de miniatures

Instructions relatives aux gestionnaires de miniatures

IID_PPV_ARGS