Sunteți pe pagina 1din 6

.

NET COM Interoperability


Using COM Components from .NET Framework

The .NET Framework exposes COM objects through a proxy called the runtime callable wrapper
(RCW). The primary function of RCW is to marshal call between a managed client (.Net) and
unmanaged COM object. The runtime maintains a single RCW for each COM object. The primary
goal of this article is to create a demo project to show how to call a COM component from .NET
client and to implement events raised by the COM component. The example uses a COM
component and .NET client extending the functionality of the COM component using delegation.

Step 1
Let’s start by creating a COM component (DotNetInterOp.dll) in VB. The Component consists of a
single class “CEmp”, that have some properties (FirstName, LastName, DOB) and raises an event
(Senior). After Creating DotNetInterOp.dll register it using regsvr32 from the command line

regsvr32 C:\testbeds\DptNetInterOP\DotNetInterOp.dll

CEmp Class of DotNetInterOp component


Option Explicit
Public Event Senior()
Private mstrFirstName As String
Private mstrLastName As String
Private mdtDOB As Date
Public Property Get FirstName() As String
FirstName = mstrFirstName
End Property
Public Property Let FirstName(xstrFirstName As String)
mstrFirstName = xstrFirstName
End Property
Public Property Get LastName() As String
LastName = mstrLastName
End Property
Public Property Let LastName(xstrLastName As String)
mstrLastName = xstrLastName
End Property
Public Property Get DOB() As Date
DOB = mdtDOB
End Property
Public Property Let DOB(xdtDOB As Date)
mdtDOB = xdtDOB
If DateDiff("YYYY", mdtDOB, Now) > 60 Then
RaiseEvent Senior
End If
End Property

Step 2
To use this COM component in .NET, the TypeLib of the component should be imported into an
Assembly containing the metadata so that managed clients can create instances of the COM type
and call its methods, just as if it were a .NET instance. There are four ways to create an interop
assembly

To add a reference to a type library using Visual Studio.Net. Open a .NET project in Visual
Studio.Net and add a reference to the COM component using the add reference dialog box. This
would automatically create an interop assembly containing the metadata.

Type Library Importer


Use Type Library Importer (TlbImp.exe). TlbImp.exe is a command-line tool that converts COM
type library to assembly containing metadata.
TypeLibConverter Class
The TypeLibConverter Class of the System.Runtime.InteropServices namespace provides methods
to convert a type library to an assembly. This API can convert in-memory Type library and
produces output as TlbImp.exe

Custom Wrappers
You can create a duplicate definition of the class or interface in managed source code. You then
compile the source code with a compiler that targets the runtime to produce metadata in an
assembly. To define COM types manually, you must know the precise descriptions of the coclasses
and interfaces being defined and knowledge of the type library-to-assembly conversion rules.
Writing a custom wrapper is an advanced technique that you seldom perform.

In our example we will use the TlbImp.exe to create metadata from the coclasses and interfaces
definitions in our DotNetInterOp.dll Type library. From the command line

tlbimp C:\testbeds\DptNetInterOP\DotNetInterOp.dll
/out:C:\DOTNet\TestBeds\VB\RCW\RCW\DotNetInterOp.dll

Step 3
Use the COM component, as it was a .NET component; add reference to the assembly created in
the previous step and code against the assembly by creating CEmp object and delegation the calls
to this object.

The .NET Client has two classes CEmp and CEmps, CEmp is a wrapper over our COM component’s
CEmp and exposes FirstName, LastName and IsSenior properties. The FirstName, LastName
properties just delegates to the Properties of COM’s CEmp but IsSenior uses the event raised by
the COM component to set its value. The CEmps class is a collection of CEmps and exposes
methods to test our code.

VB.Net Client of the COM Component


