在C#中调用VBScript和JavaScript等脚本的实现

在C#中调用VBScript、JavaScript等脚本的实现

作者:郑佐

2004-04-26

以前在做工作流(workflow)项目的时候,里面有一项就是在用户制定流程定义时可以编写脚本来控制活动的跳转,而这些脚本定义后存在数据库中,当流程启动的时候,工作流引擎会控制活动执行顺序,串型的两个活动比较简单,但有的活动到下一个活动有条件判断,或者存在多个分支,简单的还好,只要在数据库表中加个字段就可以实现,复杂一点的就需要通过脚本实现了。当时经验不够,几天都没找到快速的解决办法,想自己写一个自定义脚本引擎没有把握,而且时间也不够,还是在网上找找看吧,花了一些时间,还是找到了一个自认为比较好的解决办法,写出来同大家分享。
下面通过两部分来说明实现以及应用。

一.使用MSScriptControl

到微软的网站上下载Windows Script Control,它是一个ActiveX(R) 控件,所以在.NET中使用我Interop了一下。下载安装完成后,新建一个C#的Windows应用程序项目,在解决方案资源管理器中选中引用节点,右键点击选择添加引用菜单,弹出添加引用对话框,单击浏览找到安装Windows Script Control的目录,选取msscript.ocx文件确定。那么在引用节点下会增加一个MSScriptControl组件,下面是他Interop后的所有对象。

ScriptControl 对支持 ActiveX(TM) Script 的宿主 Script 引擎提供简单接口。接下来我们对被转化成ScriptControlClass类的ScriptControl的属性和方法进行一些说明。

属性

AllowUI 属性:应用于 ScriptControl 本身或 Scirpt 引擎显示的用户界面元素,可读写。

CodeObject 属性:返回对象,该对象用于调用指定模块的公用成员。只读。

Error 属性:返回 Error 对象,其中包含所发生的最后一个错误的相关详细信息。只读。

Language 属性:设置或返回正在使用的 Script 语言名称。可读写。

Modules 属性:为 ScriptControl 对象返回模块集合。只读。

Procedures 属性:返回在指定模块中定义的过程集合。只读。

SitehWnd 属性:设置或返回窗口的 hWnd,通过执行 Script 代码,此窗口用于显示对话框和其他用户界面元素。可读写。

State 属性:设置或返回 ScriptControl 对象的模式。可读写。

Timeout 属性:设置或返回时间(毫秒),此时间后用户可选择中止 Script 代码的执行或允许代码继续执行。可读写。

UseSafeSubset 属性:设置或返回 Boolean 值,指明宿主应用程序是否有保密性要求。如果宿主应用程序需要安全控制,则 UseSafeSubset 为 True,否则为 False。可读写。

方法

AddCode 方法:向模块添加指定代码。可多次调用 AddCode 方法。

AddObject 方法:使主机对象模型对 Script 引擎可用。

Eval 方法:计算表达式并返回结果。

ExecuteStatement 方法:执行指定的语句。

Reset 方法:放弃所有已经添加到 ScriptControl 中的 Script 代码和对象。

Run 方法:运行指定过程。

事件

Error 事件:出现运行时错误时,发生此事件。

Timeout 事件:当超出了 Timeout 属性指定的时间且用户在结果对话框中选定了 End 时,发生此事件。

补充几点

AllowUI 属性如果设置为false,则显示对话框之类的语句不起作用,如在 VBScript 中MsgBox 语句,JavaScript中的alert等,并且如果执行的脚本超出TimeOut设置的毫秒数,也不会跳出超出时间提醒的对话框,反之则相反;重新设置 Language 属性会清空AddCode加载的代码;对于TimeOut属性,发生超时时,ScriptControl 检查对象的 AllowUI 属性,确定是否允许显示用户界面元素。

如果读者需要更详细的了解,可以查看MSDN文档。

为了使控件更容易使用,我用一个ScriptEngine类包装了一下,下面是完整代码:

using System;

using MSScriptControl;

using System.Text;

namespace ZZ

{

     /// <summary>

     /// 脚本类型

     /// </summary>

     public enum ScriptLanguage

     {

         /// <summary>

         /// JScript脚本语言

         /// </summary>

         JScript,

         /// <summary>

         /// VBscript脚本语言

         /// </summary>

         VBscript,

         /// <summary>

         /// JavaScript脚本语言

         /// </summary>

         JavaScript

     }

     /// <summary>

     /// 脚本运行错误代理

     /// </summary>

     public delegate void RunErrorHandler();

     /// <summary>

