Calling Managed Components from a COM Client

Team-Fly    

 
Application Development Using Visual Basic and .NET
By Robert J. Oberg, Peter Thorsteinson, Dana L. Wyatt
Table of Contents
Chapter 17.  Interoperability


Calling Managed Components from a COM Client

Obviously, it is much more likely that you will want to write new .NET applications that make use of legacy COM components; however, there may be times when you need to go in the opposite direction. For example, you may have an existing application that makes use of one or more COM components, and you would like to rewrite several of those COM components as .NET components to be used in future .NET solutions. However, in the meantime, you may want to make use of those new .NET components in your existing COM client applications as well.

COM client programs may use early binding (v-table interface) or late binding ( IDispatch interface) to access managed .NET components. Early binding requires that type library information is available at compile time. Late binding does not require any type library information at compile time, since binding takes place at runtime via the IDispatch interface methods .

However, regardless of whether the client uses early or late binding, a bridge is required between the unmanaged native execution environment of the COM client and the managed execution environment of the .NET component. This bridge is known as the COM Callable Wrapper (CCW), which acts as a proxy for the managed object, as shown in Figure 17-8. Only one CCW object is created for any given managed object created for a COM client. The CCW manages object lifetime according to the reference counting rules of IUnknown , and it also manages marshaling for the method calls made on the object.

Figure 17-8. A COM callable wrapper between unmanaged and managed code.

graphics/17fig08.gif

While the RCW assembly is explicitly created as a file, the CCW is created dynamically at runtime by the Common Language Runtime. The CLR creates exactly one CCW for a managed object regardless of the number of COM clients that request its services, and both COM and .NET clients can make requests on the same .NET object simultaneously .

A Late Binding COM Client

There are many variations of a COM client calling a .NET component. We will illustrate with just one scenario, a late binding COM client calling a managed component. We will create a .NET component that can be called through VBScript on the bank.htm Web page.

Looking at the VBScript code used in createobject on bank.htm , we see that the ProgId of the COM object is BankDual.Account2.1. We wish to create a .NET object that can be used in place of this COM object and that has the same ProgId. To avoid confusion with the COM object, unregister it running the batch file unreg_bankdual.bat in the directory LegacyComServer . Now, if you access bank.htm in Internet Explorer and click the Create button, you will get an error.

VB.NET code for implementing a compatible bank account object is in the file Account.vb in the NetServer example.

graphics/codeexample.gif
 ' Account.vb Imports System  Imports System.Runtime.InteropServices   <ProgId("BankDual.Account2.1")> _  Public Class Account     Private m_balance As Integer     Sub New()         m_balance = 1000     End Sub     Public Sub Deposit(ByVal amount As Integer)         m_balance += amount     End Sub     Public Sub Withdraw(ByVal amount As Integer)         m_balance -= amount     End Sub     Public ReadOnly Property Balance() As Integer         Get             Return m_balance         End Get     End Property End Class 

The code shown in bold enables us to assign BankDual.Account2.1 as the ProgId, making it compatible with the COM object we are replacing. If we left these lines out, we would still be able to call the object through COM. The ProgId would be created from the namespace and the class name , or NetServer.Account. Other attributes would let us assign various GUIDs, which would be useful in an early binding scenario. Note that to distinguish our .NET component from the COM component it is replacing, we have assigned the starting balance to be 1000.

We are going to deploy our component in the Global Assembly Cache, so we need to create a strong name, as discussed in Chapter 9. We generate a public-private key pair and place them in a file keypair.snk , using the command

 sn -k keypair.snk 

In our Visual Studio project we reference this key file in AssemblyInfo.vb ,

 <Assembly: AssemblyVersion("1.0.*")>  <Assembly: AssemblyKeyFile("..\..\keypair.snk")>  

Our project creates the target assembly NetServer.dll in the top-level source directory, where we also have the keypair.snk file. We can run all the command-line programs from the directory C:\OI\NetVB\Chap17\NetServer . We can then place our assembly in the GAC using the command

 gacutil /i netserver.dll 

You can use the .NET Admin Tool discussed in Chapter 9 to inspect the contents of the GAC, verifying that NetServer has indeed been deployed there. See Figure 17-9.

Figure 17-9. Inspecting the GAC using the .NET Admin Tool.

graphics/17fig09.jpg

In order to make our .NET component available to COM clients, we must provide suitable entries in the Registry. This will enable the COM run-time to locate the appropriate server path and so on. The Assembly Registration Utility, Regasm.exe , reads the metadata within an assembly and adds these necessary entries to the Registry, which allows COM clients to use the .NET assembly's components as if they were just old-fashioned registered COM components (via the CCW proxy).

The syntax for using Regasm.exe is shown next . This allows COM client programs to create instances of managed classes defined by in the assembly.

 Regasm AssemblyPath [options] Where the options may be any of the following. /unregister          Unregister types /tlb[:FileName]      Specified typelib /regfile[:FileName]  Specified output reg file name /codebase            Sets the code base in the registry /registered          Only refer to preregistered typelibs /nologo              Prevents displaying logo /silent              Prevents displaying of messages /verbose             Displays extra information /? or /help          Display usage help message 

We run this utility on NetServer using the command shown in bold ,

 C:\OI\NetVB\Chap17\  NetServer>regasm netserver.dll  RegAsm - .NET Assembly Registration Utility Version 1.0.2914.16 Copyright (C) Microsoft Corp. 2001.  All rights reserved. Types registered successfully 

We can use the OLE/COM Object Viewer to inspect the entries made in the Registry. Note that there is a special category of COM objects called .NET Category. Figure 17-10 shows the Registry entries for our NetServer.Account object. Note that the ProgId is BankDual.Account2.1, as specified by the attribute in our VB.NET source code. Note also that the InprocServer32 is mscoree.dll , which is the DLL implementing the CLR. As previously mentioned, there is no file created for the CCW. Instead, when the wrapped component is to be instantiated , the CLR creates the CCW on the fly.

Figure 17-10. OLE/COM Object Viewer shows Registry entries for a .NET object.

graphics/17fig10.jpg

A late-binding COM client can now call our .NET component. That is all there is to it! You can double click on bank.htm , and Internet Explorer will run the VBScript we looked at before. Only this time, the .NET component NetServer.Account is invoked, as you can tell by noticing that the starting balance is 1000, as shown in Figure 17-11.

Figure 17-11. Accessing a .NET object in Internet Explorer.

graphics/17fig11.jpg


Team-Fly    
Top
 


Application Development Using Visual BasicR and .NET
Application Development Using Visual BasicR and .NET
ISBN: N/A
EAN: N/A
Year: 2002
Pages: 190

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