zoukankan      html  css  js  c++  java
  • c#中开发ActiveX的学习笔记

    1.为什么要用ActiveX?

    网页本身的功能是有限的,要想实现一些网页本身不支持的功能,比如:网页上的p2p视频播放,就得靠ActiveX这种古老的技术。

    2.c#能开发ActiveX吗?

    严格意义上讲,c#是不能生成纯正ocx控件的,我们在vs.net中新建项目时,也找不到专门的"ActiveX项目"新建项,最多也只就能新建"类库"得到一个dll而非ocx(因此我们也无法用传统的regsvr32来注册该dll),但是c#能开发com组件,activeX控件本质上讲跟com是一类技术,所以用c#开发"能够让网页调用的com类库"还是可行的。

    3.开发步骤:

    (1)新建一个类库 (2)修改项目的"属性",在“生成”选项中把“输出”中的“为com互操作注册”勾中,然后再到“应用程序”选项中找到“程序集信息”按钮,点击它,在弹出的界面中勾中“使程序集COM可见(M)”

    (3)修改AssemblyInfo.cs,增加[assembly: AllowPartiallyTrustedCallers()],完整内容类似下面这样:

    复制代码
     1 using System.Reflection;  2 using System.Runtime.CompilerServices;  3 using System.Runtime.InteropServices;  4 using System.Security;  5   6 // General Information about an assembly is controlled through the following   7 // set of attributes. Change these attribute values to modify the information  8 // associated with an assembly.  9 [assembly: AssemblyTitle("ActiveXDemo")] 10 [assembly: AssemblyDescription("")] 11 [assembly: AssemblyConfiguration("")] 12 [assembly: AssemblyCompany("Microsoft")] 13 [assembly: AssemblyProduct("ActiveXDemo")] 14 [assembly: AssemblyCopyright("Copyright ? Microsoft 2009")] 15 [assembly: AssemblyTrademark("")] 16 [assembly: AssemblyCulture("")] 17 [assembly: AllowPartiallyTrustedCallers()] 18  19 // Setting ComVisible to false makes the types in this assembly not visible  20 // to COM components.  If you need to access a type in this assembly from  21 // COM, set the ComVisible attribute to true on that type. 22 [assembly: ComVisible(true)] 23  24 // The following GUID is for the ID of the typelib if this project is exposed to COM 25 [assembly: Guid("bd585d12-7f22-4b3f-959f-18efbfc53f94")] 26  27 // Version information for an assembly consists of the following four values: 28 // 29 //      Major Version 30 //      Minor Version  31 //      Build Number 32 //      Revision 33 // 34 // You can specify all the values or you can default the Build and Revision Numbers  35 // by using the '*' as shown below: 36 // [assembly: AssemblyVersion("1.0.*")] 37 [assembly: AssemblyVersion("1.0.0.0")] 38 [assembly: AssemblyFileVersion("1.0.0.0")]
    复制代码

    (4)新建一个IObjectSafety接口文件IObjectSafety.cs,内容如下:

    复制代码
     1 using System;  2 using System.Collections.Generic;  3 using System.Text;  4 using System.Runtime.InteropServices;  5   6 namespace ActiveXDemo  7 {  8     [ComImport, GuidAttribute("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]  9     [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] 10     public interface IObjectSafety 11     { 12         [PreserveSig] 13         int GetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions, [MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions); 14  15         [PreserveSig()] 16         int SetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] int dwOptionSetMask, [MarshalAs(UnmanagedType.U4)] int dwEnabledOptions); 17     } 18  19 }
    复制代码

    该内容除命名空间可以更改外,其它内容都是固定的,不要修改 (5)新建一个:Windows Forms-->“用户控件”,我们的主要逻辑就写在这里(还可以在它上面随便放置其它windows常用控件,跟winForm开发一样),不过首先要修改类定义,让其实现我们刚才定义的接口

    复制代码
      1 using System;   2 using System.Runtime.InteropServices;   3 using System.Threading;   4 using System.Windows.Forms;   5    6    7 namespace ActiveXDemo   8 {   9     [Guid("8d7d8518-ca58-4863-b94d-3c616fda7b35")]  10     public partial class MyActiveX : UserControl,IObjectSafety  11     {  12         delegate void D(object obj);  13   14         public MyActiveX()  15         {  16             InitializeComponent();  17         }  18   19         #region IObjectSafety 成员  20   21         private const string _IID_IDispatch = "{00020400-0000-0000-C000-000000000046}";  22         private const string _IID_IDispatchEx = "{a6ef9860-c720-11d0-9337-00a0c90dcaa9}";  23         private const string _IID_IPersistStorage = "{0000010A-0000-0000-C000-000000000046}";  24         private const string _IID_IPersistStream = "{00000109-0000-0000-C000-000000000046}";  25         private const string _IID_IPersistPropertyBag = "{37D84F60-42CB-11CE-8135-00AA004BB851}";  26   27         private const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001;  28         private const int INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002;  29         private const int S_OK = 0;  30         private const int E_FAIL = unchecked((int)0x80004005);  31         private const int E_NOINTERFACE = unchecked((int)0x80004002);  32   33         private bool _fSafeForScripting = true;  34         private bool _fSafeForInitializing = true;  35   36         public int GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions)  37         {  38             int Rslt = E_FAIL;  39   40             string strGUID = riid.ToString("B");  41             pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;  42             switch (strGUID)  43             {  44                 case _IID_IDispatch:  45                 case _IID_IDispatchEx:  46                     Rslt = S_OK;  47                     pdwEnabledOptions = 0;  48                     if (_fSafeForScripting == true)  49                         pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;  50                     break;  51                 case _IID_IPersistStorage:  52                 case _IID_IPersistStream:  53                 case _IID_IPersistPropertyBag:  54                     Rslt = S_OK;  55                     pdwEnabledOptions = 0;  56                     if (_fSafeForInitializing == true)  57                         pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;  58                     break;  59                 default:  60                     Rslt = E_NOINTERFACE;  61                     break;  62             }  63   64             return Rslt;  65         }  66   67         public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions)  68         {  69             int Rslt = E_FAIL;  70             string strGUID = riid.ToString("B");  71             switch (strGUID)  72             {  73                 case _IID_IDispatch:  74                 case _IID_IDispatchEx:  75                     if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_CALLER) && (_fSafeForScripting == true))  76                         Rslt = S_OK;  77                     break;  78                 case _IID_IPersistStorage:  79                 case _IID_IPersistStream:  80                 case _IID_IPersistPropertyBag:  81                     if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_DATA) && (_fSafeForInitializing == true))  82                         Rslt = S_OK;  83                     break;  84                 default:  85                     Rslt = E_NOINTERFACE;  86                     break;  87             }  88   89             return Rslt;  90         }  91   92         #endregion  93   94         private void MyActiveX_Load(object sender, EventArgs e)  95         {  96               97         }  98   99  100         public void Start(object obj)  101         { 102             for (int i = 0; i < 10; i++) 103             { 104                 Thread t = new Thread(new ParameterizedThreadStart(ShowTime)); 105                 t.Start(obj.ToString() + ",线程:" + i.ToString());                 106             }         107         } 108  109         private void button1_Click(object sender, EventArgs e) 110         { 111             Start("Hello World"); 112         } 113  114         void ShowTime(object obj) 115         { 116             if (this.listBox1.InvokeRequired) 117             { 118                 D d = new D(DelegateShowTime); 119                 listBox1.Invoke(d, obj); 120             } 121             else 122             { 123                 this.listBox1.Items.Add(obj); 124             } 125  126              127         } 128  129  130         void DelegateShowTime(object obj) 131         { 132             this.listBox1.Items.Add(obj); 133         } 134  135  136     } 137 }
    复制代码

    #region IObjectSafety 成员 ... #endregion这一段的内容是固定的,不要修改,其它内容根据自己的业务要求自行修改,另外类前面要加上Guid的标识,以便网页调用时,能用CLSID="xxx"来调用

    基本上这样弄完后,就可以在网页中,用类似下面这样的代码来本机调用了:

    注意:c#定义的public方法,如果想直接让js调用,只能返回string,DateTime,int,double这一类基本值类型,其它返回类型比如array,object,在js中要么直接报错,要么得到null

    复制代码
    <object id="x" classid="clsid:8d7d8518-ca58-4863-b94d-3c616fda7b35"></object> <hr /> <input type="button" value="调用ActiveX中的多线程方法" onclick="fnTest()" /> <script type="text/javascript"> var fnTest = function(){     var x = document.getElementById("x");     x.Start("这是js中的参数"); } </script>
    复制代码

    4.安装部署

    前面已经提到了,c#开发的(伪)"ActiveX"控件并非纯正的ocx,所以只能用RegAsm.Exe xxx.dll来进行程序集的注册,这里要注意一点:在开发机上,项目编译后vs.net会自动将bindebugxxx.dll调用regasm注册,但在别人机器上就不行了,为了能在调试时模拟其它机器的运行结果,可以在编译后,手动用类似 regAsm.exe D:MyDocActiveXDemooutputActiveXDemo.dll /u 来反注册(在vs.net命令行模式下)

    当然,如果您不勾选3.(2)中所说的“为com互操作注册”,vs编译时便不会自动注册,但是这样调试起来不太方便,另外注册/反注册时的RegAsm.exe要起开发环境中的版本一致(比如你开发时设置是64位版本,那么反注册也要用64位版本的RegAsm.exe)

    另外,我们也不可能在每个客户机上手动用RegAsm.exe来帮客户注册,所以我们还得新建安装项目来做一个安装包,这个比较简单,直接新建一个"其他项目类型-->安装和部署-->安装项目"即可

    然后在安装项目上,右键"添加"-->"项目输出"-->"主输出"-->在项目下拉框中选择activex所对应的项目即可.

    注意:"主输出来自xxx"的属性栏中,有一个"Register"必须选择"vsdrpCOM"

    另外还有一个问题,可能是我机器的个别现象,每次activex项目有修改时,建议最好手动清除安装项目debug目录下的文件,再重新生成安装项目,否则有时候会发现activex修改了,但是安装包中包含的dll还是未修改过的版本。  

    后话:c#开发的东西是运行于.net 框架之上的,就好比java开发的东西必须要java runtime才能运行一样,利用本文方法开发出来的dll也必须要安装.net框架才能跑起来,幸好最新的win7中已经集成了.net框架,当然您如果对于庞大的.net框架安装程序很敏感,仍然觉得纯正的ocx更好的话,建议还是用vb/delphi/c++这一类老牌的开发工具/语言实现。(可以参考我的另一篇重温delphi之:如何快速开发原生ActiveX控件)

    示例源代码下载:http://files.cnblogs.com/yjmyzz/ActiveXDemo.rar

  • 相关阅读:
    HDU 1874 畅通工程续(dijkstra)
    HDU 2112 HDU Today (map函数,dijkstra最短路径)
    HDU 2680 Choose the best route(dijkstra)
    HDU 2066 一个人的旅行(最短路径,dijkstra)
    关于测评机,编译器,我有些话想说
    测评机的优化问题 时间控制
    CF Round410 D. Mike and distribution
    数字三角形2 (取模)
    CF Round410 C. Mike and gcd problem
    CF Round 423 D. High Load 星图(最优最简构建)
  • 原文地址:https://www.cnblogs.com/yelanggu/p/6397302.html
Copyright © 2011-2022 走看看