如何在C#中创建ActiveX控件?

时间:2011-10-10 12:34:19

标签: c# com activex tstcon32

我无法在C#中创建一个正常运行的ActiveX控件;我尝试过以下教程但没有成功。

我创建了一个示例类库项目,其中包含以下代码:

namespace AACWCSurvey
{
    [ProgId("Prisoner.PrisonerControl")]
    [ClassInterface(ClassInterfaceType.AutoDual)]
    public class Class1
    {
        public Class1()
        {
            MessageBox.Show("FIRETRUCK!!!");
        }
    }
}

然后我做了以下步骤:

  1. 属性=>应用=>装配信息=>使程序集COM可见
  2. Build =>注册COM互操作TRUE(已选中)
  3. 为汇编(签名)制作强名称
  4. 构建项目
  5. regasm MyDll.dll /tlb /codebase

  6. 在tstcon32 =(

  7. )中看不到Prisoner.PrisonerControl

    我的操作系统是WinXP x86。


    UPD:它适用于VBScript:

    Dim objJava
    Set objJava = WScript.CreateObject("Prisoner.PrisonerControl")
    

    但它在tstcon32中不可见。

3 个答案:

答案 0 :(得分:2)

如果您使用Prisoner.PrisonerControl控件阅读the actual article,则会使用您的控件GUID在密钥内创建一个名为Control的子密钥。

在我的机器上使用guid {9DEA5F06-E324-31A7-837B-D0F3BDE91423}创建密钥

HKEY_CLASSES_ROOT\CLSID\{9DEA5F06-E324-31A7-837B-D0F3BDE91423}\Control

使控件显示在tstcon32中。无论有没有它,ActiveX都可用于javascript

var x = new ActiveXControl("Prisoner.PrisonerControl");

实际上我不得不在javascript执行和注册表路径上对抗Windows以在我的系统上测试它,因为它是一台x64机器,但这是另一个故事。

答案 1 :(得分:2)

您已经创建了一个COM服务器,但没有创建ActiveX控件,这是一个复杂得多的COM对象,您可以使用tstcon32.exe进行操作。

它必须实现一堆接口,关键的是IOleObject和IOleWindow。允许它与ActiveX主机进行必要协商并创建可见窗口的接口类型。 Winforms控件类是您创建一个类的最佳选择。

答案 2 :(得分:0)

以下是相关步骤as documented externally。对其进行了总结,省略了一些说明,但没有任何必要的步骤。

此示例也与2008年11月25日Garry Trinder的文章Using Managed Controls as ActiveX Controls非常相似,并且我也包括了本文的一些注释。

  

将Windows窗体控件公开为ActiveX控件

     

本文将介绍如何利用Windows窗体控件   .NET外部。

     

编写控件

     
      
  1. 在Visual Studio中创建一个新的控件项目-我的示例全部使用C#,但也可以使用VB.NET。
  2.   

[这里Garry的文章建议,“ 首先,创建一个托管的用户控件项目-Windows Forms类库或控件库项目。使用用户控件设计器以所需的方式设计自定义用户控件(使用任何标准控制您喜欢的对象。)“]

  
      
  1. 将控件等添加到表单中,放入代码等中。

  2.   
  3. 添加以下using子句...

  4.   
     

using System.Runtime.InteropServices;
using System.Text;
using System.Reflection;
using Microsoft.Win32;
     
      
  1. 为您的类分配属性,以便它获得ProgID。并非绝对必要,因为会生成一个,但是几乎总是最好   明确的。
  2.   
     

[ProgId("Prisoner.PrisonerControl")]
[ClassInterface(ClassInterfaceType.AutoDual)]
     

这分配了ProgID,并且还定义了接口   暴露的应该是“ AutoDual”-这是为了   班上所有公开的,非静态的成员。如果不是这样   您需要使用其他选项之一。

     
      
  1. 更新项目属性,以便为程序集注册COM互操作。
  2.   
     

