更新:2007 年 11 月
如果决定在托管源代码中手动声明 COM 类型,最好从现有的接口定义语言 (IDL) 文件或类型库开始。如果没有 IDL 文件或无法生成类型库文件,可以通过创建托管声明并将生成的程序集导出到类型库来模拟该 COM 类型。
在托管源中模拟 COM 类型
- 使用符合公共语言规范 (CLS) 的语言声明类型并编译文件。 
- 使用类型库导出程序 (Tlbexp.exe) 导出包含这些类型的程序集。 
- 将导出的 COM 类型库用作声明面向 COM 的托管类型的基础。 
创建运行库可调用包装 (RCW)
- 假定已有 IDL 文件或类型库文件,决定要将哪些类和接口包含在自定义 RCW 中。可以排除不想在应用程序中直接或间接使用的任何类型。 
- 使用符合 CLS 的语言创建源文件并声明类型。有关导入转换过程的完整说明,请参见有关从类型库转换到程序集的摘要。在创建自定义 RCW 时,您便正在以手动方式有效地执行类型库导入程序 (Tlbimp.exe) 所提供的类型转换活动。此过程后面的示例显示 IDL 或类型库文件中的类型以及它们在 C# 代码中的对应类型。 
- 当声明完成时,像编译任何其他托管源代码一样对该文件进行编译。 
- 与用 Tlbimp.exe 导入的类型一样,有些类型需要附加信息,可以将这些信息直接添加到代码中。有关详细信息,请参见如何:编辑 Interop 程序集。 
示例
下面的代码显示 IDL 中 ISATest 接口和 SATest 类的示例以及 C# 源代码中的对应类型。
IDL 或类型库文件
 [
object,
uuid(40A8C65D-2448-447A-B786-64682CBEF133),
dual,
helpstring("ISATest Interface"),
pointer_default(unique)
 ]
interface ISATest : IDispatch
 {
[id(1), helpstring("method InSArray")] 
HRESULT InSArray([in] SAFEARRAY(int) *ppsa, [out,retval] int *pSum);
 };
 [
uuid(116CCA1E-7E39-4515-9849-90790DA6431E),
helpstring("SATest Class")
 ]
coclass SATest
 {
  [default] interface ISATest;
 };
托管源代码中的包装
using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
 
[assembly:Guid("E4A992B8-6F5C-442C-96E7-C4778924C753")]
[assembly:ImportedFromTypeLib("SAServerLib")]
namespace SAServer
{
 [ComImport]
 [Guid("40A8C65D-2448-447A-B786-64682CBEF133")]
 [TypeLibType(TypeLibTypeFlags.FLicensed)]
 public interface ISATest
 {
  [DispId(1)]
  //[MethodImpl(MethodImplOptions.InternalCall,
  // MethodCodeType=MethodCodeType.Runtime)]
  int InSArray( [MarshalAs(UnmanagedType.SafeArray,
      SafeArraySubType=VarEnum.VT_I4)] ref int[] param );
 } 
 [ComImport]
 [Guid("116CCA1E-7E39-4515-9849-90790DA6431E")]
 [ClassInterface(ClassInterfaceType.None)] 
 [TypeLibType(TypeLibTypeFlags.FCanCreate)]
 public class SATest : ISATest 
 {
  [DispId(1)]
  [MethodImpl(MethodImplOptions.InternalCall, 
  MethodCodeType=MethodCodeType.Runtime)]
  extern int ISATest.InSArray( [MarshalAs(UnmanagedType.SafeArray, 
  SafeArraySubType=VarEnum.VT_I4)] ref int[] param );
 }
}