CoCreateInstance調用返回代碼0x80040154的一種解決方法


引言

      前面的一篇博文中總結了開發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了。

參考鏈接

  1. http://stackoverflow.com/questions/16697112/why-using-wic-in-my-32-bit-application-fails-in-windows-7-32-bit

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM