导入成员转换

更新:2007 年 11 月

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

  • 方法

  • 属性

  • 事件

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

方法

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

方法签名转换

方法签名转换

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

属性

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

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

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

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

  • 同时带有 [propput][propputref] 属性 (attribute) 的属性 (property) 将成为:

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

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

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

类型库表示形式

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(){}
    }
    

请参见

概念

导入库转换

导入模块转换

导入类型转换

导入参数转换

其他资源

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