Utilizing several code snippets I've attempted to hook up an ActiveX object with a Javascript event handler. I'm unable to identify why the event handler isn't being called.
Github Repository with project.
Update
By placing the javascript call to SayHello() in an 'onLoad' event, I was able to get the ActiveX event to fire. Now I'm looking toward the C# call, and how to hook it into the ActiveX object utilized by Javascript.
(This may also have relied on enable local scripts from the Advanced options of IE).
Message Continued
The event handler is done in the same form as described for this question.
<script for="MyObject" event="OnUpdateString(stuff)">
document.write("<p>" + stuff);
document.writeln("</p>");
</script>
Utilizing MSDN documentation I created a WinForms app that contains a WebBrowser control that acts as the ObjectForScripting (not related to the issue). This container makes a call out to the ActiveX event, but is unhandled by the Javascript. I'm including the C# Form code to be complete in the ActiveX interactions and to allow this to be a reference for future users of ActiveX and/or WebBrowser control.
This file is intended to be used with a new Windows Form project where a WebBrowser control was added to the main window.
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>";
}
}
}
Combining from the help of two other code snippets I created a the ActiveX object. Which, as noted, needs to be registered after being built.
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);
}
}
}
Last is the html page which is to be loaded by the browser or container. It loads the ActiveX object successfully and contains an event handler for OnUpdateString. It checks that the ActiveX provided function, SayHello, can be called and makes the call.
I'd expect the Javascript and C# call to be written to the document, but no such entries are written.
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>
The containing page shows this output
Output
Loaded ActiveX Object: true
Control Object Called.
Can Call say hello