     /// 脚本运行超时代理

     /// </summary>

     public delegate void RunTimeoutHandler();

     /// <summary>

     /// ScriptEngine类

     /// </summary>

     public class ScriptEngine

     {

         private ScriptControl msc;

         //定义脚本运行错误事件

         public event RunErrorHandler RunError;

         //定义脚本运行超时事件

         public event RunTimeoutHandler RunTimeout;

         /// <summary>

         ///构造函数

         /// </summary>

         public ScriptEngine():this(ScriptLanguage.VBscript)

         {

         }

         /// <summary>

         /// 构造函数

         /// </summary>

         /// <param name="language">脚本类型</param>

         public ScriptEngine(ScriptLanguage language)

         {

              this.msc = new ScriptControlClass();

              this.msc.UseSafeSubset = true;

              this.msc.Language = language.ToString();

              ((DScriptControlSource_Event)this.msc).Error += new DScriptControlSource_ErrorEventHandler(ScriptEngine_Error);

              ((DScriptControlSource_Event)this.msc).Timeout += new DScriptControlSource_TimeoutEventHandler(ScriptEngine_Timeout);

         }

         /// <summary>

         /// 运行Eval方法

         /// </summary>

         /// <param name="expression">表达式</param>

         /// <param name="codeBody">函数体</param>

         /// <returns>返回值object</returns>

         public object Eval(string expression,string codeBody)

         {

              msc.AddCode(codeBody);

              return msc.Eval(expression);

         }

         /// <summary>

         /// 运行Eval方法

         /// </summary>

         /// <param name="language">脚本语言</param>

         /// <param name="expression">表达式</param>

         /// <param name="codeBody">函数体</param>

         /// <returns>返回值object</returns>

         public object Eval(ScriptLanguage language,string expression,string codeBody)

         {

              if(this.Language != language)

                   this.Language = language;

              return Eval(expression,codeBody);

         }

         /// <summary>

         /// 运行Run方法

         /// </summary>

         /// <param name="mainFunctionName">入口函数名称</param>

         /// <param name="parameters">参数</param>

         /// <param name="codeBody">函数体</param>

         /// <returns>返回值object</returns>

         public object Run(string mainFunctionName,object[] parameters,string codeBody)

         {

              this.msc.AddCode(codeBody);

              return msc.Run(mainFunctionName,ref parameters);

          }

         /// <summary>

         /// 运行Run方法

         /// </summary>

         /// <param name="language">脚本语言</param>

         /// <param name="mainFunctionName">入口函数名称</param>

         /// <param name="parameters">参数</param>

         /// <param name="codeBody">函数体</param>

         /// <returns>返回值object</returns>

         public object Run(ScriptLanguage language,string mainFunctionName,object[] parameters,string codeBody)

         {

              if(this.Language != language)

                   this.Language = language;

              return Run(mainFunctionName,parameters,codeBody);

         }

         /// <summary>

         /// 放弃所有已经添加到 ScriptControl 中的 Script 代码和对象

         /// </summary>

         public void Reset()

         {

              this.msc.Reset();

         }

         /// <summary>

         /// 获取或设置脚本语言

         /// </summary>

         public ScriptLanguage Language

         {

              get{return (ScriptLanguage)Enum.Parse(typeof(ScriptLanguage),this.msc.Language,false);}

              set{this.msc.Language = value.ToString();}

         }

         /// <summary>

         /// 获取或设置脚本执行时间,单位为毫秒

         /// </summary>

         public int Timeout

         {

              get{return this.msc.Timeout;}

              set{this.msc.Timeout = value;}

         }

         /// <summary>

         /// 设置是否显示用户界面元素

         /// </summary>

         public bool AllowUI

         {

              get{return this.msc.AllowUI;}

              set{this.msc.AllowUI = value;}

         }

         /// <summary>

         /// 宿主应用程序是否有保密性要求

         /// </summary>

         public bool UseSafeSubset

         {

              get{return this.msc.UseSafeSubset;}

              set{this.msc.UseSafeSubset = true;}

         }

         /// <summary>

         /// RunError事件激发

         /// </summary>

         private void OnError()

         {

              if(RunError!=null)

                   RunError();

         }

         /// <summary>

         /// OnTimeout事件激发

         /// </summary>

         private void OnTimeout()

         {

              if(RunTimeout!=null)

                   RunTimeout();

         }

         private void ScriptEngine_Error()

         {

              OnError();

         }

         private void ScriptEngine_Timeout()

         {

              OnTimeout();

         }

     }

}

