如何:手动创建包装
更新: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 );
}
}