各位老大,如何在C#中创建Com对象??

时间:2022-06-01 19:20:26
MyChart=(HSky.XChart)Server.CreateObject("HSky.XChart"); //创建Com对象

这是在WEB创建的

知不知道在C#中应该怎么创建?

9 个解决方案

#1


或者HSkyXChart.dll这个控件能否在winform中使用??

#2


组件的使用有两种情况, 一种托管的,另一种是非托管的。
使用可以托管的组件时可以在vs.net你的工程中,点击引用,添加,就会出现一个对话框,在里边选择你所需要的组件,前提组件是要注册过的。在winform里引用之后就可以象其他类那样调用组件里的函数了。

非托管的我还没用到,所以也不太熟悉:)

#3


我已经在我的机器上注册了HSkyXChart.dll,也能够在引用中引进来,using HSky;

XChart MyChart=new XChart();

MyChart.TitleAlign=2;   //图表上标题对齐方式(1左对齐,2居中,3右对齐)
MyChart.FootAlign=2;   //图表下标题对齐方式(1左对齐,2居中,3右对齐)
等编译都没有问题,但是运行时没有这个
MyChart=(HSky.XChart)Server.CreateObject("HSky.XChart"); //创建Com对象
就不能用。产生“灾难性故障”,我想问怎么在winform中创建这个 Com对象

#4


分不是问题,解决就加分结贴

#5


俺也不是很明白,下面是微软的解释:
————————————————————————————
主 Interop 程序集是一个由供应商提供的唯一的程序集。它包含用 COM 实现的类型的类型定义(作为元数据)。只能有一个主 Interop 程序集,而且该程序集必须由 COM 类型库的发行者用强名称签名。一个主 Interop 程序集可以包装同一类型库的多个版本。

如果导入为程序集的 COM 类型库不是由原类型库的发行者签名的,该类型库不能作为主 Interop 程序集。只有类型库的发行者才能产生真正的主 Interop 程序集。该程序集将成为用于与基础 COM 类型进行交互操作的正式类型定义单元。

COM 组件的发行者生成主 Interop 程序集并将它们发布给开发人员以便在 .NET Framework 应用程序中使用。对于发行者,本节提供有关产生主 Interop 程序集的信息。对于开发人员,本节讲解如何用主 Interop 程序集编程。
————————————————————————————————————
                                   将类型库当作程序集导入
COM 类型定义通常位于类型库中。而符合 CLS 的编译器则在程序集中生成类型元数据。类型信息的这两种来源具有很大的区别。

注意   如果可用,应始终使用要集成到托管代码中的 COM 组件的作者所发布的主 Interop 程序集。主 Interop 程序集中的类型已为您导入,可以从托管代码中激活和调用。有关生成和使用主 Interop 程序集的详细信息,请参见主 Interop 程序集。
本主题将说明从类型库中生成元数据的方法。结果程序集称作 Interop 程序集。

生成元数据
COM 类型库可以是独立的 TLB 文件,如 Loanlib.tlb。某些类型库嵌入在 DLL 或 EXE 文件的资源部分。类型库信息的其他来源包括 OLB 和 OCX 文件。

当找到包含目标 COM 类型实现的类型库后,可以通过下表所述的选项来生成包含类型元数据的 Interop 程序集。

选项 说明 
Visual Studio .NET 自动将类型库中的 COM 类型转换为程序集中的元数据。 
类型库导入程序 提供命令行开关,用以调整结果 Interop 程序集文件中的元数据、导入现有类型库中的类型以及生成 Interop 程序集和命名空间。 
TypeLibConverter 类 公开用于执行转换相关操作的方法。可以将内存中的类型库信息转换为元数据。 
自定义包装 用此选项可以从头开始创建类型定义,但我们不建议这样做。这样做要求具有高级编程技能。 

有关 COM Interop 导入过程的详细信息,请参见有关从类型库转换到程序集的摘要。

Visual Studio .NET
当添加对给定类型库的引用时,Visual Studio .NET 将生成包含元数据的 Interop 程序集。如果主 Interop 程序集可用,则 Visual Studio 在生成新的 Interop 程序集之前将使用现有程序集。

添加对类型库的引用 

在计算机上安装 COM DLL 或 EXE 文件,除非 Windows Setup.exe 会为您执行此安装。 
从“项目”菜单中选择“添加引用”。 
选择“COM”选项卡。 
从“可用引用”列表中选择类型库,或通过浏览选择 TLB 文件。 
单击“确定”。 
类型库导入程序
类型库导入程序 (Tlbimp.exe) 是一种命令行工具,它可以将包含在 COM 类型库中的 coclass 和接口转换为元数据。此工具将自动为类型信息创建 Interop 程序集和命名空间。当类的元数据变为可用时,托管客户端可以创建 COM 类型的实例并调用其方法,就像它是 .NET 实例一样。Tlbimp.exe 一次将整个类型库转换为元数据,它不能为类型库中所定义的类型的子集生成类型信息。

从类型库生成 Interop 程序集 

使用以下命令可在 Loanlib 命名空间中生成 Loanlib.dll 程序集。 
tlbimp Loanlib.dll
如果添加 /out: 开关,将生成名称已更改的 Interop 程序集(如 LOANLib.dll)。更改 Interop 程序集名称有助于将它同初始的 COM DLL 区分开来,并避免可能因重名而导致的问题。