上面的包装定义了一个ScriptLanguage枚举,这样操作起来更方便一点。另外脚本引擎包括了Error事件和Timeout事件,根据实际使用情况可进行注册。

二.脚本引擎演示

     我建了个窗体程序,测试包括脚本语言的选择,是否开启AllowUI属性,超时时间的设置,以及脚本引擎调用方法的选择。测试程序代码比较长,下面列出了主要部分:

using System;

using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

namespace ZZ

{

     public class Form1 : System.Windows.Forms.Form

     {

         private ScriptEngine scriptEngine;

         private System.Windows.Forms.CheckBox checkBoxAllowUI;

         private System.Windows.Forms.TextBox textBoxResult;

         private System.Windows.Forms.NumericUpDown numericUpDownTimeout;

         private System.Windows.Forms.TextBox textBoxCodeBody;

         private System.Windows.Forms.Button buttonRun;

         private System.Windows.Forms.Button buttonCancel;

         private System.Windows.Forms.ComboBox comboBoxScript;

         private System.Windows.Forms.TextBox textBoxParams;

         private System.Windows.Forms.RadioButton radioButtonEval;

         private System.Windows.Forms.RadioButton radioButtonRun;

         private System.Windows.Forms.TextBox textBoxMethodName;

         private System.ComponentModel.Container components = null;

         public Form1()

         {

              InitializeComponent();

              this.comboBoxScript.SelectedIndex = 0;

              this.scriptEngine = new ScriptEngine();

              this.scriptEngine.UseSafeSubset = true;

              this.scriptEngine.RunError += new RunErrorHandler(scriptEngine_RunError);

              this.scriptEngine.RunTimeout += new RunTimeoutHandler(scriptEngine_RunTimeout);

         }

         protected override void Dispose( bool disposing )

         {

              if( disposing )

                   if (components != null)

                       components.Dispose();

              base.Dispose( disposing );

         }

         #region Windows 窗体设计器生成的代码

         private void InitializeComponent()

         {

              //省略

         }

         #endregion

          [STAThread]

         static void Main()

         {

              Application.Run(new Form1());

         }

         //运行脚本

         private void buttonRun_Click(object sender, System.EventArgs e)

         {

              this.scriptEngine.Reset();

              this.scriptEngine.Language = (ScriptLanguage)Enum.Parse(typeof(ScriptLanguage),this.comboBoxScript.SelectedItem.ToString());

              this.scriptEngine.Timeout = (int)this.numericUpDownTimeout.Value;

              this.scriptEngine.AllowUI = this.checkBoxAllowUI.Checked;

              if(this.radioButtonEval.Checked)//执行Eval方法

              {

                   this.textBoxResult.Text = this.scriptEngine.Eval(this.textBoxMethodName.Text+"("+this.textBoxParams.Text+")",this.textBoxCodeBody.Text).ToString();

              }

              else//执行Run方法

              {

                   string[] parameters = (string[])this.textBoxParams.Text.Split(‘,‘);

                   object [] paramArray = new object[parameters.Length];

                   for(int i = 0;i<parameters.Length;i++)

                       paramArray[i] = Int32.Parse(parameters[i]);

                   this.textBoxResult.Text = this.scriptEngine.Run(this.textBoxMethodName.Text,paramArray,this.textBoxCodeBody.Text).ToString();

              }

         }

         //退出程序

         private void buttonCancel_Click(object sender, System.EventArgs e)

         {

              this.Close();

         }

         //错误函数

         private void scriptEngine_RunError()

         {

              MessageBox.Show("RunError执行脚本错误!");

         }

         private void scriptEngine_RunTimeout()

         {

              MessageBox.Show("RunTimeout执行脚本超时,引发错误!");

         }

     }

}

在文本框中写了一个JavaScript的函数。输入12,输出12000012。

如果把超时时间调整为1毫秒,那么执行该脚本就会跳出下面的超时提醒框,同时激发事件。

总结,上面演示了JavaScript脚本,如果有兴趣读者可以写一些VBsript函数进行测试,脚本语言也只列出了三种,看了帮助,他还支持其他一些脚本,如果需要可以添加。另外,因为是调用Com,有些返回值是obejct类型的,需要进行转换。在CSDN的技术论坛C#板块下时常有朋友问这方面的问题,对于碰到这类问题的朋友,希望通过这篇文章能获得一些你需要的帮助,很高兴能和搞.net的朋友进行交流,我的邮件地址[email protected]。

引用 :http://blog.csdn.net/zhzuo/article/details/22031

资料: http://www.cnblogs.com/hailexuexi/archive/2011/02/15/1955166.html

