Script宿主、Script引擎、Script(脚本)之间的关系
要想实现基于COM组件的脚本支持功能,我们需要正确理解Script各方以及相互之间的关系。有关脚本的概念有:Script Host(Script宿主)、Script Engine(Script引擎)、Script(脚本) 。
什么是Script宿主呢?听起来象生物学术语。类似生物学的概念,可以简单认为是我们所编写的脚本要控制的功能对象,是我们编写的应用程序,想提供给最终用户的功能组件。举例说,Word是微软提供给大家的文字处理系统,它采用了基于COM的软件结构,如果我们为Word编写一些脚本(就是平常所说的“宏”),那么,脚本所依附的对象 Word就是Script宿主了。脚本功能的最终执行者就是Script宿主。我们编写的任何自主应用程序都可以看作宿主,都可以嵌入脚本解释能力。当然,宿主应当是也最好是基于COM编程的。另一方面,脚本就是对宿主进行服务请求或进行控制的代码。
Script引擎就是Script宿主和Script之间的“桥梁”。脚本引擎获取脚本,并按照语法进行解释,并控制宿主程序提供的对象的属性,调用相关方法,实现脚本要求的功能。向脚本提供可利用的对象并解释脚本以实现二次开发是引擎的主要功能。
三者之间的关系可以用如下的图形来表示。
--------------------------------------------------------------------------------
向脚本控件提供对象
--------------------------------------------------------------------------------
控制宿主提供的对象
从输入部件获取要解释执行的脚本
Script引擎对象的属性、方法、事件
Script引擎是作为一个ActiveX控件提供给用户的,在利用它之前,我们来看一看此控件的属性和方法。
属性:
AllowUI:可读写,布尔值,检测是否允许运行用户的接口元素。如果为False,则诸如消息框之类的界面元素不可见。
CodeObject:返回宿主被调用的特定的公用成员对象。只读。
Modules:只读。返回宿主提供给脚本的组件库模块。COM组件通常都是以对象收集的形式向用户提供可以留给用户二次开发的对象集合,每一个收集即一个Modules(模块)。
Language:设置或获取脚本引擎解释的语言,例如:VBScript、JScript。
Name:返回模块、过程、或者对象的名字,只读属性。
Procedures:返回模块中定义的过程,只读。
SitehWnd:窗口句柄,如果本控件以ActiveX控件创建,则此属性为控件的容器;如果是以自动化对象创建,则为0,即桌面。此属性可读写。
State:设置或返回控件的状态,如果为0,控件只执行语句但不转发事件,为1则为加入的本控件接受的对象转发事件。
Timeout:设置或返回控件的相应脚本的超时值。当超时值到达时,将引发Timeout事件。也可设为-1,表示无超时设定。
UseSafeSubset:设置或返回宿主程序是否关心安全。宿主程序的安全级别可以从此属性设置。
Error:错误对象,发生错误时,此属性返回一个错误对象。
方法:
AddCode :往一个模块加入一些代码。格式为:AddCode code, 可以调用多次。
AddObject:向一个模块加入一个对象,格式:ScriptControl.AddObject(name, object[, addMembers]),name为欲加入的对象名字,Object为实际的对象,addMembers为可选指示此对象是否为全局对象,False为局部对象。只有往本对象中加入对象后才能在脚本中使用这些对象。
Eval:求值表达式。格式为object.Eval(expression) 。
ExecuteStatement:解释并执行脚本语句。格式:object.ExecuteStatement statement。
Reset:丢弃所有的对象和代码。State属性将为0。
Run:运行一个指定的过程。格式:object.Run(procedureName, parameters()),procedureName为要运行的过程名,parameters()为
事件
仅有两个事件:error 和TimeOut。前者可以用于错误捕获,后者在脚本得不到响应时发生。
VB开发实例
假设我们要在VB中开发一个编辑软件,此系统显然就是前文提到的脚本技术中的宿主,为了支持二次开发将系统设计为基于COM,并且向用户提供两个对象“WORD”及“MyBox”。实际上为了简化问题,达到演示说明的目的,此例子并未自行设计复杂的代码,向用户提供的对象实际都是“现成”的棗“WORD”就是您系统中安装的Office中的Word,只不过被我“转手”以“我提供的对象”形象出现,在Office VBA中Word所有的方法属性都可以在本系统的脚本功能中提供给用户;“MyBox”实际上是设计时添加的一个TextBox控件,但最终是以我的文本框提供给使用者。界面很简单(朴素?投机取巧?),尽量不转移大家的注意力,以了解本文所述的脚本技术实现。代码及注释如下:
VERSION 5.00
‘需要使用一个自动化服务器和一个ActiveX控件支持本例子。
Object = "{0E59F1D2-1FBE-11D0-8FF2-00A0D10038BC}#1.0#0"; "MSSCRIPT.OCX"
Begin VB.Form Form1
Caption = "具有脚本支持功能的演示系统"
ClientHeight = 4335
ClientLeft = 60
ClientTop = 345
ClientWidth = 4680
LinkTopic = "Form1"
ScaleHeight = 4335
ScaleWidth = 4680
StartUpPosition = 3 'Windows Default
Begin VB.TextBox Text2
Height = 1095
Left = 120
MultiLine = -1 'True
TabIndex = 2
Text = "vbscript.frx":0000
‘用户可以通过脚本代码窗输入控制此对象的属性的代码(我的对象名字为MyBox),也可以通过WORD对象来启动并控制您系统中的Office Word
ToolTipText = “在脚本代码框中输入代码以控制本对象的属性 ”
Top = 3120
Width = 2415
End
Begin VB.TextBox Text1
Height = 2295
Left = 120
MultiLine = -1 'True
ScrollBars = 3 'Both
TabIndex = 1
Text = "‘在此输入脚本代码"
ToolTipText = " 你可以在代码中控制两个本系统提供的对象:WORD和MyBox。"
Top = 480
Width = 4335
End
Begin VB.CommandButton Command1
Caption = "执行脚本代码"
BeginProperty Font
Name = "MS Sans Serif"
Size = 9.75
Charset = 0
Weight = 400
Underline = 0 'False
Italic = 0 'False
Strikethrough = 0 'False
EndProperty
Height = 735
Left = 2760
TabIndex = 0
Top = 3480
Width = 1815
End
‘脚本对象的缺省属性
Begin MSScriptControlCtl.ScriptControl ScriptControl1
Left = 0
Top = 2160
_ExtentX = 1005
_ExtentY = 1005
AllowUI = -1 'True
End
Begin VB.Label Label1
Caption = "请在此输入您的VB代码"
BeginProperty Font
Name = "MS Sans Serif"
Size = 9.75
Charset = 0
Weight = 400
Underline = 0 'False
Italic = 0 'False
Strikethrough = 0 'False
EndProperty
Height = 255
Left = 120
TabIndex = 3
Top = 120
Width = 3255
End
End
Attribute VB_Name = "Form1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Private Sub Command1_Click()‘当点击Command1 时
ScriptControl1.ExecuteStatement Text1.Text‘解释并执行脚本
End Sub
Private Sub Form_Load() ‘窗体载入时
Dim ob As Object ‘定义一个对象变量
Set ob = CreateObject("Word.Application")‘创建一个自动化对象,引用编程ID
ScriptControl1.State = Connected‘设置脚本控件的状态
ScriptControl1.AddObject "WORD", ob ‘向脚本对象加入一个可接收的对象“WORD”
ScriptControl1.AddObject "MyBox", Text2 ‘加入一个本窗体的VB基本控件TextBox
End Sub
实例的运行要求:VB6.0、Pwin98,并且原则上要求您的系统中安装Word97,但如果您可以将Form_Load()中的CreateObject("Word.Application")语句修改,把“Word.Application”(Word97的在注册表中的ProgID)替换成任何您系统中现有的任何自动化对象的ProgID。在启动本例子后你可以在脚本输入框中输入如下代码以观察效果,也可以在了解脚本提供的对象的属性和方法基础上写入您自己的任何代码:
Word.visible =True ‘使Word对象显现,跟通过常规方法启动它一样使用它。
MyBox.Text =“这是在脚本中设置的内容”
补充几点
关于宿主提供的对象。
可以在编写宿主时添加任何自定义的对象,在本例这些对象可以是VB编写的对象、VB提供的控件(包括ActiveX控件)、系统中存在的自动化对象(甚至您用其它诸如Delphi等编写的控件、COM对象),但对于自定义对象必须用AddObject方法加入到脚本控件Modules。
对运行时对象的控制
在使用Object.xxx形式引用对象的方法和属性时必须要确认所输入代码的有效性。所谓“有效性”是指在脚本控件解释这些代码时所引用的属性、方法等必须可用或有效(有些属性只读或只写,有写方法在某些状态下不能调用),不能出现拼写错误。本例子未进行错误捕获,感兴趣大家可以自行设计。
C++中的脚本引擎利用
除了在VB中可以使用ScriptControl外还可以在C++中使用它。Visual Studio97中使用脚本功能必须实现一些特殊的接口,比较繁琐,利用此控件可以省下脚本支持接口方面的周折。我们开发的很多自主软件都没有利用脚本支持功能,导致软件使用和二次开发不便,例如WPS97就没有类似Word97的宏功能,应该说是我们国产软件同世界软件之间的一个差距(因手头没有 WPS2000,所以无法对其进行评论)。一般现在开发软件利用C++可以方便的实现COM,可以利用脚本控件轻松实现脚本支持,为自己的软件增色,何乐而不为呢?