Creating COM Components using Visual C#.NET

Developers are sometimes asked to support older software systems that utilize obsolete technologies. This may be difficult when the development tools used to implement the older software system are not available and have been replaced by newer tools that do not seem to support the former tools’ technologies. Faced with the need to replace a COM component that is used by VBScript in an ASP application, a developer may need to create the replacement using Visual Studio .NET. This guide is motivated at helping developers create COM components using Visual Studio.NET and C#.

Creating the COM Object
  1. Launch Microsoft Visual Studio .NET and create a new Visual C# Project with the Empty Project template. In our example we will create the project and name it “COMTest.” Save the project.
  2. Open a console window and navigate to the project’s folder.
  3. Create a key pair that will be used to sign the .NET assembly with a strong name. [“sn -k key.snk” at the command prompt]
  4. Under Project->COMTest Properties, set the Output Type to Class Library. Output Type is found within General, which is found under Common Properties.
  5. Add a class called “COMObject” to the COMTest project, which will create COMObject.cs.
  6. Add an assembly attribute to COMObject.cs.
    “[assembly:System.Reflection.AssemblyKeyFileAttribute( @”..\..\key.snk” )]”
  7. Generate a globally unique identifier for use with COMObject.
    1. Start guidgen.exe (this should be easily done when opening a console window and entering “guidgen” at the command prompt).
    2. Select the Registry Format option in the guidgen utility, generate a new guid, and copy the GUID.
  8. Use System.Runtime.InteropServices.GuidAttribute to generate an attribute for class COMObject. Pass the GUID as a string to GUIDAttribute, but remove the curly braces that surround the GUID that was copied onto the clipboard.
  9. Create a public member function for COMObject that is named “COMObjectFunction” with the following code:
    public string COMObjectFunction()
    {
    	return "Hello, COM!";
    }
    
  10. Build the solution.
  11. Register the Assembly. [“regasm COMTest.dll /tlb:COMTest.tlb /codebase COMTest” at the command prompt, while in the directory that contains COMTest.dll]
  12. The assembly is now accessible using COM.
Testing the COM Object

Test procedures for the COM object that was created above:

  1. Create a file called “test.vbs.”
  2. Place the following into test.vbs:
    dim o
    set o = createobject( "COMTest.COMObject" )
    Wscript.Echo o.COMObjectFunction
    
  3. Execute test.vbs.

Running test.vbs should cause a MessageBox, which contains the string that was returned by COMObject’s COMObjectFunction, to be displayed.

To be truly a COM component, the developer may need to utilize the DispId and other attributes for the member functions and properties. This mini-howto was written to meet the immediate need of replacing a COM component used by VBScript ASP applications. The components created through this mini-howto may not work in environments that do not have the .NET framework installed, or they may not work with applications that use the IUnknown and IDispatch methods.

Questions, comments, and responses are welcomed and appreciated.

46 Responses to “Creating COM Components using Visual C#.NET”

Newer Comments »
  1. Chinnu Says:

    Excellent Article…Very Easy to Understand, self explanatory

  2. sunil Says:

    this article copy to another article.It is very bad….

  3. Steve Says:

    Hi Sunil,

    I’m actually kind of offended that you would think that this article is a copy of another, since it took me time to record and validate the procedure I provide above. I’ve even included source material, which I used to construct this article, under “References.” Maybe, there is some confusion, and other people may have duplicated the quality content that I have written and present on my blog.

  4. dror Says:

    Hello.
    I cannot make this work.. as much as i tried and followed your instrucations which are great btw!

    I am using Visual Studio 2005 C# .. it seems the this article was written in Visual Studio 2003, but i managed to over come the changes (or not)

    I receive the error: “ActiveX component can’t create object: COMTest.COMObject”

    If you know way i will be glad to hear ..

  5. dror Says:

    ha, now it is working..
    I add to add public to the “class COMObject” -> “public class COMObject”
    Strange, i thought by default it is public.
    Also using [assembly:System.Reflection.AssemblyKeyFileAttribute( @”..\..\key.snk” )] in visual studio 2005 generates an Warrning, but it works..

    thanks.

  6. Steve Says:

    Thanks dror for pointing out the problem with the class’s scope. It seemed to generate the new class of the COMTest namespace with public specified. I’m glad the quick howto worked out okay for you.

  7. claude Says:

    everything working for me now (initially the regasm.exe being called by default was the one from 1.1 framework so I ran into couple problems… after I used the one from 2.0 everything was fine)

    one problem remains though, in ASP when I try to instantiate my object I get an error: Server.CreateObject Failed … Invalid class string

    my vbs file works fine though, and in both I am using the same ProgID… any idea?

  8. Steve Says:

    You’ll want to check whether or not the desired .NET framework is running under your web server. Also, you’ll want to determine if the script has the proper permissions to create an instance of the class.

  9. claude Says:

    the right .NET framework is running, 2.0.50727

    as for permissions I granted the IUSR user full access to the folder where I register the DLL from as well as every registry entry that was related to my COM components… I also did a reset of child permissions when doing these just in case

    I restarted my computer and IIS many times…

    what else?

  10. claude Says:

    FYI I am running Windows XP Pro with IIS 5.1

  11. Steve Says:

    I’ll have to investigate the problem further over the weekend. :)

  12. claude Says:

    I thought it was because I was trying to register a COM written in C#… Now I am creating simple COM using VC++ and I am getting the same problem, my .vbs file are working fine, but I can’t get IIS to recognize my class… i am getting the same error…
    Server.CreateObject Failed … Invalid class string

    I feel I’ve tried everything (third day of trying now….) I’ve even tried adding the users “anonymous” and “everyone” to the local Administrator group, I tried granting permissions to users IUSR, anonymous, everyone, etc… to all the registry keys related to my ProgID, nothing works, it’s driving me insane… most of my experience as software developer is with .NET, TSQL and classic ASP…. I never had to create COM components so now I feel so stupid lol

  13. Karthik Says:

    Good tutorial, works good. Thanks for the article.

  14. Stif Says:

    Hi

    I’m experiencing problems calling a third party dll from within my COM component. Short (as short as possible) scenario: I’ve made a Business and DataLayer using NHibernate and Castle.Windsor (both layers are NOT comvisible). To call these layers from a vbscript or ASP I’ve made a COM object wrapping the methods offered by the business layer (BL). First I experienced problems with configuration. The contructor for the main BL class instantiates a WindsorContainer (for Dependency injection) which looks in the configuration file for a custom configuration section. Because wscript.exe is the actual application calling the COM dll .NET started looking for Wscript.exe.config. I’ve managed to override this setting, with this line AppDomain.CurrentDomain.SetData(“APP_CONFIG_FILE”, “ZebraZone.Toolset.Service.dll.config”);. But now, when I try to create the third party objects (like the WindsorContainer) .NET cannot find the correct dll (though it resides in the same dir as the COM dll). Putting the third party dll in c:\WINDOWS\System32\ (same dir as wscript.exe) solves this problem. But that is not a workable solution. I want to tell .NET to go looking for referenced dll in a folder of my choice, how do I do that? I’ve already tried stuff like this: AppDomain.CurrentDomain.SetData(“APPBASE”, “c:\\Visual Studio Projects\\ZebraZone\\COMTest\\COMTest\\bin\\Debug\\”); or replacing APPBASE by RELPATH, PRIVATE_BINPATH, CACHE_BASE, DYNAMIC_BASE, SHADOW_COPY_DIRS. Nothing helps, I’m getting desperate…
    Grtz
    Stif

  15. Danny Says:

    Hi Steve and mates, i am not sure if this is the roght place to put ina question… but kindly help me…
    i have a situation, i have a classlibrary/dll created in c# .net, with few methods. I need to make this as a activex or a ocx to make it available as a natural COM component and not a .net assemby. So that i can use it in one of my delphi application.
    any idea would be highly appreciated and helpful…
    also, is there any way to write c# code and compile it other than
    using .net..
    thanks and regards,
    Danny

  16. Scriptor Says:

    I had a lot of problems getting this to work, because step 1.) says create and Empty project. But you should choose Create a Class Library.

    Also step 6. is easier to handle when you have the properties folder in your project (via Create Class Library), right click to open and go to signing and set the key.snk there.

    Also be sure that you are using the Visual Studio Command Prompt, not the regular Windows Command prompt, otherwise it won’t recognize the build commands.

  17. Steve Says:

    I believe I wrote this up on a previous version of Visual Studio .NET, but I hope you were able to accomplish what you needed. Thanks for the feedback.

  18. Scriptor Says:

    I did get it to work, but then I tried to make a change and rebuilt the dll and now I only get “Server object error ‘ASP 0177 : 800401f3”. I am going through the steps again. This is the most comprehensive article I can find out there, great job…

  19. Scriptor Says:

    Ok, I figured it out. With my version of visual studio 2005,
    1.) Create a new Project Class Library
    2.) Create a key pair
    3.) A Properties folder with an AssemblyInfo.cs file was created right click on the folder and open properties. The default should be ‘Class Library’
    4.) Goto the signing tab and check Sign the assembly, browse and point it to the ‘key.snk’ file.
    5.) open the AssemblyInfo.cs , add [assembly: AssemblyKeyFileAttribute(@”..\..\key.snk”)]
    6.) in the AssemblyInfo.cs set [assembly: ComVisible(true)], now copy the assembly GUID that was auto created with the file.
    7.) put [System.Runtime.InteropServices.GuidAttribute(“paste guid here”)] in your main class file in between the Namespace and Class.

    ..continue with step 10 above…

    When building and regasm you get warnings but it works perfect in classic ASP VB Script.

  20. DotNet Says:

    well done to both the author and Scriptor. But I need to point out that in Scriptor’s step list, instead of copying the GUID from AssemblyInfo.cs, we should use guidgen.exe to generate a new GUID as described in the step7 in the author’s list. Otherwise, you get the following error when execute regasm /tlb:COMTest.tlb in the CP:

    RegAsm : error RA0000 : Type library exporter encountered an error while processing ‘COMTest.COMobj, COMTest’. Error: Element not found.

Newer Comments »

Leave a Reply