Importing ActiveX controls turns out to be fairly straightforward. Many of the COM components that companies develop are not ActiveX controls, however; they are standard COM dynamic link library (DLL) files. To see how to use these with .NET, you return to VB6 and create a COM business object that will act exactly as the component from the previous section did.
The first step is to create a new ActiveX DLL project. This is how
VB6 creates standard COM DLLs. Name the class
ComCalc
and name the project
ComCalculator
. Save the file and project. Copy the
methods from Example 22-4 into the code window.
Example 22-4. Implementing the methods for ComCalc
Public Function _ Add(left As Double, right As Double) _ As Double Add = left + right End Function Public Function _ Subtract(left As Double, right As Double) _ As Double Subtract = left - right End Function Public Function _ Multiply(left As Double, right As Double) _ As Double Multiply = left * right End Function Public Function _ Divide(left As Double, right As Double) _ As Double Divide = left / right End Function
Build the DLL by using the menu sequence File → Make
ComCalculator.dll. You can test this by returning to your earlier
test program and removing the Calculator
control
from the form. Add the new DLL by opening the project reference
window and navigating to the ComCalculator
, as
shown in Figure 22-12.
The code to exercise the COM component is very similar to the earlier
example. This time, however, you instantiate a
ComCalc
object and call its methods, as shown in
Example 22-5.
Example 22-5. The driver program for ComCalc.dll
Private Sub btnAdd_Click( ) Dim theCalc As New ComCalc Label1.Caption = _ theCalc.Add(CDbl(Text1.Text), _ CDbl(Text2.Text)) End Sub Private Sub btnDivide_Click( ) Dim theCalc As New ComCalc Label1.Caption = _ theCalc.Divide(CDbl(Text1.Text), _ CDbl(Text2.Text)) End Sub Private Sub btnMultiply_Click( ) Dim theCalc As New ComCalc Label1.Caption = _ theCalc.Multiply(CDbl(Text1.Text), _ CDbl(Text2.Text)) End Sub Private Sub btnSubtract_Click( ) Dim theCalc As New ComCalc Label1.Caption = _ theCalc.Subtract(CDbl(Text1.Text), _ CDbl(Text2.Text)) End Sub
Now that you have a working
ComCalc
DLL, you can import it to .NET. Before you
can import it, however, you must choose between
early
and late binding
.
When the client calls a method on the server, the address of the
server’s method in memory must be resolved. That process is
called binding
.
With early binding
, the resolution of the
address of a method on the server occurs when the client project is
compiled and metadata is added to the client .NET module. With
late binding,
the resolution does not happen
until runtime, when COM explores the server to see if it supports the
method.
Early binding has many advantages. The most significant is performance. Early-bound methods are invoked far more quickly than late-bound methods. For the compiler to perform early binding, it must interrogate the server’s type library. For the compiler to interrogate the server’s type library it must first be imported into .NET.
The
VB6-created COM DLL has a type library within it, but the format of a
COM type library cannot be used by a .NET application. To solve this
problem, you must import the COM type library into an assembly. Once
again, you have two ways of doing this. You can allow the Integrated
Development Environment (IDE) to import the class by registering the
component, as shown in the following section, or you can import the
type library manually by using the standalone program
TlbImp.exe
.
TlbImp.exe
will produce a proxy assembly with a
manifest within it. This proxy assembly is called a Runtime
Class Wrapper
(RCW). The .NET client will use the
RCW to bind to the methods in the COM object, as shown in the
following section.
Start by copying the ComCalculator.DLL
file to
your .NET environment and registering it with
Regsvr32
. Then you’re ready to import the
COM object into .NET, by running TlbImp.exe
. The
syntax is to enter the name of the COM component, followed by an
optional name for the filename produced, as shown in Figure 22-13.
Now it’s time to create a driver program to test the COM
object, which you’ll name COMDllTest
.
If you decided not to import the library manually, you import it through the IDE. To do so, select the COM tab on the Add Reference dialog and select the registered COM object, as shown in Figure 22-14.
This will invoke TlbImp
for you and will copy
the resulting RCW to:
C:/Documents and Settings/Administrator/Application Data/Microsoft/VisualStudio/RCW
You’ll have to be careful, however, because the DLL it produces has the same name as the COM DLL.
If you do use TlbImp.exe
, you can add the
reference from the Projects tab. Browse to the directory where
ComCalculatorDLLNET.dll
was created, and add it
to the references.
In either case, you can now create the user interface, which is, again, similar to that used for testing the ActiveX control, as shown in Figure 22-15.
All that is left is to wire up the event handlers for the four buttons, as shown in Example 22-6.
Example 22-6. Implementing event handlers for the VB 6 COM DLL test form
private void btnAdd_Click( object sender, System.EventArgs e) { Double left, right, result; left = Double.Parse(textBox1.Text); right = Double.Parse(textBox2.Text);ComCalculator.ComCalc theCalc = new ComCalculator.ComCalc( );
result = theCalc.Add(ref left, ref right); label1.Text = result.ToString( ); } private void btnSubtract_Click( object sender, System.EventArgs e) { Double left, right, result; left = Double.Parse(textBox1.Text); right = Double.Parse(textBox2.Text);ComCalculator.ComCalc theCalc = new ComCalculator.ComCalc( );
result = theCalc.Subtract(ref left, ref right); label1.Text = result.ToString( ); } private void btnMultiply_Click( object sender, System.EventArgs e) { Double left, right, result; left = Double.Parse(textBox1.Text); right = Double.Parse(textBox2.Text);ComCalculator.ComCalc theCalc = new ComCalculator.ComCalc( );
result = theCalc.Multiply(ref left, ref right); label1.Text = result.ToString( ); } private void btnDivide_Click( object sender, System.EventArgs e) { Double left, right, result; left = Double.Parse(textBox1.Text); right = Double.Parse(textBox2.Text);ComCalculator.ComCalc theCalc = new ComCalculator.ComCalc( );
result = theCalc.Divide(ref left, ref right); label1.Text = result.ToString( ); }
Rather than referring to an ActiveX control that is on the form, you
must instantiate the ComCalculator.ComCalc
object.
The COM object is then available for use as if it had been created in
a .NET assembly, and the running program works as expected, as shown
in Figure 22-16.
If you do not have a type library file for your third-party COM object, you must use late binding with reflection. In Chapter 18, you saw how to invoke methods dynamically in .NET assemblies; the process with COM objects is not terribly different.
To see how to do this, start with the application shown in Example 22-6, but remove the reference to the imported
library. The four button handlers must now be rewritten. You can no
longer instantiate a ComCalculator.Calc
object, so
instead you must invoke its methods dynamically.
Just as you saw in Chapter 18, you begin by
creating a Type
object to hold information about
the ComCalc
type.
Type comCalcType; comCalcType = Type.GetTypeFromProgID("ComCalcDLL.ComCalc");
The call to GetTypeFromProgID
instructs the .NET
Framework to open the registered COM DLL and retrieve the necessary
type information for the specified object. This is the equivalent to
calling GetType
, as you did in Chapter 18:
Type theMathType = Type.GetType("System.Math");
You can now proceed exactly as you would if you were invoking this
method on a class described in a .NET assembly. You start by calling
CreateInstance
to get back an instance of the
ComCalc
object:
object comCalcObject = Activator.CreateInstance(comCalcType);
You next create an array to hold the arguments, and then invoke the
method using InvokeMember
, passing in the method
you want to invoke as a string, a binder flag, a null binder, the
object returned by CreateInstance
, and the input
argument array:
object[] inputArguments = {left, right }; result = (Double) comCalcType.InvokeMember( "Subtract", // the method to invoke BindingFlags.InvokeMethod, // how to bind null, // binder comCalcObject, // the COM object inputArguments); // the method arguments
The results of this invocation are cast to Double
,
and stored in the local variable result
. You can
then display this result in the user interface, as shown in Figure 22-17.
Because all four event handlers must replicate this work, differing
only in the method they call, you’ll factor the common code to
a private helper method named Invoke
, as shown in
Example 22-7.
Example 22-7. Late binding of COM objects
private void btnAdd_Click( object sender, System.EventArgs e) { Invoke("Add"); } private void btnSubtract_Click( object sender, System.EventArgs e) { Invoke("Subtract"); } private void btnMultiply_Click( object sender, System.EventArgs e) { Invoke("Multiply"); } private void btnDivide_Click( object sender, System.EventArgs e) { Invoke("Divide"); } private void Invoke(string whichMethod) { Double left, right, result; left = Double.Parse(textBox1.Text); right = Double.Parse(textBox2.Text); // create a Type object to hold type information Type comCalcType; // an array for the arguments object[] inputArguments = {left, right }; // get the type info from the COM object comCalcType = Type.GetTypeFromProgID( "ComCalculator.ComCalc"); // create an instance object comCalcObject = Activator.CreateInstance(comCalcType); // invoke the method dynamically and // cast the result to double result = (Double) comCalcType.InvokeMember( whichMethod, // the method to invoke BindingFlags.InvokeMethod, // how to bind null, // binder comCalcObject, // the COM object inputArguments); // the method arguments label1.Text = result.ToString( ); }
18.191.144.65