Using COM Components

   


Using COM Components

Access unmanaged code from a Windows service, a serviced component, a .NET Remoting object, and an XML Web service.

You might already have a lot of development done in your organization that you would like to reuse with .NET as you slowly migrate toward it. Fortunately, if your old programs use COM architecture, you don't have to do a "big bang" migration all at once. .NET components can call COM components, and COM components can call .NET components. This means that you can migrate one component (a control, a class library, and so on) at a time and still keep all your code working together.

NOTE

ActiveX Controls Prior to .NET, ActiveX was a major means of delivering encapsulated functionality such as controls to the Windows applications. I won't be discussing ActiveX in this book because it is a client-side technology and has little use for creating server-side applications and components. For more information on using ActiveX from .NET applications, refer to my book, MCAD/MCSD Training Guide: Exam 70-306, Developing and Implementing Windows-based Application With Visual Basic .NET and Visual Studio .NET .


Why might you want to undertake such a gradual migration? There are four basic reasons for maintaining part of a system in COM components while moving other parts to .NET components:

  • It takes time to learn enough about Visual Basic .NET and the .NET Framework to be productive. While you're making your way up the learning curve, you might have to continue development of existing COM components.

  • You might have components that can't be easily moved to .NET because they use language features that are no longer supported or because of other implementation quirks .

  • It takes time to move code from one system to the other. Unless you can afford extended downtime, a gradual move lets you write the converted code at a slower pace.

  • Your application might depend on third-party controls or libraries for which you do not have the source code.

In the following sections, you'll learn how to encapsulate COM components for use with .NET applications. There are both command-line and GUI tools for working with COM components. Before I talk about those tools, though, you should know a bit more about wrapper classes.

Understanding Runtime Callable Wrappers

As you probably already know, Visual Basic .NET creates code that operates within the .NET CLR. Code that operates within the CLR is called managed code . Managed code benefits from the services that the CLR offers, including garbage collection, memory management, and support for versioning and security.

Code that does not operate within the CLR is called unmanaged code . Code that was created by tools older than the .NET Framework is unmanaged code by definition. COM components are unmanaged code because COM was designed before the CLR existed, and COM components don't make use of any of the services of the CLR.

Managed code expects that all the code with which it interacts will use the CLR. This is an obvious problem for COM components. How can you take a component that was developed before the advent of .NET and make it look like a .NET component to other .NET components? The answer is to use a proxy. In general terms, a proxy accepts commands and messages from one component, modifies them, and passes them to another component. The particular type of proxy that allows you to use COM components within a .NET application is called a runtime callable wrapper ( RCW ) . That is, it's a proxy that can be called by the CLR.

Figure 8.1 shows schematically how the pieces fit together.

Figure 8.1. RCW allows you to use COM components within the .NET framework.

Building a COM DLL

To see how COM interoperability works, you need a COM library. Step by Step 8.1 shows how to build a simple one.

STEP BY STEP

8.1 Building a COM Dynamic Link Library (DLL)

  1. Launch Visual Basic 6. Create a new ActiveX DLL project.

  2. Select the Project1 node in the Project Explorer window and rename it MyCustomer .

  3. Select the Class1 node in the Project Explorer window and rename it Balances .

  4. Add this code to the Balances class:

     Option Explicit Private mintCustomerCount As Integer Private macurBalances(1 To 10) As Currency ' Create a read-only CustomerCount property Public Property Get CustomerCount() As Integer     CustomerCount = mintCustomerCount End Property ' Create a GetBalance method Public Function GetBalance(_    CustomerNumber As Integer) As Currency     GetBalance = macurBalances(CustomerNumber) End Function ' Initialize the data Private Sub Class_Initialize()     Dim intI As Integer     mintCustomerCount = 10     For intI = 1 To 10         macurBalances(intI) = _           Int(Rnd(1) * 100000) / 100     Next intI End Sub 
  5. Save the Visual Basic project.

  6. Select File, Make MyCustomer.dll to create the COM component.

NOTE

If You Don't Have Visual Basic Even if you don't have Visual Basic, you can still test COM interoperability by working with a COM library already installed on your computer. A variety of Microsoft componentsincluding Office, SQL Server, and ADOinstall COM libraries.


Registering a COM DLL

In Step by Step 8.1, by building the MyCustomer.dll using Visual Basic 6, the COM DLL is automatically registered in the Windows Registry.

If you are using the code files from the CD or you have a COM DLL from another source, you need to register the COM DLL in the Windows Registry before you can use it in .NET code. You can register by using regsvr32.exe at the command prompt as shown here:

 regsvr32 MyCustomer.dll 

