|
Introduction
"Basics of Building .NET applications" (see http://www.15seconds.com/issue/010129.htm), my last article, discussed how to use the legacy code from managed/.NET code. In this article, I will cover how to use managed components from unmanaged code.
.NET runtime allows us to use legacy COM code from .NET components. We can call it backward compatibility. In the same way, .NET runtime also provides us forward compatibility, means accessing .NET components from COM components.
Download complete source code for this article.
Differences Between .NET Framework and COM Framework
The .NET framework object model and its workings are different from Component Object Model (COM) and its workings. For example, clients of .NET components don't have to worry about the lifetime of the object. Common Language Runtime (CLR) manages things for them. In contrast, clients of COM objects must take care of the lifetime of the object. Similarly, .NET objects live in the memory space that is managed by CLR. CLR can move objects around in the memory for performance reasons and update the references of objects accordingly, but COM object clients have the actual address of the object and depend on the object to stay on the same memory location.
Similarly, .NET runtime provides many new features and constructs to managed components. For example, .NET components can have parameterized constructors, functions of the components can have accessibility attributes (like public, protected, internal, and others) associated with them, and components can also have static methods. Apart from these features, there are many others. These include ones that are not accessible to COM clients because standard implementation of COM does not recognize these features. Therefore .NET runtime must put something in between the two, .NET server and COM client, to act as mediator.
The .NET and COM Mediator
.NET runtime provides COM Interoperability wrappers for overcoming the differences between .NET and COM environments. For example, runtime creates an instance of COM Callable Wrapper (CCW) when a COM client accesses a .NET component. In the same way, an instance of Runtime Callable Wrapper (RCW) is created when a .NET client accesses a COM component. These wrappers abstract the differences and provide the seamless integration between the two environments.
The following diagram illustrates CCW and RCW.
Let's Do Something Practical
For demonstration purposes, I have created a .NET component in C# named CManagedServer. This component is in the ManagedServer assembly. For client side, I have created a Visual Basic (VB) 6.0-based client that uses the services of our managed server.
Step 1
First, we create the managed server. The following code for CManagedServer is very simple and contains a single method named "SayHello."
using System;
namespace ManagedServer
{
public class CManagedServer
{
public CManagedServer()
{}
public string SayHello(string r_strName)
{
string str ;
str = "Hello " + r_strName ;
return str ;
}
}
}
For compilation and creation of ManagedServer assembly, use the following command:
csc /out:ManagedServer.dll /target:library ManagedServer.cs
pause
This command will create the ManagedServer.dll file. This is our managed server.
Step 2
Standard COM implementation relies on the Windows registry for looking up the information related to COM components, like CLSID, Interface IDs, the path of the component's housing (DLL/exe), the component threading model, etc. .NET framework does not depend on the registry and uses metadata for this information. Therefore, we have to generate the COM-compatible registry entries for our managed server so that the COM runtime could instantiate our server.
Like tlbimp.exe, there is a tool named regasm.exe. This tool reads the metadata information within an assembly and adds the corresponding COM-compatible registry entries. Classes in the assembly are not COM creatable until they are actually registered in the Windows registry.
Regasm.exe tool can also generate the COM type library for our manager server. We will reference this type library in VB 6.0 client.
The following command can be used for creating the registry entries and type library for our managed server:
regasm ManagedServer.dll /tlb
pause
Following is the output that will be generated after successful execution of the above command:
At this point, standard COM registry entries will have been created. Look at the following figure, this shows the registry entries on my PC:
Step 3
Now we will create the client of our managed server. I have created a simple client.
Step 2 created a tlb so we will reference it in the VB client. The following figure shows the ManagedServer tlb listed in the "References" dialog.
The following is the code that creates the object and calls its SayHello Method.
Private Sub cmdAccessManagedComponent_Click()
Dim objServer As New ManagedServer.CManagedServer
MsgBox objServer.SayHello("15 Seconds reader")
Set objServer = Nothing
End Sub
The above code is very simple and COM Interoperability wrappers have abstracted all the complexities of accessing .NET components.
Running the UnmanagedClient.exe and pressing the "Access managed component" button, will produce the following output:
Conclusion
This is what we need to do to access .NET components from unmanaged code.
If you want to develop some of your application components in .NET, you should consider that many of the features of .NET components are not exposed to COM clients. This will require some design-time decisions and may affect the way you design your object hierarchies (because inheritance hierarchy of .NET components is flattened for COM clients).
One more thing, currently .NET components are accessible to COM clients only. .NET components cannot be accessed from Win32 DLLs or executables. I am not sure whether Microsoft will incorporate this in future.
About the Author
Mansoor Ahmed Siddiqui is a software consultant and technical writer working in the United States. He is in the field of Software Development since 1997. His areas of expertise include designing and
development of Web-based applications, client-server applications, and three-tier applications with a special focus on middle-tier and Win32 programming. He has expertise in UML, Visual C++, MFC, ATL, Visual Basic 6.0, Rational Rose, SQL Server 7.0, ASP, JavaScript, XML, ADO, COM/DCOM/COM+, MTS, MSMQ, Java, JSP, Servlets, EJBs, J2EE, VB .NET and C#. Currently he is working with Visual Studio 7.0 and .NET Platform. Apart from this, he is also an MCSD and brainbench certified in different languages.
Other interests are listening to music, swimming, playing cricket, and hanging out with friends. He can be reached at mansoorasiddiqui@hotmail.com
|