tlbimp LoanLib.dll /out: LOANLib.dll
TypeLibConverter 类
TypeLibConverter 类(位于 System.Runtime.InteropServices 命名空间中)提供了将类型库中的 coclass 和接口转换为程序集中的元数据的方法。此 API 将生成与 Tlbimp.exe 相同的元数据输出。不过,与 Tlbimp.exe 不同的是,TypeLibConverter 类可以将内存中的类型库转换为元数据。

自定义包装
当类型库不可用或不正确时,一种可选的做法是在托管源代码中创建类或接口的重复定义。然后,用面向运行库的编译器来编译源代码以生成程序集中的元数据。

要手动定义 COM 类型,必须具备下列各项: 

所定义的 coclass 和接口的精确描述。 
可生成正确 .NET Framework 类定义的编译器,如 C# 编译器。 
有关类型库到程序集转换规则的知识。 
编写自定义包装是一种较少使用的高级技术。有关生成自定义包装的其他信息,请参见自定义标准包装。

#6


继续,在msdn找到的:
——————————————————————————
创建 COM 类包装
要使 C# 代码引用 COM 对象和接口,需要在 C# 内部版本中包含 COM 接口的 .NET Framework 定义。完成此操作的最简单方法是使用 TlbImp.exe(类型库导入程序),它是一个包括在 .NET Framework SDK 中的命令行工具。TlbImp 将 COM 类型库转换为 .NET Framework 元数据,从而有效地创建一个可以从任何托管语言调用的托管包装。用 TlbImp 创建的 .NET Framework 元数据可以通过 /R 编译器选项包括在 C# 内部版本中。如果使用 Visual Studio 开发环境,则只需添加对 COM 类型库的引用,将为您自动完成此转换。
TlbImp 执行下列转换: 
COM coclass 转换为具有无参数构造函数的 C# 类。 
COM 结构转换为具有公共字段的 C# 结构。 
检查 TlbImp 输出的一种很好的方法是运行 .NET Framework SDK 命令行工具 Ildasm.exe(Microsoft 中间语言反汇编程序)来查看转换结果。
虽然 TlbImp 是将 COM 定义转换为 C# 的首选方法,但也不是任何时候都可以使用它(例如,在没有 COM 定义的类型库时或者 TlbImp 无法处理类型库中的定义时,就不能使用该方法)。在这些情况下,另一种方法是使用 C# 属性在 C# 源代码中手动定义 COM 定义。创建 C# 源映射后,只需编译 C# 源代码就可产生托管包装。
执行 COM 映射需要理解的主要属性包括: 
ComImport,它将类标记为在外部实现的 COM 类。 
Guid,它用于为类或接口指定通用唯一标识符 (UUID)。 
InterfaceType,它指定接口是从 IUnknown 还是从 IDispatch 派生。 
PreserveSig,它指定是否应将本机返回值从 HRESULT 转换为 .NET Framework 异常。 
这些属性中的每一个都在本教程的某个实际示例的上下文中进行了显示。
声明 COM coclass
COM coclass 在 C# 中表示为类。这些类必须具有与其关联的 ComImport 属性。下列限制适用于这些类: 
类不能从任何其他类继承。 
类不能实现任何接口。 
类还必须具有为其设置全局唯一标识符 (GUID) 的 Guid 属性。 
以下示例在 C# 中声明一个 coclass:
// 
// declare FilgraphManager as a COM coclass 
// 
[ComImport, Guid("E436EBB3-524F-11CE-9F53-0020AF0BA770")] 
class FilgraphManager

}
C# 编译器将添加一个无参数构造函数,可以调用此构造函数来创建 COM coclass 的实例。
创建 COM 对象
COM coclass 在 C# 中表示为具有无参数构造函数的类。使用 new 运算符创建该类的实例等效于在 C# 中调用 CoCreateInstance。使用以上定义的类,就可以很容易地实例化此类:
class MainClass 
{
    public static void Main() 
    {
        // 
        // Create an instance of a COM coclass - calls
        //
        // CoCreateInstance(E436EBB3-524F-11CE-9F53-0020AF0BA770, 
        //                  NULL, CLSCTX_ALL, 
        //                  IID_IUnknown, &f) 
        //
        // returns null on failure. 
        // 
        FilgraphManager f = new FilgraphManager(); 
    }
}
声明 COM 接口
COM 接口在 C# 中表示为具有 ComImport 和 Guid 属性的接口。它不能在其基接口列表中包含任何接口,而且必须按照方法在 COM 接口中出现的顺序声明接口成员函数。
在 C# 中声明的 COM 接口必须包含其基接口的所有成员的声明,IUnknown 和 IDispatch 的成员除外(.NET Framework 将自动添加这些成员)。从 IDispatch 派生的 COM 接口必须用 InterfaceType 属性予以标记。
从 C# 代码调用 COM 接口方法时,公共语言运行库必须封送与 COM 对象之间传递的参数和返回值。对于每个 .NET Framework 类型均有一个默认类型,公共语言运行库将使用此默认类型在 COM 调用间进行封送处理时封送。例如,C# 字符串值的默认封送处理是封送到本机类型 LPTSTR(指向 TCHAR 字符缓冲区的指针)。可以在 COM 接口的 C# 声明中使用 MarshalAs 属性重写默认封送处理。
在 COM 中,返回成功或失败的常用方法是返回一个 HRESULT,并在 MIDL 中有一个标记为“retval”、用于方法的实际返回值的 out 参数。在 C#(和 .NET Framework)中,指示已经发生错误的标准方法是引发异常。
默认情况下,.NET Framework 为由其调用的 COM 接口方法在两种异常处理类型之间提供自动映射。 
返回值更改为标记为 retval 的参数的签名(如果方法没有标记为 retval 的参数,则为 void)。 
标记为 retval 的参数从方法的参数列表中剥离。 
任何非成功返回值都将导致引发 System.COMException 异常。
此示例显示用 MIDL 声明的 COM 接口以及用 C# 声明的同一接口(注意这些方法使用 COM 错误处理方法)。
下面是该接口的原始 MIDL 版本:

  odl, 
  uuid(56A868B1-0AD4-11CE-B03A-0020AF0BA770), 
  helpstring("IMediaControl interface"), 
  dual, 
  oleautomation 

interface IMediaControl : IDispatch 

  [id(0x60020000)] 
  HRESULT Run(); 

  [id(0x60020001)] 
  HRESULT Pause(); 

  [id(0x60020002)] 
  HRESULT Stop(); 

  [id(0x60020003)] 
  HRESULT GetState( [in] long msTimeout, [out] long* pfs); 

  [id(0x60020004)] 
  HRESULT RenderFile([in] BSTR strFilename); 

  [id(0x60020005)] 
  HRESULT AddSourceFilter( [in] BSTR strFilename, [out] IDispatch** ppUnk);

  [id(0x60020006), propget] 
  HRESULT FilterCollection([out, retval] IDispatch** ppUnk); 

  [id(0x60020007), propget] 
  HRESULT RegFilterCollection([out, retval] IDispatch** ppUnk); 

  [id(0x60020008)] 
  HRESULT StopWhenReady(); 
};
下面是该接口的 C# 等效版本:
using System.Runtime.InteropServices;

// Declare IMediaControl as a COM interface which 
// derives from the IDispatch interface. 
[Guid("56A868B1-0AD4-11CE-B03A-0020AF0BA770"),
    InterfaceType(ComInterfaceType.InterfaceIsDual)] 
interface IMediaControl // cannot list any base interfaces here 

    // Note that the members of IUnknown and Interface are NOT
    // listed here 
    //
    void Run();

    void Pause();
    
    void Stop();

    void GetState( [In] int msTimeout, [Out] out int pfs);

    void RenderFile(
    [In, MarshalAs(UnmanagedType.BStr)] string strFilename);

    void AddSourceFilter(
    [In, MarshalAs(UnmanagedType.BStr)] string strFilename, 
    [Out, MarshalAs(UnmanagedType.Interface)] out object ppUnk);

    [return : MarshalAs(UnmanagedType.Interface)]
    object FilterCollection();

    [return : MarshalAs(UnmanagedType.Interface)]
    object RegFilterCollection();
    
    void StopWhenReady(); 
}
请注意,C# 接口是如何映射错误处理情况的。如果 COM 方法返回错误,则 C# 一方将引发异常。
若要防止 HRESULT 翻译为 COMException,请在 C# 声明中将 PreserveSig(true) 属性附加到方法。有关详细信息,请参见 PreserveSigAttribute 类。
使用转换而不是 QueryInterface
只有在可以访问 C# coclass 实现的接口时,C# coclass 才会非常有用。在 C++ 中,可以使用 IUnknown 接口上的 QueryInterface 方法定位对象接口。在 C# 中,通过将 COM 对象显式转换为所需的 COM 接口,可以做到这一点。如果转换失败,则引发无效转换异常:
// Create an instance of a COM coclass:
FilgraphManager graphManager = new FilgraphManager();

// See if it supports the IMediaControl COM interface. 
// Note that this will throw a System.InvalidCastException if 
// the cast fails. This is equivalent to QueryInterface for 
// COM objects:
IMediaControl mc = (IMediaControl) graphManager;

// Now you call a method on a COM interface: 
mc.Run();

#7


示例 1:使用 TlbImp
本例显示如何使用 TlbImp 创建 AVI 查看器。程序从命令行读取 AVI 文件名,创建 Quartz COM 对象的实例,然后使用 RenderFile 和 Run 方法显示 AVI 文件。

以下是生成该程序的步骤: 

在 TLB 上运行 TlbImp。本示例使用的媒体播放机包含在应位于 Windows 系统目录中的 Quartz.dll 中。使用以下命令创建 .NET Framework DLL: 
tlbimp c:\winnt\system32\quartz.dll /out:QuartzTypeLib.dll 
请注意,得到的 DLL 需要命名为 QuartzTypeLib,以便 .NET Framework 可以在运行时正确加载包含类型。 

可以使用 Ildasm 工具查看得到的 DLL。例如,若要显示 QuartzTypeLib.dll 文件的内容,请使用以下命令: 
Ildasm QuartzTypeLib.dll
生成程序时使用 C# 编译器选项 /R 以包含 QuartzTypeLib.dll 文件。 
然后就可以使用此程序显示影片(用于测试的一个影片示例是驻留在 Windows 目录中的 Clock.avi)。