Imports Microsoft.VisualBasic
Imports DotNetInterOp
Public Class CEmp
Private mobjEmp As DotNetInterOP.CEmp
Private mblnIsSenior As Boolean
Sub New(ByVal xstrFName As String, ByVal xstrLName As String, ByVal xdtDOB As Date)
mobjEmp = New DotNetInterOp.CEmp()
AddHandler mobjEmp.Senior, New DotNetInterOp.__CEmp_SeniorEventHandler(AddressOf Senior)
With mobjEmp
.FirstName = xstrFName
.LastName = xstrLName
.DOB = xdtDOB
End With
End Sub
Public ReadOnly Property FirstName()
Get
Return mobjEmp.FirstName
End Get
End Property
Public ReadOnly Property LastName()
Get
Return mobjEmp.LastName
End Get
End Property
Public ReadOnly Property IsSenior()
Get
IsSenior = mblnIsSenior
End Get
End Property
Private Sub Senior()
mblnIsSenior = True
End Sub
End Class

Using a .NET Component from COM


When a COM client calls a .NET object, the .NET framework will create a COM callable wrapper
(CCW). COM clients use the CCW as a proxy for the managed object. Their primary purpose of
CCW is to marshal calls between managed and unmanaged code and also to manage the object
identity and object lifetime of the managed objects they wrap. The primary goal of this article is
to create a demo project to show how to call a .NET component from COM client and to
implement events raised by the .NET component.
The example uses a .NET component and COM client extending the functionality of the .NET
component using delegation. This is a follow on article and we will be using the same demo
project the only difference would be the client now is COM using .NET component.

Step 1
Let’s start by creating a Strong Name for the .NET component we would be creating in next steps.
Strong name is a unique name created by hashing a 128-bit encryption key against the name of
the Assembly (ComInterOp in our case). The strong name is created using SN.exe, that would
create ComInterOp.snk file, which we would use while creating the .NET Assembly.
The command line instruction to create a strong name
sn –k ComInterOp.snk

Step 2
Now lets create a .NET Assembly. Our assembly has only one class CEmp that exposes properties
(FirstName, LastName, DOB) and raises an event (Senior). Raising an event from .NET
Component and consuming it in COM component is done by defining event sink interface in
managed code and then apply the ComSourceInterfacesAttribute to connect the event sink
interface to the managed class.

The command line instruction to create an assembly using the strong name (for vbc switch info
see MSDN) vbc /out:ComInterOp.dll /t:library /keyfile:ComInterOp.snk CEmp.vb

VB.Net CEmp class code


Imports System
Imports Microsoft.VisualBasic
Imports System.Runtime.InteropServices
<InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)> _
Public Interface evtSenior
Sub Senior()
End Interface
<ComSourceInterfacesAttribute("evtSenior")> _
Public Class CEmp
Private mstrFirstName As String
Private mstrLastName As String
Private mdtDOB As Date
Public Event Senior()
Public Property FirstName() As String
Get
FirstName = mstrFirstName
End Get
Set(ByVal Value As String)
mstrFirstName = Value
End Set
End Property
Public Property LastName() As String
Get
LastName = mstrLastName
End Get
Set(ByVal Value As String)
mstrLastName = Value
End Set
End Property
Public Property DOB() As Date
Get
DOB = mdtDOB
End Get
Set(ByVal Value As Date)
mdtDOB = Value
If DateDiff(DateInterval.Year, Value, Now) > 60 Then
RaiseEvent Senior()
End If
End Set
End Property
End Class

Step 3
Once the assembly is created we have to create a Type library so the COM client can use the
Assembly seamlessly. We can package an assembly for COM by following methods.

Type Library Exporter


Using the Type Library Exporter (Tlbexp.exe) the classes and interfaces contained in an assembly
are converted into to a COM type library. Once the TypeLib is created COM clients can create an
instance of the .NET class and call the methods of that object, just as if it were a COM object.

TypeLibConverter Class
The TypeLibConverter Class of the System.Runtime.InteropServices namespace provides methods
to convert an assembly to a TypeLib. This API produces same output as Tlbexp.exe

