• c# ActiveX 控件的开发


    关于ActiveX控件的开发,网上很多例子,昨天也整整研究一天才捋顺了.

    网上大部分例子都是js调用控件的方法,由于要实现在html页面"相应"控件的事件,整整折腾一天.

    关键点在于 "创建ActiveX控件" 的 第2,和第7

    该技术局限性较大,如浏览器端需安装 .net 框架,仅限于IE浏览器.

    关于ActiveX的证书及浏览器安装时设置,可参考 http://www.cnblogs.com/weixing/archive/2013/06/28/3161165.html 这也是我看到比较详细的介绍了.

    创建ActiveX控件
    1.创建一个类库;
    2.项目属性-应用程序-程序集信息-"使程序集COM可见"勾上;
    3.项目属性-生成-"为COM互操作注册"勾上.(这个折腾一天,否则注册事件不可用);
    4.创建接口: IObjectSafety (注意GUID不能变);
    5.创建ActiveX控件的基类并实现IObjectSafety,ActiveX控件可以继承它来减少代码;
    6.创建一个ActiveX自定义控件如:ActiveXDemo1;
    7.定义ActiveXDemo1的"方法接口"及"事件接口".(如使用自定义事件需用此方式), "事件接口"成员应加上[DispId(x)]标识;
    8.创建ActiveX控件完成.

    IObjectSafety  接口定义

        [ComImport, Guid("4A359FBB-C9A4-494E-B048-AC068DB4FCB2")] //该GUID不能变
        [InterfaceType(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);
        }
    }
    

    ActiveX控件基类(ActiveXControlBase)

        public class ActiveXControlBase : 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
        }
    

      自定义ActiveX控件

        [ComVisible(true)]
        [Guid("684AAD87-C086-4F27-AE55-941A1AAC7212")]
        [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
        public interface IThreadDemoEvent
        {
            [DispId(1)] //使用事件,必须加上该标识
            void ShowMessage1(string str_Msg);
            [DispId(2)]
            void ShowMessage2(string str_Msg);
        }
    
        [ComVisible(true)]
        [Guid("4D12136B-9545-423B-A110-B9405ADF8B30")]
        [InterfaceType(ComInterfaceType.InterfaceIsDual)]
        public interface IThreadDemo
        {
            string StartTimer();
            string StopTimer();
        }
    
        [Guid("2B4FCB85-A3B7-43BD-B104-7380E7F3483F"),
         ClassInterface(ClassInterfaceType.AutoDual),
         ComDefaultInterface(typeof(IThreadDemo)),
         ComSourceInterfaces(typeof(IThreadDemoEvent)),
         ComVisible(true)
        ]
        public class ActivexThreadDemo : ActiveXControlBase, IThreadDemo
        {
            ~ActivexThreadDemo()
            {
                ShowMessage1("释放了啊");
            }
    
            Thread _th;
            bool _isStop;
    
            public event ShowMessageHandle ShowMessage1;
            public event ShowMessageHandle ShowMessage2;
    
            void ThreadMethd()
            {
                while (true)
                {
                    Thread.Sleep(3000);
                    if (ShowMessage1 != null)
                    {
                        ShowMessage1.Invoke(DateTime.Now.ToString());
                    }
                    if (_isStop) break;
                }
                _th.Abort();
                _th = null;
            }
    
            public string StartTimer()
            {
                if (_th == null)
                {
                    _isStop = false;
                    _th = new Thread(ThreadMethd);
                    _th.IsBackground = false;
                    _th.Start();
                    return "开起计时";
                }
                if (ShowMessage2 != null)
                {
                    ShowMessage2("执行了 StartTimer");
                }
                return "已经开起过计时;";
            }
    
            public string StopTimer()
            {            
                if (_isStop)
                {                
                    return "已经停止计时了!";
                }
                else
                {
                    _isStop = true;
                    return "停止计时";
                }            
            }
        }
    

      

    注意:
    不能使用泛型委托来声明事件,如:public event Action<T> ShowMessageHandle;
    当类里面包含 static成员,刷新页面不会清空
    跨线程触发事件: [事件].Invoke(参数1,参数2 ...);

    ActiveX控件Setup
    1.创建Installer项目;
    2.右击项目 添加->项目输出 打开添加项目输出组对话框,并选择ActiveX控件类库;
    3.主输出文件的属性 Register 值为 vsdrpCOM (关键),RemovePreviousVersions 设置为true

    web页面测试;
    1.创建一个object 标签,calassid为控件GUID
    <object id="ActiveXObj1" classid="clsid:3BCF612C-91CF-4543-83BB-FD2331FDDCB6" ></object>
    2.调用控件方法
    var r = document.ActiveXObj1.Test1();
    3."注册控件的事件"
    <script language="javascript" type="text/javascript" for="ActiveXObj1" event="ShowMessage1(msg)">
    alert("ActiveXObj1 :"+ msg )
    </script>

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>ActiveX测试页面</title>    
        
        <script type="text/javascript">
    
            function test1() {
                var r = document.ActiveXObj1.Test1();
                window.status = r;
            }
    
            function StartTimer() {
                alert(document.ActiveThreadEvent);
                var r = document.ActiveThreadEvent.StartTimer();
                window.status = r;
            }
            function StopTimer() {
                var r = document.ActiveThreadEvent.StopTimer();
                window.status = r;
            }
        </script>
        <!--事件的注册-->
        <script language="javascript" type="text/javascript" for="ActiveXObj1" event="ShowMessage1(msg)">           
            alert("ActiveXObj1 :"+ msg )
        </script>
         <script language="javascript" type="text/javascript" for="ActiveXObj1" event="ShowMessage2(msg)">           
            alert("ActiveXObj1:" + msg)
        </script>
    
        <!--线程事件注册-->
        <script language="javascript" type="text/javascript" for="ActiveThreadEvent" event="ShowMessage1(msg)">           
            alert("ActiveThreadEvent :"+ msg )
        </script>
         <script language="javascript" type="text/javascript" for="ActiveThreadEvent" event="ShowMessage2(msg)">           
            alert("ActiveThreadEvent:" + msg)
        </script>
    </head>
    <body> 
     <object id="ActiveXObj1" classid="clsid:3BCF612C-91CF-4543-83BB-FD2331FDDCB6" ></object>
     <br />
     <object id="ActiveThreadEvent" classid="clsid:2B4FCB85-A3B7-43BD-B104-7380E7F3483F" ></object>
     <br />
      <br />
      <input type="button" value="测试4-相应事件!" onclick="test1();" /><br />
      <input type="button" value="开始计时!" onclick="StartTimer();" /><br />
      <input type="button" value="停止计时!" onclick="StopTimer();" /><br />
      
    </body>
    </html>
    

      

    源码共享:  戳我

  • 相关阅读:
    Python在函数中使用*和**接收元组和列表
    nvidia-smi实时刷新并高亮显示状态
    linux docker
    linux Vue+nginx+django 实现前后端分离
    linux mysql 主从复制
    linux redis
    linux mysql主从复制
    linux python虚拟环境 相关的
    linux dns
    2 linux vim sudo 文件权限
  • 原文地址:https://www.cnblogs.com/xtdhb/p/4275369.html
Copyright © 2020-2023  润新知