Click here to Skip to main content
Click here to Skip to main content
Articles » Languages » VB6 Interop » General » Downloads
 
Add your own
alternative version

Interop Forms Toolkit 2.0 Tutorial

, 16 Jun 2007 CPOL
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.
csharp_samples.zip
XamlUserControl
bin
Debug
XamlUserControl.dll
images
roundcornersheet.png
Star.png
obj
Debug
TempPE
UserControl1.baml
XamlUserControl.dll
Properties
Settings.settings
CSDailyDilbertControl
CSDailyDilbertControl
bin
Debug
CSDailyDilbertControl.dll
CSDailyDilbertControl.tlb
Dilbert.bmp
InteropUserControl.bmp
InteropUserControl.manifest
InteropUserControl.res
obj
Debug
CSDailyDilbertControl.dll
Refactor
TempPE
Web References.DDService.Reference.cs.dll
Properties
Settings.settings
Web References
DDService
DailyDiblert.disco
DailyDiblert.wsdl
Reference.map
CSMultithreadedControl
CSMultithreadedControl
bin
Debug
obj
Debug
Refactor
TempPE
Properties
CSXamlEmbeddedForm
CSXamlEmbeddedForm
bin
Debug
CSXamlEmbeddedForm.dll
CSXamlEmbeddedForm.tlb
PresentationCore.dll
System.Printing.dll
XamlUserControl.dll
InteropForm Wrapper Classes
obj
Debug
CSXamlEmbeddedForm.dll
Refactor
TempPE
Documents and Settings
jashley.CORPORATE
My Documents
Visual Studio 2005
Projects
CSMultithreadedControl
CSMultithreadedControl
bin
Debug
obj
Debug
Refactor
TempPE
Properties
bin
Debug
obj
Debug
Refactor
TempPE
Properties
InteropUserControl.bmp
InteropUserControl.manifest
InteropUserControl.res
csinteropusercontrolitemtemplate.zip
__TemplateIcon.ico
InteropUserControl.vstemplate
csinteropusercontrolprojecttemplate.zip
InteropUserControl.manifest
InteropUserControl.res
__TemplateIcon.ico
csinteropusercontrollibrary.vstemplate
InteropUserControl.bmp
source_code.zip
DailyDilbertControl
DailyDilbertControl
bin
Debug
DailyDilbertControl.dll
DailyDilbertControl.tlb
Dilbert.bmp
InteropUserControl.bmp
InteropUserControl.manifest
InteropUserControl.RES
My Project
Application.myapp
Settings.settings
obj
Debug
DailyDilbertControl.dll
TempPE
My Project.Resources.Designer.vb.dll
Web References.DDService.Reference.vb.dll
Resources
Web References
DDService
DailyDiblert.disco
DailyDiblert.wsdl
Reference.map
XamlUserControl.dll
roundcornersheet.png
Star.png
UserControl1.baml
XamlUserControl.dll
Settings.settings
MultithreadedControl
bin
Debug
MultithreadedControl.dll
MultithreadedControl.tlb
InteropUserControl.bmp
InteropUserControl.manifest
InteropUserControl.res
My Project
Application.myapp
obj
Debug
MultithreadedControl.dll
TempPE
VB6Project
Form1.frm
Project1.vbp
Project1.vbw
XamlEmbeddedForm
bin
Debug
PresentationCore.dll
System.Printing.dll
XamlEmbeddedForm.dll
XamlEmbeddedForm.tlb
XamlUserControl.dll
XamlUserControl.pdb
zh-CHS
PresentationCore.resources.dll
System.Printing.resources.dll
InteropForm Wrapper Classes
My Project
Application.myapp
Settings.settings
obj
Debug
TempPE
XamlEmbeddedForm.dll
VB6Project
Form1.frm
Project1.vbp
Project1.vbw
using System;
using System.Text;
using System.Windows.Forms;
using Microsoft.InteropFormTools;
using Microsoft.VisualBasic.Logging;
using Microsoft.VisualBasic.ApplicationServices;
using Microsoft.VisualBasic.Devices;
using Microsoft.Win32;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Diagnostics;

#if COM_INTEROP_ENABLED
sealed class ComRegistration
{
    private ComRegistration()
    {
    }

    const int OLEMISC_RECOMPOSEONRESIZE = 1;
    const int OLEMISC_CANTLINKINSIDE = 16;
    const int OLEMISC_INSIDEOUT = 128;
    const int OLEMISC_ACTIVATEWHENVISIBLE = 256;
    const int OLEMISC_SETCLIENTSITEFIRST = 131072;