// interop1.cs
// compile with: /R:QuartzTypeLib.dll
using System;
class MainClass 

      /************************************************************ 
      Abstract: This method collects the file name of an AVI to 
      show then creates an instance of the Quartz COM object.
      To show the AVI, the program calls RenderFile and Run on 
      IMediaControl. Quartz uses its own thread and window to 
      display the AVI.The main thread blocks on a ReadLine until 
      the user presses ENTER.
            Input Parameters: the location of the AVI file it is 
            going to display
            Returns: void
      **************************************************************/ 
      public static void Main(string[] args) 
      { 
            // Check to see if the user passed in a filename 
            if (args.Length != 1)
            { 
                  DisplayUsage();
                  return;
            } 
 
            if (args[0] == "/?")
            { 
                  DisplayUsage();
                  return;
            } 
 
            string filename = args[0]; 
 
            // Check to see if the file exists
            if (!System.IO.File.Exists(filename))
            {
                  Console.WriteLine("File " + filename + " not found.");
                  DisplayUsage();
                  return;
            }
    
            // Create instance of Quartz
            // (Calls CoCreateInstance(E436EBB3-524F-11CE-9F53-0020AF0BA770,
            // NULL, CLSCTX_ALL, IID_IUnknown, &graphManager).): 
 
            try
            {
                  QuartzTypeLib.FilgraphManager graphManager = 
                        new QuartzTypeLib.FilgraphManager();
 
                  // QueryInterface for the IMediaControl interface:
                  QuartzTypeLib.IMediaControl mc =
                        (QuartzTypeLib.IMediaControl)graphManager;
 
                  // Call some methods on a COM interface 
                  // Pass in file to RenderFile method on COM object. 
                  mc.RenderFile(filename);
 
                  // Show file. 
                  mc.Run();
            }
            catch(Exception ex)
            {
                  Console.WriteLine("Unexpected COM exception: " + ex.Message);
            }
 
            // Wait for completion.
            Console.WriteLine("Press Enter to continue."); 
            Console.ReadLine();
      }
    
      private static void DisplayUsage() 
      { 
            // User did not provide enough parameters. 
            // Display usage: 
            Console.WriteLine("VideoPlayer: Plays AVI files."); 
            Console.WriteLine("Usage: VIDEOPLAYER.EXE filename"); 
            Console.WriteLine("where filename is the full path and"); 
            Console.WriteLine("file name of the AVI to display."); 
      } 
}
运行示例
若要显示影片示例 Clock.avi,请使用以下命令:

interop1 %windir%\clock.avi
当您按 ENTER 键后,屏幕上将显示影片。

#8


我在这里举个COM控件的使用例子:AxWindowsMediaPlayer
实例化对象:this.axWindowsMediaPlayer1 = new AxWMPLib.AxWindowsMediaPlayer();

//具体完整代码如下:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace WindowsApp.FirstApp
{
public class Form26 : System.Windows.Forms.Form
{
private System.Windows.Forms.MainMenu mainMenu1;
private System.Windows.Forms.MenuItem menuItem1;
private System.Windows.Forms.MenuItem menuItem2;
private AxWMPLib.AxWindowsMediaPlayer axWindowsMediaPlayer1;
private System.Windows.Forms.OpenFileDialog openFileDialog1;

private System.ComponentModel.Container components = null;

public Form26()
{
InitializeComponent();
}

protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(Form26));
this.mainMenu1 = new System.Windows.Forms.MainMenu();
this.menuItem1 = new System.Windows.Forms.MenuItem();
this.menuItem2 = new System.Windows.Forms.MenuItem();
this.axWindowsMediaPlayer1 = new AxWMPLib.AxWindowsMediaPlayer();
this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
((System.ComponentModel.ISupportInitialize)(this.axWindowsMediaPlayer1)).BeginInit();
this.SuspendLayout();
// 
// mainMenu1
// 
this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
  this.menuItem1});
// 
// menuItem1
// 
this.menuItem1.Index = 0;
this.menuItem1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
  this.menuItem2});
this.menuItem1.Text = "文件(&F)";
// 
// menuItem2
// 
this.menuItem2.Index = 0;
this.menuItem2.Text = "打开";
this.menuItem2.Click += new System.EventHandler(this.menuItem2_Click);
// 
// axWindowsMediaPlayer1
// 
this.axWindowsMediaPlayer1.Enabled = true;
this.axWindowsMediaPlayer1.Location = new System.Drawing.Point(0, 0);
this.axWindowsMediaPlayer1.Name = "axWindowsMediaPlayer1";
this.axWindowsMediaPlayer1.OcxState = ((System.Windows.Forms.AxHost.State)(resources.GetObject("axWindowsMediaPlayer1.OcxState")));
this.axWindowsMediaPlayer1.Size = new System.Drawing.Size(296, 272);
this.axWindowsMediaPlayer1.TabIndex = 0;
// 
// Form26
// 
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.BackColor = System.Drawing.SystemColors.Window;
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.axWindowsMediaPlayer1);
this.Menu = this.mainMenu1;
this.Name = "Form26";
this.Text = "Form26";
((System.ComponentModel.ISupportInitialize)(this.axWindowsMediaPlayer1)).EndInit();
this.ResumeLayout(false);

}
#endregion

private void menuItem2_Click(object sender, System.EventArgs e)
{
openFileDialog1.Filter=@"视频文件(*.avi;*.wmv;*.dat;*.mpg;*.mpeg;8.mov;*.wm;*wma)
|*.avi;*.wmv;*.dat;*.mpg;*.mpeg;*.mov;*.wm;*wma|音频文件(*.wav;*.mp3;*.snd;*.au;*.midi;*.mid)
|*.wav;*.mp3;*.snd;*.au;*.midi;*.mid|所有文件(*.*)|*.*";
if(openFileDialog1.ShowDialog()==DialogResult.OK)
{
axWindowsMediaPlayer1.URL = openFileDialog1.FileName;
}
}
}
}

//测试通过

#9


比较复杂,我干脆用WS来生成算了,反正我的程序也用到WEB的部分,一起调用就是了。

各位,怎么加分?

#1


或者HSkyXChart.dll这个控件能否在winform中使用??

#2


组件的使用有两种情况, 一种托管的,另一种是非托管的。
使用可以托管的组件时可以在vs.net你的工程中,点击引用,添加,就会出现一个对话框,在里边选择你所需要的组件,前提组件是要注册过的。在winform里引用之后就可以象其他类那样调用组件里的函数了。

非托管的我还没用到,所以也不太熟悉:)

#3


我已经在我的机器上注册了HSkyXChart.dll,也能够在引用中引进来,using HSky;

XChart MyChart=new XChart();

MyChart.TitleAlign=2;   //图表上标题对齐方式(1左对齐,2居中,3右对齐)
MyChart.FootAlign=2;   //图表下标题对齐方式(1左对齐,2居中,3右对齐)
等编译都没有问题,但是运行时没有这个
MyChart=(HSky.XChart)Server.CreateObject("HSky.XChart"); //创建Com对象
就不能用。产生“灾难性故障”,我想问怎么在winform中创建这个 Com对象

#4


分不是问题,解决就加分结贴

#5


俺也不是很明白,下面是微软的解释:
————————————————————————————
主 Interop 程序集是一个由供应商提供的唯一的程序集。它包含用 COM 实现的类型的类型定义(作为元数据)。只能有一个主 Interop 程序集,而且该程序集必须由 COM 类型库的发行者用强名称签名。一个主 Interop 程序集可以包装同一类型库的多个版本。

如果导入为程序集的 COM 类型库不是由原类型库的发行者签名的,该类型库不能作为主 Interop 程序集。只有类型库的发行者才能产生真正的主 Interop 程序集。该程序集将成为用于与基础 COM 类型进行交互操作的正式类型定义单元。

COM 组件的发行者生成主 Interop 程序集并将它们发布给开发人员以便在 .NET Framework 应用程序中使用。对于发行者,本节提供有关产生主 Interop 程序集的信息。对于开发人员,本节讲解如何用主 Interop 程序集编程。
————————————————————————————————————
                                   将类型库当作程序集导入
COM 类型定义通常位于类型库中。而符合 CLS 的编译器则在程序集中生成类型元数据。类型信息的这两种来源具有很大的区别。

注意   如果可用,应始终使用要集成到托管代码中的 COM 组件的作者所发布的主 Interop 程序集。主 Interop 程序集中的类型已为您导入,可以从托管代码中激活和调用。有关生成和使用主 Interop 程序集的详细信息,请参见主 Interop 程序集。
本主题将说明从类型库中生成元数据的方法。结果程序集称作 Interop 程序集。

生成元数据
COM 类型库可以是独立的 TLB 文件,如 Loanlib.tlb。某些类型库嵌入在 DLL 或 EXE 文件的资源部分。类型库信息的其他来源包括 OLB 和 OCX 文件。

当找到包含目标 COM 类型实现的类型库后,可以通过下表所述的选项来生成包含类型元数据的 Interop 程序集。

选项 说明 
Visual Studio .NET 自动将类型库中的 COM 类型转换为程序集中的元数据。 
类型库导入程序 提供命令行开关,用以调整结果 Interop 程序集文件中的元数据、导入现有类型库中的类型以及生成 Interop 程序集和命名空间。 
TypeLibConverter 类 公开用于执行转换相关操作的方法。可以将内存中的类型库信息转换为元数据。 
自定义包装 用此选项可以从头开始创建类型定义,但我们不建议这样做。这样做要求具有高级编程技能。 

有关 COM Interop 导入过程的详细信息,请参见有关从类型库转换到程序集的摘要。

Visual Studio .NET
当添加对给定类型库的引用时,Visual Studio .NET 将生成包含元数据的 Interop 程序集。如果主 Interop 程序集可用,则 Visual Studio 在生成新的 Interop 程序集之前将使用现有程序集。

添加对类型库的引用 

在计算机上安装 COM DLL 或 EXE 文件,除非 Windows Setup.exe 会为您执行此安装。 
从“项目”菜单中选择“添加引用”。 
选择“COM”选项卡。 
从“可用引用”列表中选择类型库,或通过浏览选择 TLB 文件。 
单击“确定”。 
类型库导入程序
类型库导入程序 (Tlbimp.exe) 是一种命令行工具,它可以将包含在 COM 类型库中的 coclass 和接口转换为元数据。此工具将自动为类型信息创建 Interop 程序集和命名空间。当类的元数据变为可用时,托管客户端可以创建 COM 类型的实例并调用其方法,就像它是 .NET 实例一样。Tlbimp.exe 一次将整个类型库转换为元数据,它不能为类型库中所定义的类型的子集生成类型信息。

从类型库生成 Interop 程序集 

使用以下命令可在 Loanlib 命名空间中生成 Loanlib.dll 程序集。 
tlbimp Loanlib.dll
如果添加 /out: 开关,将生成名称已更改的 Interop 程序集(如 LOANLib.dll)。更改 Interop 程序集名称有助于将它同初始的 COM DLL 区分开来,并避免可能因重名而导致的问题。

tlbimp LoanLib.dll /out: LOANLib.dll
TypeLibConverter 类
TypeLibConverter 类(位于 System.Runtime.InteropServices 命名空间中)提供了将类型库中的 coclass 和接口转换为程序集中的元数据的方法。此 API 将生成与 Tlbimp.exe 相同的元数据输出。不过,与 Tlbimp.exe 不同的是,TypeLibConverter 类可以将内存中的类型库转换为元数据。

