引言
前面的一篇博文中總結了開發Windows Thumbnail Handler的一些經驗。在公司實際項目中,需要同時針對圖片和視頻實現縮略圖。同時還要在圖片和視頻文件的頂部加上LOGO。像如下這樣的:

於是考慮了一下實現方案:
(1)LOGO資源采用Base64編碼編譯到DLL中去
(2)公司自有的圖片和視頻文件進行全景拼接時依賴一串參數,而這串參數需要從文件中提取。因此采用
RecipeThumbnailProvider實現
IInitializeWithFile接口比較合適,這樣能得到文件路徑,具備更靈活的可操作性。
(3)LOGO資源使用Windows自帶的解碼庫來進行解碼,也就是Windows Image Component(
WIC).
這么一思考,還是挺靠譜的。於是就動手開始編碼,編寫了一個解碼LOGO資源的函數:
/**
* Decode the Base64-encoded string to get logo resources.
*/
HRESULT RecipeThumbnailProvider::GetLogoFromString(LPCWSTR encodedString, UINT* width, UINT* height, PBYTE* rawPixels)
{
IStream* pImageStream = NULL;
HRESULT hr = E_FAIL;
DWORD dwDecodedImageSize = 0;
DWORD dwSkipChars = 0;
DWORD dwActualFormat = 0;
if (CryptStringToBinary(encodedString, NULL, CRYPT_STRING_BASE64, NULL, &dwDecodedImageSize, &dwSkipChars, &dwActualFormat))
{
BYTE* pbDecodedImage = static_cast<BYTE*>(LocalAlloc(LPTR, dwDecodedImageSize));
if (pbDecodedImage)
{
if (CryptStringToBinary(encodedString, lstrlen(encodedString), CRYPT_STRING_BASE64, pbDecodedImage, &dwDecodedImageSize, &dwSkipChars, &dwActualFormat))
{
pImageStream = SHCreateMemStream(pbDecodedImage, dwDecodedImageSize);
if (pImageStream != NULL)
{
IWICImagingFactory* pImageFactory;
hr = CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pImageFactory));
LOGINFO(L"CoCreateIntance() returns 0x%x", hr);
if (SUCCEEDED(hr))
{
IWICBitmapDecoder* pDecoder;
hr = pImageFactory->CreateDecoderFromStream(pImageStream, &GUID_VendorMicrosoft, WICDecodeMetadataCacheOnDemand, &pDecoder);
if (SUCCEEDED(hr))
{
IWICBitmapFrameDecode* pBitmapFrameDecode;
hr = pDecoder->GetFrame(0, &pBitmapFrameDecode);
if (SUCCEEDED(hr))
{
IWICBitmapSource* pBitmapSourceConverted = NULL;
WICPixelFormatGUID guidPixelFormatSource;
hr = pBitmapFrameDecode->GetPixelFormat(&guidPixelFormatSource);
if (SUCCEEDED(hr) && (guidPixelFormatSource != GUID_WICPixelFormat24bppBGR))
{
IWICFormatConverter* pFormatConverter;
hr = pImageFactory->CreateFormatConverter(&pFormatConverter);
if (SUCCEEDED(hr))
{
hr = pFormatConverter->Initialize(pBitmapFrameDecode, GUID_WICPixelFormat24bppBGR, WICBitmapDitherTypeNone, NULL, 0, WICBitmapPaletteTypeCustom);
if (SUCCEEDED(hr))
{
hr = pFormatConverter->QueryInterface(&pBitmapSourceConverted);
}
pFormatConverter->Release();
}
}
else
{
hr = pBitmapFrameDecode->QueryInterface(&pBitmapSourceConverted);
}
if (SUCCEEDED(hr))
{
hr = pBitmapSourceConverted->GetSize(width, height);
if (SUCCEEDED(hr))
{
WICRect rect = { 0, 0, *width, *height };
*rawPixels = static_cast<BYTE*>(LocalAlloc(LPTR, (*width)*(*height)*3));
hr = pBitmapSourceConverted->CopyPixels(&rect, (*width) * 3, (*width)*(*height) * 3, *rawPixels);
}
else
{
*width = 0;
*height = 0;
*rawPixels = NULL;
}
pBitmapSourceConverted->Release();
}
pBitmapFrameDecode->Release();
}
pDecoder->Release();
}
pImageFactory->Release();
}
pImageStream->Release();
}
}
}
LocalFree(pbDecodedImage);
}
return hr;
}
當我注冊好COM組件開始使用時,在本機上測試簡直完美。滿以為就這么搞定了,然而並么有。在另外一台Win7機器上測試時,縮略圖中並沒有出現想象中的LOGO。一看日志文件,發現一直在報:CoCreateInstance()調用返回0x80040154。於是下面的代碼都沒執行,LOGO資源自然沒有加載成功了。那么CoCreateInstance()為啥會返回0x80040154呢?這個代碼又意味着什么嗯?從網上的搜索結果來看,0x80040154是表示"Class Not Registered"。也就是說COM類並沒有注冊,在注冊表\HKEY_CLASSES_ROOT\CLSID\下面也就沒有類ID了。我們程序中使用了WIC組件來解碼圖片,那么難道是WIC組件類沒有注冊嗎?
再一想,開發時采用的一直是Windows10,可以正常運行。到了Windows7上為啥就不行了呢?難道是WIC在Windows7上不支持?這個懷疑顯然是不成立的,從MSDN上來看從XP SP2就開始支持了啊:
那么難道是參數給的不對?以CLSID_WICImagingFactory為關鍵字一搜索果然搜到了
一篇帖子:
CLSID_WICImagingFactory在Windows10上被解析為了
CLSID_WICImagingFactory2:
而這個GUID在Windows7上是不存在的(搜索注冊表即可看到結果):
自然CoCreateInstance()調用就會返回0x80040154了。解決方案就是傳遞
CLSID_WICImagingFactory1給CoCreateInstance()。這樣就能同時兼容Windows10和Windows7了。
參考鏈接
