利用几个代码片段,我试图用Javascript事件处理程序挂钩ActiveX对象 . 我无法确定为什么没有调用事件处理程序 .
Github Repository with project.
Update
通过在'onLoad'事件中将javascript调用放到SayHello(),我能够触发ActiveX事件 . 现在我正在寻找C#调用,以及如何将其挂钩到Javascript使用的ActiveX对象 .
(这也可能依赖于从IE的高级选项中启用本地脚本) .
Message Continued
事件处理程序在same form as described for this question中完成 .
<script for="MyObject" event="OnUpdateString(stuff)">
document.write("<p>" + stuff);
document.writeln("</p>");
</script>
利用MSDN documentation我创建了一个WinForms应用程序,其中包含一个WebBrowser控件,该控件充当ObjectForScripting(与问题无关) . 此容器调用ActiveX事件,但未被Javascript处理 . 我要在ActiveX交互中包含C#Form代码,并允许它作为ActiveX和/或WebBrowser控件的未来用户的参考 .
此文件旨在与新的Windows窗体项目一起使用,其中WebBrowser控件已添加到主窗口 .
C# Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ActiveXObjectSpace;
namespace TestActiveX
{
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
[System.Runtime.InteropServices.ComVisibleAttribute(true)]
public partial class Form1 : Form
{
MyObject myObject = new MyObject();
public Form1()
{
InitializeComponent();
Text = "ActiveX Test";
Load += new EventHandler(Form1_Load);
}
private void Form1_Load(object sender, EventArgs e)
{
webBrowser1.AllowWebBrowserDrop = false;
webBrowser1.ObjectForScripting = this;
webBrowser1.Url = new Uri(@"C:\path\to\TestPage.html");
// Call ActiveX
myObject.SayHello("C# Launch");
}
public string ControlObject()
{
return "<p>Control Object Called.</p>";
}
}
}
在two other code snippets的帮助下,我创建了一个ActiveX对象 . 如上所述,需要在构建之后注册 .
C# ObjectX.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
/// http://blogs.msdn.com/b/asiatech/archive/2011/12/05/how-to-develop-and-deploy-activex-control-in-c.aspx
/// https://stackoverflow.com/questions/11175145/create-com-activexobject-in-c-use-from-jscript-with-simple-event
///
/// Register with %NET64%\regasm /codebase <full path of dll file>
/// Unregister with %NET64%\regasm /u <full path of dll file>
namespace ActiveXObjectSpace
{
/// <summary>
/// Provides the ActiveX event listeners for Javascript.
/// </summary>
[Guid("4E250775-61A1-40B1-A57B-C7BBAA25F194"), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IActiveXEvents
{
[DispId(1)]
void OnUpdateString(string data);
}
/// <summary>
/// Provides properties accessible from Javascript.
/// </summary>
[Guid("AAD0731A-E84A-48D7-B5F8-56FF1B7A61D3"), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IActiveX
{
[DispId(10)]
string CustomProperty { get; set; }
}
[ProgId("MyObject")]
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
[Guid("7A5D58C7-1C27-4DFF-8C8F-F5876FF94C64")]
[ComSourceInterfaces(typeof(IActiveXEvents))]
public class MyObject : IActiveX
{
public delegate void OnContextChangeHandler(string data);
new public event OnContextChangeHandler OnUpdateString;
// Dummy Method to use when firing the event
private void MyActiveX_nMouseClick(string index)
{
}
public MyObject()
{
// Bind event
this.OnUpdateString = new OnContextChangeHandler(this.MyActiveX_nMouseClick);
}
[ComVisible(true)]
public string CustomProperty { get; set; }
[ComVisible(true)]
public void SayHello(string who)
{
OnUpdateString("Calling Callback: " + who);
}
}
}
最后是由浏览器或容器加载的html页面 . 它成功加载ActiveX对象并包含OnUpdateString的事件处理程序 . 它检查可以调用ActiveX提供的函数SayHello并进行调用 .
我希望将Javascript和C#调用写入文档,但不会写入此类条目 .
TestPage.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>DemoCSharpActiveX webpage</title>
</head>
<body>
<script type="text/javascript">
window.objectLoadFailure = false;
</script>
<object id="MyObject" onerror="window.objectLoadFailure = true" classid="clsid:7A5D58C7-1C27-4DFF-8C8F-F5876FF94C64"></object>
<script for="MyObject" event="OnUpdateString(stuff)">
document.write("<p>" + stuff);
document.writeln("</p>");
</script>
<script type="text/javascript">
document.write("<p>Loaded ActiveX Object: " + !window.objectLoadFailure);
document.writeln("</p>");
if (typeof window.external.ControlObject !== "undefined") {
document.write(window.external.ControlObject());
}
var obj = document.MyObject;
if (typeof obj.SayHello !== "undefined") {
document.writeln("<p>Can Call say hello</p>")
}
obj.SayHello("Javascript Load");
</script>
</body>
</html>
包含页面显示此输出
Output
加载的ActiveX对象:调用的真实控制对象 . 可以打电话打招呼
1 回答
Updated ,只要您可以从HTML(
MyObject.object != null
)实例化<object>
,JavaScript事件处理程序的最终问题就是您在调用MyObject.SayHello("Javascript Load")
之前使用document.write
终止原始HTML文档,并将其替换为<p>Loaded ActiveX Object: ...</p>
. 到那时,所有原始的JavaScript事件处理程序都消失了 .因此,以下工作正常,事件被触发和处理(使用
alert
):要使原始逻辑工作,您可以直接操作DOM而不是使用
document.write
. 或者,至少在OnUpdateString
被触发并处理后调用它 .既然我已经看到了完整的消息来源,我可以在这里说出一些错误 .
您可以在
SayHello
内点击一个断点,因为您从C#[MyObject myObject = new MyObject()
]创建MyObject
并从C#[myObject.SayHello("C# Launch")
]调用它 . 删除它,你会发现当你从JavaScript [obj.SayHello("Javascript Load")
]调用它时,它永远不会被调用 .这会导致另一个问题:
<object>
无法成功创建,甚至更多,因此您的JavaScript脚本都不会运行,因为您的测试HTML文件是从本地文件系统提供的(通过file://
协议) . 这是一项安全限制 . 尝试更改您的脚本,如下所示,看不到任何警报实际显示:FEATURE_LOCALMACHINE_LOCKDOWN
,FEATURE_BLOCK_LMZ_SCRIPT
,FEATURE_BLOCK_LMZ_OBJECT
键 . 你可以使用我改编自我的其他related answer的以下代码:<object>
(alert(MyObject.object)
显示null
) . 最后,您需要在ActiveX对象上实现IObjectSafety接口,并且只需要在您自己的HTML页面上实现site-lock . 如果没有正确的IObjectSafety
,将无法在默认的IE安全设置下创建对象 . 如果没有站点锁定,它可能会成为一个巨大的安全威胁,因为任何恶意脚本都可能在您的应用程序上下文之外创建和使用您的对象 .Updated 发表评论:
在您的代码中,
myObject
实例仅由C#创建和访问:此实例与您从HTML创建的
<object id="MyObject" onerror="window.objectLoadFailure = true" classid="clsid:7A5D58C7-1C27-4DFF-8C8F-F5876FF94C64"></object>
实例无关 . 它们是两个独立的,无关的对象 . 您的事件处理程序仅适用于后者<object>
实例 . 您甚至不订阅new MyObject()
实例上的任何事件 .如果我理解你的目标,你需要这个:
现在,将调用JavaScript事件处理程序,您将看到
"C# Button"
警报 .