建置縮圖處理常式
從 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元素是由Source屬性所組成,指定基底 64 編碼影像,以及選擇性的 Size屬性。
Size 有兩個值:Small 和 Large。 這可讓您提供具有不同影像的多個 圖片 節點。 然後擷取的映射取決於呼叫GetThumbnail中提供的cx) 大小上限 (值。 因為 Windows 永遠不會調整影像大小超過其大小上限,所以可以針對不同的解析度提供不同的影像。 不過,為了簡單起見,此範例會省略 Size 屬性,並針對所有情況只提供一個影像。
此處顯示的 _GetBase64EncodedImageString 方法會使用 XML 檔物件模型 (DOM) API 來擷取 圖片 節點。 從該節點,它會從 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 接著會將擷取的字串傳遞至 _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;
}
相關主題