Как подключить обработчик событий 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" предупреждение.