    public static void RegisterControl(System.Type t, string BitmapId)
    {
        try
        {
            GuardNullType(t, "t");
            GuardTypeIsControl(t);

            //CLSID
            string key = @"CLSID\" + t.GUID.ToString("B");

            using (RegistryKey subkey = Registry.ClassesRoot.OpenSubKey(key, true))
            {

                //InProcServer32
                RegistryKey InprocKey = subkey.OpenSubKey("InprocServer32", true);
                if (InprocKey != null)
                {
                    InprocKey.SetValue(null, Environment.SystemDirectory + @"\mscoree.dll");
                }

                //Control
                using (RegistryKey controlKey = subkey.CreateSubKey("Control"))
                { }

                //Misc
                using (RegistryKey miscKey = subkey.CreateSubKey("MiscStatus"))
                {
                    int MiscStatusValue = OLEMISC_RECOMPOSEONRESIZE +
                        OLEMISC_CANTLINKINSIDE + OLEMISC_INSIDEOUT +
                        OLEMISC_ACTIVATEWHENVISIBLE + OLEMISC_SETCLIENTSITEFIRST;

                    miscKey.SetValue("", MiscStatusValue.ToString(), RegistryValueKind.String);
                }

                //ToolBoxBitmap32
                using (RegistryKey bitmapKey = subkey.CreateSubKey("ToolBoxBitmap32"))
                {
                    //'If you want to have different icons for each control in this assembly
                    //'you can modify this section to specify a different icon each time.
                    //'Each specified icon must be embedded as a win32resource in the
                    //'assembly; the default one is at index 101, but you can add additional ones.
                    bitmapKey.SetValue("", Assembly.GetExecutingAssembly().Location + ", " + BitmapId,
                                       RegistryValueKind.String);
                }

                //TypeLib
                using (RegistryKey typeLibKey = subkey.CreateSubKey("TypeLib"))
                {
                    Guid libId = Marshal.GetTypeLibGuidForAssembly(t.Assembly);
                    typeLibKey.SetValue("", libId.ToString("B"), RegistryValueKind.String);
                }

                //Version
                using (RegistryKey versionKey = subkey.CreateSubKey("Version"))
                {
                    int major, minor;
                    Marshal.GetTypeLibVersionForAssembly(t.Assembly, out major, out minor);
                    versionKey.SetValue("", String.Format("{0}.{1}", major, minor));
                }

            }
            string sSource;
            string sLog;
            string sEvent;

            sSource = "Host .NET Interop UserControl in VB6";
            sLog = "Application";
            sEvent = "Registration successful: key = " + key;

            if (!EventLog.SourceExists(sSource))
                EventLog.CreateEventSource(sSource, sLog);

            EventLog.WriteEntry(sSource, sEvent, EventLogEntryType.Warning, 234);
        }
        catch (Exception ex)
        {
            LogAndRethrowException("ComRegisterFunction failed.", t, ex);
        }
    }

    public static void UnregisterControl(Type t)
    {
        try
        {
            GuardNullType(t, "t");
            GuardTypeIsControl(t);

            //CLSID
            string key = @"CLSID\" + t.GUID.ToString("B");
            Registry.ClassesRoot.DeleteSubKeyTree(key);
        }
        catch (Exception ex)
        {
            LogAndRethrowException("ComUnregisterFunction failed.", t, ex);
        }

    }

    private static void GuardNullType(Type t, string param)
    {
        if (null == t)
        {
            throw new ArgumentException("The CLR type must be specified.", param);
        }
    }


    private static void GuardTypeIsControl(Type t)
    {
        if (!typeof(System.Windows.Forms.Control).IsAssignableFrom(t))
        {
            throw new ArgumentException("Type argument must be a Windows Forms control.");
        }
    }

    private static void LogAndRethrowException(string message, Type t, Exception ex)
    {
        try
        {
            if (null != t)
            {
                message += Environment.NewLine + String.Format("CLR class '{0}'", t.FullName);
            }

            throw new ComRegistrationException(message, ex);
        }
        catch (Exception ex2)
        {
            string sSource;
            string sLog;
            string sEvent;

            sSource = "Host .NET Interop UserControl in VB6";
            sLog = "Application";
            sEvent = t.GUID.ToString("B") + " registration failed: " + Environment.NewLine + ex2.Message;

            if (!EventLog.SourceExists(sSource))
                EventLog.CreateEventSource(sSource, sLog);

            EventLog.WriteEntry(sSource, sEvent, EventLogEntryType.Warning, 234);
        }
    }
}

[Serializable()]
public class ComRegistrationException : Exception
{
    public ComRegistrationException() { }
    public ComRegistrationException(string message, Exception inner)
        : base(message, inner)
    {
    }
}



//Helper functions to convert common COM types to their .NET equivalents
[ComVisible(false)]
internal sealed class ActiveXControlHelpers : System.Windows.Forms.AxHost
{
    internal ActiveXControlHelpers()
        : base(null)
    {
    }

    internal static System.Drawing.Color GetColorFromOleColor(int oleColor)
    {
        return AxHost.GetColorFromOleColor(CIntToUInt(oleColor));
    }

    internal static new int GetOleColorFromColor(System.Drawing.Color color)
    {
        return CUIntToInt(AxHost.GetOleColorFromColor(color));
    }

    internal static int CUIntToInt(uint uiArg)
    {
        if (uiArg <= int.MaxValue)
        {
            return (int)uiArg;
        }

        return (int)(uiArg - unchecked(2 * ((uint)(int.MaxValue) + 1)));
    }

