Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / VB

.NET Appications Automation

2.67/5 (4 votes)
22 Jul 20072 min read 1   468  
An article on creation automated interface for .NET applications.
Screenshot - netappauto0.jpg

.NET test driver for automated application VB6 test driver for automated application

Introduction

By integration of application it's often possible to archive more functionality with less cost than implementing all of it in single application. There are a lot of existing applications, which are created for COM platform. They are still in heavy use, but current tendency on Microsoft Windows is migration to .NET as development platform. So arises task of integration of existing COM-applications with new applications being developing with .NET.

There is good sample of application automation in COM world: Microsoft Excel. It's possible to run the application as standalone full-fledged application, but also to control it from outer script.

Working on integration between .NET and Visual Basic applications there is arisen idea to use similar mechanism to allow obligatory integration between two applications created with two different frameworks. It's known that .NET platform provides tools for calling it from COM and vise-versa. But attempt to find analogue for Visual Basic ActiveX-exe in .NET world was not successful. By finding some clue on starting application by manual loading assembly and using Reflection was found the way to implement required integration ability.

To investigate the possibility was created presented in the article prototype.

Proof of concept prototype

The common architecture of the solution is next:

Architecture of the prototype

The core of the integration is interface library: it exposes application interface to clients and provides factory to load the automated application.

C#
// FILE: IControllableApp.cs
// automation interface exposed to COM

namespace icontrollable_app
{
    [Guid("63B13299-D126-488f-8CCD-807C00456EDB")]
    public interface IControllableApp
    {
        void Start();

        void Finish();

        void AddLine(string line);
    }
}

// FILE: ControllableAppFactory.cs
// automation application factory

using System;
using System.Reflection;
using System.Runtime.InteropServices;

namespace icontrollable_app
{
    [ClassInterface(ClassInterfaceType.AutoDual)]
    [Guid("027BD25E-DDA9-4152-9430-59EC342347B4")]
    [ProgId("ControllableApp.ControllableAppFactory")]
    public class ControllableAppFactory
    {
        /// <summary />
        /// for access from COM
        /// </summary />
        /// <param name="appPath" />path to exe assembly.
        /// NOTE: dependend assemblies must be availble 
        /// in search path.</param />
        /// <returns /></returns />
        public IControllableApp CreateApp(string appPath)
        {
           return ControllableAppFactory.Create(appPath);
        }

        [ComVisible(false)]
        public static IControllableApp Create(string appPath)
        {
            Assembly assembly = Assembly.LoadFile(appPath);
            Type t = assembly.GetType("controllable_app.AppMainForm");
            Object instance = Activator.CreateInstance(t);
            IControllableApp app = (IControllableApp)instance;
            return app;
        }
    }
}

The automated application must have the class that implements exposed automation interface. The simplest way to do it is implementation of the interface by main form.

C#
//FILE: AppMainForm.cs

namespace controllable_app
{
    public partial class AppMainForm : Form, IControllableApp
    {
        public AppMainForm()
        {
            InitializeComponent();
        }

        #region IControllableApp Members

        public void Start()
        {
            this.Show();
        }

        public void Finish()
        {
            this.Hide();
        }

        public void AddLine(string line)
        {
            listBox1.Items.Add(line);
        }

        #endregion
    }
}

Access from both .NET and Visual Basic clients performed through interface library. Simplest way to do it from VB6 - use late binding to access factory and automated application.

C#
//FILE: TestDriverForm.cs

namespace net_driver
{
    public partial class TestDriverForm : Form
    {
        IControllableApp m_app = null;
        public TestDriverForm()
        {
            InitializeComponent();
        }

        private void btnFinish_Click(object sender, EventArgs e)
        {
            if (m_app != null)
            {
                m_app.Finish();
                m_app = null;
            }
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            const string PATH = @"..\..\..\controllable_app\bin\Debug\controllable_app.exe";
            string test_app_path = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), PATH);
            m_app = ControllableAppFactory.Create(test_app_path);
            m_app.Start();
        }

        private void btnAddLine_Click(object sender, EventArgs e)
        {
            if (m_app != null)
            {
                m_app.AddLine(textBox1.Text);
            }
        }
    }
}


'FILE: Form1.frm

Private m_app As Object

Private Sub btnFinish_Click()
    If Not m_app Is Nothing Then
        m_app.Finish
        Set m_app = Nothing
    End If
End Sub

Private Sub cmdAddLine_Click()
    If Not m_app Is Nothing Then
        m_app.AddLine txtLine.Text
    End If
End Sub

Private Sub cmdStart_Click()
    Dim factory As Object
    Set factory = CreateObject("ControllableApp.ControllableAppFactory")
    Dim appPath As String
    appPath = App.Path + "\..\controllable_app\bin\Debug\controllable_app.exe"
    Set m_app = factory.CreateApp(appPath)
    Set factory = Nothing
    m_app.Start
End Sub

Benefits

The proposed approach has several benefits:
  • Accessibility to automated application both from COM and .NET clients.
  • Migration to .NET platform without loosing existing functionality.
  • Possibility to independly create separate parts of the system.
  • Possibility to gradually update old applications with reworked .NET versions.

Visual Studio 2005 specific

VS2005 have one quirk related to exposing .NET to COM. After application of required attributes to classes and interfaces it need to open AssemblyInfo.cs and manually modify next line:

C#
[assembly: ComVisible(true)]

Without this line all attempts to access COM interfaces will be unsuccessful.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here