Assembly Registration Tool


The Assembly Registration Tool (Regasm.exe), reads the metadata within an assembly and adds
the necessary entries to the registry, which allows COM clients to create .NET Framework classes
transparently. The Assembly Registration tool can generate and register a type library when you
apply the /tlb: option. COM clients require that type libraries be installed in the Windows registry.
Without this option, Regasm.exe only registers the types in an assembly, not the type library.
Registering the types in an assembly and registering the type library are distinct activities.

The .NET Services Installation Tool (Regsvcs.exe) (see MSDN for more info).

In our example we will use the RegAsm.exe to create TypeLib from the classes and interfaces
definitions in our ComInterOp.dll assembly. The command line instruction to create and register
ComINterOp.tlb is
regasm ComInterOp.dll /tlb:ComInterOp.tlb

Step 4
Now the .NET component (ComInterOp.dll) should be installs in the GAC(global assembly cache)
to work with the COM code. The command line instruction to install ComINterOp.dll in GAC is
Gacutil -i ComInterOp.dll

Step 5
To use the .NET component, as it was a COM component, add reference to the TypeLib from the
COM component project created in the previous steps and code against it by creating CEmp
object and delegation the calls to this object.

The COM Client has two classes CEmp and CEmps, CEmp is a wrapper over our .NET component’s
CEmp and exposes FirstName, LastName and IsSenior properties. The FirstName, LastName
properties just delegates to the properties of .NET CEmp but IsSenior uses the event raised by
the .NET component to set its value. The CEmps class is a collection of CEmps and exposes
methods to test our code.

COM Component
'Class Emps
Option Explicit
Private Emps As Scripting.Dictionary
Private Sub Class_Initialize()
Set Emps = New Scripting.Dictionary
Dim objEmp As CEmp
Set objEmp = New CEmp
objEmp.InitMe "John", "Doe", "01/01/1970"
Emps.Add 0, objEmp
Set objEmp = New CEmp
objEmp.InitMe "Mike", "Edwards", "01/01/1941"
Emps.Add 1, objEmp
Set objEmp = New CEmp
objEmp.InitMe "Debra", "Bunn", "01/01/1930"
Emps.Add 2, objEmp
End Sub
Public Function PrintEmps() As String
PrintEmps = PrintBool(True) & PrintBool(False)
End Function
Public Function PrintBool(ByVal xblnSeniors As Boolean) As String
Dim intCount As Integer
Dim objEmp As CEmp
Dim strPrint As String
For intCount = 0 To Emps.Count - 1
Set objEmp = Emps(intCount)
If xblnSeniors = objEmp.IsSenior Then
strPrint = strPrint & PrintEmp(objEmp) & Chr(13)
End If
Next intCount
PrintBool = strPrint
End Function
Private Function PrintEmp(ByVal xobjEmp As CEmp) As String
Dim strPrint As String
strPrint = xobjEmp.FirstName & Chr(9) & xobjEmp.LastName
PrintEmp = strPrint
End Function
'End Class Emps
'Class Emp
Option Explicit
Private mblnIsSenior As Boolean
Private WithEvents mobjEmp As ComInterOp.CEmp
Public Sub InitMe(ByVal xstrFName As String, ByVal xstrLName As String, ByVal xdtDOB As Date)
Set mobjEmp = New ComInterOp.CEmp
With mobjEmp
.FirstName = xstrFName
.LastName = xstrLName
.DOB = xdtDOB
End With
End Sub
Public Property Get FirstName() As String
FirstName = mobjEmp.FirstName
End Property
Public Property Get LastName() As String
LastName = mobjEmp.LastName
End Property
Public Property Get IsSenior() As Boolean
IsSenior = mblnIsSenior
End Property
Private Sub mobjEmp_Senior()
mblnIsSenior = True
End Sub
'End Class Emp

S-ar putea să vă placă și