导入成员转换

本主题描述导入过程如何转换以下成员:

  • 方法

  • 属性

  • 事件

Tlbimp.exe 将 DefaultMemberAttribute 应用于任何 DispID 为 0 的方法或属性。 请注意,C# 开发人员必须将这些成员当作数组来处理。 有关其他信息,请参见编程语言文档。

方法

当 COM 互操作导入 COM 类型时,它将生成等效于原 COM 方法签名的 .NET Framework 方法签名。 在转换过程中,它会将 COM 中的参数、返回值和 HRESULT 映射到 .NET Framework 方法签名中的相应对象,如下图所示。

方法签名转换

方法签名转换

您可以通过对象查看器或反射来检查方法语法,就像处理其他任何 .NET 类一样。 默认情况下,当 COM 对象返回失败的 HRESULT 时,运行时将引发相应的异常。

属性

COM 开发人员可以在接口上声明属性和方法。 所有属性都具有相应的访问器方法,用于设置或获取属性值。 当导入过程利用属性将接口的类型库说明转换为元数据时,它将创建一个属性并为属性创建一个或多个访问器方法。

类型库转换过程将按以下方式转换属性访问器方法:

  • 具有 [propget] 特性的属性将成为相同类型的托管属性,它带有名为 get_propertyname 的相应方法。

  • 带有 [propput] 特性或 [propputref] 特性的属性将成为相同类型的托管属性,它带有名为 set_propertyname 的相应方法。

  • 同时带有 [propput][propputref] 特性的属性将成为:

    • [propputref] 特性具有相同类型的托管属性,它带有名为 set_propertyname 的相应方法。

    • 另一个与 [propput] 特性具有相同类型的访问器方法,它具有名称 let_propertyname

以下类型库将显示最初的属性。

k639e386.collapse_all(zh-cn,VS.110).gif类型库表示形式

interface ISample : IDispatch {
    [propget]    HRESULT prop1([out, retval] short *pVal);
    [propput]    HRESULT prop1([in] short newVal);

    [propget]    HRESULT prop2([out, retval] INew **pVal);
    [propputref] HRESULT prop2([in] INew *newVal);

    [propget]    HRESULT prop3([out, retval] INew **ppINew);
    [propput]    HRESULT prop3([in] BSTR text);
    [propputref] HRESULT prop3([in] INew *pINew);
}

转换后的属性显示在以下 Visual Basic 2005 代码段中。

Public Property 
    Get Prop1() As Integer … End Get    
    Set Prop1(val as Integer) … End Set
End Property

Public Property 
    Get Prop2() As INew … End Get 
    Set Prop2(val as INew) … End Set
End Property

Public Property
    Get Prop3() As INew … End Get 
    Set Prop3(val as INew) … End Set 
End Property

Public let_prop3(String as Text)

事件

COM 类型库可以定义用于事件的接口。 在该库中,指明事件出处的 coclass 可以通过指定 [source] 特性来标识事件接口。 事件接收器会实现接口,而事件源则使用接口。 未在类型库中描述的 COM 连接点接口会将事件接收器连接到事件源。

在以下 IDL 代码示例中,Button 类实现 IButton 接口,并指明 IButtonEvents 接口上事件的出处。

interface IButton {
    HRESULT Init();
}

interface IButtonEvents {
    HRESULT Click([in] int x, [in] int y);
    HRESULT Resize([out, retval] int *pRetval};
}

coclass Button {
    [default] interface IButton;
    [default, source] interface IButtonEvents;
}

.NET 事件模型与 COM 连接点模型之间存在很大的差异。 接收事件的托管类是通过将委托传递给事件源(而不是使用 COM 连接点)来完成类似任务的。 COM 互操作服务消除了这两种不同的事件模型之间的差异。

