Click here to Skip to main content
15,879,326 members
Articles / Desktop Programming / Windows Forms

Interop Forms Toolkit 2.0 Tutorial

Rate me:
Please Sign up or sign in to vote.
4.84/5 (62 votes)
16 Jun 2007CPOL16 min read 483K   13.8K   149  
Interop Forms Toolkit 2.0 is a new bridging tool allowing developers to use .NET Forms and .NET UserControls in VB6. This tutorial demonstrates how to add webservices, multithreading, and XAML to VB6 projects. It also provides custom C# Interop UserControl templates for use with the Toolkit.
using System.ComponentModel;
using System.Runtime.InteropServices;
using Microsoft.VisualBasic;
using System.Windows.Forms;
using System.Security.Permissions;
using System.Drawing;


namespace CSMultithreadedControl
{
    // Nested Types
    [ComVisible(true), Guid(BackgroundWorker.EventsId), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    public interface __BackgroundWorker
    {
        [DispId(1)]
        void Click();
        [DispId(2)]
        void DblClick();
        [DispId(3)]
        void StartEvent(string simpleEventText);
        [DispId(4)]
        void FinishAsyncEvent(string asyncEventText);
    }

    [Guid(BackgroundWorker.InterfaceId), ComVisible(true)]
    public interface _BackgroundWorker
    {
        [DispId(1)]
        bool Visible { [DispId(1)] get; [DispId(1)] set; }
        [DispId(2)]
        bool Enabled { [DispId(2)] get; [DispId(2)] set; }
        [DispId(3)]
        int ForegroundColor { [DispId(3)] get; [DispId(3)] set; }
        [DispId(4)]
        int BackgroundColor { [DispId(4)] get; [DispId(4)] set; }
        [DispId(5)]
        Image BackgroundImage { [DispId(5)] get; [DispId(5)] set; }
        [DispId(6)]
        void Refresh();
        [DispId(7)]
        void StartProcessing();
    }

    [Guid(BackgroundWorker.ClassId), ClassInterface(ClassInterfaceType.None)]
    [ComSourceInterfaces("CSMultithreadedControl.__BackgroundWorker")]
    [ComClass(BackgroundWorker.ClassId, BackgroundWorker.InterfaceId, BackgroundWorker.EventsId)]
    public partial class BackgroundWorker : UserControl, _BackgroundWorker
    {
        #region VB6 Interop Code

#if COM_INTEROP_ENABLED

        #region "COM Registration"

        //These  GUIDs provide the COM identity for this class 
        //and its COM interfaces. If you change them, existing 
        //clients will no longer be able to access the class.

        public const string ClassId = "b2de35de-e9f6-4cdc-a519-aa5aacd50e58";
        public const string InterfaceId = "9208d266-f8b3-496d-92ef-789acbb2cf32";
        public const string EventsId = "3a76eaf7-c224-4546-b648-88ecb011576c";

        //These routines perform the additional COM registration needed by ActiveX controls
        [EditorBrowsable(EditorBrowsableState.Never)]
        [ComRegisterFunction]
        private static void Register(System.Type t)
        {
            ComRegistration.RegisterControl(t);
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        [ComUnregisterFunction]
        private static void Unregister(System.Type t)
        {
            ComRegistration.UnregisterControl(t);
        }


        #endregion

        #region "VB6 Events"

        //This section shows some examples of exposing a UserControl's events to VB6.  Typically, you just
        //1) Declare the event as you want it to be shown in VB6
        //2) Raise the event in the appropriate UserControl event.
        public delegate void ClickEventHandler();
        public delegate void DblClickEventHandler();
        public new event ClickEventHandler Click; //Event must be marked as new since .NET UserControls have the same name.
        public event DblClickEventHandler DblClick;

        private void InteropUserControl_Click(object sender, System.EventArgs e)
        {
            if (null != Click)
                Click();
        }

        // Handles Me.DoubleClick
        private void InteropUserControl_DblClick(object sender, System.EventArgs e)
        {
            if (null != DblClick)
                DblClick();
        }

        private void InteropUserControl_Load(object sender, System.EventArgs e)
        {
            this.progressBar1.Value = 0;
            this.labelWarningMessage.Visible = false;
        }

        #endregion

        #region "VB6 Properties"

        //The following are examples of how to expose typical form properties to VB6.  
        //You can also use these as examples on how to add additional properties.

        //Must Shadow this property as it exists in Windows.Forms and is not overridable
        public new bool Visible
        {
            get { return base.Visible; }
            set { base.Visible = value; }
        }

        public new bool Enabled
        {
            get { return base.Enabled; }
            set { base.Enabled = value; }
        }

        public int ForegroundColor
        {
            get 
            {
                return ActiveXControlHelpers.GetOleColorFromColor(base.ForeColor);
            }
            set
            {
                base.ForeColor = ActiveXControlHelpers.GetColorFromOleColor(value);
            }
        }

        public int BackgroundColor
        {
            get
            {
                return ActiveXControlHelpers.GetOleColorFromColor(base.BackColor);
                }
            set
            {
                base.BackColor = ActiveXControlHelpers.GetColorFromOleColor(value);
            }
        }

        public override System.Drawing.Image BackgroundImage
        {
            get{return null;}
            set
            {
                if(null != value)
                {
                    MessageBox.Show("Setting the background image of an Interop UserControl is not supported, please use a PictureBox instead.", "Information");
                }
                base.BackgroundImage = null;
            }
        }

        #endregion

        #region "VB6 Methods"

            public override void Refresh()
            {
                base.Refresh();
            }

            //Ensures that tabbing across VB6 and .NET controls works as expected
            private void InteropUserControl_LostFocus(object sender, System.EventArgs e)
            {
                ActiveXControlHelpers.HandleFocus(this);
            }

            public BackgroundWorker()
            {
                //This call is required by the Windows Form Designer.
                InitializeComponent();
                //' Add any initialization after the InitializeComponent() call.
                base.Click += new System.EventHandler(InteropUserControl_Click);
                this.DoubleClick += new System.EventHandler(InteropUserControl_DblClick);
                this.ControlAdded += new System.Windows.Forms.ControlEventHandler(this.InteropUserControl_ControlAdded);

                this.LostFocus += new System.EventHandler(InteropUserControl_LostFocus); 
                this.ControlAdded += new ControlEventHandler(InteropUserControl_ControlAdded);
                

                //'Raise Load event
                    this.OnCreateControl();
            }

            [SecurityPermission(SecurityAction.LinkDemand, Flags =SecurityPermissionFlag.UnmanagedCode)]
            protected override void WndProc(ref System.Windows.Forms.Message m)
            {

                const int WM_SETFOCUS = 0x7;
                const int WM_PARENTNOTIFY = 0x210;
                const int WM_DESTROY = 0x2;
                const int WM_LBUTTONDOWN = 0x201;
                const int WM_RBUTTONDOWN = 0x204;

                if (m.Msg == WM_SETFOCUS)
                {
                    //Raise Enter event
                    this.OnEnter(System.EventArgs.Empty);
                }
                else if( m.Msg == WM_PARENTNOTIFY && (m.WParam.ToInt32() == WM_LBUTTONDOWN || m.WParam.ToInt32() == WM_RBUTTONDOWN))
                {

                    if (!this.ContainsFocus)
                    {
                        //Raise Enter event
                        this.OnEnter(System.EventArgs.Empty);
                    }
                }
                else if (m.Msg == WM_DESTROY && !this.IsDisposed && !this.Disposing)
                {
                    //Used to ensure that VB6 will cleanup control properly
                    this.Dispose();
                }

                base.WndProc(ref m);
            }



            //This event will hook up the necessary handlers
            private void InteropUserControl_ControlAdded(object sender, ControlEventArgs e)
            {
                ActiveXControlHelpers.WireUpHandlers(e.Control, ValidationHandler);
            }

            //Ensures that the Validating and Validated events fire appropriately
            internal void ValidationHandler(object sender, System.EventArgs e)
            {
                if( this.ContainsFocus) return;

                //Raise Leave event
                this.OnLeave(e);

                if (this.CausesValidation)
                {
                    CancelEventArgs validationArgs = new CancelEventArgs();
                    this.OnValidating(validationArgs);

                    if(validationArgs.Cancel && this.ActiveControl != null)
                        this.ActiveControl.Focus();
                    else
                    {
                        //Raise Validated event
                        this.OnValidated(e);
                    }
                }

            }

        #endregion

        public delegate void StartEventHandler(string simpleEventText);
        public delegate void FinishAsyncEventHandler(string asyncEventText);

        public event StartEventHandler StartEvent;
        public event FinishAsyncEventHandler FinishAsyncEvent;

        public void StartProcessing()
        {   
            if(StartEvent != null)
                StartEvent(".NET process starting");
            this.backgroundWorker1.RunWorkerAsync();
        }
        int prog = 0;
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            //wait
            prog = 0;
            while (prog < 100)
            {
                System.Threading.Thread.Sleep(100);
                prog = prog + 2;
                this.backgroundWorker1.ReportProgress(prog);
            }
            prog = 0;
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.labelWarningMessage.ForeColor = Color.Red;
            this.labelWarningMessage.Text = "Working in background...";
            this.labelWarningMessage.Visible = true;
            this.progressBar1.Value = e.ProgressPercentage;
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            this.labelWarningMessage.Visible = false;
            if (FinishAsyncEvent != null)
                FinishAsyncEvent("Interop User Control process finished.");
        }

#endif

        #endregion

        //Please enter any new code here, below the Interop code
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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


Written By
Software Developer (Senior)
United States United States
James is a program writer for a respectable software company. He is also a Microsoft MVP.

Comments and Discussions