在我的机器上,我想不出有哪一个程序不用到一两个按钮。事实上,按钮是为数不多的、可以说是每个应用程序都要用到的Windows控件之一。即使是在一个简单对话框中显示信息的应用程序中,通常也要在用完对话框后关闭它时使用OK按钮。只要说按钮(或某些程序设计环境中所说的命令按钮)是使你机器正常运转的一个控件就够了。它还是绝对能为你提供全部所需特色,而且程序员改变最多的一个控件。
注 按钮是每个应用程序都使用的一个控件,也是对定制控件的潜力进行讨论时最好的入口点。
程序员对一个控件的用途作了这么多的强调,但这并没有用去我多少时间,使我不能在本章的这一节中,确定用哪一种控件向你说明如何去对它进行修改。我还想增加一个新特色,你也许在按钮中并没有发现这一特色,而这个特色最终是每个人都必需的。正是为了说明下述特色,我才选择 On/Off按钮作为本章中控件的基础──就好象在进行应用程序设计中每个人要打开/关闭某个东西一样。将这种特色内置于你使用的控件之中是非常好的。对于从Visual C++中得到的缺省控件来说,我还增加了其它几个特色。尽管我的这个按钮也许不能将商业化程序中所用控件的花哨特色全部囊括,但它能帮你开始创建你自己的定制控件。
定义工程
从用户和程序员两个角度来说,本章前面讨论过开发ActiveX控件的一些规则。现在再从程序员角度深入探讨一下。在开始讨论第一个程序设计例子之前,我们快速地看一下,定义一个具体的ActiveX控件必须记住哪些规则。下列的建议可以加深你对创建ActiveX控件必须遵守的一些特殊约束的理解。
技巧 尽管使用能生成 OCX 的编译器就能创建ActiveX 控件,但你会发现使用Microsoft Visual C++(4.2版以上)产品将会为你节约许多时间。你在本章还会看到,要使OCX像ActiveX控件那样正确地工作,哪怕在最好的环境中,也需要一些额外的步骤。使用旧版编译器意味着你需要用DOS命令行工具来处理额外的步骤。Microsoft Visual C++编译器的4.2及5.x都把这些工具作为软件包的一部分,而且将它们的使用自动化了。
保持代码小型化 经验告诉我们,应该保持ActiveX控件的体积在40KB以下。通常用户不想下载庞大的、仅能用于对页面图形作动画处理的控件。实在没办法时,把一个大的组件分成几个小的功能块来实施。
技巧 还可以像第8章讨论过的那样,把控件压缩进CAB文件也能够减少下载规模。
使用最少的持久数据 一些OCX要求大量的持久数据来完成任务。例如,你可能会把一个电子表格控件粘贴到窗体上,而没想到它所包含的持久数据的数量。ActiveX控件没有这般奢侈,因为你不能对客户机有太多的假设。持久数据不仅增加装入时间和内存需求,而且扩大了控件自身的规模。
将功能特色限制在最低限度 众多的功能的确能为屏幕演示增光添彩。为本地机器编写OCX时,几个额外特色不会增加什么问题。事实上,如果不包括它们就会使多数程序员感到吃惊。但传输时间的确是Internet的一大问题。向控件中每增加一个不是真正必需的图形或其它特殊声音效果,都要增加装入时间,并且降低控件的价值。ActiveX 控件甚至不能假定一些特殊效果是否能够在客户机上正确工作(举例来说,客户机可能没有声卡)。
功能单一是关键 建库的原始动机之一是,用容易访问的形式,存贮大量预编译过的函数调用。作为OCX的前辈,DLL存在的理由正在于此。你会发现市场上的许多OCX (如DLL)都不止包含一个对象(如按钮)。事实上它们包含了一簇对象。这一策略对于桌面系统来说当然很不错,但到了Internet上就行不通了。要保证在一个控件中保持一个对象。遵循这样的原理去模块化控件,确保了用户不必下载他们绝对需要功能以外的东西。
注释 本章中还将对对象进行相当多的讨论。本章中每个对象都是Windows对象(或COM使用的特殊形式)。一些C++程序员可能认为Windows对象就是C++ 对象。因为COM使用一种特殊形式的Windows对象,这些程序员就认为,使用手边的C++对象写OCX不会出问题。越过真理一步就是谬误。尽管可以用C++对象创建Windows对象,但存在一些限制。本章篇幅不足以全面讨论C++程序设计中对象的种种复杂性──这个题目,一些作者要用一章或两章的篇幅来作综述性讨论──但是,了解一下对于用C++写OCX时能做些什么以及应做些什么、有哪些限制,都是很重要的。最好按照本章例子中的方法去写OCX,这样才不会出问题。
测试、测试、再测试 仅仅在本地或仅仅在网络上测试ActiveX控件都是不够的。应该使用不同的连接,在多种情况下进行测试。本章最后会看到三个层次的本地测试以及一个层次的针对Internet的测试。可能你想再加进几个层次的测试,根本上说,你对一个ActiveX测试永远不嫌多。(在发布控件之前测试它是重要的,但在出问题后一定要去查出缺陷,所以要使ActiveX控件正常工作,维护精确的问题日志也很重要的。) 编写代码
现在到了看一下简单编码示例的时候了。本章使用Microsoft Visual C++6.0(尽管你能够使用4.2以上版本),这在前面已提到过。让我们开始创建一个C++新工程。但是,与你创建过的其它工程不一样,现在要用MFC ActiveX ControlWizard(MFC ActiveX控件生成向导)来创建工作区。现在开始吧,使用Flie(文件)|New(新建)命令,系统显示New(新建)对话框,选择Project Tab(工程页),则会看到如下所示的对话框。

该对话框中的MFC ActiveX Control Wizard(MFC ActiveX控件生成向导)就是开始创建本工程的那个选项。这个向导提供了一个OCX框架,通过建立这个框架来创建本例的最后版本。
注释 本例中我使用了新的Microsoft Developer Studio(开发人员工作室)。看到的所有的屏幕图像都是Windows 95下的。如选择使用老的界面,你的屏幕图像就会与这儿的图像不一样。即便你也在使用Developer Studio接口,因为这一产品提供的配置选项可以修改,因此,仍可能产生一些小的差别。
工程开始时,在Project Name(工程名)域中键入工程名。本例用OCXExmpl作为工程名。在工程列表框中单击MFC ActiveX Control Wizard(MFC ActiveX控件生成向导),然后单击OK。Microsoft Visual C++自动选择了Win32选项,它还创建了一个工程目录。
接下来你看到的是MFC ActiveX Control Wizard(MFC ActiveX 控件生成向导)屏幕的两个对话框。我采用了这两个对话框的缺省设置,但对第二个对话框的subclass(子类)域作了选择,如果你也想创建像这个例子一样的控件,那么,在这个域中选择BUTTON类。否则,可以浏览可用类的列表框以确定用什么作为你的控件的基础。还要注意到 Visual C++允许创建自己的基类。
在第二个向导屏幕上单击Finish(完成)按钮后,则会看到如下的New ProjectInformation(新工程信息)对话框。

浏览一下所提供的功能列表,确认工程中包含了你所需要的一切内容。核对工程建立无误后,单击OK,则启动了工程。Visual C++将使硬盘转动一会儿,然后就会看到工程框架。
修改缺省的About对话框
现在已有了一个框架,我们把它填充好。我总是先处理简单的事情(谁不是这样呢?)。首先修改About对话框。Visual C++ 自动为你创建这个对话框,你需要做的事就是定制它。访问About框很容易,使用View(视图)|ResourceSymbols(资源符号)命令则显示出如下图所示的Resource Symbols(资源符号)对话框。
选择IDD_ABOUTBOX-OCXEXMPL项,单击View Use按钮显示该对话框。图10.1 显示了修改示例中About对话框的一种方法。也许你想把版权信息以及公司信息也包含到About对话框中。请留意Microsoft为对话框提供了多种工具,其中之一是定制控件按钮,你能够把另一个OCX贴到About对话框或其它你创建的对话框中。
技巧 用右键单击一个控件,然后从上下文相关菜单中选择Properties(属性) ,于是Properties(属性)对话框显示出来。通过改变Properties(属性)对话框中 General(普通的)属性页上的Caption(标题)属性,可以改变静态文本控件的文本。用右键单击Visual C++的大部分对象,都会显示一个上下文相关菜单──大部分这样的菜单中都包含Properties(属性)选项。用右键单击Visual C++中某个对象的目的,就在于让你看到能够对这个特定对象做些什么。请记住,对象不仅仅指控件,它也可以是代码行、工具栏、甚至可以是各种窗口。
Visual C++的最新版本可能要求你对 About对话框做一些过去不必做的事。你可能需要为About对话框创建一个类──Visual C++的老版本只是假定你会创建新类。双击About对话框,则看到Adding a Class(添加类)对话框,如下图所示(若没看到该对话框,则说明已有一个类赋给了About对话框,你不必再往下继续做了)。

图10.1 该对话框编辑器看起来和Visual Basic的一样,区别在于你必须在主编辑器屏幕中单独访问它

选择Creat a New Class(创建新类)选项,单击OK。Visual C+ + 则显示如下的 New Class(新类)对话框。

我们这儿用CAboutBox作为类名,把它键入到Name(名称)域。这时这个例子所需的一切都准备好了。单击OK,则创建所需的类。这时,就会看到在MFC ClassWizard (类向导)对话框中出现了一个新项,如下图所示(如果屏幕显示不是这样,那么选一下ClassInfo选项卡即可)。

这个对话框把新类的有关信息都显示出来。Header(头文件)及Source(源码)两项是与这个类相关的文件的存放位置。你还会看到,这个类的对话框资源是IDD_ABOUTBOX_OCXEXMPL。单击OK,关闭MFC ClassWizard(类向导)对话框。
添加属性及事件
定制对话框的工作很有趣,现在就让我们继续创建OCX吧。首先要完成的工作是使按钮控件的某些属性和事件让使用该OCX控件的人能够访问(即可见)。例如,在用户单击按钮时要能检测到这个事件。肯定你想改变缺省的属性,如按钮正面上显示的标题等。第一次创建这个按钮时,没有多少属性是可见的。为了使这些元素成为可见状态,需要使用Class Wizard(类向导)。使用View(视图)|ClassWizard(类向导)命令,系统显示MFC ClassWizard (类向导)对话框。选取Automation(自动化)这一页,然后在Class Name(类名)域选择OCXExmplCtrl。
注 Visual C++对你创建的控件作的假设非常少,甚至于使用什么属性和方法使控件可见也不做任何假定。
在这个例子中,使用了两类不同的属性(实际上Microsoft提供了许多供你使用的属性)。第一种是常备(Stock)属性。你会发现,第一次创建OCX时,就连我们都认为是理所当然的Caption(标题)属性等等一类事物都是不可见的。常备属性(在图10.2中用S表示)是由父类缺省支持的一种属性。另一种是定制属性(在图10.2中用C表示)。定制属性是把一个特定类作为子类时你向它添加的属性,其中之一是我们将用于创建一个 OnOff控件的OnOff属性。本章下面来讨论做这些事的过程。图10.2 显示了创建我们例子时所有属性的完整列表。
注 常备属性是基类的一部分,定制属性是把控件作成子类时创建的属性。

创建新属性的过程很简单。只要单击一个Add Property(添加属性)按钮就可以显示出下图所示的Add Property对话框。

Add Property(添加属性)对话框中包含一些以前我们未曾见到过的重要特性。External Name 组合框包含了创建 OCX 时选择的基类的全部缺省属性,在我们的例子中,就可见到Caption属性等。为了创建常备属性,从这个列表中选一项并单击OK即可,Visual C++将处理细节。现在接着创建出本例子程序中的全部常备属性(参见图10.2)。
我们还需要三个定制属性:ModalResult、OnOff及StdButtonType。为了创建它们,把它们键入到刚才提到的External Name(外部名称)域中。然后需要在Type (类型)字段中为它们选择数据类型。在我们例子中,ModalResult和StdButtonType属性是long型,而OnOff是BOOL型。(在这里,你可能要先关闭MFC ClassWizard(类向导)对话框,然后再打开它,否则在有些时候,你选择的属性可能没记录下来。)
这个例子中我们使用的事件都是常备的,他们来自于按钮基类的一部分。要做的是单击ActiveX Events(事件)页,系统显示如图10.3所示。添加常备事件的做法与添加一个常备属性的方法一样,只需单击Add Event(添加事件)按钮显示出Add Event(添加事件)对话框,从Extenal Name(外部名称)组合框中选取一个常备的名称,然后单击OK即可。图10.3显示了需要为这个例子选择的全部常备事件。
定义属性页
现在该向属性页中添加一些功能了,访问属性页的方法与访问About对话框的方法相同,就是使用View(视图)|Resource Symbols(资源符号)命令。在 Resource Symbols(资源符号)对话框选择IDD_PROPPAGE_OCXEXMPL项。属性页用途广泛,其中绝大多数是面向配置的。
Visual C++支持两种标准规格的属性页,OCX的缺省选择是250×62的小号规格。这种规格对我们的目的说来太小了,所以需要把它变成250×110的大号属性页。创建一个控件时一定要确定用这一种还是另一种。你不用标准尺寸时也不会发生什么坏事,但用户可能会收到警告信息,说你没使用标准尺寸的属性页。

现在要完成的工作是,为向页中定义标准的按钮类型来添加一种方法,如图10.4所示。它们是单选按钮,你需要10个按钮(现在不必担心如何配置它们,下述段落中会进行讲解)。每个单选按钮应有不同的ID,以便于能检测出用户单击的是哪一个。(参见Radio Button Properties(单选按钮属性)对话框中General页上的ID域)。

属性页上已有了10个标准的单选按钮,现在让它们完成一些任务。用右键单击其中一个单选按钮,从上下文菜单中选择Properties(属性),系统显示RadioButton Properties(单选按钮属性)对话框,如下图所示。

为了使单选按钮看起来与如图10.4所示的外观相同,要对它们作些小的改动。首先,在 Radio Button Properties(单选按钮属性)对话框选择Style(风格)页,并为每个按钮选中Push-like复选框。还需把这些单选按钮放入一个组,使得当你选择一个新按钮时,当前选择能消除掉。为了完成这个任务,先对使用IDC_RADIO1缺省ID的组中的第一个单选按钮,复选Group及Tabstop复选框,而对(该组中)其它的单选按钮都只复选Tabstop复选框。否则,最后得到的是每组只有一个按钮的10个组而不是有10个按钮的一个组。Visual C++把它看到的第一个选择了Group 复选框的按钮作为组的起点,顺序下去,在VisualC++看到选择了Group复选框的下一个按钮之前,所有按钮都归为这一个组。
技巧 大多数Microsoft产品推荐使用尺寸为250×62或250×110对话框单元的属性页,但你可以按照需要使用任意尺寸的属性页, 当你试图访问这个属性页时,你就会看到一条消息,说你没使用标准尺寸。清除这一消息,则属性按通常那样显示出来。
在这个对话框中,我们要对单选按钮再做一件事。为了在单选按钮和OCX 控件之间建立OLE连接,要对它们的输出赋以OLE属性。按下CTRL键并双击该组中第一个单选按钮(None),系统显示Add Member Variable(添加成员变量)对话框,如下图所示:

技巧 键入CTRL-W显示MFC ClassWizard对话框,选择Member Variable(成员变量)页,再单击Add Variable(添加变量)按钮,也可以访问这个对话框。
这儿定制的各个项目都是十分关键的,原因在于Visual C++不检查它们的对错,并且也不能从列表中选择它们。在Member Variable Name(成员变量名)域,键入m_stdButtorType,这是前面我们创建的定制属性之一的内部名称。保持Category(范畴)域及Variable Type (变量类型)域不变。在 Optional PropertyName (可选属性名称)域中,键入StdButtonType,这是把属性页链接到你的OCX控件的一个项。记住C++是区分大小写的,所以大写很重要。
技巧 Optional Property Name(可选属性名称)域的下拉列表中通常包含了从控件基类继承来的属性的完整列表。
添加代码
直到现在,我们还没有向我们的应用程序中添加一行代码。因为我们一直在忙于建立代码框架。现在该向OCX中添加代码了。首先要添加一些代码,使得我们的控件能与使用这个控件的用户交换数据,例如,当看到控件属性对话框时,通常想看到这些属性的当前值,类似地,当改变了一个属性值时,就想确信实际控件也随之改变。程序列表10.1是需要添加的代码。


现在假定你不喜欢按钮的缺省大小,并且想在用户把按钮插入到Web 页或其它框架中时,显示一个具体的标题。可以在OnReset()函数中改变这两个属性。程序列表10.2 中显示了需要修改的代码。请注意,我们使用COleControl 类的函数来完成所需的修改。SetText()函数修改按钮的标题。每当用户插入这一控件时,标题“Button”就会显示在该控件上。SetControlSize()函数把控件大小变成75×25个像素。显然,可以按你自己的意愿设置这些属性,甚至能够选择其中一个按钮作为缺省按钮。


现在我们有了交换信息的方法,并且把控件按我们的要求进行了设置。下面来实现我们创建的三个定制属性。是的,每当你创建一个定制属性时,就需要定义一些代码,使得这种属性能完成一些任务。否则,它就只能呆在那里干不成事。程序列表 10.3 列出了用以实现ModalResult、OnOff和StdButtonType属性所需添加的代码。下一节我来解释一下这些代码的内部操作方式。在目前,你只要知道这些代码实现了我们创建的属性就够了。





我们现在需要在OCXEXMPLCtl.cpp文件中做最后的一些编码工作。当用户单击按钮时怎么办?如果他使用的是标准按钮类型之一,OnOff控件将返回一个标准的模式结果值。但是,OnOff控件还有一个特殊行为。如果你把OnOff属性设置为True,按钮则随着用户的单击而在On和Off之间切换。我们需要添加一些特殊的事件代码来处理这种情况。使用View(视图)|ClassWizard(类向导)命令显示出MFC ClassWizard(MFC类向导)对话框,选取Message Maps(消息映射)页,选择 Class Name (类名)域中的COCXExmplCtrl项,在Messages(消息)列表中选中OnClick,单击Add Function(添加函数)向类中添加一个函数框架,这时MFC ClassWizard(MFC类向导)对话框如下图所示:

现在向OnClick()函数中添加代码。单击Edit Code(编辑代码)按钮,VisualC++就把你带入到新函数中。程序列表10.4列出了需要添加的代码。


现在我们已经实现了函数编码部分,但我们还需要向 OCXEXMPLCtl.h文件中添加两个支持项。第一个项是枚举类型,其唯一目的是使源代码容易阅读。每个元素对应一个标准按钮类型。第二个项是一个特殊变量。如果注意一下代码,就会看到我们一直引用一个名为m_SetOn的成员变量,但这个变量现在还不是类的一部分。程序列表10.5显示了如何向头文件中添加所需的枚举类型及特殊变量──就在Event maps和Dispatch and event IDs项之间添加。


