ATL和MFC创建ActiveX控件的区别
1个回答
展开全部
ATL和MFC创建ActiveX控件的区别
在visual C++
6.0中,ATL和MFC代表了两种不同的框架,分别面向不同类型的基于Windows的开发。ATL提供了一种框架来实现创建COM客户机和服务器所必
须的样板文件代码;MFC代表了创建独立的Windows应用的一种简单、一致的方法。这两种框架都可以用来创建ActiveX控件。
ActiveX控件的完全形态
ActiveX控件基于构件对象模型COM,使得ActiveX控件成为可能的COM的基本原则是一个对象的接口和其实现能够而且应该分开对待。只要
COM的对象和它的客户方代码就接口细节达成了一致,如何实现就不成其问题。ActiveX控件展示了大量
ActiveX控件包容器理解的接口。因为客户方代码和控件认可这些接口的外在表现,你可以编写一个ActiveX控件然后简单的将它放入包容器中。包容
器将通过良好定义的接口来驱动控件,而这些控件将以自己的方式做出合适的响应。在更高的层次上,一个ActiveX控件是实现了几个主要ActiveX技
术的一个COM对象,包括通常的引入COM接口,OLE嵌入协议,连接点和属性页。在较低的编程层次上,ActiveX控件只是实现了某些类型接口的
COM类。当一些客户方代码成功的查询到这些接口之一时,它就知道如何使用一个ActiveX控件了。
一个ActiveX控件暴露的接口主要分为3类。第一,ActiveX控件是可嵌入的对象;就是说,它们实现了大多数的OLE文档、in-place激活和嵌入协议。ActiveX控件实现了如下的接口:
IOleObject, IPersistStorage, IDataObject, IOleInPlaceActiveObject,
IOleInPlaceObject, IViewObject2和IRunnableObject (这一个很少用到).
第二ActiveX控件通常都支持属性页,这样客户方就可以修改控件的属性了。最后,ActiveX控件通常都利用COM的连接点技术,实现了客户方能发
现的外出接口。
为了帮助比较ATL和MFC框架,我们来看一下写在每一种框架中的相同的控件。此控件监视创建它的线程上传递的消息流。消息流控件是一个很不错的例子,因
为它演示了一个ActiveX控件所有主要的方面,包括送入接口、外出接口,属性,永久性以及属性页。让我们从研究这两个框架提供的标准的COM支持开始
吧。
MFC的基本COM支持
Microsoft建立MFC使得开发Windows®应用程序比使用SDK容易多了。有了MFC,Microsoft接着增加了对即存框架的COM支
持。这意味着MFC的开发者在增加越来越多的函数时必须保持框架的完整。同时,Visual
C++®编译器那时还不支持模板,因此,它们不得不借助非模板的其它手段来将COM功能掺入它们的类中。Microsoft通过加入一些虚函数到
CcmdTarget类和一些宏中解决了这个问题,使得在MFC中实现COM接口有了可能。
MFC内部的COM支持从CcmdTarget开始,CcmdTarget类实现了Iunknown接口,还包括了一个用于引用计数的成员变量
(m_dwRef)以及用于实现IUnknown 的6个函数:: InternalAddRef, InternalRelease,
InternalQueryInterface, ExternalAddRef, ExternalRelease, 和
ExternalQueryInterface.。QueryInterface的两个版本——AddRef和Release支持COM聚合。
InternalAddRef,
InternalRelease和InternalQueryInterface完成引用计数和QueryInterface操作,而
ExternalAddRef, ExternalRelease和
ExternalQueryInterface代理控制聚合的对象(如果此对象参与聚合的话)。
MFC使用嵌套的类复合策略来实现COM接口。在MFC中,想实现COM
接口的类是从CcmdTarget中派生的。每个由CcmdTarget派生出的类实现的接口得到它自己的嵌套类。MFC使用宏
BEGIN_INTERFACE_PART和END_INTERFACE_PART来产生嵌套类。
最后,MFC实现了表驱动的QueryInterface。MFC的接口映射的工作机理同它的消息映射基本相同:
MFC的消息映射把一个Windows消息和一个C++类中的函数相联系;MFC的接口映射把一个接口的GUID和一个表示此接口的特定的vptr的地址
相联系。每个基于CcmdTarget的类实现COM接口通过更多的宏:DECLARE_INTERFACE_MAP,
BEGIN_INTERFACE_MAP, INTERFACE_PART,和 END_INTERFACE_MAP来增加一个接口映射。
为了理解这些宏在实际中是什么样子的,请看图1,它说明了实现ActiveX控件,COleControl
的MFC类。当你细读代码时,注意ColeControl带有夹在一对BEGIN_INTERFACE_PART 和
END_INTERFACE_PART宏之间的每个接口的签名,还要注意ColeControl的接口映射表有22个条目。
除了实现了Iunknown接口,MFC还包括IclassFactory的一个标准实现。再一次,MFC通过若干宏提供了此支持。MFC有两个宏来提供
类对象:DECLARE_OLECREATE_EX 和
IMPLEMENT_OLECREATE_EX.。在一个基于CcmdTarget的类中使用这些宏增加一个ColeObjectFactory类型的静
态成员到该类中。如果你看一下AFXDISP.H中 ColeObjectFactory的定义,你将会看到用在COleObjectFactory
中的MFC的嵌套类宏为实现IClassFactory2定义了一个嵌套类。IClassFactory::CreateInstance的MFC版本使
用MFC的动态创建机制(DECLARE_DYNCREATE
和 IMPLEMENT_DYNCREATE宏打开此功能)来实例化COM类,因此买入MFC的COM支持同样意味着买入它的动态创建机制。
最后几个由MFC提供的在ActiveX控件内的基本COM支持是对Idispatch的支持。用Visual C++ 和
MFC实现一个分发接口几乎是微不足道的。在MFC中实现一个分发接口,只需要使用ClassWizard就可以了。ClassWizard中的自动创建
板有一个按钮用于添加属性,另一个用于添加方法。在MFC中,Idispatch支持来自CcmdTarget类。IDispatch
的MFC的实际实现在一个叫做COleDispatchImpl
的类中,ColeDispatchImpl派生自Idispatch,实现了所有4个Idispatch函数:GetTypeInfoCount,
GetTypeInfo, GetIDsOfNames, 和
Invoke.。由CcmdTarget派生的类通过调用EnableAutomation,将IDispatch
vptr加入到它们的接口映射中。当客户在基于MFC的ActiveX控件上调用IDispatch
的QueryInterface时,CcmdTarget交出链接在ColeDispatchImpl上的vptr。
每次你使用ClassWizard将一个自动属性或者方法加入到一个类中时,你同时也在该类的分发映射表中加入了一项。一个分发映射表是一个将
DISPIDs(用来调用分发成员的符号)和它们的供人读的名字以及和实际完成这个工作的某些C++代码联系起来的简单的表格。
ColeDispatchImpl的调用以及GetIDsOfNames函数通过在类的分发映射表中查找分发成员并分发DISPID相对应的函数来工作。
MFC能为某些基于COM的高级技术如OLE文档、OLE拖放和自动操作提供非常好的支持,然而,如果你想更改框架——比如说,你想将分发接口编程双接口
的——你就得大动手脚了。另一方面,ATL更加是COM中心的。
ATL的基本的COM支持
ATL的目标是使开发者不必重写IUnknown, IDispatch,
IclassFactory和其它的分支以将常规的DLL和EXE变成基于COM的DLL和EXE。从这个角度讲,ATL是一个比MFC精简的多的框架,
它设计和生成时就考虑了COM支持。它使用基于模板的方法,通过继承ATL提供的模板,开发者可以加入各种COM功能片断。
ATL的原始COM支持是从对Iunknown的支持开始的。ATL的Iunknown实现分成两个部分:CcomObjectRootEx类,用来处理Iunknown部分的引用计数;CcomObjectRootBase类,用来处理QueryInterface。
CcomObjectRootEx是一个基于模板的类,将线性模型作为其唯一参数。这是一个真正有趣的说明ATL怎样使用模板将算法作为模板参数传递的例
子。ATL有两个处理引用计数的类,用于处理不同的线性模型: CComSingleThreadModel 和
CcomMultiThreadModel。这些类每个都有一个递增和一个递减函数。它们之间的区别是CcomSingleThreadModel用标准
C++操作符(++和——)实现递增和递减;而CcomMultiThreadModel使用线程安全的InterlockedIncrement
和
InterlockedDecrement函数来实现这两个功能。根据用来实例化CcomObjectRootEx的模板参数,它能正确的运行给定的组件
类型。你很快将会看到它的用法的一个例子。象MFC,ATL使用基于表的查找机制实现QueryInterface.。
CComObjectRootBase 通过一个接口映射处理类的QueryInterface函数。BEGIN_ COM_MAP 和
END_COM_MAP
宏定义了一个接口映射的开始和结束。然而,不像MFC,ATL提供了17种途径来组成一个接口映射,例如使用从ATL的基于模板的接口实现类如
IOleObjectImpl 来的vptrs。这包括了那些从tear-off 的类或者由聚合提供的类来的vptrs。
在ATL里,C++类通过继承CcomObjectRootEx,指定它们想用的组件模型(记住,MFC的Iunknown支持是内建在CcmdTarget中的)变成了COM类。
ATL的类对象(以及IClassFactory)支持也来自模板,而MFC的类对象支持通过
ColeObjectFactory和一些宏而有效。ATL的类对象支持来自CComCoClass/CcomClassFactory类家族和
CcomCreator类家族。CcomCoClass包含了类的GUID,定义了COM类的错误处理设施。CcomCreator类提供了
CreateInstance的实现,供CcomClassFactory使用。对于MFC,你可以通过若干宏,使所有这种支持有效。ATL包括
DECLARE_CLASS_FACTORY,
DECLARE_CLASS_ FACTORY2, DECLARE_CLASS_FACTORY_AUTO_THREAD, 以及
DECLARE_CLASS_FACTORY_SINGLETON等宏用来使各种具体的类工厂支持有效。
最后,ATL
对IDispatch的支持还来自模板类,——其名字是IDispatchImpl.。比起MFC的Idispatch支持来,ATL对
Idispatch的支持更加是COM中心的。MFC使用了一种hand-rolled
的IDispatch实现,而ATL使用更加标准的方法来加载一个接口的类型信息并代表标准的类型库编译器。
图2显示了一个标准的基于ATL的控件。最值得注意的一点是MFC和ATL各是怎样引入实现一个控件所需的必要的各种接口的。MFC对标准控件接口的支持
是内建在ColeControl类中的。你从ColeControl中派生出你的控件并且一次性继承所有的函数调用。注意ATL通过模板继承以零碎的方式
逐个引入每个功能片断。这是一个非常重要的差异,因为这意味着用ATL你可以忽略一些接口实现模板(例如,使你的控件更为精简)剥掉不希望的功能。对
MFC,你不能完成同样的动作——不管你想不想,你将获得所有接口。
关于例子应用
这里我将使用的例子是一个通过一个分支过程监控消息流的ActiveX控件,它实时的显示消息流图。这两个控件实际上有着相同的功能。它们都把图表提交到
屏幕。它们都带流入接口以便包容器能通知控件开始和停止该图表。它们都支持图表线的颜色和消息间隔长度作为属性而可以永久存在。最后,它们都支持缺省事件
集,将关于在一个特定时间段里处理的消息的数量通知包容器。图3显示了这两个控件。
可以看一下:
在visual C++
6.0中,ATL和MFC代表了两种不同的框架,分别面向不同类型的基于Windows的开发。ATL提供了一种框架来实现创建COM客户机和服务器所必
须的样板文件代码;MFC代表了创建独立的Windows应用的一种简单、一致的方法。这两种框架都可以用来创建ActiveX控件。
ActiveX控件的完全形态
ActiveX控件基于构件对象模型COM,使得ActiveX控件成为可能的COM的基本原则是一个对象的接口和其实现能够而且应该分开对待。只要
COM的对象和它的客户方代码就接口细节达成了一致,如何实现就不成其问题。ActiveX控件展示了大量
ActiveX控件包容器理解的接口。因为客户方代码和控件认可这些接口的外在表现,你可以编写一个ActiveX控件然后简单的将它放入包容器中。包容
器将通过良好定义的接口来驱动控件,而这些控件将以自己的方式做出合适的响应。在更高的层次上,一个ActiveX控件是实现了几个主要ActiveX技
术的一个COM对象,包括通常的引入COM接口,OLE嵌入协议,连接点和属性页。在较低的编程层次上,ActiveX控件只是实现了某些类型接口的
COM类。当一些客户方代码成功的查询到这些接口之一时,它就知道如何使用一个ActiveX控件了。
一个ActiveX控件暴露的接口主要分为3类。第一,ActiveX控件是可嵌入的对象;就是说,它们实现了大多数的OLE文档、in-place激活和嵌入协议。ActiveX控件实现了如下的接口:
IOleObject, IPersistStorage, IDataObject, IOleInPlaceActiveObject,
IOleInPlaceObject, IViewObject2和IRunnableObject (这一个很少用到).
第二ActiveX控件通常都支持属性页,这样客户方就可以修改控件的属性了。最后,ActiveX控件通常都利用COM的连接点技术,实现了客户方能发
现的外出接口。
为了帮助比较ATL和MFC框架,我们来看一下写在每一种框架中的相同的控件。此控件监视创建它的线程上传递的消息流。消息流控件是一个很不错的例子,因
为它演示了一个ActiveX控件所有主要的方面,包括送入接口、外出接口,属性,永久性以及属性页。让我们从研究这两个框架提供的标准的COM支持开始
吧。
MFC的基本COM支持
Microsoft建立MFC使得开发Windows®应用程序比使用SDK容易多了。有了MFC,Microsoft接着增加了对即存框架的COM支
持。这意味着MFC的开发者在增加越来越多的函数时必须保持框架的完整。同时,Visual
C++®编译器那时还不支持模板,因此,它们不得不借助非模板的其它手段来将COM功能掺入它们的类中。Microsoft通过加入一些虚函数到
CcmdTarget类和一些宏中解决了这个问题,使得在MFC中实现COM接口有了可能。
MFC内部的COM支持从CcmdTarget开始,CcmdTarget类实现了Iunknown接口,还包括了一个用于引用计数的成员变量
(m_dwRef)以及用于实现IUnknown 的6个函数:: InternalAddRef, InternalRelease,
InternalQueryInterface, ExternalAddRef, ExternalRelease, 和
ExternalQueryInterface.。QueryInterface的两个版本——AddRef和Release支持COM聚合。
InternalAddRef,
InternalRelease和InternalQueryInterface完成引用计数和QueryInterface操作,而
ExternalAddRef, ExternalRelease和
ExternalQueryInterface代理控制聚合的对象(如果此对象参与聚合的话)。
MFC使用嵌套的类复合策略来实现COM接口。在MFC中,想实现COM
接口的类是从CcmdTarget中派生的。每个由CcmdTarget派生出的类实现的接口得到它自己的嵌套类。MFC使用宏
BEGIN_INTERFACE_PART和END_INTERFACE_PART来产生嵌套类。
最后,MFC实现了表驱动的QueryInterface。MFC的接口映射的工作机理同它的消息映射基本相同:
MFC的消息映射把一个Windows消息和一个C++类中的函数相联系;MFC的接口映射把一个接口的GUID和一个表示此接口的特定的vptr的地址
相联系。每个基于CcmdTarget的类实现COM接口通过更多的宏:DECLARE_INTERFACE_MAP,
BEGIN_INTERFACE_MAP, INTERFACE_PART,和 END_INTERFACE_MAP来增加一个接口映射。
为了理解这些宏在实际中是什么样子的,请看图1,它说明了实现ActiveX控件,COleControl
的MFC类。当你细读代码时,注意ColeControl带有夹在一对BEGIN_INTERFACE_PART 和
END_INTERFACE_PART宏之间的每个接口的签名,还要注意ColeControl的接口映射表有22个条目。
除了实现了Iunknown接口,MFC还包括IclassFactory的一个标准实现。再一次,MFC通过若干宏提供了此支持。MFC有两个宏来提供
类对象:DECLARE_OLECREATE_EX 和
IMPLEMENT_OLECREATE_EX.。在一个基于CcmdTarget的类中使用这些宏增加一个ColeObjectFactory类型的静
态成员到该类中。如果你看一下AFXDISP.H中 ColeObjectFactory的定义,你将会看到用在COleObjectFactory
中的MFC的嵌套类宏为实现IClassFactory2定义了一个嵌套类。IClassFactory::CreateInstance的MFC版本使
用MFC的动态创建机制(DECLARE_DYNCREATE
和 IMPLEMENT_DYNCREATE宏打开此功能)来实例化COM类,因此买入MFC的COM支持同样意味着买入它的动态创建机制。
最后几个由MFC提供的在ActiveX控件内的基本COM支持是对Idispatch的支持。用Visual C++ 和
MFC实现一个分发接口几乎是微不足道的。在MFC中实现一个分发接口,只需要使用ClassWizard就可以了。ClassWizard中的自动创建
板有一个按钮用于添加属性,另一个用于添加方法。在MFC中,Idispatch支持来自CcmdTarget类。IDispatch
的MFC的实际实现在一个叫做COleDispatchImpl
的类中,ColeDispatchImpl派生自Idispatch,实现了所有4个Idispatch函数:GetTypeInfoCount,
GetTypeInfo, GetIDsOfNames, 和
Invoke.。由CcmdTarget派生的类通过调用EnableAutomation,将IDispatch
vptr加入到它们的接口映射中。当客户在基于MFC的ActiveX控件上调用IDispatch
的QueryInterface时,CcmdTarget交出链接在ColeDispatchImpl上的vptr。
每次你使用ClassWizard将一个自动属性或者方法加入到一个类中时,你同时也在该类的分发映射表中加入了一项。一个分发映射表是一个将
DISPIDs(用来调用分发成员的符号)和它们的供人读的名字以及和实际完成这个工作的某些C++代码联系起来的简单的表格。
ColeDispatchImpl的调用以及GetIDsOfNames函数通过在类的分发映射表中查找分发成员并分发DISPID相对应的函数来工作。
MFC能为某些基于COM的高级技术如OLE文档、OLE拖放和自动操作提供非常好的支持,然而,如果你想更改框架——比如说,你想将分发接口编程双接口
的——你就得大动手脚了。另一方面,ATL更加是COM中心的。
ATL的基本的COM支持
ATL的目标是使开发者不必重写IUnknown, IDispatch,
IclassFactory和其它的分支以将常规的DLL和EXE变成基于COM的DLL和EXE。从这个角度讲,ATL是一个比MFC精简的多的框架,
它设计和生成时就考虑了COM支持。它使用基于模板的方法,通过继承ATL提供的模板,开发者可以加入各种COM功能片断。
ATL的原始COM支持是从对Iunknown的支持开始的。ATL的Iunknown实现分成两个部分:CcomObjectRootEx类,用来处理Iunknown部分的引用计数;CcomObjectRootBase类,用来处理QueryInterface。
CcomObjectRootEx是一个基于模板的类,将线性模型作为其唯一参数。这是一个真正有趣的说明ATL怎样使用模板将算法作为模板参数传递的例
子。ATL有两个处理引用计数的类,用于处理不同的线性模型: CComSingleThreadModel 和
CcomMultiThreadModel。这些类每个都有一个递增和一个递减函数。它们之间的区别是CcomSingleThreadModel用标准
C++操作符(++和——)实现递增和递减;而CcomMultiThreadModel使用线程安全的InterlockedIncrement
和
InterlockedDecrement函数来实现这两个功能。根据用来实例化CcomObjectRootEx的模板参数,它能正确的运行给定的组件
类型。你很快将会看到它的用法的一个例子。象MFC,ATL使用基于表的查找机制实现QueryInterface.。
CComObjectRootBase 通过一个接口映射处理类的QueryInterface函数。BEGIN_ COM_MAP 和
END_COM_MAP
宏定义了一个接口映射的开始和结束。然而,不像MFC,ATL提供了17种途径来组成一个接口映射,例如使用从ATL的基于模板的接口实现类如
IOleObjectImpl 来的vptrs。这包括了那些从tear-off 的类或者由聚合提供的类来的vptrs。
在ATL里,C++类通过继承CcomObjectRootEx,指定它们想用的组件模型(记住,MFC的Iunknown支持是内建在CcmdTarget中的)变成了COM类。
ATL的类对象(以及IClassFactory)支持也来自模板,而MFC的类对象支持通过
ColeObjectFactory和一些宏而有效。ATL的类对象支持来自CComCoClass/CcomClassFactory类家族和
CcomCreator类家族。CcomCoClass包含了类的GUID,定义了COM类的错误处理设施。CcomCreator类提供了
CreateInstance的实现,供CcomClassFactory使用。对于MFC,你可以通过若干宏,使所有这种支持有效。ATL包括
DECLARE_CLASS_FACTORY,
DECLARE_CLASS_ FACTORY2, DECLARE_CLASS_FACTORY_AUTO_THREAD, 以及
DECLARE_CLASS_FACTORY_SINGLETON等宏用来使各种具体的类工厂支持有效。
最后,ATL
对IDispatch的支持还来自模板类,——其名字是IDispatchImpl.。比起MFC的Idispatch支持来,ATL对
Idispatch的支持更加是COM中心的。MFC使用了一种hand-rolled
的IDispatch实现,而ATL使用更加标准的方法来加载一个接口的类型信息并代表标准的类型库编译器。
图2显示了一个标准的基于ATL的控件。最值得注意的一点是MFC和ATL各是怎样引入实现一个控件所需的必要的各种接口的。MFC对标准控件接口的支持
是内建在ColeControl类中的。你从ColeControl中派生出你的控件并且一次性继承所有的函数调用。注意ATL通过模板继承以零碎的方式
逐个引入每个功能片断。这是一个非常重要的差异,因为这意味着用ATL你可以忽略一些接口实现模板(例如,使你的控件更为精简)剥掉不希望的功能。对
MFC,你不能完成同样的动作——不管你想不想,你将获得所有接口。
关于例子应用
这里我将使用的例子是一个通过一个分支过程监控消息流的ActiveX控件,它实时的显示消息流图。这两个控件实际上有着相同的功能。它们都把图表提交到
屏幕。它们都带流入接口以便包容器能通知控件开始和停止该图表。它们都支持图表线的颜色和消息间隔长度作为属性而可以永久存在。最后,它们都支持缺省事件
集,将关于在一个特定时间段里处理的消息的数量通知包容器。图3显示了这两个控件。
可以看一下:
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询