The Interop Type Library is statically linked with the unmanaged code so that this code can communicate with the CCW about the .NET component included in your application.. In order for
Trang 1file for a second time Using this method meant that when you upgraded a component, you automatically
upgraded all the utilizing applications However, this practice didn’t work out so well In fact, it became
a very big contributor to DLL hell and the main reason why Microsoft began promoting the practice of
installing private NET component assemblies.
After you have your components physically in place, the only remaining task is to register the ActiveX
component using regsvr32, just as you would when deploying an ActiveX-enabled application
Public Assemblies
The opposite of a private assembly is a public assembly Public assemblies share the RCW Interop DLL
for other applications In order to create a public assembly, you must put the RCW file into the Global
Assembly Cache (GAC), as shown in Figure 28-11.
MyApp.exe C:\Program Files\First Application Location\
YourApp.exe C:\Program Files\Second Application Location\
Interop.MyCOM.dll Global Assembly Cache (GAC)
MyCOM.dll
C:\Program Files\Third Party COM Controls\
(Managed Code)
(ActiveX DLL)
Figure 28-11
You can find the GAC atC:\Windows\assembly Installing items in the GAC can be as simple as dragging-and-dropping the item into this folder through Windows Explorer Although the GAC is open to every-one, it is not recommended that you blindly install your components into this section unless you have a very good reason to do so
You can also add items to the GAC from the command line using the Global Assembly Cache Tool (Gacu-til.exe) It enables you to view and manipulate the contents of the global assembly cache and download cache While the Explorer view of the GAC provides similar functionality, you can use Gacutil.exe from build scripts, makefile files, and batch files
It is hard to find a very good reason to install your ActiveX Interop Assemblies into the GAC If we had
to pick a time to do this, it would be if and when we had a highly shared ActiveX component that many NET applications would be utilizing on the same machine In a corporate environment, this might occur when you are upgrading existing business logic from ActiveX to NET enablement on a server that many applications use In a commercial setting, we avoid using the GAC
Trang 2Using NET from Unmanaged Code
.NET provides the opposite of COM interoperability by enabling you to use your newly created NET
components within unmanaged code This section discusses using NET components with Visual Basic
6 executables The techniques shown in this section are identical when you are using ActiveX OCXs or
DLLs instead of executables
The COM-Callable Wrapper (CCW) is the piece of the NET Framework that enables unmanaged code
to communicate with your NET component The CCW, unlike the RCW, is not a separate DLL that you
distribute with your application Instead, the CCW is part of the NET Framework that gets instantiated
once for each NET component that you are using
Figure 28-12 shows how the CCW marshals the communication between the unmanaged code and the
.NET component in much the same way that the RCW marshals the code between managed code and
COM code
Your ActiveX Code
.NETs Built-In Interoperability Technology
Your NET Component Code
Managed Code Unmanaged Code
COM Code
COM-Callable Wrapper (CCW)
.NET Component
Figure 28-12
The COM-Callable Wrapper
The COM-Callable Wrapper or CCW, as previously stated, is not a separate DLL like the RCW Instead,
the CCW uses a specially created type library based on the NET component This type library is called
an Interop Type Library The Interop Type Library is statically linked with the unmanaged code so that
this code can communicate with the CCW about the NET component included in your application
In order for a NET component to generate an Interop Type Library, you tell Visual Studio 2008 to
gen-erate it when the component is built Both Visual Basic and C# projects have a setting in the Compile
properties section of the Class Library project’s Property Pages dialog
Right-click the project in the Solution Explorer and choose Properties to see the project’s properties
Figure 28-13 shows the project’s properties for a Visual Basic 2008 Class Library application This is
shown directly in the Visual Studio document window
Trang 3Figure 28-13
C# has a slightly different dialog, as shown in Figure 28-14 In both dialogs, the property is called Register for COM Interop In Visual Basic, you can find this property on the Compile page; in C#, you can find it
on the Build tab of the properties pages
After you set this option by checking the check box, when you build the project a separate type library
file (.tlb) is generated for the DLL that you are building This.tlbfile is your key to including NET
components in COM applications
Normally in Visual Basic, when you add a reference to a DLL, you navigate from the References section
of the Visual Basic project to find the ActiveX DLL that you want to add If you use NET components,
they cannot be properly referenced in this manner because they are not ActiveX Instead, you reference the Interop Type Library, which makes the functionality of the corresponding NET component available
to your application
The NET Framework also gives you a method to create Interop Type Library files manually for NET
components You do this through a command-line tool called the Type Library Exporter (as compared
to the Type Library Importer used for COM Interoperability) The Type Library Exporter is invoked
using thetlbexp.exeexecutable
Trang 4Figure 28-14
For example, to create the Interop Type Library for theNameComponent.dllin the next example, you use
the following command:
tlbexp NameComponent.dll /out:NameComponentEx.tlb
The/out:parameter specifies the name of the Interop Type Library that is to be created If you omit this
parameter, you get a file with the same name as the ActiveX component, but with a.tlbextension
The Type Library Exporter is useful when you are not using Visual Studio 2008 as your development
environment, if you want to have more control over the assemblies that get created for you, or if you are
automating the process of connecting to NET components
Using NET Components Within COM Objects
The next example illustrates how NET components can be utilized within COM code To begin, create
and compile the NET code found in Listing 28-5 in either Visual Basic or C#
After you have typed your code into your Class Library project, build the component and call it
Name-Component Remember to choose to include the Register for the COM Interop setting of True (by checking
the appropriate check box) from the project properties pages, as shown in Figure 28-13 for Visual Basic
code and Figure 28-14 for C# code If you aren’t using Visual Studio 2008, you can usetblexp.exeto
generate the Interop Type Library manually as described previously
Trang 5Listing 28-5: The NET component
VB
Public Class NameFunctions
Private m_FirstName As String
Private m_LastName As String
Public Property FirstName() As String
Get
Return m_FirstName
End Get
Set(ByVal Value As String)
m_FirstName = Value
End Set
End Property
Public Property LastName() As String
Get
Return m_LastName
End Get
Set(ByVal Value As String)
m_LastName = Value
End Set
End Property
Public Property FullName() As String
Get
Return m_FirstName + " " + m_LastName
End Get
Set(ByVal Value As String)
m_FirstName = Split(Value, " ")(0)
m_LastName = Split(Value, " ")(1)
End Set
End Property
Public ReadOnly Property FullNameLength() As Long
Get
FullNameLength = Len(Me.FullName)
End Get
End Property
End Class
C#
using System;
using System.Runtime.InteropServices;
namespace NameComponent
Continued
Trang 6[ComVisible(true)]
public class NameFunctions
{
private string m_FirstName;
private string m_LastName;
public string FirstName
{
get
{
return m_FirstName;
}
set
{
m_FirstName=value;
}
}
public string LastName
{
get
{
return m_LastName;
}
set
{
m_LastName=value;
}
}
public string FullName
{
get
{
return m_FirstName + " " + m_LastName;
}
set
{
m_FirstName=value.Split(’ ’)[0];
m_LastName=value.Split(’ ’)[1];
}
}
public long FullNameLength
{
get
{
return this.FullName.Length;
}
}
}
}
Trang 7After you have created the NET component, you can then create the consuming Visual Basic 6 code
shown in Listing 28-6
Listing 28-6: VB6 code using the NET component
Option Explicit
Public Sub Main()
Dim o As NameComponent.NameFunctions
Set o = New NameComponent.NameFunctions
o.FirstName = "Bill"
o.LastName = "Evjen"
MsgBox "Full Name is: " + o.FullName
MsgBox "Length of Full Name is: " + CStr(o.FullNameLength)
o.FullName = "Scott Hanselman"
MsgBox "First Name is: " + o.FirstName
MsgBox "Last Name is: " + o.LastName
o.LastName = "Evjen"
MsgBox "Full Name is: " + o.FullName
Set o = Nothing
End Sub
Remember to add a reference to the NET component You choose Project ➪ References and select the
.NET component that was created either by Visual Studio or by manually usingtlbexp.exe
When you run the code in Listing 28-6, you see that Visual Basic 6 does not miss a beat when communi-cating with the NET component
It is also possible to register the assemblies yourself Earlier you learned how to manually create Interop Type Libraries with the Type Library Exporter This tool does not register the assemblies created but
instead generates only the type library
To register the assemblies yourself, you use the Assembly Registration Tool (regasm.exe) This tool is
similar theregsvr32.exefor NET components
To useregasm.exe, use a command syntax similar to the following example:
regasm NameComponent.dll /tlb:NameComponentEx.tlb /regfile:NameComponent.reg
The/tlb:option specifies the name of the type library, and the/regfile:option specifies the name of
a registry file to be created that can be used later in an installation and deployment application
Trang 8Early versus Late Binding
The preceding example illustrates the use of early binding, the technique most Visual Basic 6 developers
are used to However, in some cases, it is desirable to use late binding Performing late binding with NET
components is similar to performing late binding with ActiveX components, as shown in Listing 28-7
Listing 28-7: Late binding with VB6
Option Explicit
Public Sub Main()
Dim o As Object
Set o = CreateObject("NameComponent.NameFunctions")
o.FirstName = "Bill"
o.LastName = "Evjen"
MsgBox "Full Name is: " + o.FullName
MsgBox "Length of Full Name is: " + CStr(o.FullNameLength)
o.FullName = "Scott Hanselman"
MsgBox "First Name is: " + o.FirstName
MsgBox "Last Name is: " + o.LastName
o.LastName = "Evjen"
MsgBox "Full Name is: " + o.FullName
Set o = Nothing
End Sub
Error Handling
Handling errors that are raised from NET components in Visual Basic 6 is easily accomplished via the
Interop functionality Listing 28-8 shows code for both Visual Basic and C# to throw exceptions for a
custom error When theNumeratoror theDenominatorparameters are greater than 1000 in theDivide
function, a custom exception is thrown up to the calling code, which is Visual Basic 6 in this example
Notice how the divide-by-zero error possibility is not handled in this example This is done intentionally
to demonstrate how interoperability handles unhandled errors
Listing 28-8: Raising errors
VB
Public Class CustomException
Inherits Exception
Trang 9Sub New(ByVal Message As String)
MyBase.New(Message)
End Sub
End Class
Public Class DivideFunction
Public Function Divide(ByVal Numerator As Double, _
ByVal Denominator As Double) As Double
If ((Numerator > 1000) Or (Denominator > 1000)) Then
Throw New CustomException("Numerator and denominator both " & _
"have to be less than or equal to 1000.") End If
Divide = Numerator / Denominator
End Function
End Class
C#
using System;
namespace DivideComponent
{
public class CustomException:Exception
{
public CustomException(string message):base(message)
{
}
}
public class DivideFunction
{
public double Divide(double Numerator, double Denominator)
{
if ((Numerator > 1000) || (Denominator > 1000))
throw new CustomException("Numerator and denominator " +
"both have to be less than or equal to 1000.");
return Numerator / Denominator;
}
}
}
Now that you have the code for the NET component, compile it with the Register for COM Interop flag set to True in the project’s Property Pages dialog and call the componentDivideComponent
The consuming Visual Basic 6 code is shown in Listing 28-9 Remember to add a reference to the Interop Type Library of theDivideComponentgenerated by Visual Studio
Trang 10Listing 28-9: VB6 experiencing NET errors
Option Explicit
Public Sub Main()
Dim o As DivideComponent.DivideFunction
Set o = New DivideComponent.DivideFunction
MsgBox "1 divided by 3: " + CStr(o.divide(1, 3))
MsgBox "1 divided by 0: " + CStr(o.divide(1, 0))
MsgBox "2000 divided by 3000: " + CStr(o.divide(2000, 3000))
Set o = Nothing
End Sub
The Visual Basic 6 code example in Listing 28-9 does not handle the errors thrown by the NET
compo-nent, but it can easily do so usingOn Error, Visual Basic 6’s method for trapping raised errors
Instead of trapping the errors, make sure that the Error Trapping setting in the Options dialog of Visual
Basic 6 is set to Break in Class Module
When the application is run, the first example of 1 divided by 3 works fine; you see the output properly
The second example, which you would expect to end in a divide-by-zero error, does not Instead, an
invalid property value is returned to Visual Basic 6 The final example, which does not pass the custom
error handling in the NET component, raises a Visual Basic error, as you would expect
Deploying NET Components with COM Applications
Deploying NET components with COM applications is similar to deploying COM components There
are two scenarios in this deployment scheme:
❑ Using private assemblies
❑ Using shared assemblies
The following sections discuss these two scenarios
Private Assemblies
Private assemblies mean the deployment of the NET component is installed in each individual directory
where the application is installed, within the same machine The only needed component is the NET DLL
and the calling application The Interop Type Library that you created earlier with Visual Studio 2008 or
tlbexp.exeis statically linked with the component or application that references the NET component
The only additional task you must complete is to properly register the NET assembly usingregasm.exe
This is an extra step that is not needed in 100 percent NET applications; it is required only for the