以前在做工作流(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类型的,需要进行转换。

转载于:https://www.cnblogs.com/pojianhuadie/archive/2006/05/08/393982.html

在.net中调用vb脚本(ITpro专用的vb脚本,而不是浏览器vb脚本)相关推荐

  1. iOS程序中调用系统自带应用(短信,邮件,浏览器,地图,appstore,拨打电话,iTunes,iBooks )...

    在网上找到了下在记录下来以后方便用 在程序中调用系统自带的应用,比如我进入程序的时候,希望直接调用safar来打开一个网页,下面是一个简单的使用: 查看更多iPhone应用程序的调用和第三方应用程序的 ...

  2. 服务器脚本执行sql文件命令行,sh命令执行sql脚本

    sh命令执行sql脚本 内容精选 换一换 GAUSS-51400 : "Failed to execute the command: %s."SQLSTATE: 无错误原因: 执行 ...

  3. java 执行js脚本_java中调用js脚本

    JDK1.6加入了对Script(JSR223)的支持.这是一个脚本框架,提供了让脚本语言来访问Java内部的方法.你可以在运行的时候找到脚本引擎,然后调用这个引擎去执行脚本.这个脚本API允许你为脚 ...

  4. 在c#中调用windows脚本的方法

    在c#中调用windows脚本的方法 方法1:直接调用   CODE:   System.Diagnostics.Process proc = new System.Diagnostics.Proce ...

  5. Mac笔记本中是用Idea开发工具在Java项目中调用python脚本遇到的环境变量问题解决...

    问题描述: mac笔记本本身会自带几个python版本,比如python2.7版本,我没有改动mac默认的python版本,只是安装了python3.7版本. 使用Pycharm开发Python项目没 ...

  6. c++中调用python脚本提示 error LNK2001: 无法解析的外部符号 __imp_Py_Initialize等错误的解决方法

    c++中调用python脚本提示 error LNK2001: 无法解析的外部符号 __imp_Py_Initialize等错误的解决方法 时间:2017-05-09 12:32:06阅读:234评论 ...

  7. excel调用python编程-如何在excel中调用python脚本

    如何在excel中调用python脚本 发布时间:2020-07-03 14:15:28 来源:亿速云 阅读:155 如何在excel中调用python脚本?针对这个问题,这篇文章详细介绍了相对应的分 ...

  8. 【Groovy】Groovy 脚本调用 ( Java 类中调用 Groovy 脚本 )

    文章目录 前言 一.Groovy 类中调用 Groovy 脚本 1.参考 Script#evaluate 方法分析 Groovy 类中调用 Groovy 脚本 2.创建 Binding 对象并设置 a ...

  9. 【Groovy】Groovy 脚本调用 ( Groovy 类中调用 Groovy 脚本 | 创建 GroovyShell 对象并执行 Groovy 脚本 | 完整代码示例 )

    文章目录 一.Groovy 类中调用 Groovy 脚本 1.创建 GroovyShell 对象并执行 Groovy 脚本 2.代码示例 二.完整代码示例 1.调用者 Groovy 脚本的类 2.被调 ...

最新文章

  1. MySQL 优化原理(一)
  2. spring自定义作用域 依赖注入之手动注入
  3. MongoDB数据库备份与恢复
  4. 苹果4如何添加时间插件_苹果手机如何添加九键或26键输入法?iPhone怎样快速切换输入法?...
  5. 如何删除Mac系统里面的所有 DS_Store 文件呢?
  6. JavaScript六种继承方式的递进推演
  7. SWIG Python-C封装 char*相关问题(3)
  8. Docker使用概览图
  9. docker教程_7 Docker-Compose
  10. es6 babel编译
  11. java播放加密后的wav文件,使用Java实时同时播放WAV文件
  12. Android 端天气预报APP的实现(二)阿里云天气预报API的获取
  13. poi设置excel表格边框,字体等
  14. fl_studio-声卡设置、1
  15. 退欧令英国科技业措手不及,可能不再享受多项利好政策
  16. 10个空手套白狼案例:不花一分钱为自己赚大钱
  17. 计算机英语名词简释及省略解释
  18. mysql 按照年龄段分组查询
  19. Mysql插入JSON串会被去一层转义
  20. 【工具】推荐一个轻量级视频播放器——MPC-HC

热门文章

  1. ES6——扩展运算符/三点运算符(...)
  2. LeetCode(811)——子域名访问计数(JavaScript)
  3. 住170平以上的大平层大户型什么感觉?
  4. 摄影专业学生,没有摄影棚,怎么练摄影?
  5. 引人注目的意思是什么,怎么用引人注目造句,引人注目的近义词有哪些?
  6. 营销任何产品都只解决2个功能
  7. 10个人做抖音,8个做不起来,为啥?
  8. React和Vue的模块化
  9. 历史上有过哪些有名的神级显卡?
  10. 华为手机芯片断供,有没有可能回收旧手机解决目前困境?