65.9K
CodeProject 正在变化。 阅读更多。
Home

为您的 .NET 应用程序添加 JavaScript 和 VBScript

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.84/5 (6投票s)

2020年1月14日

MIT

3分钟阅读

viewsIcon

10983

downloadIcon

180

使用 Microsoft 的活动脚本技术轻松为您的应用程序添加脚本支持

Scripting

引言

我想暂时摆脱构建解析器之类的事情,做一些不同的事情,所以这里有一个方便的小库,我已将其添加到您的 .NET 应用程序中以添加脚本支持。

偶尔,我发现需要在我的应用程序中执行 JavaScript,有时是为了抓取,有时只是为了拥有 JS 脚本支持(VBScript 也可以使用),并且至少有一次是为了模拟旧版 ASP。

Microsoft 提供了用于使用这些 COM 接口,但从 .NET 使用它们很麻烦。

幸运的是,这个小库让事情变得简单。

概念化这个混乱的局面

Microsoft 提供了一个可扩展的脚本框架,他们在旧版 ASP 页面和 Internet Explorer 中使用。 默认情况下,Windows 附带 VBScript 和 JavaScript (JScript),但第三方已经添加了其他脚本。

这些脚本引擎是 COM 可见的,并将它们的脚本公开为 COM 对象,这些对象可以调用您的代码或被您的代码调用。 唯一的问题是接口很混乱。

我所做的是将这些接口包装在两个易于使用的对象中,`ScriptHost` 和 `ScriptEngine`。

使用这个烂摊子

首先,脚本引擎无法独立存在。 他们需要一个扎根的地方。 这就是 `ScriptHost` 的作用。 `ScriptHost` 管理脚本引擎的创建和生命周期,并为脚本引擎提供各种服务,例如错误报告和对象检索。 在创建任何脚本引擎之前,我们必须创建其中一个小型对象。 记住在完成后将其释放。 关闭脚本宿主也会关闭它创建的所有引擎。

接下来,我们有 `ScriptEngine`,您可以通过 `ScriptHost.Create()` 获取它。 这些代表脚本代码的独立区域。 为了了解这意味着什么,要知道网页中的每个 `<script>` 块都对应于其中一个,而页面本身将是 `ScriptHost`。 将一种语言传递给 `Create()` 以获取您所需语言的脚本引擎。 有一个 "快速 "JS 引擎,您可以通过传递 `ChakraJS` 常量来访问它,但我还没有测试过它,我不确定它实际上有多快。

使用 `ScriptEngine`,我们可以 `Evaluate()` 表达式,`Run()` 语句,或 `AddCode()` 到脚本块中。 我们还可以将对象添加到 Globals 字典中,然后可以通过其名称在您的脚本代码中访问这些对象。

希望演示代码能让一切都变得清晰

Console.WriteLine("Creating script host");
using (var host = new ScriptHost())
{
    // create a JavaScript engine
    Console.WriteLine("Creating javascript engine");
    var engine = host.Create("javascript"); // you can use the ChakraJS const here 
                                            // for IE9+'s fast engine
                                            // evaluate an expression
    Console.WriteLine("Evaluate 2+2: ");
    Console.WriteLine(engine.Evaluate("2+2"));
                
    // add some code to the current script
    Console.WriteLine("Add code: var i = 1;");
    engine.AddCode("var i = 1;");
                
    // get the object for the script
    Console.Write("i = ");
    dynamic obj = engine.Script;
                
    // print var i
    Console.WriteLine(obj.i);
                
    // add an app object to the script
    Console.WriteLine("Add global app object");
    engine.Globals.Add("app", new AppObject());
                
    // let the script call the app object
    Console.Write("Run \"app.writeLine('Hello World!');\": ");
    engine.Run("app.writeLine('Hello World!');");
}

请注意,我们已将 `AppObject` 添加到上面的脚本引擎中。 这是它的定义

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDispatch /*.AutoDual */)]  // automatically 
                                 // implements com interface IDispatch ( and IUnknown )
public class AppObject
{
    /// <summary>
    /// allows scripts to write to the console
    /// </summary>
    public void writeLine(string s) { Console.WriteLine(s); }
}

请注意,我们已从 `System.Runtime.InteropServices` 添加了几个属性。 这是必需的,以便 .NET 创建让脚本通过 COM/OLE 自动化与对象通信所需的基础设施。 如果您不添加这些,您的脚本将无法与您的对象通信,并且您将收到错误。

另请注意,奇怪的是,尽管每个脚本引擎都有自己的全局集合,但脚本站点中的所有全局变量都共享相同的命名容器。 这意味着无论在哪个脚本引擎下创建,每个名称只有一个全局变量是有效的。 如果两个脚本引擎具有相同名称的项,则只有第一个实例将与该名称关联。 将对象添加到两个或多个脚本引擎下相同的名称是可以的。 我不是这样设计的 - 这是 Microsoft Active Script 框架设计的一部分。

就这样。 从这里开始,将 JavaScript 和 VBScript 脚本添加到您的应用程序应该足够简单了。 玩得开心!

历史

  • 2020 年 1 月 14 日 - 初次提交
© . All rights reserved.