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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Android源码框架分析

Android进程保活-自“裁”或者耍流氓

本篇文章是后台杀死系列的最后一篇,主要探讨一下进程的保活,Android本身设计的时候是非常善良的,它希望进程在不可见或者其他一些场景下APP要懂得主动释放,可...

4761
来自专栏北京马哥教育

mysql分表,分区的区别和联系

一,什么是mysql分表,分区 什么是分表,从表面意思上看呢,就是把一张表分成N多个小表,具体请看mysql分表的3种方法 什么是分区,分区呢就是把一张表的数据...

3018
来自专栏杨建荣的学习笔记

关于奇怪的并行进程分析(一) (r6笔记第41天)

在使用orabbix进行监控的时候,得益于使用 实时DB time监控的选项,对于几分钟内的性能抖动也能够狠容易的记录下来,而且会把这个监控的结果基本真实反应出...

2877
来自专栏ShaoYL

iOS定位--CoreLocation框架

41210
来自专栏Jerry的SAP技术分享

SAP产品的Field Extensibility

SAP开发人员的工作职责,除了实现软件的功能性需求外,还会花费相当的精力实现一些非功能性需求,来满足所谓的SAP Product Standard(产品标准)。...

1141
来自专栏更流畅、简洁的软件开发方式

其实添加数据也可以这样简单——表单的第三步抽象(针对UI及后置代码)

终于赶出来了,现写了一遍代码。 感谢大家的支持,感谢大家提出自己的看法。衷心的感谢,真的。 应该是先写第二步的,但是想一想还是先写第三步吧。 一般大项目里...

2649
来自专栏FreeBuf

Cisco Linksys无线路由固件安全分析与后门研究

最近我对嵌入式设备安全方面比较感兴趣,所以我决定找点东西练练手,于是我在淘宝上搜了一下,发现Linksys WRT54Gv5无线路由比较流行,决定就拿这个下手了...

2865
来自专栏DeveWork

制作WordPress“带Gravatar头像评论”小工具(集成主题中、含选项)

最近在进一步折腾WordPress 主题的开发,在侧边栏小工具那里想做一个可独立于主题的、类似插件的带头像评论小工具。通过WordPress 官方文档与一些资料...

2165
来自专栏c#开发者

数据驱动开发For Silverlight WCF RIA1.0 三步曲

数据驱动开发For Silverlight WCF RIA1.0 三步曲 WCF RIA 1.0的正式发布,让Silverlight开发业务应用系统变得更加简...

2694
来自专栏张善友的专栏

WCF 性能基准报告

现在我能找到的关于WCF性能方面的文章主要有几个,一个是微软Connected Frameworks Team的Saurabh Gupta (PM)2007年初...

2009

扫码关注云+社区