zoukankan      html  css  js  c++  java
  • C#制作ActiveX浏览器插件& OCX

    原文:https://www.cnblogs.com/mooncher/p/6848626.html

    开发环境:VS2008

    第一步 创建项目

    新建一个项目,选择“Windows窗体控件库”,创建一个用户控件项目“ActiveXDemo”(注意,这里起名不能用中文,否则后面会出问题),里面有个用户控件类UserControl1.cs

    在类中写上你自己需要的业务逻辑代码,保存

    第二步 设置项目属性

    在AssemblyInfo.cs里添加[assembly: AllowPartiallyTrustedCallers()],需要引用using System.Security;命名空间

    设置项目属性,右键项目——属性

    选择“应用程序”,点开“程序集信息”

    勾选“使程序集COM可见”,点“确定”

    然后选择“生成”,滚动拉倒底部,勾选“为COM互操作注册”

    然后保存,重新编译项目,至此,此时的“ActiveXDemo.dll”就成了一个ActiveX控件

    第三步 安装外部工具

    安装外部工具“OLE/COM对象查看器”和“创建GUID”(已有这两款工具的可以忽略此步骤)

     

    1.OLE/COM对象查看器

    这款工具是用来查看ActiveX控件的,也就是验证你的项目有没有成为一个ActiveX控件

    安装方法:点开VS顶部菜单栏“工具”——“外部工具”

    然后,添加一个“OLE/COM对象查看器”,对应的命令程序一般放在C:Program FilesMicrosoft SDKsWindowsv6.0ABinOleView.Exe

    VS2010+win10:  命令:C:Program Files (x86)Microsoft SDKsWindowsv7.0AinOleView.Exe

    点击“应用”,“确定”,这就算是安装完成,再重新点开顶部的“工具”菜单看看,里面就有一项“OLE/COM对象查看器”

    点击“OLE/COM对象查看器”,展开左侧的“.NET Category”

    你会发现,这里面就有你刚刚创建的ActiveX控件

    这就是OLE/COM对象查看器的作用

    2.创建GUID

    高版本的VS貌似都自带了这个工具,但是在有的低版本或者安装不完整比如Vs2008中不一定有这个工具,所以在没有的时候需要安装一下

    安装方法同上,只不过命令程序的地址一般是C:Program Files (x86)Microsoft Visual Studio 9.0Common7Toolsguidgen.exe

    此工具的用途在下面的步骤中会讲到

    第四步 提高ActiveX插件的安全等级

    IE怎么知道一个插件是脚本安全的?它是通过以下两个办法。

    一是查询ActiveX组件是否实现了IObjectSafety接口,并且返回脚本安全;

    二是查询ActiveX组件是否在注册表的Component  Category Manager里表明自己实现了CATID_SafeForInitializing和CATID_SafeForScripting。

    这里我们只说第一种实现IObjectSafety接口

    首先,为控件类UserControl1添加一个GUID,这个编号将用于B/S系统的客户端调用时使用(可以使用 工具-创建GUID 菜单创建一个GUID):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
     
    namespace ActiveXDemo
    {
        [Guid("BB725724-65D6-4e71-AA11-DEDFAFE9248F"), ProgId("ActiveXDemo.UserControl1"), ComVisible(true)]
        public partial class UserControl1 : UserControl,IObjectSafety
        {

     注意,要引入System.Runtime.InteropServices;命名空间

    其次,为了让ActiveX控件获得客户端的信任,控件类还需要实现一个名为“IObjectSafety”的接口,因此在项目中添加一个接口类IObjectSafety

    直接将下列代码复制粘贴,不要作任何改动,尤其是GUID,都是固定的,不能改

    复制代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Runtime.InteropServices;
    
    namespace ActiveXDemo
    {
        [ComImport, GuidAttribute("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]
        [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IObjectSafety
        {
            [PreserveSig]
            int GetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions, [MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions);
    
            [PreserveSig()]
            int SetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] int dwOptionSetMask, [MarshalAs(UnmanagedType.U4)] int dwEnabledOptions);
        }
    }
    复制代码

    同样,需要引入System.Runtime.InteropServices;命名空间

    接着,在控件类UserControl1中实现IObjectSafety的接口

    复制代码
            #region IObjectSafety 成员
    
            private const string _IID_IDispatch = "{00020400-0000-0000-C000-000000000046}";
            private const string _IID_IDispatchEx = "{a6ef9860-c720-11d0-9337-00a0c90dcaa9}";
            private const string _IID_IPersistStorage = "{0000010A-0000-0000-C000-000000000046}";
            private const string _IID_IPersistStream = "{00000109-0000-0000-C000-000000000046}";
            private const string _IID_IPersistPropertyBag = "{37D84F60-42CB-11CE-8135-00AA004BB851}";
    
            private const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001;
            private const int INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002;
            private const int S_OK = 0;
            private const int E_FAIL = unchecked((int)0x80004005);
            private const int E_NOINTERFACE = unchecked((int)0x80004002);
    
            private bool _fSafeForScripting = true;
            private bool _fSafeForInitializing = true;
    
            public int GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions)
            {
                int Rslt = E_FAIL;
    
                string strGUID = riid.ToString("B");
                pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
                switch (strGUID)
                {
                    case _IID_IDispatch:
                    case _IID_IDispatchEx:
                        Rslt = S_OK;
                        pdwEnabledOptions = 0;
                        if (_fSafeForScripting == true)
                            pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
                        break;
                    case _IID_IPersistStorage:
                    case _IID_IPersistStream:
                    case _IID_IPersistPropertyBag:
                        Rslt = S_OK;
                        pdwEnabledOptions = 0;
                        if (_fSafeForInitializing == true)
                            pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
                        break;
                    default:
                        Rslt = E_NOINTERFACE;
                        break;
                }
    
                return Rslt;
            }
    
            public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions)
            {
                int Rslt = E_FAIL;
                string strGUID = riid.ToString("B");
                switch (strGUID)
                {
                    case _IID_IDispatch:
                    case _IID_IDispatchEx:
                        if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_CALLER) && (_fSafeForScripting == true))
                            Rslt = S_OK;
                        break;
                    case _IID_IPersistStorage:
                    case _IID_IPersistStream:
                    case _IID_IPersistPropertyBag:
                        if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_DATA) && (_fSafeForInitializing == true))
                            Rslt = S_OK;
                        break;
                    default:
                        Rslt = E_NOINTERFACE;
                        break;
                }
    
                return Rslt;
            }
    
            #endregion
    复制代码

     这些代码也是固定的,不能改动,直接复制粘贴就行了

     第五步 制作成安装文件

    在原项目解决方案中新建一个安装项目,在VS2008中,是这样操作的

    新建项目——其他项目类型——安装和部署——安装项目

    注意,这里下方“解决方案”这里要选择“添入解决方案”

    然后,右键安装项目——添加——项目输出

    将我们的项目ActiveXDemo设为主输出

    点确定,然后在主输出文件上右键——属性

    将Register属性设为vsdrpCOM

    重新编译安装项目,打开安装项目所在目录

    至此,ActiveX浏览器插件的安装包就制作好了,双击setup.exe文件或ActiveXDemoSetup.msi文件可以将浏览器插件安装到你的电脑

    第六步 使用ActiveX插件

    新建一个Web项目或者一个Html文件,在需要使用浏览器插件的页面上加入以下代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>无标题页</title>
    </head>
    <body>
    <object id="csharpActiveX" classid="clsid:BB725724-65D6-4e71-AA11-DEDFAFE9248F" width="100%" height="150"></object>
     
        <form id="form1" runat="server">
        <div>
        <input type='button' onclick='csharpActiveX.Test()' value='我是按钮'/>
        </div>
        </form>
    </body>

     其中,重点是object标签里的classid属性,属性里面的GUID对应的就是第四步中指定的GUID

    直接使用object定义的id属性就可以调用UserControl1类中的方法,是不是很方便?

    为了更方便直观的看出插件有没有正常加载,可以再加入一些检测代码,如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <body>
    <object id="csharpActiveX" classid="clsid:BB725724-65D6-4e71-AA11-DEDFAFE9248F" width="100%" height="150"></object>
     
        <form id="form1" runat="server">
        <div>
        <input type='button' onclick='csharpActiveX.Test()' value='我是按钮'/>
        </div>
        </form>
    </body>
    <script type="text/javascript">
        var objCard = document.getElementById("csharpActiveX");
     
        if (objCard.object==null) {
            alert("csharpActiveX插件未安装!");
        }
        else{
            alert("已检测到csharpActiveX插件!");
        }
    </script>
    </html>

     然后,由于只有IE支持ActiveX浏览器插件,所以在IE浏览器中打开这个页面,看一下效果

    这时,不放心的话,可以再检查咱们的ActiveX插件究竟有没有安装上

    点开工具栏“工具”——“管理加载项”

    可以看到其中有一项ActiveXDemo.UserControl1,这就是我们安装上去的浏览器插件

    第七步 ActiveX插件调用页面Js

    这里,主要需要引入一个程序集叫Microsoft.mshtml.dll,它在系统文件夹里C:Program Files (x86)Microsoft.NETPrimary Interop Assemblies

    引入后,开始在插件项目里写上注册Js函数相关的代码,如下

    复制代码
            private IHTMLWindow2 temphtml = null;
            private string functionstr = "";
    
            public void RegJs(object objWinJs, string funcJs)
            {
                temphtml = (IHTMLWindow2)objWinJs;
                if (temphtml != null && !string.IsNullOrEmpty(funcJs))
                {
                    functionstr = funcJs;
                }
                else
                {
                    temphtml = null;
                    functionstr = "";
                    MessageBox.Show("注册ActiveX插件回调脚本失败");
                }
            }    
    复制代码

    以及,执行页面Js函数的代码

    复制代码
            private void ShowResult(object s, EventArgs e)
            {
                try
                {
                    //必须要阻塞线程一段时间,以免在交易超时的情况下,由于read太快导致读取不完整
                    System.Threading.Thread.Sleep(500);
                    string txt = serialPort.ReadExisting();
    
                    temphtml.execScript("var msgActiveX='" + txt+"';", "JScript");
                    temphtml.execScript(functionstr + "()", "JScript");
    
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message.ToString());
                }     
            }
    复制代码

    在这里,我向页面输出了一个msgActiveX变量,并调用了前面注册过的Js函数

    然后,我们还需要在页面加载的时候,调用插件的注册JS函数方法,以及此Js函数定义

    复制代码
    <script type="text/javascript">
        Ext.onReady(
        function() {
            objCard.regJs(window, 'test');
        }
        );
        function test() {
            var str = msgActiveX.substring(5);
            var objJson = eval('(' + str + ')');
            alert(objJson.responseCode);
            //alert("回调函数执行成功");
        } </script>
    复制代码

     至此,恭喜你已成功掌握了制作ActiveX浏览器插件的技能~

  • 相关阅读:
    hdu2083 简易版之最短距离
    android:layout_gravity和android:gravity属性的差别
    java设计模式演示样例
    [CSS] Transition
    [React] React Fundamentals: Precompile JSX
    [React] React Fundamentals: JSX Deep Dive
    [React] React Fundamentals: Build a JSX Live Compiler
    [Angular 2] 8. Better ES5 Code
    [rxjs] Throttled Buffering in RxJS (debounce)
    [rxjs] Demystifying Cold and Hot Observables in RxJS
  • 原文地址:https://www.cnblogs.com/luofuxian/p/12849706.html
Copyright © 2011-2022 走看看