    internal static uint CIntToUInt(int iArg)
    {
        if (iArg < 0)
        {
            return (uint)(uint.MaxValue + iArg + 1);
        }
        return (uint)iArg;
    }

    private const int KEY_PRESSED = 0x1000;

    [DllImport("user32.dll")]
    static extern short GetKeyState(int nVirtKey);

    private static int CheckForAccessorKey()
    {
        Keyboard keyboard = new Keyboard();
        if (keyboard.AltKeyDown)
        {
            for (int i = (int)Keys.A; i <= (int)Keys.Z; i++)
            {
                if ((GetKeyState(i) != 0 && KEY_PRESSED != 0))
                {
                    return i;
                }
            }
        }
        return -1;
    }


    [ComVisible(false)]
    internal static void HandleFocus(UserControl f)
    {
        Keyboard keyboard = new Keyboard();
        if (keyboard.AltKeyDown)
        {
            HandleAccessorKey(f.GetNextControl(null, true), f);
        }
        else
        {
            //Move to the first control that can receive focus, taking into account
            //the possibility that the user pressed <Shift>+<Tab>, in which case we
            //need to start at the end and work backwards.
            System.Windows.Forms.Control ctl = f.GetNextControl(null, !keyboard.ShiftKeyDown);
            while (null != ctl)
            {
                if (ctl.Enabled && ctl.CanSelect)
                {
                    ctl.Focus();
                    break;
                }
                else
                {
                    ctl = f.GetNextControl(ctl, !keyboard.ShiftKeyDown);
                }
            }
        }
    }

    private static void HandleAccessorKey(object sender, UserControl f)
    {
        int key = CheckForAccessorKey();
        if (key == -1)
            return;

        Control ctlCurrent = f.GetNextControl((Control)sender, false);

        do
        {
            ctlCurrent = f.GetNextControl(ctlCurrent, true);
            if (ctlCurrent != null && Control.IsMnemonic(Convert.ToChar(key), ctlCurrent.Text))
            {
                //'VB6 handles conflicts correctly already, so if we handle it also we'll end up 
                //'one control past where the focus should be
                if (!KeyConflict(Convert.ToChar(key), f))
                {

                    //'If we land on a label or other non-selectable control then go to the next 
                    //'control in the tab order
                    if (!ctlCurrent.CanSelect)
                    {
                        Control ctlAfterLabel = f.GetNextControl(ctlCurrent, true);
                        if (ctlAfterLabel != null && ctlAfterLabel.CanFocus)
                        {
                            ctlAfterLabel.Focus();
                        }
                    }
                    else
                    {
                        ctlCurrent.Focus();
                    }
                    break;
                }
            }

            //'Loop until we hit the end of the tab order
            //'If we've hit the end of the tab order we don't want to loop back because the
            //'parent form's controls come next in the tab order.
        } while (ctlCurrent != null);
    }


    private static bool KeyConflict(char key, UserControl u)
    {
        bool flag = false;
        foreach (Control ctl in u.Controls)
        {
            if (Control.IsMnemonic(key, ctl.Text))
            {
                if (flag)
                {
                    return true;
                }
                flag = true;
            }
        }
        return false;
    }

    //Handles <Tab> and <Shift>+<Tab>
    internal static void TabHandler(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Tab)
        {
            Control ctl = sender as Control;
            UserControl userCtl = GetParentUserControl(ctl);
            Control firstCtl = userCtl.GetNextControl(null, true);
            do
            {
                firstCtl = userCtl.GetNextControl(firstCtl, true);
            } while (firstCtl != null && !firstCtl.CanSelect);

            Control lastCtl = userCtl.GetNextControl(null, false);
            do
            {
                lastCtl = userCtl.GetNextControl(lastCtl, false);
            } while (lastCtl != null && lastCtl.CanSelect);

            if (ctl.Equals(lastCtl) || ctl.Equals(firstCtl) || lastCtl.Contains(ctl) || firstCtl.Contains(ctl))
            {
                userCtl.SelectNextControl((Control)sender, lastCtl.Equals(userCtl.ActiveControl), true, true, true);
            }
        }
    }

    private static UserControl GetParentUserControl(Control ctl)
    {
        if (ctl == null)
        {
            return null;
        }

        do
        {
            ctl = ctl.Parent;
        } while (ctl.Parent != null);

        if (ctl != null)
        {
            return (UserControl)ctl;
        }

        return null;
    }

    internal static void WireUpHandlers(Control ctl, EventHandler ValidationHandler)
    {
        if (ctl != null)
        {
            ctl.KeyDown += new KeyEventHandler(TabHandler);
            ctl.LostFocus += new EventHandler(ValidationHandler);

            if (ctl.HasChildren)
            {
                foreach (Control child in ctl.Controls)
                {
                    WireUpHandlers(child, ValidationHandler);
                }
            }
        }
    }
}

#endif

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)

Share

About the Author

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

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.1411023.1 | Last Updated 16 Jun 2007
Article Copyright 2007 by James Ashley
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid