Thursday, August 28, 2008

COM Interoperability

COM components and .NET components are not compatible since they have different internal architectures. However, there are tools available in the .NET SDK for generating COM proxies for .NET components and .NET proxies for COM components. Using these proxies we can use COM components in .NET projects and .NET components in non-.NET projects. Let's now discuss these two situations.

Using COM Components in .NET Application

Here we would be using a COM component called 'AtlServer' that exposes an interface 'IMath' containing two methods Add( ) and Sub( ). The component is stored in the file 'AtlServer.dll'. Note that 'AtlServer.dll' must be registered in you machine. If it is not registered simply build the 'AtlServer' project so that the .NET will make the registration or use the 'regsvr32' utility.
We now plan to use this COM component in a .NET project. For this we have created a console application and named it as 'AtlClient'. To use the COM component in our project we would have to create a wrapper class for the COM component. A wrapper class surrounds a class that follows a different architecture than .NET. This class provides a familiar interface to the .NET architecture.
We can create a wrapper class in two ways. First is to use the 'TlbImp.exe' tool provided in the .NET SDK. TlbImp stands for 'Type Library Importer'. This EXE is invoked from the command prompt as shown below:

c:\com_interop\AtlServer\Debug>tlbimp AtlServer.dll /out:NetAtlServer.dll

The /out option will store the newly created wrapper class in the 'NetAtlServer.dll' file. We would have to copy 'NetAtlServer.dll' in the 'Debug' sub-directory of our .NET project.
The second way to create a wrapper class is to right click in the 'Solution Explorer' and choose the 'Add Reference' option. Next we must choose the 'COM' tab. On doing so the window shown below would appear.


To select the file click on the 'Browse' button, locate the file and select it. On clicking 'OK', a file with the same name i.e. 'AtlServer.dll' would get created in the 'Debug' sub-directory of our project and would contain the wrapper class called CMath. We can now call the methods of the class as shown in the following code.

using System ;
using AtlServer ;
namespace AtlClient
{

class Class1
{

[ STAThread ]
static void Main ( string [ ] args )
{

CMathClass m = new CMathClass( ) ;
Console.WriteLine ( m.Add ( 10, 20 ) ) ;
Console.WriteLine ( m.Sub ( 20, 30 ) ) ;

}

}

}

Using .NET Components In Non-.NET Projects

To use a .NET component in a non-.NET project we have to use a tool called RegAsm, standing for 'Registry Assembly'. This tool registers a .NET component into the system registry so that standard Windows client can bind to the classes in the component.
The .NET component that we have created is just a simple class library called 'NetServer' that contains the following code.

using System ;

namespace NetServer
{

public interface IMath
{

int Add ( int n1, int n2 ) ;
int Sub ( int n1, int n2 ) ;

}

public class CMath : IMath
{

public int Add ( int n1, int n2 )
{

return n1 + n2 ;

}


public int Sub ( int n1, int n2 )
{

return n1 - n2 ;

}

}

}

Here we have declared an interface called IMath and implemented this interface in the CMath class. On building this project we get the 'NetServer.dll' file.
Now we need to register this component in the registry using the RegAsm tool as well as create a corresponding COM type library file ( .tlb file). To create a COM type library file we need to use the TlbExp tool. TlbExp stands for 'Type Library Exporter'. This tool interrogates the assembly's manifest and outputs a corresponding COM type library. We have used both the tools as shown in the following figure.


Now let us create a non-.NET project that would use this component. We have created our project in VC++. To create this project, click on 'Visual C++ Projects' and select 'Win32 Project'. Name the project as NetClient. On clicking 'OK' the window shown in the following figure would appear. In the 'Application Settings' tab select the 'Console Application' option and click on the 'Finish' button.


We need to add the following code to our project.

# include "stdafx.h"
# include "iostream.h"
# import "C:\dotnet\c#\com-interop\NetServer\bin\Debug\NetServer.tlb"

using namespace NetServer ;

int _tmain ( int argc, _TCHAR* argv [ ] )
{

CoInitialize ( NULL ) ;
IMathPtr p ;
HRESULT hr = p.CreateInstance ( "NetServer.Math" ) ;
if ( FAILED ( hr ) )
{

cout << "CreateInstance Failed" << endl ;
return 0 ;

}

cout <<> Add ( 10, 20 ) << endl ;
cout <<> Sub ( 20, 10 ) << endl ;

return 0 ;

}

Here we have imported the Type Library using the #import directive. Then we have created a pointer called IMathPtr. Using the CreateInstance( ) method we have stored the component object's address in the interface pointer and then used it to call the Add( ) and Sub( ) methods. On executing this program we would get the output on the console.

0 comments: