C# Classes as COM Objects


COM Interoperability is the feature of Microsoft .Net that allows managed .Net code to interact with unmanaged code using Microsoft's Component Object Model semantics. Most of the hoopla about COM Interoperability in .NET centers on the ability of .Net code to invoke legacy COM objects (such as ActiveX controls and COM objects encapsulated in DLLs).

But there exists the equally powerful and useful ability to develop new components in .Net and make those components accessible to unmanaged code as COM objects. That is the side of COM Interoperability that we discuss in this article.

This article assumes that the reader has a basic familiarity with COM and .Net terminology.

.Net Interfaces and Classes

The basis for accessing .Net objects either from other .Net code or from unmanaged code is the Class. A .Net class represents the encapsulation of the functionality (methods and properties) that the programmer wants to expose to other code. In C++, classes supported multiple inheritance from other classes. .Net doesn't support multiple inheritance, but does support implementation of multiple interfaces. A .Net interface is the abstract declaration of the methods and properties that classes which implement the interface are expected to provide in their implementations. Declaring a .Net interface doesn't generate any code, and a .Net interface is not callable directly. But any class which implements ("inherits") the interface must provide the code that implements each of the methods and properties declared in the interface definition.

Example 1: C# Interface and Class Definitions

interface IDotNetInterface
{
void Initialize();

string Caption
{
set;
}

int ShowDialog(string sText);
}

class DotNetClass : IDotNetInterface
{
// Need a public default constructor for COM Interop.

public DotNetClass()
{
}

public void Initialize()
{
m_sCaption = "";
}

public string Caption
{
set { m_sCaption = value; }
}

public int ShowDialog(string sText)
{
System.Windows.Forms.MessageBox.Show(sText, m_sCaption);
}

private string m_sCaption;
}

Although a .Net class is not directly invokable from unmanaged code, Microsoft has provided the capability of wrapping the .Net interface in an unmanaged layer of code that exposes the methods and properties of the .Net class as if the class were a COM object. There are two requirements for making a .Net class visible to unmanaged code as a COM object:

Requirement 1: Creating a Description of the COM class and Interfaces

For a client of a COM object to have access to the object, the client needs a description of the object — how to locate it and how to call its methods and properties. For a "real" unmanaged COM class, this description is available in the form of a Type Library — a binary description of the GUIDs, classes, and interfaces (methods, properties, and parameters) that the COM class supports.

.Net assemblies don't include information in Type Library compatible format. So it is necessary for the programmer to run one of two .Net-supplied utilities to extract the assembly description of a class into a Type Library file. One utility is TLBEXP.EXE, the .Net Type Library Exporter. This command line utility takes as input the name of an assembly DLL file to be converted to a Type Library. The programmer can also specify the name of a Type Library file to be created.

Example 2: Using TLBEXP to create a Type Library from an Assembly

tlbexp ComServer.dll /out:ComServer.tlb

Assembly exported to C:\Magellan\Source\Output\Debug\ComServer.tlb

Once a Type Library has been created, it can be referenced by a COM client to obtain the information necessary for the COM client to bind to the interfaces of the COM class, and activate the COM class at runtime.

Another command line utility for creating a Type Library from an assembly is REGASM.EXE, the .Net Assembly Registration utility. In addition to creating a Type Library, this utility also creates the Windows Registry entries necessary for making the assembly visible as a COM object to clients (see below).

Requirement 2: Registration of the COM Class and Interfaces

For a COM class to be accessible by the client at runtime, the COM infrastructure must know how to locate the code that implements the COM class. COM doesn't know about .Net classes, but .Net provides a general "surrogate" DLL – mscoree.dll — which acts as the wrapper and intermediary between the COM client and the .Net class.

Example 3A: Registering an Assembly for COM Interop

regasm ComServer.dll

Example 3B: Registering an Assembly for COM Interop and generating a Type
Library

regasm ComServer.dll

Note that there is also a property in the Project Properties for a .Net class library DLL called "Register for COM Interop". Setting this property to True instructs the IDE to automatically register the assembly for COM Interop each time you build it, so you don't have to perform this step manually.

Accessing a .Net Class from Unmanaged Code

There are several ways to access a .Net class from unmanaged code. Following is a C++ example. Note that this example uses the #import directive to specify the exported .Net Type Library to use for extracting description information for the .Net class. This example also uses the ATL Smart Pointer template (CComPtr) to make creating and managing the lifetime of a COM object easier and more automatic.

Example 4: C++ Client Code for Accessing DotNetClass

#include <windows.h>
#include <atlbase.h>
#include <atlcom.h>

#import "ComServer.tlb" raw_interfaces_only

void main()
{
CComPtr<idotnetinterface> srpDotNet;

srpDotNet.CreateInstance(CLSID_DotNetClass, CLSCTX_ALL);

HRESULT hr = srpDotNet.Initialize();
if (SUCCEEDED(hr))
{
hr = srpDotNet.put_Caption(L"Client");
hr = srpDotNet.ShowDialog(L"Hello from the Client");
}
}
</idotnetinterface></atlcom.h></atlbase.h></windows.h>

To access a .Net class from VB6 code, you would, in the VB6 IDE, do the following:

- Select (References) menu. Browse to location of exported .Net Type Library. Select that Type Library.

- Now write code that accesses the class. You should find that the IntelliSense feature of VB6 can provide you hints of the methods and properties available for any instance of the .Net class that you declare in your code.

Summary

There is a lot more to COM Interoperability and taking advantage of managed-unmanaged code interaction than was presented here, but this article has attempted to make the programmer aware of the capability for developing reusable .Net code and class libraries that can be invoked from both managed and un
managed code.

<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,19,0" width="468" height="60"><param name="movie" value="/banners/Ad2.swf?clickTAG=http://www.red-gate.com/products/ants_profiler/index.htm?utm_source=chelp%26utm_medium=banner%26utm_content=vsmenu%26utm_campaign=antsprofiler" /><param name="quality" value="high" /> <embed src="http://www.csharphelp.com/banners/Ad2.swf?clickTAG=http://www.red-gate.com/products/ants_profiler/index.htm?utm_source=chelp%26utm_medium=banner%26utm_content=vsmenu%26utm_campaign=antsprofiler" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" width="468" height="60"></embed> </object>

Related Articles :

Twitter Digg Delicious Stumbleupon Technorati Facebook Email

No comments yet... Be the first to leave a reply!