时间: 2024-08-24 06:12:24

在C#中调用VBScript和JavaScript等脚本的实现的相关文章

Shell中调用/引用/包含另外的脚本文件的两种方法

脚本 first (测试示例1) #vi  first.sh 1 #!/bin/bash 2 echo 'your are in first file' 问)在当前脚本文件中调用另外一个脚本文件? 方法一: 使用 source 脚本 second (测试示例2)# vi second.sh 1 #!/bin/bash 2 echo 'your are in second file' 3 source first.sh 注意事项:分别建立# vi first.sh 和 second.sh 测试:#

在批处理中调用VBScript(支持获取返回值)

有个帖子简单介绍了利用mshta来调用vbs的方法(链接).虽该文章作者认为 到此,在bat中使用vbs得到了完全解决.从此可以在bat和vbs间自由的航行了. 但任然无法获取vbs的返回值,可见该方法有一定缺陷.于是写出该帖子来补充一下下~先不看这个缺陷,原调用代码的html标签也可以不要(lz最早是看见zhonghua兄使用该方法) Mshta Vbscript:VBS命令(Close) 感谢zhonghua,我们来看几个例子: Mshta Vbscript:Msgbox("Hello,wo

C# winForm中调用javascript文件中的方法

目前有很多的SNS社区或类SNS的网站,例如开心.51.校内等,但是发现大多数社区在邀请好友的时候都没有提供对QQ邮箱或者QQ空间好友列表获取的功能,不过似乎海内支持,但是网上相关QQ的文章还不是很多,希望这篇文章能给你带来一些帮助. QQ空间及邮箱登陆的校验方式: QQ空间及邮箱登陆的时候,用户输入的密码首先会被页面中的一段Js加密,然后加密过后的密码会加上验证码形成一个新的字串,接着这个新的字串被MD5(32位)加密,加密过后形成最终的密码,这就是我们为什么经常会发现我们在提交的时候我们的密

在 Flash ActionScript 2.0 中调用 Javascript 方法

本篇文章由:http://xinpure.com/call-the-javascript-method-in-flash-actionscript-2-0/ 在 Flash ActionScript 2.0 中调用 Javascript 方法 最近在工作中,有个这样的需求: 要从 Flash ActionScript 2.0 中调用网页上的 Javascript 方法 这是一个关于 Flash 和 Javascript 交互的问题. 在 ActionScript 2.0 中调用外部 javasc

Hybrid App开发模式中, IOS/Android 和 JavaScript相互调用方式

IOS:Objective-C 和 JavaScript 的相互调用 iOS7以前,iOS SDK 并没有原生提供 js 调用 native 代码的 API.但是 UIWebView 的一个 delegate 方法使我们可以做到让 js 需要调用时,通知 native.在 native 执行完相应调用后,可以用stringByEvaluatingJavaScriptFromString 方法,将执行结果返回给 js.这样,就实现了 js 与 native 代码的相互调用.具体让 js 通知 na

JDK1.7中调用javascript方法

import java.io.File; import javax.script.Invocable; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; public class TestJs { public static void main(String[] args) throws Exception { Script

Effective JavaScript Item 38 在子类构造函数中调用父类构造函数

本系列作为Effective JavaScript的读书笔记. 在一个游戏或者图形模拟的应用中,都会有场景(Scene)这一概念.在一个场景中会包含一个对象集合,这些对象被称为角色(Actor).而每个角色根据其类型会有一个图像用来表示,同时场景也需要保存一个底层图形展示对象的引用,被称为上下文(Context): function Scene(context, width, height, images) { this.context = context; this.width = width

javascript引擎在c,c+中调用

JavaScript是一种广泛用于Web客户端开发的脚本语言,常用来控制浏览器的DOM树,给HTML网页添加动态功能.目前JavaScript遵循的web标准的是ECMAScript262.由于JavaScript提供了丰富的内置函数.良好的对象机制.所以JavaScript还可以嵌入到某一种宿主语言中,弥补宿主语言的表现力,从而实现快速.灵活.可定制的开发. 软件程序应用javascript 现有的主流浏览器基本上都实现了一个自己的JavaScript引擎.这些JavaScript引擎可以分析

C#中调用javascript

结合网上的代码整理了一下c#中调用js的方法,仅用于留存. ps.测试用的js文件需要放到bin\Debug下 代码如下: using System; using System.IO; namespace CallJSTest { class Program { static void Main(string[] args) { CallJs(); } private static void CallJs() { string path = AppDomain.CurrentDomain.Bas