如何在Javascript中处理ActiveX事件

20

这是对这里的回答的一种跟进。

我有一个自定义的ActiveX控件,它正在触发一个带有“msg”参数的事件(“ReceiveMessage”),需要由Web浏览器中的Javascript处理。从历史上看,我们已经能够在不同的项目中使用以下仅适用于IE的语法来实现这一点:

function MyControl::ReceiveMessage(msg)
{
   alert(msg);
}
然而,当控件被埋在布局中时,Javascript无法找到该控件。具体来说,如果我们将其放入一个普通的HTML页面中,它可以正常工作,但是如果我们将其放入由<Form>标签包装的ASPX页面中,就会出现“MyControl未定义”的错误。我们已尝试以下变化:
var GetControl = document.getElementById("MyControl");
function GetControl::ReceiveMessage(msg)
{
   alert(msg);
}

...但会导致JavaScript错误“GetControl未定义”。

如何正确处理从ActiveX控件发送的事件?目前我们只关心在IE中使其正常工作。对于我们正在做的事情,这必须是自定义的ActiveX控件。

谢谢。


澄清一点 - getElementById 函数运行良好。我们有一个对控件的引用,但 Javascript 不喜欢我们使用该引用的 :: 语法。 - Raelshark
我以前从未见过 :: 语法,它在哪里有文档记录? - AnthonyWJones
很难找到实际的文档,但这里有一个链接指向一个MSDN文章提到了它:http://msdn.microsoft.com/en-us/library/ms974564.aspx - Raelshark
1
值得注意的是,只有使用 OBJECT 标记创建 ActiveX 对象时,事件才能正确连接。如果您正在使用 CreateActiveXObject() 创建对象,则可以执行此操作:http://www.codeproject.com/KB/dotnet/extend_events.aspx?display=Print - Rory
你提到的链接现在正在使用HTTPS -- (https://msdn.microsoft.com/en-us/library/ms974564.aspx)。此外,我曾在[这里](http://stackoverflow.com/q/41713117/111794)提出和回答了这个问题; 我还编写了一个来解决这个问题。(@Rory) - Zev Spitz
7个回答

13

我能使用以下脚本块格式使其工作,但我仍然好奇这是否是最佳方式:

<script for="MyControl" event="ReceiveMessage(msg)">
    alert(msg);
</script>

在互联网上的许多示例中,我看到了以下代码:<script for="MyControl" event="ReceiveMessage"> function ReceiveMessage(msg) { alert(msg); } </script> 虽然上述代码可以工作,但请注意,如果您的事件将被多次触发,则会失败。当我将ReceiveMessag事件钩子连接到ActiveX控件中的计时器时,我发现了这一点,该计时器在给定间隔之后触发。每次事件触发时,处理程序都会被调用事件已触发的次数。(例如:第1次触发:1次,第2次触发:2次,第3次触发:3次)。不知道为什么!有答案吗? - Raj Rao
如果你在<script for="..."标签内使用::语法,那么它会按照你所说的方式进行操作——每次调用时都会重新连接事件。如果只是使用script for或者只是使用function ::语法,我认为它可以正常工作(除非在FORM标签内)。 - Rory
你们中有人成功地让这个方法适用于具有 EventArgs 对象作为参数的方法吗? - Camilo Sanchez
1
没事了,我解决了,ActiveX接口中涉及的每种类型都需要设置为ComVisible。 - Camilo Sanchez
1
从IE 9开始,如果使用HTML object标记,则此事件绑定方法有效。 如果使用“var ax = new ActiveXObject('myProgId')”,那么动态事件绑定就会起作用->“eval('function ax :: EventInterfaceMethod(args){return my JavaScriptMethod(args);}'” - J. Andrew Laughlin
@J.AndrewLaughlin 这个能够正常工作是因为使用 eval 时,函数声明会在变量初始化之后被评估。参见这里 - Zev Spitz

8

我之前在我的应用程序中使用过ActiveX。我将对象标签放置在ASP.NET表单中,以下JavaScript适用于我。

function onEventHandler(arg1, arg2){
    // do something
}

window.onload = function(){
    var yourActiveXObject = document.getElementById('YourObjectTagID');
    if(typeof(yourActiveXObject) === 'undefined' || yourActiveXObject === null){
        alert('Unable to load ActiveX');
        return;
    }

    // attach events
    var status = yourActiveXObject.attachEvent('EventName', onEventHandler);
}

1
这是MSDN链接http://msdn.microsoft.com/en-us/library/ms536343(VS.85).aspx - Zuhaib
我已经有一段时间没有测试这个了,但我相信.attachEvent()只能在控件是使用静态HTML创建的时候才能工作,或者可能是使用document.write()创建的。 - Taudris
1
附注:attachEvent 是 IE 特有的,不适用于 Chrome,基于 WebKit 的相关方法名称是 addEventListener。并且为了更清楚地解释 camilin87 的帖子,这两种方法仅适用于标准事件类型,即 onclick、ontouch 等。不适用于自定义 ActiveX 的事件名称。 - Eric F.
@Taudris 当控件是动态创建时,attachEvent() 对我很有用。我动态创建了 <object> 标签,然后使用 attachEvent() 来挂钩对象的 ActiveX 事件。请注意,在 IE11 模式下,attachEvent() 不可用,因此似乎您提供的动态方法是 IE11 的唯一选择。我为我的应用程序创建了一个函数来使用 attachEvent()(如果可用),但如果不可用,则使用 eval() 方法。 - ewh
@ewh 我向您推荐我的问题答案,以及我为注册任何ActiveX对象事件处理程序编写的 - Zev Spitz

5

好的,但如果您正在使用继承的UserControl (ActiveX)和C# (.NET 2.0)…… 唯一的方法是通过“扩展”事件处理程序功能: http://www.codeproject.com/KB/dotnet/extend_events.aspx?display=Print

我们的朋友Werner Willemsens提供的上述项目链接挽救了我的项目。 如果不这样做,javascript就无法绑定到事件处理程序。

他以复杂的方式使用了“扩展”由于他选择的示例,但如果您将其简单化,将句柄直接附加到事件本身,它也可以工作。 C# ActiveX应支持“ScriptCallbackObject”来将事件绑定到像下面这样的javascript函数:

  var clock = new ActiveXObject("Clocks.clock");
  var extendedClockEvents = clock.ExtendedClockEvents();
  // Here you assign (subscribe to) your callback method!
  extendedClockEvents.ScriptCallbackObject = clock_Callback; 
  ...
  function clock_Callback(time)
  {
    document.getElementById("text_tag").innerHTML = time;
  }

当然,您需要实现IObjectSafety和其他安全相关的内容才能使其更好地工作。

1

我发现这段代码在一个表单标签内有效。在这个例子中,callback是由javascript传递给ActiveX控件的函数参数,而callbackparam是在activeX控件内生成的回调事件的参数。这样我就可以使用相同的事件处理程序来处理不同类型的事件,而不必尝试声明一堆独立的事件处理程序。

<object id="ActivexObject" name="ActivexObject" classid="clsid:15C5A3F3-F8F7-4d5e-B87E-5084CC98A25A"></object>

<script>
function document.ActivexObject::OnCallback(callback, callbackparam){
callback(callbackparam);
}
</script>


1
如果您在页面上有一个id为'MyControl'的ActiveX元素,则您的JavaScript处理程序语法如下:

function MyControl::ReceiveMessage(msg)
{
   alert(msg);
}

如果<object>标签在表单内,我认为这不起作用。 - Frank Schwieterman
@FrankSchwieterman 只有在全局范围内声明了 MyControl,此处理程序才会响应。也许只有表单外的对象才会在全局范围内获取它们的 id - Zev Spitz

1
在我的情况下,我需要一种动态创建ActiveX控件并监听它们事件的方法。我成功地实现了类似以下的功能:
//create the ActiveX
var ax = $("<object></object>", {
    classid: "clsid:" + clsid,
    codebase: install ? cabfile : undefined,
    width: 0,
    height: 0,
    id: '__ax_'+idIncrement++
})
.appendTo('#someHost');

并且为事件注册一个处理程序:
//this function registers an event listener for an ActiveX object (obviously for IE only)
//the this argument for the handler is the ActiveX object.
function registerAXEvent(control, name, handler) {
    control = jQuery(control);

    //can't use closures through the string due to the parameter renaming done by the JavaScript compressor
    //can't use jQuery.data() on ActiveX objects because it uses expando properties

    var id = control[0].id;

    var axe = registerAXEvent.axevents = registerAXEvent.axevents || {};
    axe[id] = axe[id] || {};
    axe[id][name] = handler;

    var script =
    "(function(){"+
    "var f=registerAXEvent.axevents['" + id + "']['" + name + "'],e=jQuery('#" + id + "');"+
    "function document." + id + "::" + name + "(){"+
        "f.apply(e,arguments);"+
    "}"+
    "})();";
    eval(script);
}

这段代码允许您使用闭包并最小化eval()的作用域。
ActiveX控件的元素必须已经添加到文档中;否则,IE将无法找到该元素,您只会得到脚本错误。

1
尽管您的答案使用了jquery-isms,但在处理动态页面时,这是一个有用的答案。我已经成功地使用attachEvent()方法将监听器函数附加到ActiveX事件对象上。不幸的是,在IE11模式下,attachEvent()不再受支持,因此必须使用类似于您所拥有的eval()方法。标准的addEventListener()方法不支持基于ActiveX的事件类型。 - ewh

0

我认为 MyControl::ReceiveMessage 示例无法正常工作,因为 ActiveX 控件是以不同的名称或在不同的范围中公开的。

对于 GetControl::ReceiveMessage 示例,我认为函数定义在设置 GetControl 引用之前被解析,因此它不引用有效对象,无法将函数绑定到对象。

我会使用 MS 脚本调试器来解决这个问题,并尝试确定控件的默认引用是否存在不同的名称或不同的范围(可能作为表单的子级)。如果您可以确定控件的正确引用,则应该能够使用 MSDN 文章指定的 Automagic :: 方法正确地绑定函数。

还有一个想法,引用可能基于对象的名称而不是 ID,因此请尝试同时设置两者 :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接