Как подключить обработчик событий ActiveX C# в Javascript
используя несколько фрагментов кода, я попытался подключить объект ActiveX с помощью обработчика событий Javascript. Я не могу определить, почему обработчик событий не вызывается.
репозиторий Github с проектом.
обновление
разместив вызов javascript для SayHello () в событии "onLoad", я смог получить событие ActiveX для запуска. Теперь я смотрю на вызов C# и как подключить его к ActiveX объект, используемый Javascript.
(это также может зависеть от включения локальных скриптов из расширенных опций IE).
Сообщение Продолжение
обработчик событий выполняется в такая же форма как описано на этот вопрос.
<script for="MyObject" event="OnUpdateString(stuff)">
document.write("<p>" + stuff);
document.writeln("</p>");
</script>
использование документация MSDN Я создал приложение WinForms, которое содержит элемент управления WebBrowser, который действует как ObjectForScripting (не связанный с проблемой). Этот контейнер выполняет вызов события ActiveX, но не обрабатывается Javascript. Я включаю код формы C#, чтобы быть полным во взаимодействиях ActiveX и позволить этому быть ссылкой для будущих пользователей ActiveX и/или элемента управления WebBrowser.
этот файл предназначен для использования с новым проектом Windows Form, где элемент управления 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:pathtoTestPage.html");
// Call ActiveX
myObject.SayHello("C# Launch");
}
public string ControlObject()
{
return "<p>Control Object Called.</p>";
}
}
}
сочетания с помощь два другое фрагменты кода Я создал объект 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);
}
}
}
Last-это 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>
содержащая страница показывает этот вывод
выход
загруженный объект ActiveX: true
Вызывается Объект Управления.
можно позвонить сказать Привет!
1 ответов
Обновлено, пока вы можете скачать <object>
экземпляр из HTML (MyObject.object != null
), конечная проблема с обработчиком событий JavaScript заключается в том, что вы просто убиваете исходный HTML-документ с помощью document.write
до вы называете MyObject.SayHello("Javascript Load")
и заменить <p>Loaded ActiveX Object: ...</p>
. К тому времени, все оригинальные обработчики событий JavaScript ушли.
таким образом, следующее отлично работает, событие запускается и обрабатывается (с alert
):
<!DOCTYPE html>
<html>
<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 type="text/javascript" for="MyObject" event="OnUpdateString">
alert("Hello from event handler");
</script>
<script type="text/javascript" for="window" event="onload">
alert("Hello from window.onload!");
alert(MyObject.object);
MyObject.SayHello("Javascript Load");
</script>
</body>
</html>
чтобы ваша оригинальная логика работала, вы можете напрямую управлять DOM вместо использования document.write
. Или, по крайней мере, назовите его после OnUpdateString
был уволен и обрабатываются.
Теперь, когда я увидел полный источник, я могу сказать, что здесь что-то не так.
вы можете попасть в точку останова внутри
SayHello
потому что вы создаетеMyObject
из C# [MyObject myObject = new MyObject()
] и вызовите его с C# [myObject.SayHello("C# Launch")
]. Удалите это и вы увидите, что он никогда не вызывается, когда вы вызываете его из JavaScript [obj.SayHello("Javascript Load")
].-
это приводит к другой проблеме:
<object>
не удается создать успешно, и даже более того, ни один из ваших сценариев JavaScript даже не запускается, потому что ваш тестовый HTML-файл подается из локальной файловой системы (черезfile://
протокола). Это ограничение безопасности. Попробуйте изменить свой скрипт, как показано ниже, чтобы не видеть ни одного из предупреждений вверх:<script type="text/javascript" for="window" event="onload"> alert("Hello from window.onload!"); alert(MyObject.object) // null! object wasn't created... 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>
-
есть несколько способов исправить это. Самый простой, вероятно, использовать "веб-Марк". Труднее всего было бы обеспечить пользовательскую реализацию
IInternetSecurityManager
. Я бы сам воспользовался еще одним методом ... --64-->Интернет Функция Управления - и отключитьFEATURE_LOCALMACHINE_LOCKDOWN
,FEATURE_BLOCK_LMZ_SCRIPT
,FEATURE_BLOCK_LMZ_OBJECT
ключи. Вы можете использовать следующий код, который я адаптировал из моего другого обзоры ответ:// static constructor, runs first static Form1() { SetWebBrowserFeatures(); } static void SetWebBrowserFeatures() { // don't change the registry if running in-proc inside Visual Studio if (LicenseManager.UsageMode != LicenseUsageMode.Runtime) return; var appName = System.IO.Path.GetFileName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName); var featureControlRegKey = @"HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl\"; Registry.SetValue(featureControlRegKey + "FEATURE_BROWSER_EMULATION", appName, GetBrowserEmulationMode(), RegistryValueKind.DWord); // enable the features which are "On" for the full Internet Explorer browser Registry.SetValue(featureControlRegKey + "FEATURE_ENABLE_CLIPCHILDREN_OPTIMIZATION", appName, 1, RegistryValueKind.DWord); Registry.SetValue(featureControlRegKey + "FEATURE_AJAX_CONNECTIONEVENTS", appName, 1, RegistryValueKind.DWord); Registry.SetValue(featureControlRegKey + "FEATURE_GPU_RENDERING", appName, 1, RegistryValueKind.DWord); Registry.SetValue(featureControlRegKey + "FEATURE_WEBOC_DOCUMENT_ZOOM", appName, 1, RegistryValueKind.DWord); Registry.SetValue(featureControlRegKey + "FEATURE_NINPUT_LEGACYMODE", appName, 0, RegistryValueKind.DWord); Registry.SetValue(featureControlRegKey + "FEATURE_LOCALMACHINE_LOCKDOWN", appName, 0, RegistryValueKind.DWord); Registry.SetValue(featureControlRegKey + "FEATURE_BLOCK_LMZ_SCRIPT", appName, 0, RegistryValueKind.DWord); Registry.SetValue(featureControlRegKey + "FEATURE_BLOCK_LMZ_OBJECT", appName, 0, RegistryValueKind.DWord); } static UInt32 GetBrowserEmulationMode() { int browserVersion = 0; using (var ieKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Internet Explorer", RegistryKeyPermissionCheck.ReadSubTree, System.Security.AccessControl.RegistryRights.QueryValues)) { var version = ieKey.GetValue("svcVersion"); if (null == version) { version = ieKey.GetValue("Version"); if (null == version) throw new ApplicationException("Microsoft Internet Explorer is required!"); } int.TryParse(version.ToString().Split('.')[0], out browserVersion); } if (browserVersion < 7) { throw new ApplicationException("Unsupported version of Microsoft Internet Explorer!"); } UInt32 mode = 11000; // Internet Explorer 11. Webpages containing standards-based !DOCTYPE directives are displayed in IE11 Standards mode. switch (browserVersion) { case 7: mode = 7000; // Webpages containing standards-based !DOCTYPE directives are displayed in IE7 Standards mode. break; case 8: mode = 8000; // Webpages containing standards-based !DOCTYPE directives are displayed in IE8 mode. break; case 9: mode = 9000; // Internet Explorer 9. Webpages containing standards-based !DOCTYPE directives are displayed in IE9 mode. break; case 10: mode = 10000; // Internet Explorer 10. break; } return mode; }
теперь ваши скрипты работают, но
<object>
все еще не создается (alert(MyObject.object)
показываетnull
). Наконец, вам нужно будет реализоватьIObjectSafety
интерфейс на Вашем объекте ActiveX и сайт-замок это только ваши собственные HTML-страницы. Без надлежащегоIObjectSafety
объект не будет создан в настройках безопасности IE по умолчанию. Без блокировки сайта это может стать огромной угрозой безопасности, как и любой вредоносный скрипт может создавать и использовать ваш объект вне контекста вашего приложения.
Обновлено для обращения к комментарию:
я обновил проект с вашим приведенным примером, обратите внимание, что у меня был сделал изменение таким образом, что есть кнопка C# и кнопка Javascript чтобы уволить мероприятие. Кнопка JS работает, но C# не срабатывает. Я ищете кнопку " привет от: c# " тревога.
в вашем коде myObject
экземпляр создается и использовать исключительно из C#:
MyObject myObject = new MyObject();
// ...
private void button1_Click(object sender, EventArgs e)
{
// Call ActiveX
myObject.SayHello("C# Button");
}
этот экземпляр не имеет ничего общего с <object id="MyObject" onerror="window.objectLoadFailure = true" classid="clsid:7A5D58C7-1C27-4DFF-8C8F-F5876FF94C64"></object>
экземпляр, который вы создаете в HTML. Они два отдельные, несвязанные объекты. Обработчики событий работают только для последнего <object>
экземпляра. Вы даже не подписываетесь на какие-либо события на new MyObject()
экземпляра.
если я правильно понимаю вашу цель, вам нужно это:
private void button1_Click(object sender, EventArgs e)
{
// Call ActiveX
//myObject.SayHello("C# Button");
this.webBrowser1.Document.InvokeScript("eval",
new[] { "MyObject.SayHello('C# Button')" });
}
теперь обработчик событий JavaScript будет вызван, и вы увидите "C# Button"
предупреждение.