简述ATL Default Com中用到的几个宏(AC4)

本文解析了ATL中用于创建COM对象的关键宏,包括OBJECT_ENTRY_AUTO、DECLARE_REGISTRY_RESOURCEID等,介绍了它们如何帮助实现COM类工厂及COM对象的创建过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  AC4,由VS2005的ATL向导生成的默认COM对象代码分析ATL如何实现COM,第四部分。

  ATL中的宏很多,我看代码有个不太喜欢拆开宏的习惯,在没分析这些宏的时候,总觉得见了不少树木却不见树林,现在才明白,ATL中的宏宛如手术刀一样切入了各个类的内部,而且不少宏充当了ATL骨架的功能。所以如果要看ms vs appwizzard生成的代码,一定要先研究用到的宏。

  相对来说宏还是很容易的,展开就能看个透彻,我单写一部分说宏并不是要把ATL的宏详细分析,相反,我只几个而且是简述,因为我接下来要说com对象(com类厂)的创建过程,用到的几个函数都是宏实现的,如果不先了解这几个宏就不太容易弄明白。

  第一:OBJECT_ENTRY_AUTO(__uuidof(XXX), XXX),这个宏我之前已经展开说了,它把创建COM类厂、COM对象需要的一些东西“固化”在了二进制文件的特定位置。

  第二:DECLARE_REGISTRY_RESOURCEID(IDR_XXX):定义了函数: static HRESULT WINAPI UpdateRegistry(BOOL bRegister) throw() 该函数正是对_ATL_OBJMAP_ENTRY结构赋值的的第二个参数。

  第三:DECLARE_CLASSFACTORY() ,这个宏通过typedef指明了类型: _ClassFactoryCreatorClass 该类型在对_ATL_OBJMAP_ENTRY结构赋值时被第三个参数使用。该类型实际是: CComCreator< CComObjectCached < CComClassFactory > > CComCreator只有一个方法 static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv) 这正是我们在赋值的时候指明需要的。看typedef就知道,该方法就是大名鼎鼎的,可以生成classfactory的方法,该方法内部new出了CComObjectCached<CComClassFactory>,其实CComObjectCached继承自它的模板类也就是CComClassFactory,可以认为是XXX:: _ClassFactoryCreatorClass::CreateInstance创建了类工厂CComClassFactory,CComClassFactory就是IClassFacotry的一个实现。但这里,CComObjectCached的CreateInstance是静态的,这很微妙(CComClassFactory的CreateInstance方法反而不是静态的),也就是说在类工厂被创建前,类工厂(CComClassFactory)的CreateInstance是不能被使用的。(这没有任何问题,com库创建com对象确实是使用类厂指针调用的CreateInstance。)

  第四:DECLARE_AGGREGATABLE(XXX) ,这个宏typedef了一个_CreatorClass类型,该类型在_ATL_OBJMAP_ENTRY结构赋值时被第四个参数使用。这和第三点非常相似。事实上,这两个宏确实有类似之处,也有共通之处。 CreatorClass的实际类型是: CComCreator2< CComCreator < CComObject < XXX > >,CComCreator< CComAggObject < XXX > > >; 该类型的静态的CreateInstance在CComCreator2中被定义,由名字可以看出,该方法只是一个简单的聚合,该类的功能是创建com对象,CreateInstance也是简单地向带个模板参数(也就是两个CComCreate,根据pOuter信息选择一个)传递CreateInstance调用。 前面已经说过了,CoCreator创建了模板对象,并进行了简单的初始化。 CComObject是整个继承链的最末端,也就说说,用户得到的com对象其实就是CComObject,只不过这个CComObject中的某些功能被我们通过他的基类定制了。 CComObject完整满足了COM规范需求,他的AddRef、Release方法使用了基类XXX的方法,我们已经知道,这最终来自CComObjectRootEx,而QueryInterface交给了基类的_InternalQueryInterface方法。 CComAggObject从名字上就可以推测它是做对象聚合的时候接口转发的,它内部保存了CComContainedObject<XXX> m_contained;指针,所有QI转发由CComContainerObject完成,而m_contained其实就是pOuter。

  第五:BEGIN_COM_MAP(CMeee)系列 这个系列宏有: BEGIN_COM_MAP(XXX) COM_INTERFACE_ENTRY(IXXX) COM_INTERFACE_ENTRY(IDispatch) END_COM_MAP() 前面我们已经提到了CComObject会使用基类的_InternalQueryInterface方法,这组宏就是该方法被声明的地方。 被定义的方法有: static HRESULT WINAPI _Cache(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw) throw() IUnknown* _GetRawUnknown() throw() HRESULT _InternalQueryInterface(REFIID iid, void** ppvObject) throw() const static ATL::_ATL_INTMAP_ENTRY* WINAPI _GetEntries() throw() 并在_GetEntries内部定义了QI关心的类型宏。

  第六:COM_INTERFACE_ENTRY_AGGREGATE,该宏用在需要声明接口内聚的情况时。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值