详细解析代码
你对上述代码作出的最初反应肯定是觉得太可怕了,但是,如果每次处理一个函数,这实际上又相当容易。事实上,作为ActiveX控件定义处理过程的一部分,Visual C++已为你写出了大部分的代码,所以你写出的代码并没有比为一个标准应用程序所写的代码多多少。我们添加的函数,只不过是定义我们要求这个控件所要完成的特殊任务。
让我们把代码分解开来看一下。你修改的第一个函数是DoPropExchange()。这个函数在这个例子中只完成一种服务──把你的定制属性变成持久属性。实际上,PX_ 系列函数调用允许把一个特定属性的值,从一个会话期存贮到下一个会话期。对你定义的每一个变量类型都调用一次该类型的函数。每次调用都接受类似于下文所述的四个变量:
PX_Bool (pPX,"OnOff", m_OnOff,FALSE);
第一个变量是指向属性交换结构的一个指针,Visual C++自动定义这一结构,你只管使用就是了。第二个参数包含了属性的外部名,用户在PropertyInspector中可以看到它。(对于Property Inspector,Visual C++称之为属性对话框,Delphi称为对象观察器,等等)。第三个参数是属性的内部名。使用它在整个程序中确定该属性。最后的参数是定义属性的缺省值(除非你想让用户在Properties(属性)对话框中看到一个空白域)。
你修改的下一个函数是OnResetState()。这个函数提供的是,当用户把组件添加到窗体上时,用户看到的一些美学细节。在这儿,我们给予组件一个缺省标题,并改变其尺寸使之与能在Web页上正常工作的定制尺寸相匹配。如果你设计一个ActiveX控件用于其它目的,就需要改变这一设置,以满足你使用最多的程序设计语言的需要。要记住重要的是OnResetState()函数允许你对使用控件所需要的任何设置进行操作。
技巧 Microsoft使用的组件缺省尺寸差不多是Borland产品(如DelPhi)的两倍。Internet控件的尺寸可变,但本例中使用的75×25(宽×高)规格在绝大多数情况下都能工作。
在代码的消息处理程序 ( handler) 部分,三个修改过的函数中有两个需要进一步修改。ModalResultChanged()函数不需作修改,所以这里就不讨论它了。与ModalResultChange()函数相关的属性ModalResult由其它两个函数进行修改。先看一看OnOffChange()函数。我们要做的是设置内部标题标志和初始标题。如果程序员设置OnOff属性为True,我们通过设置它的标题为On把控件设置为一个on/off开关按钮。当按钮用作on/off开关时,还提供了不同的模式结果值。请留意,内部属性变量m_onOff追踪着标志的状态,而内部属性m_SetOn追踪着OnOff控件的当前状态(on或off),因为这个按钮初始时为On,所以一开始设置m_SetOn标志为True。
现在看一下这个OCX 的Property Page(属性页)中功能所需的处理过程。OnStdButtonTypeChanged函数只不过是一个case语句,它按照创建各种缺省按钮类型的需要来改变按钮的Caption和ModalResult属性。请留意,如果用户选择了缺省的按钮类型,我们还不得不关闭OnOff的按钮处理过程。
OnClick()消息处理函数在运行期间是激活的,这里有两个层次的动作。第一,需要确定程序员是不是把这个按钮定义为 on/off开关,如果是,我们就改变内部状态变量(m_SetOn)和按钮标题。该函数让按钮状态在On和Off之间按需要切换。一旦我们完成了使按钮工作所需的内部处理,我们就调用缺省的OnClick处理例程。如调用失败,则导致OCX跳过你为按钮事件附加的专用于程序设计环境的代码。例如,如果你在Visual C++应用程序中使用这个控件,附加于Visual C++中exposed事件的任何代码都会被忽略。
在能够使用这个组件之前,还得在 Visual C++中建立它。建立过程的一部分是用Windows自动为你注册OCX。我确实喜欢这一特色,因为在测试OCX 时它为我节省了不少时间。唯一的缺憾是,预先注册污染了工作环境,从Internet上使用ActiveX控件的角度来看,你必须到另一台机器上去测试这一组件。
测试控件
一旦创建了一个任意种类的ActiveX控件(不论是否你的编译器是否将它称为OCX),都要进行一些测试,从而保证它按预期的方式工作。对于想用于Internet的ActiveX控件来说,其测试工作最好分为四个阶段:三个层次的内部测试和第四层次的外部测试。下述列表说明了各个阶段的重要性。
内部测试阶段1 在标准环境中使用这个控件。在将控件从标准程序设计平台移走之前,看一下它是否能够工作正常。这样做的理由很简单:在浏览器内测试ActiveX 控件时没有调试程序可用。在把它从C++(或其它OCX/ActiveX)程序设计环境中移走之前测试ActiveX控件的基本功能,使你拥有调试程序,从而能随时找出真正严重的问题。
内部测试阶段2 在浏览器内进行本地测试。在你的本地机器上建立简短测试,看一看ActiveX控件能否装入到一个HTML页中,这样可以使后面的工作节省一些时间,你还应该验证一下,是否有足够多的属性在实际使用控件时可用,并且在你浏览测试页时它能否工作。
内部测试阶段3 使用网络连接测试整个Web页。一旦你对ActiveX 控件的基本功能完成了测试工作,并验证了它能在浏览器中正常使用,就要确定它是否能够在一整页HTML标记中正常工作。总之,不能与同在一页上的其它控件一起工作的控件有什么用呢? 控件间的相互作用能引起一些真正奇怪的问题。可以在应用程序中使用标准窗体来测试相互作用问题,但也帮不了多少忙,问题是浏览器并不是像你所喜爱的编译器那样来处理ActiveX控件。
外部测试 在未被污染的机器上核查控件功能。你遇到的最大问题是污染。请记住,大部编译器总是自动地对你所创建的OCX或ActiveX控件进行注册。而进入你的Internet站点的人却没有这个便利。非常重要的是,用未被污染的客户机和服务器在Web 页的上下文环境中测试你的新控件。换言之,测试的最后阶段,要像任何访问你的Internet站点的人那样来看待这个控件。
现在你已经明白我们要做些什么了,让我们看一下我们创建的控件的测试工作吧。在下面我将使用Visual C++ 6.0。你可以使用支持OCX 的任意程序设计环境,例如,可以使用Visual Basic或Delphi来测试OnOff控件,看看在这些语言中控件是如何工作的。重要的考虑不在于你用什么语言来测试,而在于要使用包含了全部调试支持的一些程序设计语言来完全地测试这个控件。在预定要使用控件的最安全的环境中,要确保创建的控件能够真正地按预期方式工作。由于许多Internet工具处于测试阶段,你会发现看起来好象控件能工作却又工作不了。在一个已知的环境中,通过对控件进行测试来消除控件本身的干扰,这是迈向找出问题的第一步。
内部测试阶段1:在标准环境中使用控件
内部测试的第一阶段不会是一个既长又累人的过程。真正需要完成的任务是使用标准程序设计环境创建一个工程,然后把你创建的ActiveX控件添加进去。要保证所有属性如预期的那样工作起来,花些时间彻底地核查属性页。
注 记住需要使用Project(工程)|Add to Project|Components andControls(组件与控件)命令显示出Components and Controls Gallery(组件与控件展台)对话框,在这个对话框中把OCXExmpl控件添加到当前工程中去。
在你喜欢的(支持OCX工作的)程序设计环境中创建一个新工程。对于本例来说,在Visual C++中创建一个基于对话框的应用程序就能容易地测试该控件。MFC AppWizard(MFC应用程序向导)为你做了大部分工作。(在第2章中已讨论过用Visual C++ 创建基于对话框的应用程序的过程)。我们把这个工程命名为OCXTest。

