Click here to Skip to main content
15,867,308 members
Articles / Programming Languages / Visual Basic
Article

Dynamically adding ActiveX controls in managed code

Rate me:
Please Sign up or sign in to vote.
4.71/5 (21 votes)
28 Jun 2005CPOL4 min read 187.1K   4.1K   54   30
A technique for dynamically adding ActiveX controls to managed code.

Introduction

Visual Studio .NET provides a way for developers to easily add (unmanaged) ActiveX controls to C# or VB.NET forms. However, there are times when you need to add these controls dynamically using code. I was recently presented with exactly this problem and despite searching the usual internet resources for a simple solution, all I could find was questions - no real answers.

I needed to port a suite of ActiveX controls that plug-in into a GUI framework using only their ProgID as a reference into a new .NET GUI framework. The plug-in approach used for the GUI framework was used so new controls could be easily added without the need for the GUI framework code having to change. A manager asks the framework to provide a container window and tells it what the ProgID of the contained control is. This de-coupled approach using just a control reference (in this case the ProgID) is a well used technique in plug-in architectures.

Although Visual Studio allows this to happen at design time by adding a reference or a control to the toolbox, these can't really be used dynamically using code.

Hosting an ActiveX control on a Windows form

Back in the good (bad) old days of VB6, dynamically creating controls on a form was easy. Whether a simple control or some ActiveX control, you just create an instance using CreateObject and add the control to the form's control collection. In a managed environment things are a bit more tricky. You can't just host the ActiveX control on the form because you're trying to run an unmanaged component on a managed form.

Fortunately, Microsoft has helpfully provided a runtime callable wrapper (RCW) class to simplify things - System.Windows.Forms.AxHost. Regardless of whether you are using C# or VB.NET, in a managed environment, Windows Forms can only host Windows Forms controls. All Windows Forms controls are classes that are derived from the System.Windows.Forms.Control class. To host an ActiveX control on a form, it must look like a Windows Forms control from the form's viewpoint and an ActiveX container from the ActiveX viewpoint. This is exactly what the System.Windows.Forms.AxHost class wrapper does. It also exposes the ActiveX methods, properties and events.

This is all well and good and Visual Studio does this under the hood when you add a reference to the control or use the aximp.exe command line tool. However, it's no direct use to us when we want to write code to dynamically instantiate and use ActiveX controls on a form. Clearly we need to do what AxHost does but without having to rewrite it. As it turns out, the solution is pretty straightforward. Although AxHost is an abstract class (Must Inherit if you're currently speaking VB.NET) we can use it to do all the work for us.

If you haven't used aximp.exe before MSDN can explain all.

Use the Source, Luke!

The C# AxForm class below shows how you might implement dynamic ActiveX hosting using the AxHost runtime callable wrapper class. As I said earlier, this is an abstract class, so the AxControl class has been introduced. It simply takes a ProgID as a string in the constructor and passes this onto the AxHost constructor. This is used in the InitializeComponent method to create the wrapped control using the AxControl class.

C#
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.Resources;

namespace AxForms
{
    /// <summary>
    /// Summary description for AxControl.
    /// </summary>
    public class AxControl : AxHost 
    {
        public AxControl(string strCLSID) : base(strCLSID) 
        {
        }
    }

    /// <summary>
    /// Summary description for AxForm.
    /// </summary>
    public class AxForm : Form
    {
        private AxControl m_axCtrl;
        private Container components = null;

        public AxForm(string strProgId)
        {
            InitializeComponent(strProgId);

            // TODO: Add any initialization after the InitForm call
        }


        protected override void Dispose(bool disposing)
        {
            if (disposing)
                if (components != null)
                    components.Dispose();
            base.Dispose(disposing);
        }

        private void InitializeComponent(string strProgId)
        {
            ResourceManager resources = new ResourceManager(typeof(AxForm));    

            Type type = Type.GetTypeFromProgID(strProgId, true);
            m_axCtrl = new AxControl(type.GUID.ToString());

            ((ISupportInitialize)(m_axCtrl)).BeginInit();
            SuspendLayout();

            m_axCtrl.Enabled = true;
            m_axCtrl.Name = "axCtrl";
            m_axCtrl.TabIndex = 0;

            Controls.Add(m_axCtrl);
            Name = "AxForm";
            ((ISupportInitialize)(m_axCtrl)).EndInit();
            Resize += new EventHandler(AxForm_Resize);
            ResumeLayout(false);
            OnResize();
            Show();
        }

        private void OnResize()
        {
            m_axCtrl.Width = Width;
            m_axCtrl.Height = Height;
        }

        private void AxForm_Resize(object sender, EventArgs e)
        {
            OnResize();
        }
    }
}

In this particular implementation, the hosted ActiveX control is resized to fit the form whenever it's resized - hence the need for the AxForm_Resize handler. Obviously, other implementations might want to arrange the controls differently on the form. The code would need to change, but the same idea can be used - using AxControl as an intermediate class to AxHost. Incidentally, this shows a C# implementation, but the technique is equally applicable to VB.NET.

To use the class, you only need to know the ProgID of the ActiveX control you want to host. For example:

C#
m_axForm = new AxForms.AxForm("OWC.Spreadsheet.9");

The nugatory sample code supplied demonstrates how you might use the class in your application. It has a couple of hard coded ProgIDs for the OWC spreadsheet and the Outlook control. Obviously, these will only work if these are registered on your system. Alternatively, a third option allows you to enter the ProgID of the control you want to instantiate. Note, I have omitted any error checking in the sample code for clarity.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead
United Kingdom United Kingdom
When Dave isn't trying to play drums, fly helicopters or race cars, he can be found coding hard and herding cats at JoinIn Networks He must try harder!

You can read Dave's ramblings in his blog Aliens Ate My GUI

Or, if you can be bothered, he twitters on BoomerDave

Comments and Discussions

 
Generalclass not registered Pin
simonchen.net13-Sep-11 5:17
simonchen.net13-Sep-11 5:17 
GeneralRe: class not registered Pin
simonchen.net13-Sep-11 5:30
simonchen.net13-Sep-11 5:30 
QuestionVista 64 BIt. Pin
Prem Alva17-Dec-08 14:21
Prem Alva17-Dec-08 14:21 
GeneralIt would be really good .... But..... Pin
tony697-Dec-07 0:07
tony697-Dec-07 0:07 
QuestionHow to set event callback? Pin
Goldbach20-Sep-07 2:22
Goldbach20-Sep-07 2:22 
QuestionHow to get the ProgID? Pin
jason_mf12-Jun-07 15:38
jason_mf12-Jun-07 15:38 
GeneralDynamically adding Ax and accessing control specific properties Pin
rurouniRonin12-Mar-07 9:28
rurouniRonin12-Mar-07 9:28 
GeneralRe: Dynamically adding Ax and accessing control specific properties Pin
cstrader2321-Jul-07 14:45
cstrader2321-Jul-07 14:45 
GeneralUnloading activex Pin
mailhacker7-Feb-07 4:37
mailhacker7-Feb-07 4:37 
GeneralDoesn't work in .NET 2.0 Pin
canter25-Sep-06 5:51
canter25-Sep-06 5:51 
GeneralRe: Doesn't work in .NET 2.0 Pin
David M Brooks11-Dec-06 3:12
David M Brooks11-Dec-06 3:12 
GeneralRe: Doesn't work in .NET 2.0 Pin
tanya_kuraeva5-Oct-09 2:31
tanya_kuraeva5-Oct-09 2:31 
GeneralRe: Doesn't work in .NET 2.0 Pin
willyong11-Dec-09 10:50
willyong11-Dec-09 10:50 
Generaluseful article Pin
cheesesarnie23-Aug-06 21:59
cheesesarnie23-Aug-06 21:59 
GeneralTHANK YOU VERY MUCH!!!! Pin
LomboAgridoce18-Jul-06 21:08
LomboAgridoce18-Jul-06 21:08 
QuestionHow to replace VBcontrolExtender functioality in VB.NET Pin
PatMcHargue16-May-06 6:56
PatMcHargue16-May-06 6:56 
Folks;

I have looked at the article By David Broooks, "Dynamically adding ActiveX controls in managed code", but I am still uncertain about how I can replace the VB6 'VBcontrolExtender' functional under VB.NET in order to add OCXes to my application at run time.

I have a few years of code in the OCXes that I am trying to host this way. Each OCX represents an interface to data aqcquisition hardware, and in my current VB6 application, is dynamicallty loaded depending on which piece of hardware the user wishes to connect to.

Without going into too much detail, compiling the application with all of the OCXes in it would force me to distribute an awful lot of code - which is why I was using the VBcontrolExtender under VB6 in the first place.

Following the code example by David Broooks, I can add an OCX to a form at run time, but I do not know how to get 'ObjectEvent' messages from the OCX's that I have added to the form.


I have looked high & low for a solution to this, but I am not yet expert enough in VB.NET to figure this out.

Confused | :confused:

A friend of Liberty is a friend of mine!

www.lp.org

QuestionHow to use method activeX control Pin
contactdev2-May-06 6:00
contactdev2-May-06 6:00 
AnswerRe: How to use method activeX control Pin
PatMcHargue16-May-06 7:17
PatMcHargue16-May-06 7:17 
GeneralRe: How to use method activeX control Pin
brianbruffIRL22-Jan-07 0:27
brianbruffIRL22-Jan-07 0:27 
GeneralRe: How to use method activeX control Pin
Jeffrey.Knight22-Jul-08 11:39
Jeffrey.Knight22-Jul-08 11:39 
QuestionRe: How to use method activeX control Pin
esub7-Nov-08 4:18
esub7-Nov-08 4:18 
GeneralRe: How to use Events of activeX control Pin
esub7-Nov-08 4:20
esub7-Nov-08 4:20 
QuestionRe: How to use method activeX control Pin
esub7-Nov-08 4:22
esub7-Nov-08 4:22 
AnswerHow to use Events of activeX control Pin
esub7-Nov-08 4:21
esub7-Nov-08 4:21 
GeneralSome Doubts Pin
milanboi26-Feb-06 18:33
milanboi26-Feb-06 18:33 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.