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.
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 ComCalcPublic 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 .NETCreate 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 LibraryTheVB6-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.
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.
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.dll7.2.3. Creating a Test ProgramReturn 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 DLLPublic 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 BindingTo 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).
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 handlersPrivate 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 handlerPrivate 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}
Type.InvokeMember expects several arguments:
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 bindingThe complete implementation of DoInvoke is shown in Example 7-7. Example 7-7. Implementation of DoInvoke( ) MethodPublic 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 |