當前位置:首頁>>開發(fā)編程>>VS.NET>>新聞內(nèi)容
在C#中調用JavaScript等腳本的實現(xiàn)
作者:秋楓 發(fā)布時間:2004-4-29 9:49:05 文章來源:csdn

以前在做工作流(workflow)項目的時候,里面有一項就是在用戶制定流程定義時可以編寫腳本來控制活動的跳轉,而這些腳本定義后存在數(shù)據(jù)庫中,當流程啟動的時候,工作流引擎會控制活動執(zhí)行順序,串型的兩個活動比較簡單,但有的活動到下一個活動有條件判斷,或者存在多個分支,簡單的還好,只要在數(shù)據(jù)庫表中加個字段就可以實現(xiàn),復雜一點的就需要通過腳本實現(xiàn)了。當時經(jīng)驗不夠,幾天都沒找到快速的解決辦法,想自己寫一個自定義腳本引擎沒有把握,而且時間也不夠,還是在網(wǎng)上找找看吧,花了一些時間,還是找到了一個自認為比較好的解決辦法,寫出來同大家分享。
下面通過兩部分來說明實現(xiàn)以及應用。

一.使用MSScriptControl

到微軟的網(wǎng)站上下載Windows Script Control,它是一個ActiveX(R) 控件,所以在.NET中使用我Interop了一下。下載安裝完成后,新建一個C#的Windows應用程序項目,在解決方案資源管理器中選中引用節(jié)點,右鍵點擊選擇添加引用菜單,彈出添加引用對話框,單擊瀏覽找到安裝Windows Script Control的目錄,選取msscript.ocx文件確定。那么在引用節(jié)點下會增加一個MSScriptControl組件,下面是他Interop后的所有對象。

 

 

ScriptControl 對支持 ActiveX(TM) Script 的宿主 Script 引擎提供簡單接口。接下來我們對被轉化成ScriptControlClass類的ScriptControl的屬性和方法進行一些說明。

屬性

AllowUI 屬性:應用于 ScriptControl 本身或 Scirpt 引擎顯示的用戶界面元素,可讀寫。

CodeObject 屬性:返回對象,該對象用于調用指定模塊的公用成員。只讀。

Error 屬性:返回 Error 對象,其中包含所發(fā)生的最后一個錯誤的相關詳細信息。只讀。

Language 屬性:設置或返回正在使用的 Script 語言名稱?勺x寫。

Modules 屬性:為 ScriptControl 對象返回模塊集合。只讀。

Procedures 屬性:返回在指定模塊中定義的過程集合。只讀。

SitehWnd 屬性:設置或返回窗口的 hWnd,通過執(zhí)行 Script 代碼,此窗口用于顯示對話框和其他用戶界面元素?勺x寫。

State 屬性:設置或返回 ScriptControl 對象的模式?勺x寫。

Timeout 屬性:設置或返回時間(毫秒),此時間后用戶可選擇中止 Script 代碼的執(zhí)行或允許代碼繼續(xù)執(zhí)行?勺x寫。

UseSafeSubset 屬性:設置或返回 Boolean 值,指明宿主應用程序是否有保密性要求。如果宿主應用程序需要安全控制,則 UseSafeSubset 為 True,否則為 False?勺x寫。

方法

AddCode 方法:向模塊添加指定代碼?啥啻握{用 AddCode 方法。

AddObject 方法:使主機對象模型對 Script 引擎可用。

Eval 方法:計算表達式并返回結果。

ExecuteStatement 方法:執(zhí)行指定的語句。

Reset 方法:放棄所有已經(jīng)添加到 ScriptControl 中的 Script 代碼和對象。

Run 方法:運行指定過程。

事件

Error 事件:出現(xiàn)運行時錯誤時,發(fā)生此事件。

Timeout 事件:當超出了 Timeout 屬性指定的時間且用戶在結果對話框中選定了 End 時,發(fā)生此事件。

補充幾點

AllowUI 屬性如果設置為false,則顯示對話框之類的語句不起作用,如在 VBScript 中MsgBox 語句,JavaScript中的alert等,并且如果執(zhí)行的腳本超出TimeOut設置的毫秒數(shù),也不會跳出超出時間提醒的對話框,反之則相反;重新設置 Language 屬性會清空AddCode加載的代碼;對于TimeOut屬性,發(fā)生超時時,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>

         ///構造函數(shù)

         /// </summary>

         public ScriptEngine():this(ScriptLanguage.VBscript)

         {

         }

         /// <summary>

         /// 構造函數(shù)

         /// </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">函數(shù)體</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">函數(shù)體</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">入口函數(shù)名稱</param>

         /// <param name="parameters">參數(shù)</param>

         /// <param name="codeBody">函數(shù)體</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">入口函數(shù)名稱</param>

         /// <param name="parameters">參數(shù)</param>

         /// <param name="codeBody">函數(shù)體</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>

         /// 放棄所有已經(jīng)添加到 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>

         /// 獲取或設置腳本執(zhí)行時間,單位為毫秒

         /// </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事件激發(fā)

         /// </summary>

         private void OnError()

         {

              if(RunError!=null)

                   RunError();

         }

         /// <summary>

         /// OnTimeout事件激發(fā)

         /// </summary>

         private void OnTimeout()

         {

              if(RunTimeout!=null)

                   RunTimeout();

         }

         private void ScriptEngine_Error()

         {

              OnError();

         }

         private void ScriptEngine_Timeout()

         {

              OnTimeout();

         }

     }

}

上面的包裝定義了一個ScriptLanguage枚舉,這樣操作起來更方便一點。另外腳本引擎包括了Error事件和Timeout事件,根據(jù)實際使用情況可進行注冊。

 

二.腳本引擎演示

     我建了個窗體程序,測試包括腳本語言的選擇,是否開啟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)//執(zhí)行Eval方法

              {

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

              }

              else//執(zhí)行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();

         }

         //錯誤函數(shù)

         private void scriptEngine_RunError()

         {

              MessageBox.Show("RunError執(zhí)行腳本錯誤!");

         }

         private void scriptEngine_RunTimeout()

         {

              MessageBox.Show("RunTimeout執(zhí)行腳本超時,引發(fā)錯誤!");

         }

     }

}


下面是測試程序運行界面:

 

 

在文本框中寫了一個JavaScript的函數(shù)。輸入12,輸出12000012。

如果把超時時間調整為1毫秒,那么執(zhí)行該腳本就會跳出下面的超時提醒框,同時激發(fā)事件。

 

 

  總結,上面演示了JavaScript腳本,如果有興趣讀者可以寫一些VBsript函數(shù)進行測試,腳本語言也只列出了三種,看了幫助,他還支持其他一些腳本,如果需要可以添加。另外,因為是調用Com,有些返回值是obejct類型的,需要進行轉換。在CSDN的技術論壇C#板塊下時常有朋友問這方面的問題,對于碰到這類問題的朋友,希望通過這篇文章能獲得一些你需要的幫助,很高興能和搞.net的朋友進行交流,我的郵件地址zhzuocn@163.com


最新更新
·C#中使用Split分隔字符串的技
·VS2008開發(fā)中Windows Mobile
·PC機和移動設備上絕對路徑的
·C#程序加殼的方法(使用Sixx
·當前上下文中不存在名稱Conf
·請插入磁盤:Visual Studio 2
·用VS.NET讀取Flash格式文件信
·在ASP.NET中使用AJAX的簡單方
·VS.NET 2005中常用的一些代碼
·安裝VS.NET 2005 SP1補丁全攻
相關信息
·C#中使用Split分隔字符串的技巧
·PC機和移動設備上絕對路徑的獲取(C#)
·C#程序加殼的方法(使用Sixxpack)
·當前上下文中不存在名稱ConfigurationManager的解決方法
·C#的支付寶Payto接口代碼
·C#實現(xiàn)窗口最小化到系統(tǒng)托盤
·解密QQ的MsgEx.db消息文件格式
·QQ的TEA填充算法C#實現(xiàn)
·C#用Guid獲取不規(guī)則的唯一值(標識)
·基于Windows Mobile 5.0的掌上天氣預報設計
畫心
愚愛
偏愛
火苗
白狐
畫沙
犯錯
歌曲
傳奇
稻香
小酒窩
獅子座
小情歌
全是愛
棉花糖
海豚音
我相信
甩蔥歌
這叫愛
shero
走天涯
琉璃月
Nobody
我愛他
套馬桿
愛是你我
最后一次
少女時代
灰色頭像
斷橋殘雪
美了美了
狼的誘惑
我很快樂
星月神話
心痛2009
愛丫愛丫
半城煙沙
旗開得勝
郎的誘惑
愛情買賣
2010等你來
我叫小沈陽
i miss you
姑娘我愛你
我們都一樣
其實很寂寞
我愛雨夜花
變心的玫瑰
犀利哥之歌
你是我的眼
你是我的OK繃
貝多芬的悲傷
哥只是個傳說
丟了幸福的豬
找個人來愛我
要嫁就嫁灰太狼
如果這就是愛情
我們沒有在一起
寂寞在唱什么歌
斯琴高麗的傷心
別在我離開之前離開
不是因為寂寞才想你
愛上你等于愛上了錯
在心里從此永遠有個你
一個人的寂寞兩個人的錯