建置縮圖處理程式
從 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,其功能是以像素表示的影像最大期望大小進行呼叫。 雖然 參數名為 cx,但其值會當做影像 x 和 y 維度的大小上限使用。 如果擷取的縮圖不是正方形,則較長的軸會受限於 cx,並保留原始影像的外觀比例。
傳回時,GetThumbnail 會提供所擷取映射的句柄。 它也提供值,指出影像的色彩格式,以及其是否具有有效的 Alpha 資訊。
範例中的 GetThumbnail 實作會從呼叫私用 _GetBase64EncodedImageString 方法開始。
IFACEMETHODIMP CRecipeThumbProvider::GetThumbnail(UINT cx,
HBITMAP *phbmp,
WTS_ALPHATYPE *pdwAlpha)
{
PWSTR pszBase64EncodedImageString;
HRESULT hr = _GetBase64EncodedImageString(cx, &pszBase64EncodedImageString);
.recipe 文件類型只是註冊為唯一擴展名的 XML 檔案。 它包含名為 Picture 的元素,可提供影像的相對路徑和檔名,以作為這個特定 .recipe 檔案的縮圖。 Picture 元素包含指定 base 64 編碼影像的 Source 屬性,以及選擇性的 Size 屬性。
Size 有兩個值:Small 和 Large。 這可讓您提供具有不同影像的多個 圖片 節點。 擷取的映像依賴於呼叫 GetThumbnail時提供的大小上限值(cx)。 因為 Windows 絕不會調整影像大小,因此可以針對不同的解析度提供不同的影像。 不過,為了簡單起見,此範例會省略 Size 屬性,並且為所有情況只提供一個影像。
此處顯示的 _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 映像組件 (WIC) API 從數據流擷取位圖,並取得該位圖的控制代碼。 Alpha 信息已設定、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;
}