This post originated from an RSS feed registered with .NET Buzz
by Peter van Ooijen.
Original Post: Turn a .NET winforms application into a (COM) automation server
Feed Title: Peter's Gekko
Feed URL: /error.htm?aspxerrorpath=/blogs/peter.van.ooijen/rss.aspx
Feed Description: My weblog cotains tips tricks and opinions on ASP.NET, tablet PC's and tech in general.
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.
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 {
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.