使用 JScript 的 HTA 中的 ActiveX 事件处理程序

ActiveX event handlers in an HTA using JScript

在 C# 中,我可以按如下方式编写事件处理程序:

var wdApp = new Microsoft.Office.Interop.Word.Application();
wdApp.DocumentBeforeSave += (Document doc, ref bool saveAsUI, ref bool cancel) => {
   //do stuff here
};

在VBA/VB6中,我可以使用静态事件处理:

Dim WithEvents wdApp As Word.Application

Private Sub wdApp_DocumentBeforeSave(ByVal Doc As Document, SaveAsUI As Boolean, Cancel As Boolean)
    'do stuff here
End Sub

我更愿意使用动态事件处理。但是,在 JScript 中,即使使用静态事件处理和描述的语法 here:

var wdApp = new ActiveXObject('Word.Application');
wdApp.Visible = true;

function wdApp::Quit() {
    window.alert('Quit');
};

失败:

0x800a138f - JScript runtime error: Object expected

此外,静态事件处理是 VBA/VB6 中的一个选项,因为声明可以标记为 Private。但是,在 JScript 中,变量和处理程序都必须在全局范围内声明。

两个问题:

  1. 如何在 HTA 环境中使用 JScript 处理自动化创建对象的事件? (注意:我知道在 WSH 中可以使用传递给 CreateObject 的前缀和名为 wdApp_Quit 的函数,但我正在寻找 HTA 解决方案。)

  2. 如何在不污染全局范围的情况下做到这一点?


有一个较旧的问题 here

错误似乎是因为

  1. 在Javascript/JScriptfunction declarations are evaluated first,变量初始化之前。好像代码是这样写的:

     var wdApp;
     function wdApp::Quit() { ... }
     wdApp = new ActiveXObject('Word.Application');
    
  2. Microsoft JScript 解析器将 specially-named 声明(带有 ::)解释为将函数附加为事件处理程序的指令。

  3. 但是在声明的时候,处理程序不能附加到wdApp引用的对象上,因为wdApp在那个时候仍然是undefined.因此,错误。

解决办法是在wdApp初始化后强制对函数声明求值。这可以通过以下三种方式之一完成1:

  1. 由于函数声明仅在函数范围内被提升,因此将函数声明包装在 IIFE 中:

     var wdApp = new ActiveXObject('Word.Application');
     (function() {
         function wdApp::Quit() {
             //do stuff here
         }
     })();
    
  2. 使用某种字符串 -> 代码机制创建声明 -- evalsetTimeout 和字符串、window.execScriptnew Function:

     var wdApp = new ActiveXObject('Word.Application');
     eval('function wdApp::Quit() { ... }`);
    
  3. 初始化当前SCRIPT块之前的变量。 Scripting Events 文章中的大多数示例通过在 SCRIPT 块之前的某个元素上设置 id 属性 来实现:

<object progid="ordersystem.clsorder" id="myorder" events="true"/>
<script language="jscript">
    function myorder::onNew() {
      WScript.Echo("new order received from myorder")
    }
//...

但这也可以使用多个 SCRIPT 块来完成:

    <SCRIPT>
        var wdApp = new ActiveXObject('Word.Application');
    </SCRIPT>
    <SCRIPT>
        function wdApp::Quit() {
            //do stuff here
        }
    </SCRIPT>

就污染全局命名空间而言,只有第三种变体需要 wdApp 在全局命名空间中;其他两个变体可以包装在 IIFE 中。


1.从技术上讲,在IE和HTAs下还有第四种方式,但是涉及non-standardHTML而不是non-standardJavascript;但它只能在使用 HTML OBJECT 标记而不是 new ActiveXObject( ... ) 声明对象时使用。

<script for="wdApp" event="Quit">
    //do stuff here
</script>