如果您使用的是VB.NET,则还需要一个强大的命名程序集。   奇怪的是,您没有使用C#,这似乎是C#的一个功能   环境,而不是编译器或CLR的功能。

     
      
  1. 将以下两个方法添加到您的类中。
  2.   
     

[ComRegisterFunction()]
public static void RegisterClass ( string key )
{ 
  // Strip off HKEY_CLASSES_ROOT\ from the passed key as I don't need it
  StringBuilder sb = new StringBuilder ( key ) ;
  sb.Replace(@"HKEY_CLASSES_ROOT\","") ;

  // Open the CLSID\{guid} key for write access
  RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(),true);

  // And create the 'Control' key - this allows it to show up in 
  // the ActiveX control container 
  RegistryKey ctrl = k.CreateSubKey ( "Control" ) ; 
  ctrl.Close ( ) ;

  // Next create the CodeBase entry - needed if not string named and GACced.
  RegistryKey inprocServer32 = k.OpenSubKey ( "InprocServer32" , true ) ; 
  inprocServer32.SetValue ( "CodeBase" , Assembly.GetExecutingAssembly().CodeBase ) ; 
  inprocServer32.Close ( ) ;

  // Finally close the main key
  k.Close ( ) ;
}
     

RegisterClass函数通过ComRegisterFunction分配-   在为程序集注册时将调用此静态方法   COM互操作。我在这里所做的只是将'Control'关键字添加到   注册表,再添加CodeBase条目。

     

CodeBase很有趣-不仅适用于.NET控件。它定义一个URL   可以找到代码的路径,可以是程序集   这样的磁盘,或Web服务器上的远程程序集   某处。当运行时尝试创建控件时,它将   探测此URL并根据需要下载控件。这非常   在测试.NET组件时很有用,就像常驻的警告一样   与.EXE位于同一目录(等)中的文件不适用。

[ComUnregisterFunction()]
public static void UnregisterClass ( string key )
{
  StringBuilder sb = new StringBuilder ( key ) ;
  sb.Replace(@"HKEY_CLASSES_ROOT\","") ;

  // Open HKCR\CLSID\{guid} for write access
  RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(),true);

  // Delete the 'Control' key, but don't throw an exception if it does not exist
  k.DeleteSubKey ( "Control" , false ) ;

  // Next open up InprocServer32
  RegistryKey inprocServer32 = k.OpenSubKey ( "InprocServer32" , true ) ;

  // And delete the CodeBase key, again not throwing if missing 
  k.DeleteSubKey ( "CodeBase" , false ) ;

  // Finally close the main key 
  k.Close ( ) ;
}
     

第二个功能将删除在(if)时添加的注册表项   班级未注册-整理整齐总是一个好的建议   随你去。

     

现在您可以编译并测试控件了。

Garry博客的其他说明:

  

[The]其他注册表项:ControlMiscStatusTypeLib和   Version [可以创建]使用.REG脚本,但是通常更好   编写将在注册/注销时调用的功能

他详细描述了注册表项:

  

Control是一个空的子项。 TypeLib映射到   TypeLib(这是assemblyinfo.cs中的程序集级GUID)。   Version是程序集中的主要和次要版本号   版。唯一有趣的子项是MiscStatus。这需要   设置为由OLEMISC中的(按位)值组成的值   枚举documented here。要使该枚举可用,请添加一个   引用Microsoft.VisualStudio.OLE.Interop(以及适当的   命名空间的“使用”语句。

他的最后一句话是警告:

  

注意:这对于Excel似乎可以正常工作(测试非常有限   我已经做完了),部分使用PowerPoint,但失败了   字。可能,更多的OLEMISC值可能会改善此情况;   可能有些消息需要我们钩住;可能有   我们还需要实现一些其他接口...事实上,我只是   勉强让它以非常有限的方式工作应该告诉你   可能不是您想以任何严肃的方式使用的技术。