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.
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.
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 STEP8.1 Building a COM Dynamic Link Library (DLL)
|
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.
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
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 STEP8.2 Using the Type Library Importer Tool
|
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.
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 ).
The Visual Studio .NET interface provides a streamlined way to use a COM component from your .NET code.
STEP BY STEP8.3 Using Direct Reference with a COM Library
|
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.1The 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:
|
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
|
Top |