【问题标题】:JS Callback called from an ActiveX component not triggering if not in the main code flow如果不在主代码流中,则从 ActiveX 组件调用的 JS 回调不会触发
【发布时间】:2011-10-27 09:13:34
【问题描述】:

我有一个 ActiveX 组件,它扫描照片、将文件保存到客户端硬盘上的临时文件中并上传照片。

我有一个执行扫描部分的“TwainMan”实例,扫描完成后会触发“ImageScanned”事件。这是我的主要代码流程:

scanner = new TwainMan();
scanner.ImageScanned += new ImageScannedEventHandler(Scanner_ImageScanned);

将执行此操作的代码放入 EventHandler 委托方法“Scanner_ImageScanned”中:

private void Scanner_ImageScanned(object Sender, ImageScannedEventArgs e)
{
    this.tempFileName = scanner.ToTempFile(e.Image);
    MessageBox.Show("Scanned picture stored on the following location:\n" + this.tempFileName);

    Upload(this.tempFileName); // works just fine

    TriggerJSCallback(); // here is where the problem appears!           
}

在 TriggerJSCallback 方法中,我只触发了我的 JS 回调:

private void TriggerJSCallback()
{
    EventHandler DataPreparingFinished = this.DataPreparingFinished;
    if (null != DataPreparingFinished) { DataPreparingFinished(this.tempFileName); }
}

请注意,如果我从主流程中触发 JSCallback“DataPreparingFinished”,则 JS Callback 侦听器(在我的 html 页面中定义)工作正常,但如果从“ Scanner_ImageScanned" 委托,因此不是来自主代码流。

我做错了什么?有人可以帮忙吗?

这是 html 页面中标记内的 JS 回调定义。

<script for="AXTwain" event="DataPreparingFinished(args)" language="javascript" type="text/javascript">

    function AXTwain::DataPreparingFinished(args) {            
        alert("JS ALERT: SUCCESS!!! JS Callback working properly." + args);
        // alert("The temp file is stored on: " + AXTwain.TempFileName); 
    }

</script>

如果我能显示更多代码可能会更好,这样你就会更好地了解我的问题到底是什么。

让我们从头开始...

下面是我的 HTML 页面,其中包括我的 ActiveXObject 实例化和 JS 回调/侦听器函数。

<html xmlns="http://www.w3.org/1999/xhtml">
<head>

    <title>ActiveX TWAIN test page</title>

    <object id="AXTwain" name="AXTwain" classid="clsid:d8ea830e-38b0-4f3b-8be4-39c417c27583"></object>

</head>

<body onload="myload();">

    <h1 style="color:green;">AXTwain test page</h1> 

    <script type ="text/javascript">

        function myload() {
            if (AXTwain != null) {
                AXTwain.AcquireImage();
            }           
        }

    </script>

    <script for="AXTwain" event="DataPreparingFinished(args)" language="javascript" type="text/javascript">

        // The "for" attribute should be set to the name of instance of your COM component.
        // The "event" attribute should be set to the JavaScript function signature for the event.
        // The name of the JavaScript function is the instance name of your COM component, followed
        // by double colons, followed by the JavaScript signature of the event.

        function AXTwain::DataPreparingFinished(args) {            
            alert("JS ALERT: SUCCESS!!! JS Callback working properly." + args);            
        }

    </script>

</body>
</html>