自定义包装
当类型库不可用或不正确时,一种可选的做法是在托管源代码中创建类或接口的重复定义。然后,用面向运行库的编译器来编译源代码以生成程序集中的元数据。

要手动定义 COM 类型,必须具备下列各项: 

所定义的 coclass 和接口的精确描述。 
可生成正确 .NET Framework 类定义的编译器,如 C# 编译器。 
有关类型库到程序集转换规则的知识。 
编写自定义包装是一种较少使用的高级技术。有关生成自定义包装的其他信息,请参见自定义标准包装。

#6


继续,在msdn找到的:
——————————————————————————
创建 COM 类包装
要使 C# 代码引用 COM 对象和接口,需要在 C# 内部版本中包含 COM 接口的 .NET Framework 定义。完成此操作的最简单方法是使用 TlbImp.exe(类型库导入程序),它是一个包括在 .NET Framework SDK 中的命令行工具。TlbImp 将 COM 类型库转换为 .NET Framework 元数据,从而有效地创建一个可以从任何托管语言调用的托管包装。用 TlbImp 创建的 .NET Framework 元数据可以通过 /R 编译器选项包括在 C# 内部版本中。如果使用 Visual Studio 开发环境,则只需添加对 COM 类型库的引用,将为您自动完成此转换。
TlbImp 执行下列转换: 
COM coclass 转换为具有无参数构造函数的 C# 类。 
COM 结构转换为具有公共字段的 C# 结构。 
检查 TlbImp 输出的一种很好的方法是运行 .NET Framework SDK 命令行工具 Ildasm.exe(Microsoft 中间语言反汇编程序)来查看转换结果。
虽然 TlbImp 是将 COM 定义转换为 C# 的首选方法,但也不是任何时候都可以使用它(例如,在没有 COM 定义的类型库时或者 TlbImp 无法处理类型库中的定义时,就不能使用该方法)。在这些情况下,另一种方法是使用 C# 属性在 C# 源代码中手动定义 COM 定义。创建 C# 源映射后,只需编译 C# 源代码就可产生托管包装。
执行 COM 映射需要理解的主要属性包括: 
ComImport,它将类标记为在外部实现的 COM 类。 
Guid,它用于为类或接口指定通用唯一标识符 (UUID)。 
InterfaceType,它指定接口是从 IUnknown 还是从 IDispatch 派生。 
PreserveSig,它指定是否应将本机返回值从 HRESULT 转换为 .NET Framework 异常。 
这些属性中的每一个都在本教程的某个实际示例的上下文中进行了显示。
声明 COM coclass
COM coclass 在 C# 中表示为类。这些类必须具有与其关联的 ComImport 属性。下列限制适用于这些类: 
类不能从任何其他类继承。 
类不能实现任何接口。 
类还必须具有为其设置全局唯一标识符 (GUID) 的 Guid 属性。 
以下示例在 C# 中声明一个 coclass:
// 
// declare FilgraphManager as a COM coclass 
// 
[ComImport, Guid("E436EBB3-524F-11CE-9F53-0020AF0BA770")] 
class FilgraphManager

}
C# 编译器将添加一个无参数构造函数,可以调用此构造函数来创建 COM coclass 的实例。
创建 COM 对象
COM coclass 在 C# 中表示为具有无参数构造函数的类。使用 new 运算符创建该类的实例等效于在 C# 中调用 CoCreateInstance。使用以上定义的类,就可以很容易地实例化此类:
class MainClass 
{
    public static void Main() 
    {
        // 
        // Create an instance of a COM coclass - calls
        //
        // CoCreateInstance(E436EBB3-524F-11CE-9F53-0020AF0BA770, 
        //                  NULL, CLSCTX_ALL, 
        //                  IID_IUnknown, &f) 
        //
        // returns null on failure. 
        // 
        FilgraphManager f = new FilgraphManager(); 
    }
}
声明 COM 接口
COM 接口在 C# 中表示为具有 ComImport 和 Guid 属性的接口。它不能在其基接口列表中包含任何接口,而且必须按照方法在 COM 接口中出现的顺序声明接口成员函数。
在 C# 中声明的 COM 接口必须包含其基接口的所有成员的声明,IUnknown 和 IDispatch 的成员除外(.NET Framework 将自动添加这些成员)。从 IDispatch 派生的 COM 接口必须用 InterfaceType 属性予以标记。
从 C# 代码调用 COM 接口方法时,公共语言运行库必须封送与 COM 对象之间传递的参数和返回值。对于每个 .NET Framework 类型均有一个默认类型,公共语言运行库将使用此默认类型在 COM 调用间进行封送处理时封送。例如,C# 字符串值的默认封送处理是封送到本机类型 LPTSTR(指向 TCHAR 字符缓冲区的指针)。可以在 COM 接口的 C# 声明中使用 MarshalAs 属性重写默认封送处理。
在 COM 中,返回成功或失败的常用方法是返回一个 HRESULT,并在 MIDL 中有一个标记为“retval”、用于方法的实际返回值的 out 参数。在 C#(和 .NET Framework)中,指示已经发生错误的标准方法是引发异常。
默认情况下,.NET Framework 为由其调用的 COM 接口方法在两种异常处理类型之间提供自动映射。 
返回值更改为标记为 retval 的参数的签名(如果方法没有标记为 retval 的参数,则为 void)。 
标记为 retval 的参数从方法的参数列表中剥离。 
任何非成功返回值都将导致引发 System.COMException 异常。
此示例显示用 MIDL 声明的 COM 接口以及用 C# 声明的同一接口(注意这些方法使用 COM 错误处理方法)。
下面是该接口的原始 MIDL 版本:

  odl, 
  uuid(56A868B1-0AD4-11CE-B03A-0020AF0BA770), 
  helpstring("IMediaControl interface"), 
  dual, 
  oleautomation 

