c#开发ActiveX完全攻略

1、背景

网页本身的功能是有限的,要想实现一些网页本身不支持的功能,比如:网页上的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()],完整内容类似下面这样:

using System.Reflection;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using System.Security;
 
 // General Information about an assembly is controlled through the following 
 // set of attributes. Change these attribute values to modify the information
 // associated with an assembly.
 [assembly: AssemblyTitle("ActiveXDemo")]
 [assembly: AssemblyDescription("")]
 [assembly: AssemblyConfiguration("")]
 [assembly: AssemblyCompany("Microsoft")]
 [assembly: AssemblyProduct("ActiveXDemo")]
 [assembly: AssemblyCopyright("Copyright ? Microsoft 2009")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
 [assembly: AllowPartiallyTrustedCallers()]
 
 // Setting ComVisible to false makes the types in this assembly not visible 
 // to COM components.  If you need to access a type in this assembly from 
 // COM, set the ComVisible attribute to true on that type.
 [assembly: ComVisible(true)]
 
 // The following GUID is for the ID of the typelib if this project is exposed to COM
 [assembly: Guid("bd585d12-7f22-4b3f-959f-18efbfc53f94")]
 
 // Version information for an assembly consists of the following four values:
 //
 //      Major Version
 //      Minor Version 
 //      Build Number
 //      Revision
 //
 // You can specify all the values or you can default the Build and Revision Numbers 
 // by using the '*' as shown below:
 // [assembly: AssemblyVersion("1.0.*")]
 [assembly: AssemblyVersion("1.0.0.0")]
 [assembly: AssemblyFileVersion("1.0.0.0")]

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

using System;
 using System.Collections.Generic;
 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);
     }
 
 }

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

using System;
 using System.Runtime.InteropServices;
 using System.Threading;
 using System.Windows.Forms;
 
 
 namespace ActiveXDemo
 {
     [Guid("8d7d8518-ca58-4863-b94d-3c616fda7b35")]
     public partial class MyActiveX : UserControl,IObjectSafety
     {
         delegate void D(object obj);
 
         public MyActiveX()
         {
             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
 
         private void MyActiveX_Load(object sender, EventArgs e)
         {
             
         }
 
 
         public void Start(object obj) 
         {
             for (int i = 0; i < 10; i++)
             {
                 Thread t = new Thread(new ParameterizedThreadStart(ShowTime));
                 t.Start(obj.ToString() + ",线程:" + i.ToString());                
             }        
         }
 
         private void button1_Click(object sender, EventArgs e)
         {
             Start("Hello World");
         }
 
         void ShowTime(object obj)
         {
             if (this.listBox1.InvokeRequired)
             {
                 D d = new D(DelegateShowTime);
                 listBox1.Invoke(d, obj);
             }
             else
             {
                 this.listBox1.Items.Add(obj);
             }
 
             
         }
 
 
         void DelegateShowTime(object obj)
         {
             this.listBox1.Items.Add(obj);
         }
 
 
     }
 }

#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中的多线程方法" οnclick="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会自动将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++这一类老牌的开发工具/语言实现。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您可以使用 ActiveX 控件来自定义 CAD 的全局坐标。以下是一些步骤供您参考: 1. 首先,确保您已经安装了适当的 CAD 软件,并且该软件提供了 ActiveX 控件的支持。 2. 在 C# 项目中,添加对 CAD ActiveX 控件的引用。这通常可以通过右键单击项目,选择 "添加引用",然后在 COM 选项卡中找到合适的控件。 3. 在代码中创建一个控件实例,并将其添加到您的窗体或用户控件中。例如: ```csharp using CADActiveX; // 创建控件实例 CADControl cadControl = new CADControl(); // 将控件添加到窗体或用户控件中 this.Controls.Add(cadControl); ``` 4. 初始化并连接 CAD 控件。这可能涉及到设置一些属性或调用一些方法来加载 CAD 文件或进行其他必要的操作。 5. 通过控件提供的 API,您可以访问和操作 CAD 的全局坐标。具体的方法和属性取决于您使用的 CAD 软件和其提供的功能。您可以查阅相应的文档或参考 CAD 控件的 API 文档。 例如,如果您想获取当前选择的图形对象的全局坐标,您可以使用类似以下的代码: ```csharp CADObject selectedObject = cadControl.GetSelectedObject(); Point3D globalPosition = selectedObject.GetGlobalPosition(); ``` 请注意,这只是一个示例,具体的实现方式可能因不同的 CAD 软件而异。您需要根据您使用的 CAD 控件的 API 来确定正确的方法和属性。 希望这些信息对您有帮助!如有任何进一步的问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值