下面是我的 ActiveX 包装类...

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace AXImageAcquisition
{
    #region ActiveX attributes
    [ProgId("AXImageAcquisition.AXTwain_01")]
    [Guid("d8ea830e-38b0-4f3b-8be4-39c417c27583")]
    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.None)]
    [ComSourceInterfaces(typeof(IComEvents))]
    #endregion
    public class AXTwain
    {
        #region Class Properties and Settings

        private TwainMan scanner;
        private String tempFileName;
        public String TempFileName
        {
            get { return this.tempFileName; }
        }

        [ComVisible(false)]
        public delegate void EventHandler(string args);
        public event EventHandler DataPreparingFinished;

        public bool imageScanned = false;

        #endregion

        #region Class Constructors
        public AXTwain()
        {}
        #endregion

        #region Class Methods

        [ComVisible(true)]
        public void AcquireImage()
        {
            this.DataPreparingFinished += new EventHandler(Delegate_DataPreparingFinished);

            this.scanner = new TwainMan();
            this.scanner.ImageScanned += new ImageScannedEventHandler(Scanner_ImageScanned);            

            TriggerJSCallback(); // HERE IN THE MAIN CODE FLOW THE MESSAGE GETS TO JS!!!
        }

        /// <summary>
        /// Delegate that defines functionality for the ImageScanned event, defined in TwainMan class.
        /// </summary>
        /// <param name="Sender"></param>
        /// <param name="e"></param>
        public void Scanner_ImageScanned(object Sender, ImageScannedEventArgs e)
        {
            this.tempFileName = scanner.ToTempFile(e.Image);
            Upload(this.tempFileName);            

            TriggerJSCallback(); // HERE (NOT IN THE MAIN CODE FLOW) THE MESSAGE NEVER GETS TO JS!!! WHYYYY? :(
        }

        /// <summary>
        /// TODO!!!
        /// </summary>
        /// <param name="tempFileName"></param>
        private void Upload(string tempFileName)
        {
            // TODO
        }

        /// <summary>
        /// Test method for the DataPreparingFinished trigger.
        /// </summary>
        public void TriggerJSCallback()
        {           
            EventHandler DataPreparingFinished = this.DataPreparingFinished;
            if (null != DataPreparingFinished) DataPreparingFinished(this.tempFileName);
        }

        /// <summary>
        /// Delegate that defines functionality for the DataPreparingFinished event, which is defined in IComEvents.
        /// </summary>
        /// <param name="msg">Arguments passing from C# to JS.</param>
        void Delegate_DataPreparingFinished(string msg)
        {
            // MessageBox.Show("Delegate_DataPreparingFinished message! (C# code).\n Input message: " + msg);
        }

        #endregion
    }
}

如果您需要更多代码,我还可以复制/粘贴其余代码,即 TwainMan 类及其依赖项。然而,所有这些都来自代码项目教程here。顺便说一句,感谢作者。

【问题讨论】:

    标签: javascript c# callback activex dom-events


    【解决方案1】:

    很难确定,因为我不使用 C# 编写 ActiveX 组件,但在 c++ 中,如果从主线程以外的线程调用,这样的回调将产生完全一样的效果。 ActiveX 通常期望所有调用都发生在主线程上。不过,也有一些方法可以让其他线程与 ActiveX 一起工作,而且 C# 可能会自动为您执行此操作,因此这在 c# 中可能并不总是准确的。

    我建议你想办法在主线程上触发函数;我知道在 Silverlight 中使用 DispatcherTimer 可以做到这一点;也许你能找到类似的东西?无论如何,这就是我会尝试的。

    【讨论】:

    • 出租车,衷心感谢您的回复。当我提到“代码流”时,我并没有想到线程。所以,当我说“主代码流”时,我并不是指主线程。 :) 但也许我使用了错误的术语。 :)
    • 你确定 c# 没有在你没有意识到的情况下使用另一个线程吗?无论如何,这是我唯一的想法,但我想我会把它扔在那里作为仅供参考。如果有 DispatcherTimer 或类似的东西,我会尝试确定。不管怎样,祝你好运
    • 老实说,我也在想同样的事情,但我仍然不确定后面是否还有其他线程。恕我直言,没有,因为我没有在可用的代码中看到任何 explixit 线程开始,但要确定我必须做一些进一步的研究......找到一种尽快找出答案的方法。但是,另一方面...在另一个测试代码中,我尝试从新线程触发事件,并且 JS 回调正确地捕获了该事件。我需要做的是找到一种方法来捕获所有消息并查看我的消息是否真正触发以及它丢失的位置。
    猜你喜欢
    • 2014-10-06
    • 1970-01-01
    • 2012-06-28
    • 2015-04-24
    • 1970-01-01
    • 1970-01-01
    • 2017-06-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多