7.2. Importing COM Components


Many of the COM components that companies develop are not ActiveX Controls; they are standard COM dynamic link library (DLL ) files . To see how to use these with .NET, return to VB6 and create a COM business object that will act exactly as the component from the previous section did.

Once again, if you don't have VB6, you can download the DLL as explained earlier.


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 7-1 (shown here for your convenience in Example 7-3) into the code window.

Example 7-3. Methods for VB6 COM DLL 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 

7.2.1. Integrating the COM DLL into .NET

Create a new form called frmCOMDLL. Add a menu choice to the Fun menu on the Welcome form that invokes that form.

Now that you have created the ComCalc DLL, you can import it into .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 more quickly than late-bound methods. For the compiler to perform early binding, it must interrogate the COM object. If the compiler is going to interrogate the server's type library, it must first be imported into .NET.

7.2.2. Importing the Type Library

TheVB6-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 adding a reference to the component, or you can import the type library manually by using the standalone program TlbImp.exe.

TlbImp.exe will produce an interop assembly. The .NET object that wraps the COM object is called a Runtime Callable Wrapper (RCW). The .NET client will use the RCW to bind to the methods in the COM object, as shown in the following section.


Select the COM tab on the Add Reference dialog box and select the registered COM object, as shown in Figure 7-7.

This will invoke TlbImp for you and will copy the resulting RCW to C:\Documents and Settings\Administrator\Application Data\Microsoft\VisualStudio\RCW.

The exact directory in which the RCW will be placed will vary with how you've set up your machine.


You'll have to be careful, however, because the DLL it produces has the same name as the COM DLL.

Figure 7-7. Add Reference to ComCalculator.dll


7.2.3. Creating a Test Program

Return to frmActiveX and select all the controls (except the ActiveX Control), then copy them to the clipboard. Switch to frmCOMDLL and paste the controls to the new form. Move them into position. Note that they have all retained their names and their event handler names.

Add the following member variable to the frmCOMDLL class:

     Private theCalc As New ComCalculator.ComCalc 

Click on the event handlers and add the code in Example 7-4 to call the methods of the ComCalc object.

Example 7-4. Using the ComCalculator DLL
 Public Class frmCOMDLL     Private theCalc As New ComCalculator.ComCalc     Private Sub btnAdd_Click( _     ByVal sender As System.Object, _     ByVal e As System.EventArgs) Handles btnAdd.Click         Me.lblResults.Text = theCalc.Add(Double.Parse(txtLeft.Text), _             Double.Parse(txtRight.Text))     End Sub     Private Sub btnSubtract_Click( _     ByVal sender As System.Object, _     ByVal e As System.EventArgs) Handles btnSubtract.Click         Me.lblResults.Text = theCalc.Subtract(Double.Parse(txtLeft.Text), _             Double.Parse(txtRight.Text))     End Sub     Private Sub btnMultiply_Click( _     ByVal sender As System.Object, _     ByVal e As System.EventArgs) Handles btnMultiply.Click         Me.lblResults.Text = theCalc.Multiply(Double.Parse(txtLeft.Text), _             Double.Parse(txtRight.Text))     End Sub     Private Sub btnDivide_Click( _     ByVal sender As System.Object, _     ByVal e As System.EventArgs) Handles btnDivide.Click         Me.lblResults.Text = theCalc.Divide(Double.Parse(txtLeft.Text), _             Double.Parse(txtRight.Text))     End Sub End Class 

7.2.4. Late Binding

To invoke a COM object with late binding in Visual Basic 2005 you must use Reflection (see the sidebar "Reflection"), though this is an unusual requirement, and hence an advanced topic (i.e., feel free to skip this section, I won't be offended).

Reflection

Reflection is how a program sits up and looks at itself, or at the internal metadata of another program. Reflection is generally used for any of four tasks:


Viewing metadata

Metadata is data that is captured with a program, but is not part of the running of the program. Metadata might include version information, special attributes that tell tools like Visual Studio 2005 how to display a control and so forth. In COM, metadata is captured in a type library. In .NET, metadata is stored with the program itself.


Performing type discovery

This allows you to examine the types in an assembly and interact with or instantiate those types. This can be useful when you want to allow your users to interact with your program using a scripting language, such as JavaScript, or a scripting language you create yourself.


Late binding to methods and properties

This allows the programmer to invoke properties and methods on objects dynamically instantiated, based on type discovery. This is also known as dynamic invocation; it's what we'll use reflection for in this chapter.


Creating types at Runtime

This is called Reflection-emit, and is a very obscure and advanced use of reflection that actually allows you to create and run programs dynamically.


To see how to use late binding , remove the reference to the imported com library. The four button handlers must now be rewritten. You can no longer instantiate a ComCalculator.comCalc object, so instead you must invoke its methods dynamically.

Because all four event handlers must replicate this work of reflecting on the object, differing only in the method they call, you'll factor the common code to a private helper method named DoInvoke. Each button-click event handler calls this method with the name of the appropriate target method (Add, Subtract, Multiply, or Divide), as shown in Example 7-5.

Example 7-5. Late binding code for the Add, Subtract, Multiply, and Divide button Click event handlers
 Private Sub btnAdd_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnAdd.Click     DoInvoke("Add") End Sub Private Sub btnSubtract_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnSubtract.Click     DoInvoke("Subtract") End Sub Private Sub btnMultiply_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnMultiply.Click     DoInvoke("Multiply") End Sub Private Sub btnDivide_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnDivide.Click     DoInvoke("Divide") End Sub 

Before you implement DoInvoke, you'll need to add two member variables to the frmCOMDLL class. One of these will be a Type object that will hold information about the comCalc type. You also need a generic Object to represent the COM object you'll instantiate.

     Private comCalcType As Type = Type.GetTypeFromProgID("ComCalculator.ComCalc")     Private comCalcObject As Object 

The call to GetTypeFromProgID instructs the .NET Framework to open the registered COM DLL and retrieve the necessary type information for the specified object.

Next, add a handler for the Load event on frmCOMDLL. In this method, call CreateInstance to get back an instance of the comCalc object, as shown in Example 7-6.

Example 7-6. COMDLL form Load event handler
 Private Sub frmCOMDLL_Load(ByVal sender As System.Object, _                            ByVal e As System.EventArgs) Handles MyBase.Load     comCalcObject = Activator.CreateInstance(comCalcType) End Sub 

Now that you have the type metadata for the COM object, and have instantiated an object of that type, you can implement DoInvoke. It will invoke the methods of the COM object (Add, Subtract, Multiply, and Divide) indirectly, by calling the InvokeMember method of the Type class. This is exactly what you would do if you were invoking methods through reflection on a class described in a .NET assembly.

In DoInvoke, first create an array to hold the arguments to your method:

     Dim left As Double = Double.Parse(txtLeft.Text)     Dim right As Double = Double.Parse(txtRight.Text)     Dim inputArguments As Object = New Object(1) {left, right} 

Note that the constructor for the array of objects takes the upper bound (1), indicating that this array will hold two objects.


Type.InvokeMember expects several arguments:

  • The method you want to invoke as a string (Add, Subtract, Multiply, or Divide)

  • A binder flag (set to Reflection.BindingFlags.InvokeMethod)

  • A binder (set to Nothing)

  • The object returned by CreateInstance( )

  • The input argument array

The results of this invocation are cast to Double and stored in the local variable result:

     result = Double.Parse(comCalcType.InvokeMember( _                                     whichMethod, _                                     Reflection.BindingFlags.InvokeMethod, _                                     Nothing, _                                     comCalcObject, _                                     inputArguments)) 

You can then display this result in the user interface, as shown in Figure 7-8.

Figure 7-8. Running with late binding


The complete implementation of DoInvoke is shown in Example 7-7.

Example 7-7. Implementation of DoInvoke( ) Method
 Public Sub DoInvoke  (ByVal whichMethod As String)     Dim left As Double = Double.Parse(txtLeft.Text)     Dim right As Double = Double.Parse(txtRight.Text)     Dim result As Double = Nothing     Dim inputArguments As Object = New Object(1) {left, right}     result = Double.Parse(comCalcType.InvokeMember( _                                     whichMethod, _                                     Reflection.BindingFlags.InvokeMethod, _                                     Nothing, _                                     comCalcObject, _                                     inputArguments))     Me.lblResults.Text = result.ToString( ) End Sub 



Programming Visual Basic 2005
Programming Visual Basic 2005
ISBN: 0596009496
EAN: 2147483647
Year: 2006
Pages: 162
Authors: Jesse Liberty

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net