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.

References: Using your C# Components in Visual Basic through COM, Signing an Assembly with a Strong Name

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

  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.

  21. Vid Says:

    Hi..i am getting an error “Activex cannot create Com object” when i run the vbscript file.Can u please help me..

  22. Vid Says:

    I followed exactly the same steps u have given.

  23. taKing Says:

    This was really helpful. Reading everything I could find on the subject in MSDN twisted my brain into odd shapes. Walking through this helped to define a path for further exploration. Thanks!

    I did have difficulty using the object with Javascript in an HTML page. I’d get the error “Automation server can’t create object”. The VBscript ran fine, though. Turned out, needed to change a setting in Internet Explorer (7) – Tools, Internet Options, Security, Custom Level. Under the ActiveX Controls and plug-ins section, once I changed “Initialize and script ActiveX controls not marked as safe for scripting” to Enable, it worked. Probably not such a nifty setting to keep, though.

  24. G.senthil Says:

    Dear Friend,

    Really it’s good article. i have few doubt,

    1. how to update the dll files

    2. how to unregister the dll files

  25. Prasad Says:

    I need to .NET component other that .NET application such as MS excel or MS word? is it possible? if yes then how. Thanks in advance

  26. Victor Says:

    Hi
    Excelent Article. but I still have a problem
    I import the tlb type library in Delphi7, but the component only have the class BUT with out any method. the usless class.

    What am I miss?
    some body have a c# projet to compare and find out where are the diferences

  27. Joby Says:

    nice one :)

  28. Qian Says:

    nice work! thank you all Steve and Scriptor…

  29. Eli Jones Says:

    About your step #11 for invoking regasm.exe – understand it will only register the components for use on 32-bit processes. For it to be accessible from 64-bit processes, you need to use %SYSTEMROOT%\Microsoft.NET\Framework64\v2.0.50727\RegAsm.exe

  30. svincoll4 Says:

    So great !! It worked.

  31. John Amarsingh G Says:

    Nice article.

    Easy way of explaining….

    Keep it up..

    You can also give an example which can be downlodable….

  32. ????? ????? Says:

    you can also use it with PHP .
    samething almost , but it needs to run in wondows only ofcourse
    MethodName(with_params);
    ?>

  33. prayags Says:

    Thanks Steve.

    I would advise anybody trying this to first read the whole text by Stever and then follow the instructions by “Scriptor”.

  34. Toni Greco Says:

    To not have warning for [assembly: …] delete this line and set the snk file here:
    right click on project -> property -> tab sign -> check “Sign assembly” -> in combobox set file name.

    I use VS 2010, all work.

  35. sree Says:

    superb

  36. john Says:

    I tried this example using Visual Studio 2010. It all works except for the last step:

    U:\My Documents\Visual Studio 2010\Projects\ComTest\ComTest\bin\Debug>regasm Com
    Test.dll /tlb:COMTest.tlb /codebase COMTest
    Microsoft (R) .NET Framework Assembly Registration Utility 4.0.30319.1
    Copyright (C) Microsoft Corporation 1998-2004. All rights reserved.

    RegAsm : error RA0000 : Could not load file or assembly ‘file:///U:\My Documents
    \Visual Studio 2010\Projects\ComTest\ComTest\bin\Debug\ComTest.dll’ or one of it
    s dependencies. Operation is not supported. (Exception from HRESULT: 0x80131515)

  37. Vinícius Says:

    TKS A LOT! Worked perfectly!

  38. Sagar Says:

    I tried this example using Visual Studio 2010. But getting error
    “ActiveX component can’t create object: COMTest.COMObject”

  39. Anonymous Says:

    thanks this is working

  40. Martin Says:

    Thanks this is working with the change “class COMObject” -> “public class COMObject”

  41. Priyank Says:

    thanks. It’s working.
    I had one problem…..
    This was the error.
    RegAsm : error RA0000 : Error occurred while registering exported type library…………..

    I tried running command prompt under administrator, and it worked.. :-)

  42. Graham Says:

    Did it in VS C# Express – here are the things that are a little different:

    drop the assembly attribute, instead select “Signing” in project properties, check “Sign the assembly” and browse to your key.snk

    I had to add the path to sn.exe and guidgen.exe to my path environment variable before using cmd

    I had to run cmd as administrator to get regasm to work

    I tested it in classic asp like so:
    JScript:

    VBScript:

    Great article – just what I was looking for and I have barely ever used C# and VS so had to google how to do a couple of things that your instructions assumed I knew.

  43. tirumudi Says:

    Great work.. Understood the basics of creating COM with your simple and elegant article. thanks STEVE !

  44. Rmt Says:

    I developed the class library as explained. but while importing this library from Delphi 5, I am getting list of errors in mscorlib_TLB. Any suggestion would be highly appreciated.

  45. Pablo Mauricio Says:

    I was scared to dead after my boss asked to develop a COM component to be called from .Net and an old version of InstallShield which uses vb script. I had no idea where to start. Afar reading this article I now know exactly what to do, than you Steve.
    I would think that the .Net app can continue to call compiled dll (just to use new technology) and the vb script can call the COM component created. Since the source is the same maintenance should not be a problem.

    STEVE!! …MY QUESTION IS, can I develop this in framework 4.5 and assume that the regasm registration will translate it to COM correctly? The reason why I am asking is because we cannot assume that the server where the COM component will be deployed in the customer has framework 4.5 (we do know that they have 2.0).

  46. Mohit Says:

    Great tutorial.. I have one question.. component created using procedure mention above.. will it get the advantages of Garbage Collector?
    Thanks Steve

  47. Madhuri Says:

    .tlb has been generated in the COM components instead of .dll.

Leave a Reply