Peter's Gekko

Sponsors

The Lounge

News

Advertisement

Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
Turn a .NET winforms application into a (COM) automation server

As a start to the next 2 years of blogging I want to look back on an "ancient" technology : COM, which is still the glue between software parts created with a great diversity of tools. COM brought me to .NET, exploring the world of COM in Delphi I discovered the .NET 1.0 betas. Never to leave again.

COM support in .NET is good. You can make your .NET code accessible to any COM client (for instance VBscript) by setting the "Register for COM Interop" property in a project.

Having done that all the public classes in your assembly are available as COM server classes. Public methods and properties are exposed as COM callable methods and props. You can finetune this by setting the ComVisible attribute on a class or method

using System;
using System.Runtime.InteropServices;

namespace MyAutomationLibrary
{

   [ClassInterface(ClassInterfaceType.AutoDual)]
   [ProgId("MyComClass.Test")]
   public class MyComClass
   {

      [ComVisible(false)]
      public void MyNonComMethod()
      {

This makes building COM servers with .NET a snap.

But there is one huge drawback: you can register only a dll for COM interop. And not an exe like a WinForms application. Making a Winforms application (COM) automatable requires a little work on the architecture of your app.

  • Creat a windows forms application
  • Add a class library to the solution
  • Add System.Windows.Forms to the references of the lib
  • Add a form to the class library
  • Add the classlibrary to the references of the winforms app
  • Delete the main form of the windows app
  • Add a new class to the winform application

Your solution should now look like this

By deleting the mainform from the windows app we have also removed the entry point of the application. By default on startup a .net executable searches for a static main method. VS generates this method for you in the mainform. The new entry point will now be in the MainClass.

using System;
using System.Windows.Forms;

namespace MyAutomatableWinformApp
{

   public class MainClass
   {

       [STAThread]
       static void Main()
      {
         Application.Run(new MyWinFormClassLibrary.MainForm());
      }

   }
}

It does exactly the same as the original main method, but it creates a form which is housed in the class library instead of the exe itself. Now you still have your winform app and have moved all “real” code into a class library.

The next step is to make the application automatable. Add a new class libary to the solution and register it for COM interop. The library references the windows form class library and System.Windows.Forms. The Show method of the COM class will fire up the mainform found in the MyWinFormClassLibrary. Just creating the form and running it, like the Main method did, has one problem: the method will not return to the calling COM client untill the application has stopped running the mainform. That is when the winform app has terminated. To circumvent this the form has to be started in a separate thread. Given the great threading support in .NET this no big deal either.

using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;

[ClassInterface(ClassInterfaceType.AutoDual)]
[ProgId("MyWinComServer.Test")]
public class MyComClass
{

   private void formThread()
   {
      Application.Run(new MyWinFormClassLibrary.MainForm());
   }

   public void Show()
   {
      Thread t = new Thread(new ThreadStart(formThread));
      t.ApartmentState = ApartmentState.STA;
      t.Start();
   }

}

The actual code to run the mainform is in the private formThread method. Which is wrapped up in a ThreadStart delegate. A more detailed article on threading in winforms is here.

This snippet of VBscript will test your code

set o = CreateObject("MyWinComServer.Test")
o.Show()
msgBox("Click to stop")

It creates the mainform. You can toy around with that until you click the script-messagebox. Which will terminate your main app.

As the thread in the server interacts with the UI you have to set the thread’s appartmentstate to STA. Another thing to watch out for is when you want to access the form from other methods in your COM class. You will cross a thread boundary and have to Invoke methods and properties on the form. More details are in this article.

That should do the trick. Of a very great value was this blogpost by Rick Strahl on automating winforms in general. This result is just a couple of lines code but .NET is doing some very powerfull things here. More than enough to get you into trouble, so feel free to chime in.

 


Posted 06-03-2005 2:18 AM by pvanooijen
Filed under:

[Advertisement]

Comments

Sam wrote re: Turn a .NET winforms application into a (COM) automation server
on 06-03-2005 6:19 AM
Very nice writeup!
Adrian wrote re: Turn a .NET winforms application into a (COM) automation server
on 12-26-2006 11:01 AM

I'm new to the .NET stuff.  Does this describe how to convert a Winforms application to an ActiveX control?  If not, how would I go about doing that?

Also, what do you mean when say to "Add a class library to the solution?"

Thanks in advance :)

Adrian wrote re: Turn a .NET winforms application into a (COM) automation server
on 12-26-2006 1:41 PM

Never mind about how to add a class library to the solution--I figured out what you meant.

I created a solution based on your instructions, but apparently the COM component that this creates does not have the same interface as an ActiveX control.  Trying to view an ActiveX control with the ProgID I specified fails.

How does one go about creating an ActiveX control from a WinForm (preferably in C#)?

Thanks in advance.

Adrian wrote re: Turn a .NET winforms application into a (COM) automation server
on 12-26-2006 3:24 PM

I guess what I was trying to do is described at http://www.codeproject.com/cs/miscctrl/exposingdotnetcontrols.asp

I didn't realize that the 'control' could consist of multiple items.

pvanooijen wrote re: Turn a .NET winforms application into a (COM) automation server
on 12-27-2006 12:39 PM

Glad yu found your way around. A windows form is also a control on itself. So you can turn every winform into an (embedable) ActiveX control.

Add a Comment

(required)  
(optional)
(required)  
Remember Me?