分类: C/C++
2008-03-24 19:01:29
HRESULT GetLCID(LCID *plcid)
脚本引擎在准备执行脚本程序的时候,它首先要调用这个函数来询问脚本所使用的语言环境。你可以简单的返回 E_NOTIMPL,那么引擎就会使用当前系统默认使用的语言。
HRESULT GetItemInfo(LPCOLESTR pstrName, DWORD dwReturnMask, IUnknown **ppunkItem, ITypeInfo **ppTypeInfo)
脚本引擎执行前调用这个函数,它需要取得两个接口指针:一个是类型库的指针,因为类型库中保存有函数的参数信息(类型库本质上其实就是IDL文件的二进行形式),有了它,引擎才知道如何执行脚本中的函数;另一个指针是IUnknown, 脚本引擎将来会通过它调用 QueryInterface 取得IDispatch指针,然后就可以调用IDispatch::Invoke()执行脚本中的函数了。
另一个要说明的参数是 pstrName。一个脚本引擎对象可以同时处理多个脚本项目,因此需要通过一个项目名称来区分多个不同的脚本项目。项目名称是通过 IActiveScript::AddNamedItem() 函数来指定的。在GetItemInfo() 函数中,你要通过pstrName这个参数来区分不同的项目,给出相应的IUnknown和ITypeInfo 的指针。
HRESULT GetDocVersionString(BSTR *pbstrVersionString)
脚本引擎需要通过唯一的一个字符串在适当的时候保存和装入文档的状态,比如在IE中调用记事本编辑HTML源文件。你可以简单的返回 E_NOTIMPL,则脚本引擎默认同步使用文档。
OnScriptTerminate(VARIANT *pvarResult,EXCEPINFO *pexcepinfo)
脚本引擎执行结束后,在OnStateChange 之前调用这个函数,同时 SCRIPTSTATE_INITIALIZED 已经设置完成。参数pvarResult中传递脚本的执行结果,如果为NULL表示脚本没有执行结果。pexecpinfo为NULL表示脚本执行没有错误,否则你可以从这个结构中取得发生异常的 具体信息。
HRESULT OnStateChange(SCRIPTSTATE ssScriptState)
脚本引擎在执行脚本过程中,当状态发生改变的时候,调用该函数。更多的状态信息,可以参考IActiveScript::GetScriptState()函数。
HRESULT OnScriptError(IActiveScriptError *pase) HRESULT OnEnterScript(void) HRESULT OnLeaveScript(void)
以上三个函数比较简单,当脚本发生错误,脚本开始执行,脚本执行完毕的时候,调用这些方法来通知你的脚本主机。在错误通知的函数中,你可以根据错误原因做相应的处理。
另外,IActiveScriptSite接口并不提供窗口功能。如果想让脚本实现与用户的界面交互,那么你还需要实现IActiveScriptSiteWindow的接口。脚本引擎会通过IActiveScriptSite::QueryInterface() 来查询这个接口并使用它。
<2.2> 建立能与脚本交互的自动化对象
若想让脚本引擎在执行脚本的过程中,与你的程序进行交互,或者说你希望脚本可以调用你扩展的脚本函数。那么你需要建立一个自动化的对象,在IDispatch接口上提供后绑定的方法和属性,然后把这个对象的类型库和IUnknown的接口指针,在IActiveScriptSite::GetItemInfo()的调用中,传递给脚本引擎。
<2.3> 如何使用脚本引擎
脚本引擎,也是一个COM对象。它提供IActiveScript和IActiveScriptParse接口。目前在Windows平台上,微软提供了VBScript、JScript 等多个脚本引擎。当然,你也可以自己发明一个脚本语言,然后实现引擎所需要的接口并正确注册类型后,那么在Windows平台上就可以运行你的语言了。想象一下在HTML中可以如下使用你自己的语言,该是多么爽的一件事呀。(只可惜,我发明的语言,目前只有在我自己吃饱了饭后,孤独的自我陶醉而已。)
… …
脚本引擎 IActiveScript有13个方法,IActiveScriptParse有3个方法。这么多函数中,其实我们只需要调用5个就能满足大多数情况的需求了。具体的函数功能和参数说明,请大家参照MSDN,我就不详细描述了。如下所示是使用引擎的一般步骤:
1. CoCreateInstance() 建立引擎的COM对象,并得到IActiveScript接口指针。
2.通过QueryInterface 查询得到 IActiveScriptParse 脚本引擎解析的接口指针。
3.调用 IActiveScriptParse::InitNew() 初始化脚本引擎的解析对象
4.调用 IActiveScript::AddNamedItem() 指定本次使用引擎的项目名称。
5.调用 IActiveScriptParse::ParseScriptText() 提交脚本的文本。
6.调用 IActiveScript::SetScriptState() 开始执行。
7.调用 IActiveScript::Close() 关闭引擎,释放接口指针。
第一个步骤中,要提供脚本引擎的CLSID或ProgID。当前的Windows平台提供了5种引擎:
脚本引擎 | ProgID | CLSID |
VBScript | VBScript | {B54F3741-5B07-11CF-A4B0-00AA004A55E8} |
VBScript encoding | VBScript.Encode | {B54F3743-5B07-11cf-A4B0-00AA004A55E8} |
JScript | JScript | {F414C260-6AC0-11CF-B6D1-00AA00BBBB58} |
JScript encoding | JScript.Encode | {F414C262-6AC0-11CF-B6D1-00AA00BBBB58} |
XMLScript | XML | {989D1DC0-B162-11D1-B6EC-D27DDCF9A923} |
第四个步骤,AddNamedItem()的时候,引擎会调用主机IActiveScriptSite::GetItemInfo()的方法,用来取得与脚本交互的自动化组件的类型库和 IUnknown 指针。
三、事例程序的实现
事例程序是一个用ATL写的ActiveX控件。实现了对用户输入的一个 f(x) 函数,在当前的 ActiveX 的窗口区域中进行函数曲线的绘图功能。由于实现的是一个 ActiveX 控件,它本身就提供了IDispatch的自动化接口,因此这个ActiveX对象,既是一个脚本主机(IActiveScriptSite),又是一个和脚本交互的自动化对象。
程序的工作原理:当用户输入一个f(x)的函数式后,把这个输入按照属性提交给ActiveX对象,于是 ActiveX 开始工作。它根据目前窗口区域的像素宽度和横轴(X),纵轴(Y)的区间范围,用循环构造并执行VBScript脚本程序。比如用户输入的函数是sin(x),X的区间范围是[-4,+4],那么在这个区间中共计算200次,每次给出一个 适当的x值,调用脚本计算出y值,然后画点绘制函数曲线。下面这个脚本就是200次调用中第一次调用所动态生成的脚本代码:
'' 本次调用的序号 i = 0 '' 本次调用的计算点,自变量 x 的值 x = -4.0 '' 计算出 y=f(x) 的值 y = sin(x) '' 把结果传送回与脚本交互的自动化对象(当然,这里就是 ActiveX 对象本身) call Result( i, x, y )事例程序中,使用的是VBScript脚本引擎,你可以修改源程序中启动脚本引擎的参数来指定上表中任意一个引擎。当然,我们输入的函数表达式,就要遵照相应的脚本语言的语法了。下表列出了可以在VBScript中使用的算术运算符号和函数,方便读者使用:
+、-、*、/、^、MOD、\ | 加、减、乘、除、幂、模、商 |
Abs() | 绝对值 |
Sgn() | 判断正负数 |
Sqr() | 平方根 |
Int() | 舍弃小数,如果输入是负数,则取得小于输入值的最大负数 |
Fix() | 舍弃小数,如果输入是负数,则取得大于输入值的最小负数 |
Round() | 四舍五入 |
Log() | e为底的对数 |
Exp() | e的幂 |
Sin() | 正弦 |
Cos() | 余弦 |
Tan() | 正切 |
Atn() | 反正切 |
Result(i,x,y) | 方法 | 回传给自动化对象坐标点。不要使用,这个是动态地,自动地添加到脚本的最后一行中的调用。 |
Pi | 只读属性 | 其实就是3.1415926,比如可以这样使用 sin(x * pi) |
log10() | 方法 | 10为底的对数 |
四、结束语
本文介绍的重点是在Windows程序中调用脚本的方法。绘制任意的函数曲线,只是脚本调用功能的一个演示。你可以使用脚本引擎实现更多、更有创造性的功能。
好了,到这里,就到这里了,祝大家学习快乐^_^