サムネイル ハンドラーの構築

Windows Vista の時点では、以前のバージョンの Windows よりもファイル固有のサムネイル 画像が大きく使用されています。 これらは、すべてのビュー、ダイアログ、およびそれらを提供する任意のファイルの種類で使用されます。 サムネイルの表示も変更されました。 アイコンやサムネイルなどの個別のサイズではなく、ユーザーが選択できるサイズの連続したスペクトルを使用できます。

IThumbnailProvider インターフェイスを使用すると、古い IExtractImage または IExtractImage2 よりも簡単にサムネイルを提供できます。 ただし、IExtractImage または IExtractImage2使用する既存のコードは引き続き有効であり、サポートされていることに注意してください。

RecipeThumbnailProvider サンプル

このセクションで取り上げる RecipeThumbnailProvider サンプルは、Windows ソフトウェア開発キット (SDK) に含まれています。 既定のインストール場所は C:\Program Files\Microsoft SDKs\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 が 1 つだけあります。 パラメーターの名前は 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 ファイルです。 この特定の .recipe ファイルのサムネイルとして使用する画像の相対パスとファイル名を提供する Picture という要素が含まれています。 Picture 要素は、Base 64 でエンコードされたイメージを指定する Source 属性と、オプションの Size 属性で構成されます。

Size には、Small と Large の 2 つの値があります。 これにより、複数の Picture ノードに個別のイメージを提供できます。 取得されるイメージは、GetThumbnail の呼び出しで提供される最大サイズ値 (cx) に依存します。 Windows ではイメージのサイズが最大サイズを超えることはありませんので、解像度ごとに異なるイメージを提供できます。 ただし、わかりやすくするために、このサンプルでは Size 属性を省略し、すべての状況に対して 1 つのイメージのみを提供します。

実装をここに示す _GetBase64EncodedImageString メソッドは、XML ドキュメント オブジェクト モデル (DOM) API を使用して Picture ノードを取得します。 そのノードから 、ソース 属性データからイメージを抽出します。

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 は Windows Imaging Component (WIC) API を使用してストリームからビットマップを抽出し、そのビットマップへのハンドルを取得します。 アルファ情報が設定され、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