interface IMediaControl : IDispatch 

  [id(0x60020000)] 
  HRESULT Run(); 

  [id(0x60020001)] 
  HRESULT Pause(); 

  [id(0x60020002)] 
  HRESULT Stop(); 

  [id(0x60020003)] 
  HRESULT GetState( [in] long msTimeout, [out] long* pfs); 

  [id(0x60020004)] 
  HRESULT RenderFile([in] BSTR strFilename); 

  [id(0x60020005)] 
  HRESULT AddSourceFilter( [in] BSTR strFilename, [out] IDispatch** ppUnk);

  [id(0x60020006), propget] 
  HRESULT FilterCollection([out, retval] IDispatch** ppUnk); 

  [id(0x60020007), propget] 
  HRESULT RegFilterCollection([out, retval] IDispatch** ppUnk); 

  [id(0x60020008)] 
  HRESULT StopWhenReady(); 
};
下面是该接口的 C# 等效版本:
using System.Runtime.InteropServices;

// Declare IMediaControl as a COM interface which 
// derives from the IDispatch interface. 
[Guid("56A868B1-0AD4-11CE-B03A-0020AF0BA770"),
    InterfaceType(ComInterfaceType.InterfaceIsDual)] 
interface IMediaControl // cannot list any base interfaces here 

    // Note that the members of IUnknown and Interface are NOT
    // listed here 
    //
    void Run();

    void Pause();
    
    void Stop();

    void GetState( [In] int msTimeout, [Out] out int pfs);

    void RenderFile(
    [In, MarshalAs(UnmanagedType.BStr)] string strFilename);

    void AddSourceFilter(
    [In, MarshalAs(UnmanagedType.BStr)] string strFilename, 
    [Out, MarshalAs(UnmanagedType.Interface)] out object ppUnk);

    [return : MarshalAs(UnmanagedType.Interface)]
    object FilterCollection();

    [return : MarshalAs(UnmanagedType.Interface)]
    object RegFilterCollection();
    
    void StopWhenReady(); 
}
请注意,C# 接口是如何映射错误处理情况的。如果 COM 方法返回错误,则 C# 一方将引发异常。
若要防止 HRESULT 翻译为 COMException,请在 C# 声明中将 PreserveSig(true) 属性附加到方法。有关详细信息,请参见 PreserveSigAttribute 类。
使用转换而不是 QueryInterface
只有在可以访问 C# coclass 实现的接口时,C# coclass 才会非常有用。在 C++ 中,可以使用 IUnknown 接口上的 QueryInterface 方法定位对象接口。在 C# 中,通过将 COM 对象显式转换为所需的 COM 接口,可以做到这一点。如果转换失败,则引发无效转换异常:
// Create an instance of a COM coclass:
FilgraphManager graphManager = new FilgraphManager();

// See if it supports the IMediaControl COM interface. 
// Note that this will throw a System.InvalidCastException if 
// the cast fails. This is equivalent to QueryInterface for 
// COM objects:
IMediaControl mc = (IMediaControl) graphManager;

// Now you call a method on a COM interface: 
mc.Run();

#7


示例 1:使用 TlbImp
本例显示如何使用 TlbImp 创建 AVI 查看器。程序从命令行读取 AVI 文件名,创建 Quartz COM 对象的实例,然后使用 RenderFile 和 Run 方法显示 AVI 文件。

以下是生成该程序的步骤: 

在 TLB 上运行 TlbImp。本示例使用的媒体播放机包含在应位于 Windows 系统目录中的 Quartz.dll 中。使用以下命令创建 .NET Framework DLL: 
tlbimp c:\winnt\system32\quartz.dll /out:QuartzTypeLib.dll 
请注意,得到的 DLL 需要命名为 QuartzTypeLib,以便 .NET Framework 可以在运行时正确加载包含类型。 

可以使用 Ildasm 工具查看得到的 DLL。例如,若要显示 QuartzTypeLib.dll 文件的内容,请使用以下命令: 
Ildasm QuartzTypeLib.dll
生成程序时使用 C# 编译器选项 /R 以包含 QuartzTypeLib.dll 文件。 
然后就可以使用此程序显示影片(用于测试的一个影片示例是驻留在 Windows 目录中的 Clock.avi)。

