ActiveX(三)ActiveX 調用 Js


  在上一篇隨筆: ActiveX(二)Js 監聽 ActiveX中的事件  中,已經可以實現 Js 監聽 ActiveX中的事件,至此、Js 和 ActiveX 已經可以實現雙向通訊了。但是、這樣的實現方式,都是站在Js的角度去實現的,那么 ActiveX 能否主動調用 Js 呢?答案無疑是肯定的,在該篇隨筆中、我們將逐漸揭開這一層神秘的面紗。

 

  我第一次接觸用C#代碼調用Js是在四年前,那時候正在實習做Windows應用、需要借用 WebBrowser 控件操作js、完成一些特殊需求。當時的代碼大致如下:

        // 執行JS
        private void ExecJs()
        {
            try
            {
                if (this.webBrowser.Document != null)
                {
                    mshtml.IHTMLDocument2 currentDoc = (mshtml.IHTMLDocument2)this.webBrowser.Document.DomDocument;
                    if (currentDoc != null)
                    {
                        mshtml.IHTMLWindow2 win = (mshtml.IHTMLWindow2)currentDoc.parentWindow;
                        if (win != null)
                        {
                            //調用 函數F、傳遞一個寬度做參數
                            win.execScript(string.Format("F('{0}')", this.webBrowser.Width), "javascript");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

 

  由上述代碼、可以看出,其核心方法為 mshtml.IHTMLWindow2.execScript,注意:我們再仔細看一下方法名,有沒有覺得很熟悉?如果你還沒想起來,那我們繼續看一下 mshtml.IHTMLWindow2 這個類型中還有什么成員吧。

    [Guid("332C4427-26CB-11D0-B483-00C04FD90119")]
    [TypeLibType(4160)]
    public interface IHTMLWindow2 : IHTMLFramesCollection2
    {
        [DispId(1153)]
        dynamic _newEnum { get; }
        [DispId(1161)]
        HTMLNavigator clientInformation { get; }
        [DispId(23)]
        bool closed { get; }
        [DispId(1101)]
        string defaultStatus { get; set; }
        [DispId(1151)]
        IHTMLDocument2 document { get; }
        [DispId(1152)]
        IHTMLEventObj @event { get; }
        [DispId(1169)]
        dynamic external { get; }
        [DispId(1100)]
        FramesCollection frames { get; }
        [DispId(2)]
        HTMLHistory history { get; }
        [DispId(1125)]
        HTMLImageElementFactory Image { get; }
        [DispId(1001)]
        int length { get; }
        [DispId(14)]
        HTMLLocation location { get; }
        [DispId(11)]
        string name { get; set; }
        [DispId(5)]
        HTMLNavigator navigator { get; }
        [DispId(1164)]
        dynamic offscreenBuffering { get; set; }
        [DispId(-2147412073)]
        dynamic onbeforeunload { get; set; }
        [DispId(-2147412097)]
        dynamic onblur { get; set; }
        [DispId(-2147412083)]
        dynamic onerror { get; set; }
        [DispId(-2147412098)]
        dynamic onfocus { get; set; }
        [DispId(-2147412099)]
        dynamic onhelp { get; set; }
        [DispId(-2147412080)]
        dynamic onload { get; set; }
        [DispId(-2147412076)]
        dynamic onresize { get; set; }
        [DispId(-2147412081)]
        dynamic onscroll { get; set; }
        [DispId(-2147412079)]
        dynamic onunload { get; set; }
        [DispId(4)]
        dynamic opener { get; set; }
        [DispId(1157)]
        HTMLOptionElementFactory Option { get; }
        [DispId(12)]
        IHTMLWindow2 parent { get; }
        [DispId(1156)]
        IHTMLScreen screen { get; }
        [DispId(20)]
        IHTMLWindow2 self { get; }
        [DispId(1102)]
        string status { get; set; }
        [DispId(21)]
        IHTMLWindow2 top { get; }
        [DispId(22)]
        IHTMLWindow2 window { get; }

        [DispId(1105)]
        void alert(string message = "");
        [DispId(1159)]
        void blur();
        [DispId(1163)]
        void clearInterval(int timerID);
        [DispId(1104)]
        void clearTimeout(int timerID);
        [DispId(3)]
        void close();
        [DispId(1110)]
        bool confirm(string message = "");
        [DispId(1165)]
        dynamic execScript(string code, string language = "JScript");
        [DispId(1158)]
        void focus();
        [DispId(0)]
        dynamic item(ref object pvarIndex);
        [DispId(7)]
        void moveBy(int x, int y);
        [DispId(6)]
        void moveTo(int x, int y);
        [DispId(25)]
        void navigate(string url);
        [DispId(13)]
        IHTMLWindow2 open(string url = "", string name = "", string features = "", bool replace = false);
        [DispId(1111)]
        dynamic prompt(string message = "", string defstr = "undefined");
        [DispId(8)]
        void resizeBy(int x, int y);
        [DispId(9)]
        void resizeTo(int x, int y);
        [DispId(1160)]
        void scroll(int x, int y);
        [DispId(1167)]
        void scrollBy(int x, int y);
        [DispId(1168)]
        void scrollTo(int x, int y);
        [DispId(1173)]
        int setInterval(string expression, int msec, ref object language = Type.Missing);
        [DispId(1172)]
        int setTimeout(string expression, int msec, ref object language = Type.Missing);
        [DispId(1155)]
        void showHelp(string helpURL, object helpArg = Type.Missing, string features = "");
        [DispId(1154)]
        dynamic showModalDialog(string dialog, ref object varArgIn = Type.Missing, ref object varOptions = Type.Missing);
        [DispId(1166)]
        string toString();
    }
IHTMLWindow2

 

  想起來了沒有? 如果還沒有、那只能說你一行Js代碼都沒寫過。 沒錯,js 中的 window 對象 實現了 mshtml.IHTMLWindow2 這個接口。既然如此,我們通過一個初始化函數將 window 對象傳入,就可以得到  mshtml.IHTMLWindow2 接口了。

 

哈哈,補充一下, mshtml 命名空間 源自:Microsoft.mshtml.dll.

 

當知道了如上的信息后,一切就變的‘簡單’了:

        /// <summary>
        /// 調用Js函數
        /// </summary>
        /// <param name="functionName">js函數名</param>
        /// <param name="args">參數</param>
        /// <returns></returns>
        private dynamic RunJs(string functionName, string args = "")
        {
            dynamic dy = null;

            // 方法返回值永遠為 null
            if (this.window2 != null)
            {
                //調用函數
                dy = this.window2.execScript(string.Format("{0}('{1}')", functionName, args), "javascript");
            }
 

            return dy;
        }

通過如上的代碼,確實可以調用Js、但是、還有一個Bug... 返回值一直為Null. 

那怎么辦呢? 反射——沒錯,就是反射調用Js,也許你現在還想不明白, 先看一下代碼吧,看完后你也許會恍然大悟:

 

        /// <summary>
        /// 調用Js函數
        /// </summary>
        /// <param name="functionName">js函數名</param>
        /// <param name="args">參數</param>
        /// <returns></returns>
        private dynamic RunJs(string functionName, string args = "")
        {
            dynamic dy = null;// 第二種方式 反射調用 Js
            // 被調用的js函數必須有一個參數
            if (this.window2 != null)
            {
                dy = this.window2.GetType().InvokeMember(functionName,
                    BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public,
                    null, this.window2, new object[] { args });
            }

            return dy;
        }

 

有沒有想到呢 —— 全局的Js函數其實是屬於window對象的,當然可以用反射去調用啦。

 

 

完整的測試項目demo: TestActiveX.zip

 

下一篇,我們將探究強大的 Microsoft.mshtml.dll,有點期待。

(未完待續...)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM