用ATL开发一个控件
有了基于MFC的控件,你就可以用ATL COM App Wizard得到一个开发基于ATL的控件的触发器。使用ATL来创建控件可以分为两步。虽然MFC的Control Wizard要求你预先确定你希望在DLL中包含多少个控件,ATL COM Wizard简单的创建DLL——你可以以后使用ATL对象选项从Insert菜单添加控件。当创建一个新的基于ATL的DLL时,你可以选择混用MFC支持。你还可以选择在控件的DLL中合并任何proxy/stub代码。这使得如果有人希望远程控制你的控件实现的代码,你只要发布一个文件。
一旦生成了基于ATL的DLL,你就可以开始添加COM类了。Insert New ATL Object菜单条使得这项工作变得十分容易。选择此菜单项显示一个用来创建任何一个COM类的对话框,包括无格式的COM对象,ActiveX控件以及Microsoft事务服务器组件(Windows NT Server的一部分)。
当添加基于ATL的控件到你的工程的时候,ATL Object Wizard比MFC Object Wizard提供了更大范围的选项。对于新手来说,ATL使得你可以选择使用任何现有的线性模型实现你的控件。你可以将你的类标记为或者单线程或者单元线程的。ATL Object Wizard限制你创建一个自由的或者混合线程的控件,因为控件通常是面向UI的。
如果你创建了一个单线程的控件,一个包容的控件的客户将总是将它加载到主、单线程的单元(STA)中。结果,只有在客户进程空间运行的单主线程才会接触到你的对象,这样就免除了你保护你的控件状态不受并发访问干扰的责任。另外,因为你的对象的所有实例将只会被一个线程接触,你将不必担心DLL中的全局数据。如果你的控件是单元线程的,你还免除了保护你的控件的内部状态的大部分负担。然而,你仍然不得不保护DLL中的全局数据。为什么呢?首先,设想你的控件是由客户的单线程创建的。现在假定客户试图创建该控件的另一份拷贝——但是是从一个云向在当前进程的多线程的单元中。通过将你的对象标记为单元线程的,COM被告知你希望你的控件保护免遭并发访问。COM在它加载时为你的控件创建一个新的STA。现在当线程调用到你的对象时,它们只能通过单元边界来访问它,远程层将同步对此对象的调用。然而,当某个控件的状态被保护不被并发访问,作为在一个STA中的副产品,由控件的实例所共享的数据(象在DLL中的全局数据一样)是脆弱的。这是因为你的全局DLL数据(同时为几个对象服务,分别运行在独立的线程中)会被那些多线程同时接触到。
虽然基于MFC的COM类总是可聚合的(内置了对它的支持),ATL ObjectWizard使得你可以指定你的控件支持聚合,只是可聚合的,或者是独立的对象。根据你选择的聚合选项,ATL ObjectWizard使用一个宏来执行聚合策略。例如,缺省的COM类的实现是可聚合的——对象将既运行在独立的模式,又作为一个聚合的一部分。如果你使你的COM对象不可聚合,ObjectWizard把DECLARE_NOT_ AGGREGATABLE宏加到你的类定义中。如果你选择了仅是可聚合的,ObjectWizard把DECLARE_ ONLY_AGGREGATABLE宏加入到类定义中。
这里是宏如何工作的。缺省的对象创建在一个名为_CreatorClass的类中发生。_CreatorClass当被加入到服务器范围的对象映射后(这是OBJECT_ENTRY宏所做的工作的一部分),就成为你的COM类的创建机制。_CreatorClass其实只是一个名为CComCreator2类的别名,此类将两个从CcomCreator类中定制的类作为参数。此宏根据选择的聚合模式来特制CcomCreator类,分别使用CComObject, CComAggObject, CComFailCreator, 或者CcomPolyObject:
#define DECLARE_NOT_AGGREGATABLE(x) public: \
typedef CComCreator2< CComCreator< CComObject< x > >, \
CComFailCreator > _CreatorClass;
#define DECLARE_AGGREGATABLE(x) public: \
typedef CComCreator2< CComCreator< CComObject< x > >, \
CComCreator< CComAggObject< x > > > _CreatorClass;
#define DECLARE_ONLY_AGGREGATABLE(x) public: \
typedef CComCreator2< CComFailCreator, \
CComCreator< CComAggObject< x > > > _CreatorClass;
#define DECLARE_POLY_AGGREGATABLE(x) public: \
typedef CComCreator< CComPolyObject< x > > _CreatorClass;
ATL ObjectWizard Attributes页中最后三个检查框包括对COM例外处理的支持(例如,IsupportErrorInfo接口),连接点以及自由线程集(FTM)。你也可以添加IsupportErrorInfo到控件的继承列表中,提供ISupportErrorInfo::InterfaceSupportsErrorInfo的一个实现。打开连接点将添加IConnectionPointImpl 模板类到控件的继承列表中。
将你的控件聚合到FTM使得单元间(以及Windows 2000的上下文间)的调用更为频繁的发生,如果两个对象正好位于同一个进程中。然而,你在编写控件时不应该检查这一点,因为当你使用FTM的时候,你多少都违反了单元(以及Windows 2000的上下文)规则。关于FTM的更多细节,请参见Don Box的Effective COM (Addison-Wesley Longman, 1998)一书。
除了你可以应用到所有COM对象的一般选项,ATL ObjectWizard还提供了几个控件创建特定的选项。首先,ATL ObjectWizard让你从一个常规控件(例如一个按钮或是一个编辑控件)中进行子类划分。你可以为你的空间指定其它几个选项使得它更加不透明,给它一个更实心的背景,在运行时不可见,或者是你的控件象一个按钮那样的工作。下面是控件属性页提供的选项的一个大纲:
不透明和实心背景如果你希望使所有的包容器都不显示在控件边界之后,选择"opaque"检查框,这是控件传给它的包容器的状态信息。结果是,控件在说明它将画出它的完整矩形。选择此选项设置VIEWSTATUS_OPAQUE位以便IViewObjectExImpl::GetViewStatus向包容器指示一个不透明的控件。你可能还想选择一个实心的背景。这个选项设置VIEWSTATUS_ SOLIDBKGND 位以便GetViewStatus指示控件有一个实心的背景。
运行时不可见此选项使你的控件在运行时不可见。你可以使用不可见控件在后台完成某些操作,例如周期性的激发事件。此选项在它加入到注册表中后使得控件翻转OLEMISC_INVISIBLEATRUNTIME 位。
仿按钮此选项使你的控件象一个按钮那样工作。此时,控件将在包容器周围属性DisplayAsDefault的基础上显示为缺省的按钮。如果控件的位置标记为缺省按钮,控件将显示为一个较厚的框架。选择此选项在它加入到注册表中后使得控件翻转OLEMISC_ACTSLIKEBUTTON 。
仿标签选择此选项使得你的控件取代包容器的内部标签。这使得控件在它加入到注册表中后标记OLEMISC_ACTSLIKELABEL。
在超类基础上添加控件选择此选项使得你的控件根据一种标准window类进行子类划分。下拉列表包含了Windows定义的window类。当你选择这些类名中的一个时,向导添加一个CcontainedWindow成员变量到你的控件类中。CContainedWindow::Create将你指定的window类超类化。
规格化DC选择此选项使得你的控件在被调用来画自己时创建一个规格化的设备上下文。这标准化了控件的外观,但是效率降低了。此选项生成的代码覆盖了OnDrawAdvanced方法(而不是常规的OnDraw方法)。
可插入的选择此选项使得你的控件显示在象Microsoft Excel 和Word 这样的应用的Insert Object对话框中。你的控件就能够被插入到任何支持嵌入对象的应用中了。选择此选项在注册表项中增加了Insertable键。
仅为窗口化的选择此选项迫使你的控件窗口化,即使在支持无窗口对象的包容器中。如果你不选择此选项,你的控件将会自动的适应包容器:在支持无窗口对象的包容器中是无窗口的,在不支持无窗口对象的包容器中是有窗口的。这将使CComControlBase::m_bWindowOnly标志设置为TRUE。ATL使用此标志来决定在控件激活过程中是否要查询包容器的IoleInPlaceSiteWindowless接口。
ATL要求你预先在Stock Properties页中决定你的对象的stock属性,你可以选择Caption或者 Border Color这样的属性,或者通过点击>>按钮一次性选择所有的stock属性。这将向控件的属性映射中添加属性。
在运行ATL COM App Wizard 和 ObjectWizard之后,你就得到了一个完整的DLL,它具有一个COM DLL所必需的所有分支。此控件显示的众所周知的出口包括DllGetClassObject, DllCanUnloadNow, DllRegisterServer,和 DllUnregisterServer。另外,你得到了一个满足COM主要需求的对象——包括一个主流入接口和一个类对象。
一旦你已经使用一个向导开始了一个工程,下一步就是使控件做点有趣的事情了。通常出发点是控件的翻译代码。你立刻得到一些可视化的反馈。让我们来看一下一个基于MFC的控件的翻译是怎样发生的。转 载:http://www.qqread.com/vc/d220782020.html进入讨论组讨论。
有了基于MFC的控件,你就可以用ATL COM App Wizard得到一个开发基于ATL的控件的触发器。使用ATL来创建控件可以分为两步。虽然MFC的Control Wizard要求你预先确定你希望在DLL中包含多少个控件,ATL COM Wizard简单的创建DLL——你可以以后使用ATL对象选项从Insert菜单添加控件。当创建一个新的基于ATL的DLL时,你可以选择混用MFC支持。你还可以选择在控件的DLL中合并任何proxy/stub代码。这使得如果有人希望远程控制你的控件实现的代码,你只要发布一个文件。
一旦生成了基于ATL的DLL,你就可以开始添加COM类了。Insert New ATL Object菜单条使得这项工作变得十分容易。选择此菜单项显示一个用来创建任何一个COM类的对话框,包括无格式的COM对象,ActiveX控件以及Microsoft事务服务器组件(Windows NT Server的一部分)。
当添加基于ATL的控件到你的工程的时候,ATL Object Wizard比MFC Object Wizard提供了更大范围的选项。对于新手来说,ATL使得你可以选择使用任何现有的线性模型实现你的控件。你可以将你的类标记为或者单线程或者单元线程的。ATL Object Wizard限制你创建一个自由的或者混合线程的控件,因为控件通常是面向UI的。
如果你创建了一个单线程的控件,一个包容的控件的客户将总是将它加载到主、单线程的单元(STA)中。结果,只有在客户进程空间运行的单主线程才会接触到你的对象,这样就免除了你保护你的控件状态不受并发访问干扰的责任。另外,因为你的对象的所有实例将只会被一个线程接触,你将不必担心DLL中的全局数据。如果你的控件是单元线程的,你还免除了保护你的控件的内部状态的大部分负担。然而,你仍然不得不保护DLL中的全局数据。为什么呢?首先,设想你的控件是由客户的单线程创建的。现在假定客户试图创建该控件的另一份拷贝——但是是从一个云向在当前进程的多线程的单元中。通过将你的对象标记为单元线程的,COM被告知你希望你的控件保护免遭并发访问。COM在它加载时为你的控件创建一个新的STA。现在当线程调用到你的对象时,它们只能通过单元边界来访问它,远程层将同步对此对象的调用。然而,当某个控件的状态被保护不被并发访问,作为在一个STA中的副产品,由控件的实例所共享的数据(象在DLL中的全局数据一样)是脆弱的。这是因为你的全局DLL数据(同时为几个对象服务,分别运行在独立的线程中)会被那些多线程同时接触到。
虽然基于MFC的COM类总是可聚合的(内置了对它的支持),ATL ObjectWizard使得你可以指定你的控件支持聚合,只是可聚合的,或者是独立的对象。根据你选择的聚合选项,ATL ObjectWizard使用一个宏来执行聚合策略。例如,缺省的COM类的实现是可聚合的——对象将既运行在独立的模式,又作为一个聚合的一部分。如果你使你的COM对象不可聚合,ObjectWizard把DECLARE_NOT_ AGGREGATABLE宏加到你的类定义中。如果你选择了仅是可聚合的,ObjectWizard把DECLARE_ ONLY_AGGREGATABLE宏加入到类定义中。
这里是宏如何工作的。缺省的对象创建在一个名为_CreatorClass的类中发生。_CreatorClass当被加入到服务器范围的对象映射后(这是OBJECT_ENTRY宏所做的工作的一部分),就成为你的COM类的创建机制。_CreatorClass其实只是一个名为CComCreator2类的别名,此类将两个从CcomCreator类中定制的类作为参数。此宏根据选择的聚合模式来特制CcomCreator类,分别使用CComObject, CComAggObject, CComFailCreator, 或者CcomPolyObject:
#define DECLARE_NOT_AGGREGATABLE(x) public: \
typedef CComCreator2< CComCreator< CComObject< x > >, \
CComFailCreator
#define DECLARE_AGGREGATABLE(x) public: \
typedef CComCreator2< CComCreator< CComObject< x > >, \
CComCreator< CComAggObject< x > > > _CreatorClass;
#define DECLARE_ONLY_AGGREGATABLE(x) public: \
typedef CComCreator2< CComFailCreator
CComCreator< CComAggObject< x > > > _CreatorClass;
#define DECLARE_POLY_AGGREGATABLE(x) public: \
typedef CComCreator< CComPolyObject< x > > _CreatorClass;
ATL ObjectWizard Attributes页中最后三个检查框包括对COM例外处理的支持(例如,IsupportErrorInfo接口),连接点以及自由线程集(FTM)。你也可以添加IsupportErrorInfo到控件的继承列表中,提供ISupportErrorInfo::InterfaceSupportsErrorInfo的一个实现。打开连接点将添加IConnectionPointImpl 模板类到控件的继承列表中。
将你的控件聚合到FTM使得单元间(以及Windows 2000的上下文间)的调用更为频繁的发生,如果两个对象正好位于同一个进程中。然而,你在编写控件时不应该检查这一点,因为当你使用FTM的时候,你多少都违反了单元(以及Windows 2000的上下文)规则。关于FTM的更多细节,请参见Don Box的Effective COM (Addison-Wesley Longman, 1998)一书。
除了你可以应用到所有COM对象的一般选项,ATL ObjectWizard还提供了几个控件创建特定的选项。首先,ATL ObjectWizard让你从一个常规控件(例如一个按钮或是一个编辑控件)中进行子类划分。你可以为你的空间指定其它几个选项使得它更加不透明,给它一个更实心的背景,在运行时不可见,或者是你的控件象一个按钮那样的工作。下面是控件属性页提供的选项的一个大纲:
不透明和实心背景如果你希望使所有的包容器都不显示在控件边界之后,选择"opaque"检查框,这是控件传给它的包容器的状态信息。结果是,控件在说明它将画出它的完整矩形。选择此选项设置VIEWSTATUS_OPAQUE位以便IViewObjectExImpl::GetViewStatus向包容器指示一个不透明的控件。你可能还想选择一个实心的背景。这个选项设置VIEWSTATUS_ SOLIDBKGND 位以便GetViewStatus指示控件有一个实心的背景。
运行时不可见此选项使你的控件在运行时不可见。你可以使用不可见控件在后台完成某些操作,例如周期性的激发事件。此选项在它加入到注册表中后使得控件翻转OLEMISC_INVISIBLEATRUNTIME 位。
仿按钮此选项使你的控件象一个按钮那样工作。此时,控件将在包容器周围属性DisplayAsDefault的基础上显示为缺省的按钮。如果控件的位置标记为缺省按钮,控件将显示为一个较厚的框架。选择此选项在它加入到注册表中后使得控件翻转OLEMISC_ACTSLIKEBUTTON 。
仿标签选择此选项使得你的控件取代包容器的内部标签。这使得控件在它加入到注册表中后标记OLEMISC_ACTSLIKELABEL。
在超类基础上添加控件选择此选项使得你的控件根据一种标准window类进行子类划分。下拉列表包含了Windows定义的window类。当你选择这些类名中的一个时,向导添加一个CcontainedWindow成员变量到你的控件类中。CContainedWindow::Create将你指定的window类超类化。
规格化DC选择此选项使得你的控件在被调用来画自己时创建一个规格化的设备上下文。这标准化了控件的外观,但是效率降低了。此选项生成的代码覆盖了OnDrawAdvanced方法(而不是常规的OnDraw方法)。
可插入的选择此选项使得你的控件显示在象Microsoft Excel 和Word 这样的应用的Insert Object对话框中。你的控件就能够被插入到任何支持嵌入对象的应用中了。选择此选项在注册表项中增加了Insertable键。
仅为窗口化的选择此选项迫使你的控件窗口化,即使在支持无窗口对象的包容器中。如果你不选择此选项,你的控件将会自动的适应包容器:在支持无窗口对象的包容器中是无窗口的,在不支持无窗口对象的包容器中是有窗口的。这将使CComControlBase::m_bWindowOnly标志设置为TRUE。ATL使用此标志来决定在控件激活过程中是否要查询包容器的IoleInPlaceSiteWindowless接口。
ATL要求你预先在Stock Properties页中决定你的对象的stock属性,你可以选择Caption或者 Border Color这样的属性,或者通过点击>>按钮一次性选择所有的stock属性。这将向控件的属性映射中添加属性。
在运行ATL COM App Wizard 和 ObjectWizard之后,你就得到了一个完整的DLL,它具有一个COM DLL所必需的所有分支。此控件显示的众所周知的出口包括DllGetClassObject, DllCanUnloadNow, DllRegisterServer,和 DllUnregisterServer。另外,你得到了一个满足COM主要需求的对象——包括一个主流入接口和一个类对象。
一旦你已经使用一个向导开始了一个工程,下一步就是使控件做点有趣的事情了。通常出发点是控件的翻译代码。你立刻得到一些可视化的反馈。让我们来看一下一个基于MFC的控件的翻译是怎样发生的。转 载:http://www.qqread.com/vc/d220782020.html进入讨论组讨论。
相关图文阅读
频道图文推荐
健 康 咨 询
时 尚 咨 询



