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 the following Visual Basic 2005 code fragment.
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)
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.
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 becomesIButtonEvents_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
// 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.
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
// Direct import of original default interface. public interface IButton { void Init(); }
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
// Direct import of original event interface. // Not of interest to managed sinks. public interface IButtonEvents { void Click(int x, int y); int Resize(); }
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
andResize
events as members. It also hasadd
andremove
methods for the event delegates. In this example, the interface is calledIButtonEvents_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 ); }
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
, notIButtonEvents
.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 becomesButtonClass
. 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
// 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
Concepts
Imported Library Conversion
Imported Module Conversion
Imported Type Conversion
Imported Parameter Conversion