创建了新工程之后,必要时再创建一个窗体,并把ActiveX控件添加进去。Visual C++自动地将ActiveX控件注册,所以前一节中创建的控件就会出现在可用控件列表中。(其它程序设计环境可能需要你单独地注册你的ActiveX控件)。图10.5 显示了为调试这一例子而创建的测试程序对话框,它还显示了 Property(属性)对话框中选中的Control(控件)属性页。

绝大多数程序设计环境还提供了一种方法,使得你可以查看与一个控件相关联的所有属性。下图显示了OCXExmpl Control Properties(控件属性)对话框的All页,其中OnOff 属性设置为True。
也许你想向程序中添加一些测试代码,从而能够核查各个控件事件的作用。例如,本例中的On/Off开关按钮提供了许多依赖于怎样设置按钮属性的模式结果返回值。把OnOff属性设置为True则创建了一个开关按钮,ModalResult属性在两个值间切换。但是,也可以从Properties(属性)对话框的Control (控件)页中很容易地选择一种标准按钮值。
第一件要做的事是按下CTRL键并双击控件,然后看到Add Member Variable(添加成员变量)对话框,在Member Variable Name(成员变量名)域中键入m_OnOffButton,还要保证Category(范畴)域设置成Control(控件),并且Variable Type(变量类型)域设置成COCXExmpl。现在就能够在测试应用程序中访问控件的属性了。用右键单击控件,在上下文相关菜单中选中Events,就能看到如下图所示的 New Window Message and Event Handlers(新建窗口消息和事件处理程序)对话框。

请注意,Visual C++自动地选择了Click(单击)事件和IDC_OCXEXMPLCTRL1对象。需要你做的工作是单击Add and Edit (添加与编辑)按钮来向你的程序中添加一个新函数。看到Add Member Function(添加成员函数)对话框后,接受缺省函数名并单击OK。这时就会看到这个按钮的函数框架。
程序列表 10.6 是这个例子的C++测试代码。请注意,Visual C++自动为控件创建的GetModalResult()封装类函数的使用。在OCXEXMPLE.H文件中,可以找到Visual C++ 为你制作的全部说明。因为头文件说明了Visual C++是如何与控件打交道的,所以看一下这个头文件是有启发意义的。看一下这个文件,能帮助你找出可能漏掉的接口问题,(特别是如果你不对控件的每个属性进行完全测试时更是如此)。
注释 创建OnClickOcxexmplctrl1()函数的方法有多种,最简单的方法是使用 MFC ClassWizard(类向导)(使用View(视图)|ClassWizard(类向导)命令显示这个向导)。在Object IDs(对象标识)列表框中选中IDC_OCXEXMPLCTRL1项,并在Messages (消息)列表框中选中Click项。这时单击Add Function(添加函数)按钮,就把函数添加到了你的程序中。



我们已创建了一个简单窗体并把你的控件添加到该窗体上面,试着测试一下它吧。示例程序将显示一个简单的带有ActiveX控件的对话框。单击控件,就会看到另一个对话框,其中显示了按钮的状态,如图10.6所示。单击OK或Cancel控钮(由Visual C++自动提供)就结束本程序。如前所述,这是对控件基本功能的简单测试。到现在为止,我们核查了属性页、属性和使用控件的结果。

内部测试阶段2: 在浏览器内进行本地测试
到现在为止,我们还没有在本章中做一些哪怕是远远地接近一下在Web页中工作的事,至于向Web页中添加ActiveX控件,涉及得就更少了(在第8 章中我们确实研究过使用Web页问题,如果想了解使用Internet的简单情况时,一定去读一下这一章)。该变化一下了,测试过程的下一步就是把控件插入到一个HTML文档中,我们再次使用一个非常简单的设置。
注释 在这一节中,我们使用一个非常简单而且容易使用的实用程序。如果计划设计许多普通的或高难度的Web页,那么,应该考虑使用某个工具,比如 Visual InterDev 。但ActiveX Control Pad用作测试工具或用作设计简单Web页更好使用些。
Microsoft提供了一个ActiveX Control Pad 实用程序,可用于测试控件时快速建立HTML页。图10.7是第一次打开这个实用程序时的样子。还可以用它创建功能强大的 Web页(第8章我们讨论过创建过程)。

