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()],完整内容类似下面这样:

ExpandedBlockStart.gif 代码
 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,内容如下:

ExpandedBlockStart.gif 代码
 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开发一样),不过首先要修改类定义,让其实现我们刚才定义的接口

ExpandedBlockStart.gif 代码
  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

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

4.安装部署

前面已经提到了,c#开发的(伪)"ActiveX"控件并非纯正的ocx,所以只能用RegAsm.Exe xxx.dll来进行程序集的注册,这里要注意一点:在开发机上,项目编译后vs.net会自动将bin\debug\xxx.dll调用regasm注册,但在别人机器上就不行了,为了能在调试时模拟其它机器的运行结果,可以在编译后,手动用类似 regAsm.exe D:\MyDoc\ActiveXDemo\output\ActiveXDemo.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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值