// interop1.cs
// compile with: /R:QuartzTypeLib.dll
using System;
class MainClass 

      /************************************************************ 
      Abstract: This method collects the file name of an AVI to 
      show then creates an instance of the Quartz COM object.
      To show the AVI, the program calls RenderFile and Run on 
      IMediaControl. Quartz uses its own thread and window to 
      display the AVI.The main thread blocks on a ReadLine until 
      the user presses ENTER.
            Input Parameters: the location of the AVI file it is 
            going to display
            Returns: void
      **************************************************************/ 
      public static void Main(string[] args) 
      { 
            // Check to see if the user passed in a filename 
            if (args.Length != 1)
            { 
                  DisplayUsage();
                  return;
            } 
 
            if (args[0] == "/?")
            { 
                  DisplayUsage();
                  return;
            } 
 
            string filename = args[0]; 
 
            // Check to see if the file exists
            if (!System.IO.File.Exists(filename))
            {
                  Console.WriteLine("File " + filename + " not found.");
                  DisplayUsage();
                  return;
            }
    
            // Create instance of Quartz
            // (Calls CoCreateInstance(E436EBB3-524F-11CE-9F53-0020AF0BA770,
            // NULL, CLSCTX_ALL, IID_IUnknown, &graphManager).): 
 
            try
            {
                  QuartzTypeLib.FilgraphManager graphManager = 
                        new QuartzTypeLib.FilgraphManager();
 
                  // QueryInterface for the IMediaControl interface:
                  QuartzTypeLib.IMediaControl mc =
                        (QuartzTypeLib.IMediaControl)graphManager;
 
                  // Call some methods on a COM interface 
                  // Pass in file to RenderFile method on COM object. 
                  mc.RenderFile(filename);
 
                  // Show file. 
                  mc.Run();
            }
            catch(Exception ex)
            {
                  Console.WriteLine("Unexpected COM exception: " + ex.Message);
            }
 
            // Wait for completion.
            Console.WriteLine("Press Enter to continue."); 
            Console.ReadLine();
      }
    
      private static void DisplayUsage() 
      { 
            // User did not provide enough parameters. 
            // Display usage: 
            Console.WriteLine("VideoPlayer: Plays AVI files."); 
            Console.WriteLine("Usage: VIDEOPLAYER.EXE filename"); 
            Console.WriteLine("where filename is the full path and"); 
            Console.WriteLine("file name of the AVI to display."); 
      } 
}
运行示例
若要显示影片示例 Clock.avi,请使用以下命令:

interop1 %windir%\clock.avi
当您按 ENTER 键后,屏幕上将显示影片。

#8


我在这里举个COM控件的使用例子:AxWindowsMediaPlayer
实例化对象:this.axWindowsMediaPlayer1 = new AxWMPLib.AxWindowsMediaPlayer();

//具体完整代码如下:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace WindowsApp.FirstApp
{
public class Form26 : System.Windows.Forms.Form
{
private System.Windows.Forms.MainMenu mainMenu1;
private System.Windows.Forms.MenuItem menuItem1;
private System.Windows.Forms.MenuItem menuItem2;
private AxWMPLib.AxWindowsMediaPlayer axWindowsMediaPlayer1;
private System.Windows.Forms.OpenFileDialog openFileDialog1;

private System.ComponentModel.Container components = null;

public Form26()
{
InitializeComponent();
}

protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(Form26));
this.mainMenu1 = new System.Windows.Forms.MainMenu();
this.menuItem1 = new System.Windows.Forms.MenuItem();
this.menuItem2 = new System.Windows.Forms.MenuItem();
this.axWindowsMediaPlayer1 = new AxWMPLib.AxWindowsMediaPlayer();
this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
((System.ComponentModel.ISupportInitialize)(this.axWindowsMediaPlayer1)).BeginInit();
this.SuspendLayout();
// 
// mainMenu1
// 
this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
  this.menuItem1});
// 
// menuItem1
// 
this.menuItem1.Index = 0;
this.menuItem1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
  this.menuItem2});
this.menuItem1.Text = "文件(&F)";
// 
// menuItem2
// 
this.menuItem2.Index = 0;
this.menuItem2.Text = "打开";
this.menuItem2.Click += new System.EventHandler(this.menuItem2_Click);
// 
// axWindowsMediaPlayer1
// 
this.axWindowsMediaPlayer1.Enabled = true;
this.axWindowsMediaPlayer1.Location = new System.Drawing.Point(0, 0);
this.axWindowsMediaPlayer1.Name = "axWindowsMediaPlayer1";
this.axWindowsMediaPlayer1.OcxState = ((System.Windows.Forms.AxHost.State)(resources.GetObject("axWindowsMediaPlayer1.OcxState")));
this.axWindowsMediaPlayer1.Size = new System.Drawing.Size(296, 272);
this.axWindowsMediaPlayer1.TabIndex = 0;
// 
// Form26
// 
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.BackColor = System.Drawing.SystemColors.Window;
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.axWindowsMediaPlayer1);
this.Menu = this.mainMenu1;
this.Name = "Form26";
this.Text = "Form26";
((System.ComponentModel.ISupportInitialize)(this.axWindowsMediaPlayer1)).EndInit();
this.ResumeLayout(false);

}
#endregion

private void menuItem2_Click(object sender, System.EventArgs e)
{
openFileDialog1.Filter=@"视频文件(*.avi;*.wmv;*.dat;*.mpg;*.mpeg;8.mov;*.wm;*wma)
|*.avi;*.wmv;*.dat;*.mpg;*.mpeg;*.mov;*.wm;*wma|音频文件(*.wav;*.mp3;*.snd;*.au;*.midi;*.mid)
|*.wav;*.mp3;*.snd;*.au;*.midi;*.mid|所有文件(*.*)|*.*";
if(openFileDialog1.ShowDialog()==DialogResult.OK)
{
axWindowsMediaPlayer1.URL = openFileDialog1.FileName;
}
}
}
}

//测试通过

#9


比较复杂,我干脆用WS来生成算了,反正我的程序也用到WEB的部分,一起调用就是了。

各位,怎么加分?