在导入过程中,Tlbimp.exe 将创建几个类型,使托管应用程序能够接收由使用 .NET 事件模型的非托管类指明其出处的事件。 在以下步骤中,Tlbimp.exe 将为上例所示的 Button 类生成类和接口。

  1. 导入进程为事件接口中的每一事件创建一个委托类型。 委托名称由事件接收接口、下划线、事件名称和 EventHandler 一词组成。 例如,在上例的类型库中,Click 事件将变成 IButtonEvents_ClickEventHandler 委托。

    ' A delegate for each event.
    Delegate Sub IButtonEvents_ClickEventHandler(ByVal x As Integer, _
             ByVal y As Integer)
    Delegate Function IButtonEvents_ResizeEventHandler() As Integer
    
    // A delegate for each event.
    delegate void IButtonEvents_ClickEventHandler(int x, int y);
    delegate int IButtonEvents_ResizeEventHandler();
    

    请注意,委托的签名由非托管方法签名直接转换而来。

  2. Tlbimp.exe 以常规方式导入默认接口,并使接口名称保持不变。 在此示例中,接口名为 IButton。

    ' Direct import of original default interface.
    Public Interface IButton
        Sub Init()
    End Interface
    
    // Direct import of original default interface. 
    public interface IButton {
        void Init();
    }
    
  3. Tlbimp.exe 以常规方式导入事件接口,并使接口名称保持不变。 在此示例中,接口名为 IButtonEvent。

    ' Direct import of original event interface. 
    ' Not of interest to managed sinks.
    Public Interface IButtonEvents
        Sub Click(ByVal x As Integer, ByVal y As Integer)
        Function Resize() As Integer
    End Interface
    
    // Direct import of original event interface.
    // Not of interest to managed sinks.
    public interface IButtonEvents {
        void Click(int x, int y);
        int Resize();
    }
    
  4. Tlbimp.exe 还会创建另一个事件接口,该接口通过在原接口名称上添加“_Event”后缀来标明。 第二个事件接口具有 Click 和 Resize 成员事件。 它还具有 add 和 remove 方法,用于事件委托。 在此示例中,接口名为 IButtonEvents_Event。

    ' Modified version of the event interface with events
    ' for managed sinks.
    
    Public Interface IButtonEvents_Event
            Sub Click As IButtonEvents_Click
            Function Resize() As IButtonEvents_Resize
            Sub add_Click(ByVal Click As IButtonEvents_ClickEventHandler)
            Sub remove_Click(ByVal Click As _
                   IButtonEvents_ClickEventHandler)
            Sub add_Resize(ByVal Resize As _
                   IButtonEvents_ResizeEventHandler)
            Sub remove_Resize(ByVal Resize As _
                   IButtonEvents_ResizeEventHandler)
        End Interface
    // Modified version of the event interface with events 
    // for managed sinks.
    public interface IButtonEvents_Event {
       IButtonEvents_Click Click;
       IButtonEvents_Resize Resize;
       void add_Click(IButtonEvents_ClickEventHandler );
       void remove_Click(IButtonEvents_ClickEventHandler );
       void add_Resize(IButtonEvents_ResizeEventHandler );
       void remove_Resize(IButtonEvents_ResizeEventHandler );
    }
    

    备注

    在需要强制转换成事件接口的少数情况下,要强制转换成的是 Tlbimp.exe 所生成的接口,而不是原接口。例如,必须强制转换成 IButtonEvents_Event,而不是 IButtonEvents。

  5. Tlbimp.exe 导入指明事件出处的 coclass 以确保包括所有显式实现的接口,并在原类名后加上 Class。 例如,Button coclass 会成为 ButtonClass。 Tlbimp.exe 还会生成一个名称与该 coclass 相同的 coclass 接口。该接口实现带有 _Event 后缀的事件接口。

    ' This is the imported coclass interface.
    ' Note the underscore in IButtonEvents_Event.
        Public Interface Button
            Inherits IButton
            Inherits IButtonEvents_Event
        End Interface
    
        Public Class ButtonClass
            Implements Button
            Implements IButton
            Implements IButtonEvents_Event
            Sub Init()
            End Sub 'Init
        End Class
    
    // This is the imported coclass interface.
    // Note the underscore in IButtonEvents_Event.
    public interface Button:IButton, IButtonEvents_Event {} 
    
    public class ButtonClass:Button,IButton,IButtonEvents_Event 
    {
    void Init(){}
    }
    

请参见

概念

导入库转换

导入模块转换

导入类型转换

导入参数转换

其他资源

有关从类型库转换到程序集的摘要