Introduction
Component Object Model is a method to facilitate communication between different applications and languages. There are many other ways to structure software components. What makes COM interesting is that it is a widely accepted interoperability standard. In addition, the standard explains the way the memory should be organized for all the objects.Interfaces are the contract between the client and the server, i.e. an interface is the way in which an object exposes its functionality to the outside world. In COM, an interface is a table of pointers to functions implemented by the object. The table represents the interface, and the functions to which it points are the methods of that interface.
Creating COM components in .NET
Creating COM components in .NET is not that difficult as in C++. The following steps explain the way to create the COM server in C#:- Create a new Class Library project.
- Create a new interface, say
IManagedInterface
, and declare the methods required. Then provide theGuid
(this is theIID
) for the interface using theGuidAttribute
defined inSystem.Runtime.InteropServices
. TheGuid
can be created using the Guidgen.exe.[Guid("3B515E51-0860-48ae-B49C-05DF356CDF4B")]
- Define a class that implements this interface. Again provide the
Guid
(this is theCLSID
) for this class also. - Mark the assembly as
ComVisible
. For this go to AssemblyInfo.cs file and add the following statement[assembly: ComVisible (true)]
. This gives the accessibility of all types within the assembly to COM. - Build the project. This will generate an assembly in the output path. Now register the assembly using regasm.exe (a tool provided with the .NET Framework)- regasm \bin\debug\ComInDotNet.dll \tlb:ComInDotNet.tlb This will create a TLB file after registration.
- Alternatively this can be done in the Project properties -> Build -> check the Register for COM interop.
The following steps explain the method to create an unmanaged client. Here the client is in VC++ 6.0.
- Create an MFC AppWizard EXE using the wizard in MSDEV 6.0.
- Import the COM server (TLB file generated by regasm.exe) using the
#import
directive.#import “ComInDotNet.tlb” no_namespace named_guids raw_interfaces_only
. - Now the COM library should be loaded using the
CoInitialize
and component can be created usingCoCreateInstance
. - Next the methods defined in the COM Server can be invoked.
pInterface->Execute(“blah blah blah”);
- What is COM?
Microsoft COM (Component Object Model) technology in the Microsoft Windows-family of Operating Systems enables software components to communicate. COM is used by developers to create re-usable software components, link components together to build applications, and take advantage of Windows services. COM objects can be created with a variety of programming languages. Object-oriented languages, such as C++, provide programming mechanisms that simplify the implementation of COM objects. The family of COM technologies includes COM+, Distributed COM (DCOM) and ActiveX® Controls.
Microsoft provides COM interfaces for many Windows application programming interfaces such as Direct Show, Media Foundation, Packaging API, Windows Animation Manager, Windows Portable Devices, and Microsoft Active Directory (AD).
COM is used in applications such as the Microsoft Office Family of products. For example COM OLE technology allows Word documents to dynamically link to data in Excel spreadsheets and COM Automation allows users to build scripts in their applications to perform repetitive tasks or control one application from another.
What's new in .NET Framework 3.5 SP1?
SP1 advances the art of application development
The new ADO.NET Entity Framework feature in SP1 offers developers a model-based paradigm and a rich, standards-based framework for creating data-oriented applications shared across multiple applications and platforms. The separation of presentation, data, and business logic used in concert with a single data model will enable developers to spend less time writing plumbing code and more time refining business logic.
SP1 makes data-driven programming easier
SP1 offers developers support for ASP.NET Dynamic Data, which provides a rich scaffolding framework that enables rapid data-driven development. Since ASP.NET takes care of creating the presentation layer, a fully functional Website is output and ready for customization without the developer writing a single line of code. Further, with ADO.NET Data Services, Web developers can create RESTful Web 2.0-style applications that have better server scalability and improved caching support.
SP1 is the fastest and easiest way to deploy Windows applications
With the .NET Framework Client Profile, a small subset of the Framework that powers client applications, developers can offer their end users a dramatically streamlined and rapid application download experience. In addition, improvements in SP1 result in dramatic reductions in cold start times, allowing developers to serve a broader set of customers with varying hardware profilesSummary
This paper provides the technical overview of .NET and COM interoperability. It describes how .NET components can communicate with existing COM components without migrating those COM components into .NET components, thus helping the migration cost and business systems. This paper also provides an overview of marshalling. The intended audience is a development team that wishes to interact with COM and .NET applications. (This paper assumes that the reader has the fundamental knowledge of COM and .NET)
Introduction
From the time Microsoft engineers started working on the ideas behind COM in 1998, COM went through quite an evolution. Once .NET was released everything was about the CLR. Those business systems made lot of investments on those COM developments and they may not be willing to invest more money to build their components into .NET. Also this will make a severe impact in productivity.
Fortunately, switching from COM to .NET involves no such radical loss of productivity. The concept of providing bridge between .NET and COM components is .NET-COM interoperability. Microsoft .NET Framework provides system, tools, and strategies that enable strong integration with past technologies and allow legacy code to be integrated with new .NET components. It provides a bridge between the .NET and COM and vice versa.
There are two key concepts that make it much easier to move from COM development to .NET development, without any loss of code base or productivity.
- Interaction with COM components from .NET
- Interaction with .NET components from COM
Communication between Object and Client
COM is a binary reusable object which exposes its functionality to other components. When a client object asks for instances of server object, the server instantiates those objects and handout references to the client. So, a COM component can act as a binary contract between caller and callee. This binary contract is defined in a document known as Type library. The Type library describes to a potential client the services available from a particular server. Each COM components will expose a set of interfaces through which the communication between COM components will occurs.The following diagram shows the communication between a client and a COM object.
Fig.1 Communication between client and a COM object
In the above figure the
IUnknown
and IDispatch
are the interfaces and QueryInterface
, AddRef
, Release
, etc., are the methods exposed by those interfaces.The communication between the .NET objects occurs through Objects, there are no such interfaces for communication. So, in .NET component, there is no type libraries, instead they deal with assemblies. Assembly is a collection of types and resources that are built to work together and form a logical unit of functionality. All the information related to the assembly will be held in assembly metadata. Unlike the communication between COM components, the communication between .NET components is Object based.
Calling COM components from .NET Client
Generally COM components will expose interfaces to communicate with other objects. A .NET client cannot directly communicate with a COM component because the interfaces exposed by a COM component may not be read by the .NET application. So, to communicate with a COM component, the COM component should be wrapped in such a way that the.NET client application can understand the COM component. This wrapper is known as Runtime Callable Wrapper (RCW).The .NET SDK provides Runtime Callable Wrapper (RCW) which wraps the COM components and exposes it into to the .NET client application.
Fig.2 calling a COM component from .NET client
To communicate with a COM component, there should be Runtime Callable Wrapper (RCW). RCW can be generated by using VS.NET or by the use of TlbImp.exe utility. Both the ways will read the type library and uses
System.Runtime.InteropServices.TypeLibConverter
class
to generate the RCW. This class reads the type library and converts
those descriptions into a wrapper (RCW). After generating the RCW, the
.NET client should import its namespace. Now the client application can
call the RCW object as native calls. When a client calls a function, the call is transferred to the RCW. The RCW internally calls the native COM function coCreateInstance there by creating the COM object that it wraps. The RCW converts each call to the COM calling convention. Once the object has been created successfully, the .NET client application can access the COM objects as like native object calls.
Calling .NET components from COM Client
When a COM client requests a server, first it searches in the registry entry and then the communication starts. Calling a .NET component from a COM component is not a trivial exercise. The .NET objects communicate through Objects. But the Object based communication may not be recognized by the COM clients. So, to communicate with the .NET component from the COM component, the .NET component should be wrapped in such a way that the COM client can identify this .NET component. This wrapper is known as COM Callable Wrapper (CCW). The COM Callable Wrapper (CCW) will be used to wrap the .NET components and used to interact with the COM clients.CCW will be created by the .NET utility RegAsm.exe. This reads metadata of the .NET component and generates the CCW. This tool will make a registry entry for the .NET components.
Fig.3 calling a .NET component from COM client
Generally COM client instantiates objects through its native method
coCreateInstance
. While interacting with .NET objects, the COM client creates .NET objects by coCreateInstance
through CCW. Internally, when
coCreateInstance
is called, the call will redirect to the registry entry and the registry will redirect the call to the registered server, mscoree.dll.
This mscoree.dll will inspect the requested CLSID and reads the
registry to find the .NET class and the assembly that contains the class
and rolls a CCW on that .NET class.When a client makes a call to the .NET object, first the call will go to CCW. The CCW converts all the native COM types to their .NET equivalents and also converts the results back from the .NET to COM.
Programming model comparison of .NET-COM interoperability
The following table compares the .NET and COM based component programming models..NET | COM |
Object based communication | Interface based communication |
Garbage Collector to manage memory | Reference count will be used to manage memory |
Type Standard objects | Binary Standard objects |
Objects are created by normal new operator | Objects are created by coCreateInstance |
Exceptions will be returned | HRESULT will be returned |
Object info resides in assembly files | Object info resides in Type library |
Before the application starts to communicate, there are some technical constraints associated with this. When an object is transmitted to a receiver which is in a separate machine/process (managed/unmanaged) space, the object may need to undergo a transformation according to the native type to make it suitable for use by the recipient. That is the object will be converted into a recipient readable form. This process of converting an object between types when sending it across contexts is known as marshaling. The next section of the paper will gives an overview of marshalling in .NET.
.NET Marshalling
Thus .NET runtime automatically generates code to translate calls between managed code and unmanaged code. While transferring calls between these two codes, .NET handles the data type conversion also. This technique of automatically binding with the server data type to the client data type is known as marshalling. Marshaling occurs between managed heap and unmanaged heap. For example, Fig.4 shows a call from the .NET client to a COM component. This sample call passes a .NET string from the client. The RCW converts this .NET data type into the COM compatible data type. In this case COM compatible data type isBSTR
. Thus the RCW converts the .NET string into COM compatible BSTR
. This BSTR
will
be passed to the object and the required calls will be made. The
results will be returned to back to the RCW. The RCW converts this COM
compatible result to .NET native data type.Fig.4 Sample diagram for marshalling
Logically the marshalling can be classified into 2 types.
- Interop marshalling
- COM marshalling
In some scenarios COM component may be running in different apartment threads. In those cases i.e., calling between managed code and unmanaged code in different apartments or process, both Interop marshaler and COM marshaler are involved.
Interop marshaler
When the server object is created in the same apartment of client, all data marshaling is handled by Interop marshaling.Fig.5 Sample diagram for same apartment marshalling
COM marshaler
COM marshaling involved whenever the calls between managed code and unmanaged code are in different apartments. For eg., when a .NET client (with the default apartment settings) communicates with a COM component (whichever developed in VB6.0), the communication occurs through proxy and stub because both the objects will be running in different apartment threads. (The default apartment settings of .NET objects are STA and the components which are developed by VB6.0 are STA). Between these two different apartments COM marshaling will occurs and with in the apartment Interop marshaling will occurs. Fig.6 shows this kind of marshaling.This kind of different apartment communication will impact the performance. The apartment settings of the managed client can be changed by changing the STAThreadAttribute / MTAThreadAttribute / Thread.ApartmentState property. Both the codes can run in a same apartment, by making the managed code’s thread to STA. (If the COM component is set as MTA, then cross marshaling will occurs.)
Fig.6 Sample diagram for cross apartment marshalling
In the above scenario, the call with in different apartments will occur by COM marshaling and the call between managed and unmanaged code will occur by Interop marshaling.
Conclusion
Thus the communication between .NET applications and COM applications occurs through RCW and CCW.As you have seen, COM applications can implement .NET types to achieve type compatibility or a .NET type can implement COM interfaces to achieve binary compatibility with related coclasses.
Although the managed clients can interact with the unmanaged objects, the managed client expects that the unmanaged object should act exactly the same as managed object.
When developing against the unmanaged component through COM interoperability, managed code developers will not be able to use some features of .NET like parameterized constructors, static methods, inheritance, etc., migrating an existing component or writing a managed wrapper will make the component easier to use for managed code developers. In some cases, the developer wants to migrate parts of the application to .NET so that application can take advantage of the new features that the .NET Framework offers. For example, ASP .NET provides advanced data binding, browser-dependent user interface generation, and improved configuration and deployment. The designer should evaluate when the value of bringing these new features in to the application outweigh the cost of code migration.