Share via


Imported Member Conversion

This topic describes how the import process converts the following members:

  • Methods
  • Properties
  • Events

Tlbimp.exe applies the DefaultMemberAttribute to any method or property with a DispID of 0. Note that C# developers must treat these members as arrays. For additional information, see your programming language documentation.

Methods

When COM interop imports a COM type, it produces a .NET Framework method signature equivalent to the original COM method signature. During the conversion process, it maps COM parameters, return values, and HRESULTs to those in a .NET Framework method signature, as shown in the following illustration.

Method signature conversion

You can examine method syntax with an object viewer or by using reflection, just as with any other .NET class. By default, when the COM object returns a failure HRESULT, the runtime throws a corresponding exception.

Properties

A COM developer can declare properties and methods on interfaces. All properties have corresponding accessor methods for setting or getting the property values. When the import process converts a type library description of an interface with properties to metadata, it creates a property and one or more accessor methods for that property.

The type library conversion process transforms property accessor methods in the following ways:

  • Properties with the [propget] attribute become managed properties of the same type, with a corresponding method called get_propertyname.
  • Properties with either the [propput] attribute or [propputref] attribute become managed properties of the same type, with a corresponding method called set_propertyname.
  • Properties with both the [propput] and [propputref] attributes become:
    • Managed properties of the same type as the [propputref] attribute, with a corresponding method called set_propertyname
    • Another accessor method with the same type as the [propput] attribute, having the name let_propertyname.

The following type library shows the original properties.

Type library representation

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);
}

The converted properties appear in C++ and Visual Basic .NET code fragments.

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)
[C++]interface ISample {
    __property short get_prop1();    // propget, propset
    __property void set_prop1(short s); // propget, propset
    __property INew *get_prop2();    // propget, propset
    __property void set_prop2 (INew*p);    // propget, propset
    __property INew *get_prop3 ();      // propget, propputref
    __property void set_prop3 (INew *p);   // propget, propputref
      Let_prop3(String text);         // propput 
};

Events

A COM type library can define interfaces used for events. Within the library, a coclass that sources events can identify the event interface by specifying the [source] attribute. An event sink implements the interface and an event source consumes it. The COM connection-point interfaces, which are not described in the type library, connect the event sink to the event source.

In the following IDL code example, the Button class implements the IButton interface and sources the events on the IButtonEvents interface.

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;
}

The .NET event model differs considerably from the COM connection-point model. Managed classes that sink events do so by passing a delegate to the event source, instead of using COM connection points. The COM interop service bridges these two different event models.

During import, Tlbimp.exe creates several types that enable a managed application to sink events that are sourced by unmanaged classes using the .NET event model. In the following sequence of steps, Tlbimp.exe generates classes and interfaces for the Button class shown in the previous example.

  1. The import process creates a delegate type for each event in the event interface. Delegate names consist of the event sink interface, an underscore, the event name, and the word EventHandler. For example, in the type library in the previous example, the Click event becomes IButtonEvents_ClickEventHandler delegate.

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

    Notice that the signature of the delegate is a direct translation of the unmanaged method signature.

  2. Tlbimp.exe imports the default interface the usual way, keeping the interface name the same. In this example, the interface is called IButton.

    ' Direct import of original default interface.
    Public Interface IButton
        Sub Init()
    End Interface
    [C#]// Direct import of original default interface. 
    public interface IButton {
        void Init();
    }
    
  3. Tlbimp.exe imports the event interface the usual way, keeping the interface name the same. In this example, the interface is called 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
    [C#]// 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 also creates a second event interface, designated by the "_Event" suffix added to the name of the original interface. This second event interface has Click and Resize events as members. It also has add and remove methods for the event delegates. In this example, the interface is called 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
    [C#]// 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 );
    }
    

    Note   In the rare case that you need to cast to the event interface, you cast to the interface produced by Tlbimp.exe instead of the original interface. For example, you must cast to IButtonEvents_Event, not IButtonEvents.

  5. Tlbimp.exe imports the coclass that sources events to ensure the inclusion of all explicitly implemented interfaces, and it appends the original class name with Class. For example, the Button coclass becomes ButtonClass. Tlbimp.exe also produces a coclass interface with the same name as the coclass, which implements the event interface with the _Event suffix.

    ' 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
    [C#]// 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(){}
    }
    

See Also

Type Library to Assembly Conversion Summary | Imported Library Conversion | Imported Module Conversion | Imported Type Conversion | Imported Parameter Conversion