Consuming .NET Components from COM-Aware Clients'�A Simple Tutorial

Environment: .NET

Sometimes, it's useful to create COM components in C# and access them from unmanaged code (such as C++, VB, and JavaScript). The .NET runtime seamlessly allows unmanaged COM-aware clients to access .NET components through the COM interop. This ensures that COM-aware clients can talk to .NET components.

In this article, we are going to have a C++ client talk to a C# component.

Enter the following small example code into your favourite editor:

using System;
using System.Runtime.InteropServices;

public interface IHelloDotNet 
{

  int GetAge();

}    /* end interface IHelloDotNet */

[ClassInterface(ClassInterfaceType.None)]
public class HelloDotNet : IHelloDotNet
{
  public HelloDotNet()
  {
  }

  public int GetAge()
  {
    return 20;
  }


}    /* end class HelloDotNet */

Please note that the above is only one way to write components in C#. We could actually get .NET to auto generate the interface for the class for us, but the method of manually generating the interface and creating a class which derives from this interface is the best method (if not the most tedious) of creating C# components. Because COM interfaces are immutable, having interfaces auto generated would lead to versioning problems; any class changes would break unmanaged COM clients.

The first thing to note in this C# client is the interop attribute ClassInterface. This is one of many interop service attributes. Note that we set the attribute to ClassInterfaceType.None. This means that no class interface is generated for the class; this is correct because we have manually created our own interface. Going back to having this interface automatically created, we would use ClassInterfaceType.AutoDual. This would create a dual interface for the class and also make typeinfo available to the type library.

Now, to compile the component to a DLL, issue the following from a command prompt:

csc /target:library /out:HelloDotNot.dll HelloDotNet.cs

This generates a .NET assembly that, at the moment, COM-aware clients are clueless about. We need to get some COM-friendly type information from it so that our C++ client will be happy to play around with it. What we need to do is take in a .NET assembly and generate a typelibrary out of it so it is usable from a COM-aware client. The .NET framework provides a couple of tools to do this. We are going to use the RegASM tool; this will register the assembly and generate the type library in one go. Type in the following:

regasm HelloDotNet.dll /tlb:HelloDotNet.tlb

Now, let's get down to consuming this .NET component!

I wrote a quick C++ MFC dialog application to do this, so fire up Visual C++ and create a MFC dialog application, throw a button on the dialog, and create a handler for it. Enter the following code behind the button handler:

::CoInitialize(NULL);

HRESULT hr = spHelloNet.CreateInstance(__uuidof(HelloDotNet));
long Age   = spHelloNet->GetAge();

Simple enough, but where do spHelloNet and HelloDotNet come from?!? Easy, the type library we generated for the .NET component. So, go to the top of your dialog code and enter the following:

#import "HelloDotNet.tlb" no_namespace
IHelloDotNetPtr spHelloNet = NULL;

.NET automatically generated the IHelloDotNetPtr for us. Don't worry about it, just type it in and forget about it.

Okay, almost done. What you need to do now is drop the type library file into your client source area and copy the HelloDotNet DLL into the executable area (example: debug or release folder). We have to do this because we have not made the component shareable. By this, I mean being able to be seen by any application; at the moment it is a private component. Now, slam a break point on the line that reads spHelloNet->GetAge() and run the program. When you step over this line, the result should be 20! Violà; we have called a .NET component from an unmanaged C++ application—groovy!

GAC—Making Our Component Globally Available

I'm getting fed up with copying the type library and DLL across. How can I prevent this? There is a way of registering the component for global use. Yet again, Microsoft has thought of everything. We want our .NET assembly to be used in multiple applications; thus, it must be registered in what is called the Global Assembly Cache (GAC). This applies not only to .NET components used from .NET, but also .NET components used from COM.

Before adding assemblies to the GAC, they need to be strongly named. That sounds strange?! A strong name consists of the assembly identity (name, version, and culture), plus a public key and digital signature. This strong name is used for several reasons—it guarantees the following three things:

  • Uniqueness
  • Version protection
  • Code integrity

The first one of these is the important one. It assures us that no two will ever be the same.

Okay, enough dribble. How do I create this strong name? We use the sn utility, an example of which is shown below:

sn -k HelloDotNet.snk

This generates a key pair and stores it in the file named HelloDotNet.snk. At this point, the assembly knows nothing about the strong name. Let us change that by adding the following line to the C# code:

[assembly:AssemblyKeyFile("HelloDotNet.snk")]

You may need to put the correct path in the above also, to where the .snk file is located.

Now, we need to install the assembly into the GAC. We are going to use yet another utility, called gacutil. Enter the following:

gacutil /I HelloDotNet.dll

That is it; the component is now global and can be used with any application!

I hope this article has been of some use. I've tried not to go into any gritty details, just mainly the bare bones. Any comments and criticisms are welcome.



About the Author

Steve Green

I'm a Software Engineer with a company which writes Diagnostic Applications for vehicles. In my spare time ( what I have of it! ) I love playing Golf and Football and spending as much time as I can with my lovely baby son David.

Comments

  • What alot of crap!

    Posted by Microsoft God on 03/08/2013 02:47pm

    This is not a published paper, it's a forum!

    Reply
  • Great Article!

    Posted by JamesVespa on 05/22/2008 08:54am

    Simple and to the point just what i needed!

    Reply
  • Cool Article

    Posted by Legacy on 11/19/2003 12:00am

    Originally posted by: Bhagyashree

    Hi,
    
    This article was just what I was looking for. I wanted and overview of a >NET Component without much detail.
    Thanks a lot. I have great appreciation for people like you who take the pains of sharing your knowledge globally. I hope you get some benefits by doig this.

    Regards
    Bhagyashree

    Reply
  • For ATL, how to sink .NET events? Thanks.

    Posted by Legacy on 08/23/2003 12:00am

    Originally posted by: Dejun Y.

    For ATL, how to sink .NET events?
    Thanks.
    Dejun Y

    Reply
  • What about .Net windows forms controls???

    Posted by Legacy on 08/01/2003 12:00am

    Originally posted by: Martin

    Can they be called?????

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • With 81% of employees using their phones at work, companies have stopped asking: "Is corporate data leaking from personal devices?" and started asking: "How do we effectively prevent corporate data from leaking from personal devices?" The answer has not been simple. ZixOne raises the bar on BYOD security by not allowing email data to reside on the device. In addition, Zix allows employees to maintain complete control of their personal device, therefore satisfying privacy demands of valued employees and the …

  • Hybrid cloud platforms need to think in terms of sweet spots when it comes to application platform interface (API) integration. Cloud Velocity has taken a unique approach to tight integration with the API sweet spot; enough to support the agility of physical and virtual apps, including multi-tier environments and databases, while reducing capital and operating costs. Read this case study to learn how a global-level Fortune 1000 company was able to deploy an entire 6+ TB Oracle eCommerce stack in Amazon Web …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds