C#调用COM组件

时间:2022-08-30 18:17:36

这部分描述了在托管代码中调用COM组件的方法,
现存的COM组件在托管代码中作为中间件或者独立的功能实体是很有价值的资源
向.NET Framework报露COM组件
1. Import a type library as an assembly
COM的类型定义通常在type library(tlb)中,与之对应的是CLS兼容的编译器在assembly中产生类型元数据(type metadata),这两种类型信息的来源有很大的不同

Generating Metadata
COM 的类型库( type libraries )可以是一个单独得 Tlb 文件,例如 Loanlib.tlb 。一些类型库被嵌入到 DLL 或者 Exe 的资源文件中,还有一些类型库在 OLB 或者 OCX 中。
找到包含你的 COM 类型的类型库之后,可以有以下的选择来生成包含元数据的交互程序集( interop assembly
Option
Description
Visual Studio .NET
Automatically converts COM types in a type library to metadata in an assembly.
Type Library Importer
Provides command-line switches to adjust metadata in the resulting interop file, imports types from an existing type library, and generates an interop assembly and a namespace.
TypeLibConverter Class
Exposes methods that perform conversion-related actions. Can convert in-memory type library information to metadata.
Custom Wrappers
As a less desirable option, you can create type definitions from scratch. This requires advanced programming skills.
当添加一个给定的 type library 的引用( reference )时, Visual Studio .NET 生成包含元数据的交互程序集( interop assembly )。如果一个主交互程序集( primary interop assembly )有效的话, Visual Studio 使用存在的 assembly
To add a reference to a type library
1.      Install the COM DLL or EXE file on your computer, unless a Windows Setup.exe performs the installation for you.
2.      From the Project menu, select References.
3.      Select the COM tab.
4.      Select the type library from the Available References list, or browse for the TLB file.
5.      Click OK.
C#调用COM组件
Type Library Importer
The Type Library Importer (Tlbimp.exe) 是一个命令行的工具,它可以把 COM 的类型库中的 Coclassed interfaces 转换成元数据。
使用方法:
tlbimp Loanlib.dll
TypeLibConverter Class
TypeLibConverter class in the System.Runtime.InteropServices namespace )提供了转换类型库中的 coclasses interfaces 到元数据的方法。
Custom Wrappers
当一个类型库不可用或者不正确时,一个可选的方法就是在托管代码重创建一个 class 或者 interface 定义的副本。然后编译代码在 runtime 在程序集中产生元数据
手动定义 COM 类型,必须遵循如下
       准确的描述定义的 coclasses interfaces
       一个编译器,例如 C# 编译器可以生成对应的 .NET Framework 的类的定义
       type library-to-assembly 转化规则的相关知识
写一个自定义的包装类( wrapper )是一项应该很少使用的高级的技术。
2.      Using COM Types in Managed Code
COM 在程序集中类型定义类似其他的托管代码。托管的客户可以使用通常的方式创建 COM 类型的新的实例并且像其他托管类一样通过元数据得到类的信息。方法的语法可以通过 object viewer 或者反射( reflection )得到。当 COM 的方法返回一个失败的结果时, .NET 的客户得到一个对应的异常。
得到或者释放一个运行的 COM 对象的引用像得到或者释放其他的运行的托管对象的引用一样。当一个 .NET 的客户端得到或者释放 COM 对象的引用,运行时像其他的 COM 客户端那样维护 COM 对象的引用计数, .NET 的客户端可以认为对象可以像其他的托管对象那样被垃圾收集。
下面是 C# 的客户端代码
[C#]
using System;
using LoanLib;
public class LoanApp {
   public static void Main(String[] Args) {
      Loan ln = new Loan();
      if (Args.Length < 4)
      {
         Console.WriteLine("Usage: ConLoan Balance Rate Term Payment");
         Console.WriteLine("    Either Balance, Rate, Term, or Payment
            must be 0");
         return;
      }
      ln.OpeningBalance = Convert.ToDouble(Args[0]);
      ln.Rate = Convert.ToDouble(Args[1])/100.0;
      ln.Term = Convert.ToInt16(Args[2]);
      ln.Payment = Convert.ToDouble(Args[3]);
     
      if (ln.OpeningBalance == 0.00) ln.ComputeOpeningBalance();
      if (ln.Rate == 0.00) ln.ComputeRate();
      if (ln.Term == 0) ln.ComputeTerm();
      if (ln.Payment == 0.00) ln.ComputePayment();
      Console.WriteLine("Balance = {0,10:0.00}", ln.OpeningBalance);
      Console.WriteLine("Rate    = {0,10:0.0%}", ln.Rate);
      Console.WriteLine("Term    = {0,10:0.00}", ln.Term);
      Console.WriteLine("Payment = {0,10:0.00}/n", ln.Payment);
      bool MorePmts;
      double Balance = 0.0;
      double Principal = 0.0;
      double Interest = 0.0;
      Console.WriteLine("{0,4}{1,10}{2,12}{3,10}{4,12}", "Nbr", "Payment",
        "Principal", "Interest", "Balance");
      Console.WriteLine("{0,4}{1,10}{2,12}{3,10}{4,12}", "---", "-------",
        "---------", "--------", "-------");
      MorePmts = ln.GetFirstPmtDistribution(ln.Payment, out Balance,
        out Principal, out Interest);
       for (short PmtNbr = 1; MorePmts; PmtNbr++) {
         Console.WriteLine("{0,4}{1,10:0.00}{2,12:0.00}{3,10:0.00}
           {4,12:0.00}", PmtNbr, ln.Payment, Principal, Interest,
            Balance);
         MorePmts = ln.GetNextPmtDistribution(ln.Payment, ref Balance,
           out Principal, out Interest);
      }
    }
}