• C#开发ActiveX控件


    昨天写了篇博客《Winform 程序嵌入WPF程序 并发送消息》,没有说明为什么要嵌入WPF程序,那么今天就来唠叨唠叨其中的一个使用场景,开发ActiveX控件

    首先,新建一个类库工程HuaYun.ActiveX,右键工程属性,在“应用程序”页,点击“程序集信息”按钮,在弹出的窗体里勾选“使程序集COM可见”,具体操作如下图

    第二步,切换到“生成”的选项卡,勾选“为COM互操作注册”,如下图

    第三步,在AssemblyInfo.cs里添加[assembly: AllowPartiallyTrustedCallers()],需要引用using System.Security;命名控件

     第四步,添加一个IObjectSafety的接口,这个接口主要是在浏览器中提高控件的可信任度

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Text;
    
    namespace HuaYun.ActiveX
    {
        [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);
        }
    }

    第五步,添加一个用户控件ActiveXControl.cs,并让这个控件实现上面的IObjectSafety接口,同事在这个控件的类中加上一个Guid的特性,如:[Guid("21209360-34E1-423E-A81F-BC80B62021B7")],注意,后面在html页面中要根据这个Guid注册控件的,看看ActiveXControl.cs里的内容

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Drawing;
    using System.Data;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    
    namespace HuaYun.ActiveX
    {
        [Guid("21209360-34E1-423E-A81F-BC80B62021B7")]
        public partial class ActiveXControl : UserControl, IObjectSafety
        {
            public ActiveXControl()
            {
                InitializeComponent();
            }
    
            #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
    
        }
    }

    到这一步,ActiveX控件基本上是开发完成了,可以呈现了,新建个Html页面,在页面上加入下面一行代码,生成ActiveX控件的解决方案,注意:后面每次生成的时候都要关闭在页面中有用到这个控件的页面,不然会占这进程,生成不了

    <object id="activex" classid="clsid:21209360-34E1-423E-A81F-BC80B62021B7" codebase="lib/setup.exe" width="100%" height="200"></object>

    其中classid就是上面的ActiveXControl类里加的Guid的特性里的Guid值,codebase是后面打包成安装文件放在站点目录里的安装文件,浏览引用控件的页面看看页面效果,

    PS:ActiveX只能在IE内核的浏览器中运行,具体原因请百度脑补了,控件里的按钮点击事件跟winform的是一样的

    下面说下在ActiveX控件里注册回调的js函数,引用Microsoft.mshtml程序集,在ActiveXControl.cs里加入以下代码

    #region 注册回调函数
    
            private IHTMLWindow2 temphtml = null;
            private string functionstr = "";
    
            public void RegJs(object win, string fuc)
            {
                temphtml = (IHTMLWindow2)win;
                if (temphtml != null && !string.IsNullOrEmpty(fuc))
                {
                    functionstr = fuc;
                }
                else
                {
                    temphtml = null;
                    functionstr = "";
                    MessageBox.Show("注册脚本失败!");
                }
            }
    
            #endregion

    再个上面那个ActiveX控件里的“我是ActiveX控件”加个点击事件,在点击这个按钮的时候执行页面注册的js函数

    private void btn_Click(object sender, EventArgs e)
            {
                // 执行script脚本
                temphtml.execScript(functionstr + "()", "JScript");
            }

    好了,给上面的调用ActiveX控件加几个js函数,就可以运行了

    <head>
        <title></title>
        <script type="text/javascript">
            function load() {
                var dom = document.getElementById("activex");
                dom.regJs(window, 'test');
            }
    
            function test() {
                alert("向ActiveX控件注册回调函数");
            }
        </script>
    </head>
    <body onload="load()">
    <object id="activex" classid="clsid:21209360-34E1-423E-A81F-BC80B62021B7" codebase="lib/setup.exe" width="100%" height="200"></object>
    </body>

    运行这个页面,点击里面的按钮,调用注册的函数

    再来说下给ActiveX控件加初始化方法,并传参,也是很简单,在上面的ActiveXControl类里加入初始化方法

    #region 控件初始化方法
    
            public void Init(string message)
            {
                MessageBox.Show(message);
            }
    
            #endregion

    生成HuaYun.ActiveX工程,在调用的页面加入初始化方法

    <script type="text/javascript">
            function load() {
                var dom = document.getElementById("activex");
                dom.regJs(window, 'test');
                dom.Init('ActiveX控件初始化...');
            }
    
            function test() {
                alert("向ActiveX控件注册回调函数");
            }
        </script>

    运行页面,页面加载就会弹出“ActiveX控件初始化...”

     好了,ActiveX控件的开发步骤就介绍到这里,使用场景也因项目而异i,说下我的使用。我是在ActiveX控件里嵌入WPF程序(WPF能作出酷炫屌炸天的效果)来使用的,至于怎么嵌入可以看我上一篇博客,这里给张飞机票链接过去《Winform 程序嵌入WPF程序 并发送消息

  • 相关阅读:
    interbase C++Builder 简单例子
    delphi代码实现创建dump文件
    在Mac OSX下使用ssh建立隧道(在Windows下建立隧道可以使用putty,其间会用到ppk文件)
    为什么豌豆荚们没能成为伟大的公司?
    解读雷军演讲,小米能否借“科技业的无印良品”反弹?(坚硬和纯洁的心,才能把这个事情干好)
    SOCKET网络编程5
    SQL Server 跨网段(跨机房)复制
    Erlang千万级用户游戏框架(Openpoker)源码文件分析清单
    异步编程
    代码性能不高
  • 原文地址:https://www.cnblogs.com/zhouxiaoyun/p/5801196.html
Copyright © 2020-2023  润新知