|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionA few days ago, an article by Muhammad Musa Ali on Exposing COM interfaces of a .NET class library for Late Binding, appeared on Code Project to show all you VB guys how to create a class that can be used for interop with the world outside, i.e., inside a non-.NET client such as VB, VBA, JScript, ... Being more of a C# guy myself, I was astounded that there is such a thing as a COM class wizard for VB.NET class libraries but not for C#. Something had to be done to correct this injustice ;-), and here it is: a COM class wizard for C# class libraries. How to expose a class for COM interop (the C# way)Muhammad depicts two ways to expose a class for COM interop: the easy way and the hard way. The easy way is what VS.NET does when you let it create a COM class using the wizard. Basically, three GUIDs are created: for the class itself, the COM-visible interface this class implements, and for the events the class fires. These three GUIDs are stuffed into a Until that day, I had heard nothing about So, using this attribute in your C# classes might be possible if you add a reference to So, I tried the hard way: telling the compiler what to do by defining all the interfaces and attributes myself. There's a pretty exhaustive article on this topic on Code Project as well (Understanding Classic COM interoperability With .NET Applications), so I just depict the important steps: Define an interface you want to expose to COMCOM is interface based, so your class has to tell COM what methods and properties it is going to expose. Create your class and let it implement this interfaceSomebody has to do the actual work, so implement the interface and fill your methods and properties with life. Define an interface for events you want to raiseIn case you want to raise events for COM clients, these events (or rather event handlers) have to be declared in the form of an interface as well. Luckily, you won't have to dig very deep into COM's event model or handle ConnectionPoint details, the framework does this for you. Plug everything together using class attributesThis is where the internal plumbing happens. Tell the framework that your class exposes an interface for COM by assigning GUIDs, using [ComSourceInterfaces(typeof(IComClassEvents))]
Another important thing to do is to add a I'm inherently lazy, can't someone do this for me?These steps shown above are quite error-prone if you have to do them by hand every time. VS.NET has the concept of wizards to create code, so why not use it? To counter the VB.NET advantage of the COM class wizard, I dug a little into how these wizards work and how you could add your own wizard. Once you found the right files to change, this was quite easy. Without going into too much detail, most of the wizards creating a class for you use a template file containing most of the code the final class will contain. This template then is copied and modified by a JavaScript script to insert the correct class or namespace names, for example. Additionally, project options can be modified as well (I used this to set the "Register for COM interop" flag to true in a class library receiving such a new COM class). For example, the template for my new C# COM class has a class declaration like this: public class [!output CLASS_NAME] : [!output INTERFACE_NAME]
The parts in brackets are then replaced by variable values you create as part of the JavaScript file, resulting in a valid class declaration, provided you specify the right arguments: public class ComClass1 : IComClass1
Can I have this, too?To try it out yourself, just use the link to the installation package I've added at the top of this article. It's an MSI package that's searching for the path of your VS.NET 2003 installation, and then installs the new wizard. After installation, you can use a new template COM-Class in a C# class library project. DISCLAIMER: Although I've tested the package on my computers, I cannot make any guarantees that it will work on your machine or that it will not harm your computer in any way. If you install the package and your computer blows up afterwards, I cannot be held responsible! The installation package should work on German and English installations of VS.NET 2003. If you have a different language installed, then you might have to create copies of the template files and script in the corresponding subdirectory for your language code. The wizard files can be found at <VS.NET 2003 Root>\VC#\VC#Wizards\CSharpComClass with subdirectories 1031 (German) or 1033 (English) in the Scripts and Templates subdirectories, resp. I've also included the class template, JavaScript file, and wizard definition files (*.vsz and *.vsdir) as "source" for this article (link at the top), so if you don't trust my installer (or in case it doesn't work for you), you can use these files to add the new template by yourself. ConclusionIf you follow the steps, then COM interop isn't really that hard. Just keep in mind that the environment you test your classes in also has its influence on the results. I spent almost a whole weekend wondering why the event fired by my test class (several seconds after one of my class' functions was called) was received in a scripting environment but (seemingly) not in a VBA client, although everything else worked. Finally, I found out that the object I wanted to receive the event had been destroyed before the event was raised :(. And don't forget to vote if you like this article and the new wizard! Version history
Happy coding, mav
|
||||||||||||||||||||||