Using the Type Library Importer Tool ( tlbimp.exe )

The task of using COM components from the .NET Framework is substantially facilitated by the fact that COM components, like .NET components, have metadata that describes their interfaces. For .NET components, the metadata is embedded in the assembly manifest. For COM components, the metadata is stored in a type library. A type library can be a separate file, or (as with Visual Basic 6 class libraries) it can be embedded within another file.

The .NET Framework includes a tool, the Type Library Importer tool ( tlbimp.exe ), that can create an RCW from COM metadata contained in a type library, as seen in Step by Step 8.2.

STEP BY STEP

8.2 Using the Type Library Importer Tool

  1. Launch a .NET command prompt by selecting Start, Programs, Microsoft Visual Studio .NET, Visual Studio .NET Tools, Visual Studio .NET Command Prompt.

  2. Inside the command prompt window, navigate to the folder that contains the MyCustomer.dll COM library.

  3. Enter this command line to run the Type Library Importer tool:

     tlbimp MyCustomer.dll /out:NETMyCustomer.dll 
  4. Launch Visual Studio .NET. Create a Visual Basic ASP.NET Web Service application named 310C08 .

  5. Right-click the References node in Solution Explorer and select Add Reference.

  6. Click the Browse button in the Add Reference dialog box. Browse to the NETMyCustomer.dll file that you created in step 3 and click Open to select it. Click OK to add the reference to the project.

  7. Right-click the Service1.asmx file in Solution Explorer and rename it StepByStep8-2.asmx .

  8. Click the hyperlink on the StepByStep8-2.asmx design surface to switch to the code view. Change all the occurrences of Service1 to refer to StepByStep8_2 . Add the following attribute before the StepByStep8_2 class definition:

     <WebService(Namespace:="http://NetExam.org/Balance")> _ Public Class StepByStep8_2     Inherits System.Web.Services.WebService 
  9. Add the following Web method definition to the Web service:

     <WebMethod()> _ Public Function RetrieveBalance(_  ByVal custNumber As Short) As Decimal     Dim b As NETMyCustomer.Balances = _         New NETMyCustomer.Balances()     RetrieveBalance = b.GetBalance(custNumber) End Function 
  10. Set the Web service as the start page for the project.

  11. Run the project. You should see that a browser is launched showing the test page. Click on the RetrieveBalance method link. Enter a number between 1 and 10 for the custNumber parameter and click the Invoke button. A second browser window opens with that customer's balance.

In Step by Step 8.2, you used the Type Library Importer tool to create an RCW for the COM type library. This RCW is a library that you can add to your .NET project as a reference. After you do that, the classes in the COM component can be used just like native .NET classes.

When you use a class from the COM component, .NET makes the call to the RCW, which in turn forwards the call to the original COM component and returns the results to your .NET managed code.

The Type Library Importer tool supports the command-line options listed in Table 8.1.

Table 8.1. Command-Line Options for the Type Library Importer Tool

Option

Meaning

/asmversion: versionNumber

Specifies the version number for the created assembly

/delaysign

Prepares the assembly for delay signing

/help

Displays help for command-line options

/keycontainer: containerName

Signs the assembly with the strong name from the specified key container

/ keyfile : filename

Specifies a file containing public/private key pairs that is used to sign the resulting file

/namespace: namespace

Specifies the namespace for the created assembly

/nologo

Suppresses the banner with the copyright information for the tool

/out: filename

Specifies the name of the created assembly

/primary

Produces a primary interop assembly

/ publickey : filename

Specifies the file containing a public key that is used to sign the resulting file

/reference: filename

Specifies a file to be used to resolve references from the file being imported

/silent

Suppresses information that would otherwise be displayed on the command line during conversion

/strictref

Refuses to create the assembly if one or more references cannot be resolved

/sysarray

Imports COM SAFEARRAY as instances of the System.Array type

/unsafe

Creates interfaces without the .NET Framework security checks

/verbose

Displays additional information on the command line during conversion

  /?  

Displays help about command-line options

EXAM TIP

Options Overview You don't need to memorize all the options for the Type Library Importer tool. You should know that most of the options deal with the security of the resulting RCW and the code that it contains.

Assigning a Strong Name to a COM DLL If you want to use a COM DLL from a serviced component or place the COM DLL in the global assembly cache, you must assign a strong name to the COM DLL. You can do so by using the /keyfile option of the Type Library Importer tool ( tlbimp.exe ).


Using COM Components Directly

The Visual Studio .NET interface provides a streamlined way to use a COM component from your .NET code.

STEP BY STEP

8.3 Using Direct Reference with a COM Library

  1. Add a Web service page named StepByStep8-3.asmx to the project.

  2. Right-click the References node in Solution Explorer and select Add Reference.

  3. Select the COM tab in the Add Reference dialog box. Scroll down the list of COM components until you come to the MyCustomer library. Select the MyCustomer library, click Select, and then click OK.

  4. Add the following Web method definition to the Web service:

     <WebMethod()> _ Public Function RetrieveBalance(_  ByVal custNumber As Short) As Decimal     Dim b As NETMyCustomer.Balances = _         New NETMyCustomer.Balances()     RetrieveBalance = b.GetBalance(custNumber) End Function 
  5. Set the Web service as the start page for the project.

  6. Run the project. You should see that a browser is launched showing the test page. Click on the RetrieveBalance method link. Enter a number between 1 and 10 for the custNumber parameter and click the Invoke button. A second browser window opens with that customer's balance.

NOTE

COM DLL Must Be Registered Before It Is Used MyCustomer.dll will not be in the COM tab of the Add Reference dialog box if it was not built in Step by Step 8.1. Refer to the earlier section "Registering a COM DLL" for information on how to register a COM DLL.


When you directly reference a COM library from the Visual Studio .NET Integrated Development Environment (IDE), the effect is almost the same as if you used the Type Library Importer tool to import the same library. Visual Studio .NET creates a new namespace with the name of the original library and then exposes the classes from the library within that namespace.

Although you can use either of the two methods described in this chapter to call a COM component from a .NET component, there are reasons to prefer one method over the other:

  • For a COM component that will only be used in a single Visual Basic .NET project and that you wrote yourself, use the easiest method: direct reference from the .NET project. This method is suitable only for a truly private component that does not need to be shared by the other projects.

  • If a COM component is shared among multiple projects, use the Type Library Importer tool so that you can sign the resulting assembly and place it in the global assembly cache (GAC). Shared code must be signed with a strong name.

  • If you need to control details of the created assemblysuch as its name, namespace, or version numberyou must use the Type Library Importer tool. The direct reference method gives you no control over the details of the created assembly.

WARNING

Import Only Your Own Code You should not use either of the import methods on code written by another developer because you are not allowed to sign code written by someone else. If you need to use a COM component from another developer, you should obtain a Primary Interop Assembly (PIA) from the original developer of the component. Microsoft supplies PIAs for all its own common libraries. For example, there are PIAs for almost all the components of Microsoft Office XP, available at http://msdn.microsoft.com/downloads/default.asp?url=/downloads/sample.asp?url=/msdn-files/027/001/999/msdncompositedoc.xml.


GUIDED PRACTICE EXERCISE 8.1

The goal of this exercise is to compare the performance of two implementations of the same code, using a COM library for one implementation and a native .NET class for the other implementation. You should choose some code that takes a reasonably long time to run so that you can detect any differences between the two implementations .

How would you create such an application?

EXAM TIP

Timing Code To tell how long a piece of code takes to run, you can use arithmetic with two instances of the DateTime class to produce a TimeSpan object.


You should try working through this problem on your own first. If you get stuck, or if you'd like to see one possible solution, follow these steps:

  1. Launch Visual Basic 6. Create a new ActiveX DLL project.

  2. Select the Project1 node in the Project Explorer window and rename it Numeric .

  3. Select the Class1 node in the Project Explorer window and rename it Primes .

  4. Add this code to the Primes class:

     Option Explicit Public Function HighPrime(Max As Long) As Long         Dim a() As Byte         Dim lngI As Long         Dim lngJ As Long         ReDim a(Max)         ' In the array, 1 indicates a prime,         ' 0 indicates nonprime.         ' Start by marking multiples         ' of 2 as nonprime         For lngI = 0 To Max             If lngI Mod 2 = 0 And lngI <> 2 Then                 a(lngI) = 0             Else                 a(lngI) = 1             End If         Next lngI       ' Now execute the usual sieve       ' of erasthones algorithm         For lngI = 3 To Sqr(Max) Step 2             If a(lngI) = 1 Then               ' This is a prime,               ' so eliminate its multiples                 For lngJ = lngI + lngI To Max _                     Step lngI                     a(lngJ) = 0                 Next lngJ             End If         Next lngI         ' Find the largest prime by working backward         For lngI = Max To 1 Step -1             If a(lngI) = 1 Then                 HighPrime = lngI                 Exit For             End If         Next lngI End Function 
  5. Save the Visual Basic project.

  6. Select File, Make Numeric.dll to create the COM component. Making the file will automatically register it on your computer.

  7. In your Visual Basic .NET project, right-click the References node of Solution Explorer and select Add Reference.

  8. Select the COM tab in the Add Reference dialog box. Scroll down the list of COM components until you come to the Numeric library. Select the Numeric library, click Select, and then click OK.

  9. Add a new class to your Visual Basic .NET project. Name the class Primes.vb .

  10. Add this code to the Primes.vb class:

     Public Class Primes     Public Function HighPrime(_      ByVal Max As Long) As Long         Dim a() As Byte         Dim intI As Integer         Dim intJ As Integer         ReDim a(Max)         ' In the array, 1 indicates a prime,         ' 0 indicates nonprime.         ' Start by marking multiples         ' of 2 as nonprime         For intI = 0 To Max             If intI Mod 2 = 0 And intI <> 2 Then                 a(intI) = 0             Else                 a(intI) = 1             End If         Next intI         ' Now execute the usual         ' sieve of erasthones algorithm         For intI = 3 To System.Math.Sqrt(Max) Step 2             If a(intI) = 1 Then                 ' This is a prime, so                 ' eliminate its multiples                 For intJ = intI + intI To Max Step intI                     a(intJ) = 0                 Next intJ             End If         Next intI         ' Find the largest prime by working backwards         For intI = Max To 1 Step -1             If a(intI) = 1 Then                 HighPrime = intI                 Exit For             End If         Next intI     End Function End Class 
  11. Add a new Web service named GuidedPracticeExercise8-1.asmx to your Visual Basic .NET project.

  12. Switch to code view and add the following Web method definitions to the Web service definition:

     <WebMethod()> _ Public Function CalculateCOMHighPrime(_  ByVal maxNumber As Integer) As String     Dim COM_Primes As Numeric.Primes = _      New Numeric.Primes()     Dim dt As DateTime = DateTime.Now     Dim intHighPrime As Integer = _     COM_Primes.HighPrime(maxNumber)     Dim ts As TimeSpan = DateTime.Now.Subtract(dt)     Dim COMResults As String = "High prime = " & _      intHighPrime.ToString() & " took " & _      ts.Ticks.ToString() & " ticks"     CalculateCOMHighPrime = COMResults End Function <WebMethod()> _ Public Function CalculateNETHighPrime(_  ByVal maxNumber As Integer) As String     Dim NET_Primes As Primes = New Primes()     Dim dt As DateTime = DateTime.Now     Dim intHighPrime As Integer = _     NET_Primes.HighPrime(maxNumber)     Dim ts As TimeSpan = DateTime.Now.Subtract(dt)     Dim COMResults As String = "High prime = " & _      intHighPrime.ToString() & " took " & _      ts.Ticks.ToString() & " ticks"     CalculateNETHighPrime = COMResults End Function 
  13. Set the Web service as the start page for the project.

  14. Run the project. You should see that a browser is launched showing the test page. Click on the CalculateCOMHighPrime method link. Enter a fairly large number in the maxNumber parameter and click the Invoke button. The code uses the COM library to find the largest prime number that is smaller than the number you entered, and displays the results as shown in Figure 8.2.

    Figure 8.2. Running .NET code is faster than running COM code in the .NET framework.

  15. Click the Back button in the main page and then click on the CalculateNETHighPrime method link. In the maxNumber parameter, enter the same large number that you previously entered for COM implementation and click the Invoke button. The code uses the native .NET class to find the largest prime number that is smaller than the number you entered, and displays the results as shown in Figure 8.2.

    If you have difficulty following this exercise, review the section "Using COM Components," earlier in this chapter. After doing that review, try this exercise again.

WARNING

The Pitfalls of Performance In Guided Practice Exercise 8.1, the .NET class was faster than the COM class. But timing performance on Windows is notoriously difficultfor several reasons. First, although you can measure things down to the timer tick, the hardware does not provide precise-to-the-tick numbers . Second, because of caching and because other programs are in memory, timings tend not to be repeatable. Finally, it's hard to write exactly equivalent COM and .NET code. Nevertheless, repeated runs of a program such as this example can give you general information on which of two alternatives is faster.


REVIEW BREAK

  • Using COM components from .NET managed code requires the creation of an RCW.

  • You can create an RCW for a COM component by using the Type Library Importer tool or by directly referencing the COM component from your .NET code.

  • To use COM components that you did not create, you should obtain a PIA from the creator of the component.

  • RCWs impose a performance penalty on COM code.


   
Top


MCAD. MCSD Training Guide (Exam 70-310. Developing XML Web Services and Server Components with Visual Basic. NET and the. NET Framework)
MCAD/MCSD Training Guide (70-310): Developing XML Web Services and Server Components with Visual Basic(R) .NET and the .NET Framework
ISBN: 0789728206
EAN: 2147483647
Year: 2002
Pages: 166

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