为了创建用于测试ActiveX控件的HTML页,使用Edit(编辑)|Insert ActiveXControl(插入ActiveX控件)命令显示出Insert ActiveX Control(插入ActiveX控件)对话框。从提供的列表中选择你的控件,单击OK,就会看到ActiveX控件已装入,如图10.8所示。正常情况下,应该把该控件放入一个窗体中,但这儿唯一的目的只是测试它而已。
每装入一个新控件,ActiveX Control Pad都会自动地显示出Properties (属性)对话框,如图10.8所示。这个对话框包含了这个控件的已发布的(published)属性的标准列表。请留意图10.8还显示出了General属性页,通过用右键单击控件并在关联菜单中选择所需的项,就可显示出这个页。对我们的示例来说,要选择第二个Properties(属性)项。
我们需要改变的唯一一个属性是Properties(属性)对话框中的OnOff属性,把它变成True,然后关闭包含控件的对话框。ActiveX Control Pad就向HTML页脚本添加一个标记(如果看不懂HTML页上的专用术语的话,请到第8章找出对HTML标记的说明 )。请注意该项包含了控件的CLASSID和所有需要设置的属性。

技巧 你在HTML脚本中紧挨着<OBJECT>标记的地方会看到一个小按钮。单击这个按钮,再次显示这个控件,从而可以编辑它的属性。每当你把一个 ActiveX 控件或一个HTML页框架放入脚本时,ActiveX ControlPad就显示这个按钮,使你能容易地按需要编辑控件或页面布局。
使用工具栏上的Save(保留)按钮保存示例HTML页面,我将其命名为TestPage.HTM 。关闭ActiveX Control Pad,然后,使用你喜欢的与ActiveX兼容的Web 浏览器(写作本书时,仅限于Internet Explorer 和使用使用NCompassScriptActive 插件的Netscape Navigator)。打开这个HTML页面。如果你使用Internet Explorer,要保证把浏览器的安全层次设为中等。设置安全层次的步骤是:使用View(视图)|Options (选项)命令,选择Security(安全)页,在这个页中单击Safety Level(安全层次)按钮即可。
注 要保证保存的测试用Web页的文件扩展名为HTM。
装入TestPage.HTM文件后,所看到的如图10.9所示。现在看上去并不使人肃然起敬,但控件却能做那些标准HTML页按钮做不到的事。单击按钮,就会看到标题在On和Off 间切换。你还能监测按钮的模式结果值并确定它处于什么状态,所有这一切,一行CGI脚本代码也不用写就做到了!(本章后面将讨论从ActiveX控件中得到信息的方法。)

注释 也许你会看到Satety Violation (安全被破坏)对话框,它告诉你本页的ActiveX控件含有不安全代码。这是因为我们还没有把它注册(mark)为安全的。在第14章中会学到关于安全性的知识,第14章中包括了一旦控件完全测试完成后,怎样把它注册为安全的,现在暂且不用理会这条消息。4.2版以上的Microsoft Visual C++ 提供的工具负责处理这些细节(至少提供一个菜单使你不必回到DOS提示符下)。本章开头我就说过,可以用旧编译器编译ActiveX控件,但新的编译器使得做这类事更方便,上面的情形就是其中的一个方面。
现在,已在C++和本地ActiveX文档中测试了控件的基本功能。在移到网络上去之前,应该试试控件的各种变换,比如,OnOff控件应能在其它几个标准配置中工作,试一下看看它们是否真能工作。
现在要把OnOff控件与其它控件集成在一起使用了。我们在ActiveX ControlPad中新建一个HTML页。我们先创建一个新的HTML框架,然后把 OnOff 控件放入这个框架。使用File(文件)|New HTML Layout(新建HTML框架)命令,创建一个如图10.10 所示的窗体(这个图还显示了在下面段落中要添加的On/Off控件)。就是在这里,你可以拖几个组件来与OnOff控件集成在一起。注意到示例框架中为了进行测试,只把几个控件放到了窗体上。在这时,确实不必添加太多的复杂性,只要有足够的信息来保证控件能在一个标准的HTML环境中工作就可以了。
注 有趣的是,我们在工具箱中看到的所有控件,实际上都是ActiveX 控件而不是标准HTML控件。
这次添加ActiveX控件的过程与以前有些不同。右击Toolbox(工具箱),就会看到上下文菜单,选择 Additional Controls (附加控件)选项,就会看到如下图所示的Additional Controls(附加控件)对话框。

Additional Controls(附加控件)对话框包含了你的机器上全部ActiveX控件的完整列表(实际上不用管这些控件会不会是OCX)。还能够选择显示出可插入对象的完整列表。例如,你可以把Microsoft Word文档或一个Excel电子表格放入窗体。在第11章我们将讨论这个特殊过程。
从列表中选中OCXExmpl可选项(或者是你命名的控件名称)。要保证确实把挨着这个控件的复选框选中,否则,ActiveX Control Pad不安装它。单击OK则大功告成。你会看到一个新控件添加到了你的Toolbox(工具箱)中。抓取住它并把它挨着Command(命令)按钮放下,如图10.10所示。和以前一样,如果使用本章中的示例控件,就要保证把它的OnOff属性设置成True。
完成编辑后,保存你的框架,然后关闭本页。ActiveX Control Pad将向HTML脚本添加一个<OBJECT>标记,就如同前面为我们测试的ActiveX Control页所做的工作那样。当然,这时的不同点是我们看到了一整页控件,而不是仅仅只有一个控件在页上呆着。保存新的测试页,然后再用浏览器打开它看看控件能不能工作。在这种环境下对控件进行测试后,你就可以使用我们刚才建立的两个页,移兵到网络中进行测试了。

内部测试阶段3: 使用网络连接测试整个Web页
在网络上测试控件的方法相当多,唯一的要求是要有两台机器,一个是服务器,一个是客户机,并使用TCP/IP协议将它们连接起来。你还可以在服务器上运行HTTP服务程序。幸运的是,Windows NT 4.0的两个版本都自带有小型的HTTP服务器,你可以用它进行测试。事实上,Windows NT的新版本还将包括FTP和Gopher服务器。
Web链接 Windows 95用户进行Web页的本地测试时,不用再羡慕WindowsNT 邻居了。现在也可以得到Windows 95的个人Web服务器了。Windows95的OSR2 版的拥有者已把这一特色作为软件包的一部分使用了,这只需打开Network Properties(网络属性)对话框,并安装它就可以了。如果你的Windows95是老版本,你可以从http://www .microsoft.com/msdownload/ieplatform/iewin95/10000.htm 下载所需的支持。在http://www.microsoft.com/windows/pr/win95osr.htm可以发现为Windows95 可以下载哪些OSR功能。
你要保证能用标准浏览器和你指定的域名与服务器通信。不要错误地认为,可以通过像浏览器(如Explorer)这样的东西访问服务器,然后双击测试页。不错,这将打开浏览器,你将看到你的测试页。但是,你将使这一测试阶段的目的遭受挫折!通过 Explorer或文件管理器(File Manager)打开这个页,将使浏览器置于文件模式,它不允许你测试HTTP服务程序的能力。这一测试阶段的目的是,尽可能紧密地模拟典型用户访问你的站点时的环境。
一旦与服务器建立了链接,就能看到它提供的缺省的Web页。在其中添加一个到你的测试页的链接,使用这个链接就能测试前一节中创建的单个控件和整个HTML页。多数情况下,你会发现,对于测试的这个阶段而言,简单地测试一下链接就很充分了。换言之,如果控件在一种模式下能工作,那么,它就应该在你提供给它的全部其它模式下也能工作。例如,在我们的示例控件中,我把它作为一个on/off开关进行简单的测试,那么,标准按钮模式也应工作得很好,因为,在测试的前两个阶段,我已经彻底地测试过它们了。这正是本地测试之所以重要的原因,它能在这个阶段节省时间。(想象一下,不得不反复创建同一Web页的几个版本,并在服务器连接上测试它们,对于程序说来,这是多么没有效率的方法呀!)
外部测试:在未被污染的机器上检查控件的功能
在我们的私有环境中,已对控件进行了彻底的测试。考察了每种控件访问,我们确信控件可以与标准的HTML控件一起工作。现在该进入外部测试阶段了。
实际上,这一阶段仅仅是第三个内部阶段的扩充而已。但是,不再是从网络上访问Web 站点,而是像你的用户那样,通过电话连接来访问站点。另外,你对控件进行测试一直使用的是受了污染的机器,在这种机器上,已安装了被测试控件,而且,拥有了所有适当的注册表项。
这个测试阶段的目的分为两个方面。第一方面,想确信,当从一个未被污染的机器上进行访问时,控件仍能工作;否则,就会发现你的控件依赖于某些注册表项,或者依赖于客户机访问你的Web站点时不能满足的其它要求。第二,想检测你的Web页的下载时间,到现在为止,我们一直通过高速连接访问测试页,而使用你的站点的人就没有这种便利了。他们中的大多数人是通过拨号连接来访问你的站点的。
技巧 可能你想把你的测试页安装到你的Web站点中一个私有部分,从而防止其它人访问他们。与网络测试阶段不一样,不要在你的主Web页上放上对测试页的链接,因为你已经在以前的测试阶段中测试过连接性能,所以可以用直接地址访问测试页。
为了完成这一部分的测试工作,把测试页移到你的Web服务器的一个私有部分。从一个未被污染的机器上,使用一个支持ActiveX的浏览器,拨号进入你的Web服务器。你需要使用你的网络的私有部分的URL 而不是主页的URL 。先试一试单一控件测试页,看看ActiveX控件是否能工作,还要看一看在没有一个整页实现的影响时下载控件用多长时间。一旦检测完单一控件测试页,就转向使用整个HTML框架的第二页。若这个连接成功,你就获得了一个可以工作的ActiveX控件,这个控件能够用于增强你的正规HTML页面的功能。 |
|